about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/dependencies.yml9
-rw-r--r--.mailmap1
-rw-r--r--Cargo.lock55
-rw-r--r--Cargo.toml9
-rw-r--r--compiler/rustc_ast/src/ast.rs22
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs3
-rw-r--r--compiler/rustc_ast/src/token.rs6
-rw-r--r--compiler/rustc_ast/src/tokenstream.rs13
-rw-r--r--compiler/rustc_ast/src/visit.rs9
-rw-r--r--compiler/rustc_ast_lowering/src/block.rs4
-rw-r--r--compiler/rustc_ast_lowering/src/delegation.rs7
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs9
-rw-r--r--compiler/rustc_ast_lowering/src/index.rs4
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs4
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs65
-rw-r--r--compiler/rustc_ast_lowering/src/pat.rs3
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs3
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs6
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/expr.rs20
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs8
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs6
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs6
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs4
-rw-r--r--compiler/rustc_borrowck/src/lib.rs6
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs2
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs9
-rw-r--r--compiler/rustc_borrowck/src/type_check/canonical.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs25
-rw-r--r--compiler/rustc_builtin_macros/src/assert/context.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/debug.rs5
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/encodable.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs10
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/type_ascribe.rs35
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/mod.rs20
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs9
-rw-r--r--compiler/rustc_codegen_cranelift/src/common.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/lib.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/src/unsize.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/src/value_and_place.rs9
-rw-r--r--compiler/rustc_codegen_gcc/src/context.rs4
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/simd.rs24
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs34
-rw-r--r--compiler/rustc_codegen_ssa/Cargo.toml1
-rw-r--r--compiler/rustc_codegen_ssa/messages.ftl3
-rw-r--r--compiler/rustc_codegen_ssa/src/back/command.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs17
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/common.rs5
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs7
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs49
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/debuginfo.rs5
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/intrinsic.rs24
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs14
-rw-r--r--compiler/rustc_codegen_ssa/src/size_of_val.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/backend.rs7
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/builder.rs54
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/type_.rs14
-rw-r--r--compiler/rustc_const_eval/src/const_eval/dummy_machine.rs193
-rw-r--r--compiler/rustc_const_eval/src/const_eval/mod.rs27
-rw-r--r--compiler/rustc_const_eval/src/const_eval/valtrees.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/cast.rs12
-rw-r--r--compiler/rustc_const_eval/src/interpret/discriminant.rs158
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs27
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs17
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs12
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs2
-rw-r--r--compiler/rustc_const_eval/src/lib.rs1
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs2
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs34
-rw-r--r--compiler/rustc_const_eval/src/util/type_name.rs2
-rw-r--r--compiler/rustc_data_structures/src/sync.rs9
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs4
-rw-r--r--compiler/rustc_driver_impl/src/signal_handler.rs6
-rw-r--r--compiler/rustc_expand/messages.ftl3
-rw-r--r--compiler/rustc_expand/src/build.rs4
-rw-r--r--compiler/rustc_expand/src/errors.rs8
-rw-r--r--compiler/rustc_expand/src/mbe/macro_parser.rs17
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs8
-rw-r--r--compiler/rustc_expand/src/mbe/quoted.rs8
-rw-r--r--compiler/rustc_expand/src/mbe/transcribe.rs31
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs7
-rw-r--r--compiler/rustc_feature/src/unstable.rs4
-rw-r--r--compiler/rustc_hir/src/def.rs2
-rw-r--r--compiler/rustc_hir/src/hir.rs54
-rw-r--r--compiler/rustc_hir/src/intravisit.rs10
-rw-r--r--compiler/rustc_hir/src/lang_items.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/bounds.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs13
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs11
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs49
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsicck.rs26
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs21
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs151
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs68
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs77
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs12
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs36
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs (renamed from compiler/rustc_hir_analysis/src/astconv/bounds.rs)167
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs (renamed from compiler/rustc_hir_analysis/src/astconv/errors.rs)20
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs (renamed from compiler/rustc_hir_analysis/src/astconv/generics.rs)40
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs (renamed from compiler/rustc_hir_analysis/src/astconv/lint.rs)4
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs (renamed from compiler/rustc_hir_analysis/src/astconv/mod.rs)714
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs (renamed from compiler/rustc_hir_analysis/src/astconv/object_safety.rs)38
-rw-r--r--compiler/rustc_hir_analysis/src/hir_wf_check.rs12
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs22
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs31
-rw-r--r--compiler/rustc_hir_analysis/src/variance/constraints.rs6
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs12
-rw-r--r--compiler/rustc_hir_typeck/messages.ftl2
-rw-r--r--compiler/rustc_hir_typeck/src/_match.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs31
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs22
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs28
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs9
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs55
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/fallback.rs36
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs99
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs48
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs151
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs55
-rw-r--r--compiler/rustc_hir_typeck/src/gather_locals.rs18
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/mem_categorization.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs34
-rw-r--r--compiler/rustc_hir_typeck/src/method/mod.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs11
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs23
-rw-r--r--compiler/rustc_hir_typeck/src/op.rs18
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs33
-rw-r--r--compiler/rustc_hir_typeck/src/place_op.rs12
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs12
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs2
-rw-r--r--compiler/rustc_incremental/src/persist/dirty_clean.rs2
-rw-r--r--compiler/rustc_index_macros/src/lib.rs8
-rw-r--r--compiler/rustc_index_macros/src/newtype.rs28
-rw-r--r--compiler/rustc_infer/messages.ftl2
-rw-r--r--compiler/rustc_infer/src/errors/mod.rs13
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs25
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs81
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs71
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs16
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/suggest.rs7
-rw-r--r--compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs19
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types/mod.rs3
-rw-r--r--compiler/rustc_infer/src/infer/outlives/verify.rs2
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/mod.rs2
-rw-r--r--compiler/rustc_infer/src/lib.rs1
-rw-r--r--compiler/rustc_infer/src/traits/mod.rs2
-rw-r--r--compiler/rustc_infer/src/traits/util.rs2
-rw-r--r--compiler/rustc_interface/src/interface.rs55
-rw-r--r--compiler/rustc_interface/src/tests.rs5
-rw-r--r--compiler/rustc_interface/src/util.rs33
-rw-r--r--compiler/rustc_lexer/src/cursor.rs11
-rw-r--r--compiler/rustc_lint/src/builtin.rs6
-rw-r--r--compiler/rustc_lint/src/context.rs4
-rw-r--r--compiler/rustc_lint/src/foreign_modules.rs6
-rw-r--r--compiler/rustc_lint/src/late.rs2
-rw-r--r--compiler/rustc_lint/src/let_underscore.rs2
-rw-r--r--compiler/rustc_lint/src/levels.rs4
-rw-r--r--compiler/rustc_lint/src/passes.rs2
-rw-r--r--compiler/rustc_lint/src/reference_casting.rs6
-rw-r--r--compiler/rustc_lint/src/types.rs16
-rw-r--r--compiler/rustc_lint/src/unit_bindings.rs2
-rw-r--r--compiler/rustc_lint/src/unused.rs10
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs14
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs1
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs8
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs1
-rw-r--r--compiler/rustc_middle/Cargo.toml1
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs18
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs18
-rw-r--r--compiler/rustc_middle/src/macros.rs28
-rw-r--r--compiler/rustc_middle/src/mir/consts.rs2
-rw-r--r--compiler/rustc_middle/src/mir/coverage.rs5
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation.rs42
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs48
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs2
-rw-r--r--compiler/rustc_middle/src/mir/query.rs12
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs14
-rw-r--r--compiler/rustc_middle/src/mir/tcx.rs6
-rw-r--r--compiler/rustc_middle/src/query/erase.rs1
-rw-r--r--compiler/rustc_middle/src/query/keys.rs9
-rw-r--r--compiler/rustc_middle/src/query/mod.rs39
-rw-r--r--compiler/rustc_middle/src/thir.rs9
-rw-r--r--compiler/rustc_middle/src/thir/visit.rs1
-rw-r--r--compiler/rustc_middle/src/ty/cast.rs2
-rw-r--r--compiler/rustc_middle/src/ty/context.rs10
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs28
-rw-r--r--compiler/rustc_middle/src/ty/error.rs4
-rw-r--r--compiler/rustc_middle/src/ty/fast_reject.rs8
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs4
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs6
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs82
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs34
-rw-r--r--compiler/rustc_middle/src/ty/predicate.rs12
-rw-r--r--compiler/rustc_middle/src/ty/print/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs32
-rw-r--r--compiler/rustc_middle/src/ty/region.rs1
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs66
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs4
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs39
-rw-r--r--compiler/rustc_middle/src/ty/util.rs48
-rw-r--r--compiler/rustc_middle/src/ty/walk.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/custom/mod.rs1
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/matches/util.rs6
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs3
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs8
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs1
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs3
-rw-r--r--compiler/rustc_mir_build/src/thir/print.rs6
-rw-r--r--compiler/rustc_mir_dataflow/src/elaborate_drops.rs9
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs4
-rw-r--r--compiler/rustc_mir_dataflow/src/value_analysis.rs2
-rw-r--r--compiler/rustc_mir_transform/src/check_alignment.rs4
-rw-r--r--compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs13
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs12
-rw-r--r--compiler/rustc_mir_transform/src/coroutine/by_move_body.rs9
-rw-r--r--compiler/rustc_mir_transform/src/coverage/counters.rs39
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs200
-rw-r--r--compiler/rustc_mir_transform/src/function_item_references.rs2
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs15
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs22
-rw-r--r--compiler/rustc_mir_transform/src/jump_threading.rs2
-rw-r--r--compiler/rustc_mir_transform/src/known_panics_lint.rs4
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs5
-rw-r--r--compiler/rustc_mir_transform/src/lower_intrinsics.rs21
-rw-r--r--compiler/rustc_mir_transform/src/mentioned_items.rs117
-rw-r--r--compiler/rustc_mir_transform/src/promote_consts.rs11
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs20
-rw-r--r--compiler/rustc_mir_transform/src/ssa.rs5
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs851
-rw-r--r--compiler/rustc_monomorphize/src/lib.rs22
-rw-r--r--compiler/rustc_monomorphize/src/partitioning.rs14
-rw-r--r--compiler/rustc_next_trait_solver/src/canonicalizer.rs5
-rw-r--r--compiler/rustc_parse/messages.ftl5
-rw-r--r--compiler/rustc_parse/src/errors.rs29
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs57
-rw-r--r--compiler/rustc_parse/src/lexer/unescape_error_reporting.rs20
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs47
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs59
-rw-r--r--compiler/rustc_parse/src/parser/item.rs14
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs49
-rw-r--r--compiler/rustc_parse/src/parser/nonterminal.rs15
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs22
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs20
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs2
-rw-r--r--compiler/rustc_passes/src/check_const.rs2
-rw-r--r--compiler/rustc_passes/src/dead.rs9
-rw-r--r--compiler/rustc_passes/src/hir_stats.rs4
-rw-r--r--compiler/rustc_passes/src/liveness.rs4
-rw-r--r--compiler/rustc_passes/src/reachable.rs2
-rw-r--r--compiler/rustc_pattern_analysis/Cargo.toml4
-rw-r--r--compiler/rustc_pattern_analysis/src/constructor.rs75
-rw-r--r--compiler/rustc_pattern_analysis/src/lib.rs9
-rw-r--r--compiler/rustc_pattern_analysis/src/pat.rs80
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs15
-rw-r--r--compiler/rustc_pattern_analysis/src/usefulness.rs25
-rw-r--r--compiler/rustc_pattern_analysis/tests/common/mod.rs315
-rw-r--r--compiler/rustc_pattern_analysis/tests/complexity.rs109
-rw-r--r--compiler/rustc_pattern_analysis/tests/exhaustiveness.rs77
-rw-r--r--compiler/rustc_pattern_analysis/tests/intersection.rs69
-rw-r--r--compiler/rustc_privacy/src/lib.rs4
-rw-r--r--compiler/rustc_resolve/src/late.rs48
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs21
-rw-r--r--compiler/rustc_session/src/code_stats.rs18
-rw-r--r--compiler/rustc_session/src/config.rs45
-rw-r--r--compiler/rustc_session/src/session.rs9
-rw-r--r--compiler/rustc_smir/src/rustc_internal/internal.rs53
-rw-r--r--compiler/rustc_smir/src/rustc_internal/pretty.rs2
-rw-r--r--compiler/rustc_smir/src/rustc_smir/context.rs15
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/mir.rs8
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/ty.rs14
-rw-r--r--compiler/rustc_span/src/hygiene.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs17
-rw-r--r--compiler/rustc_symbol_mangling/src/test.rs2
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs39
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs6
-rw-r--r--compiler/rustc_target/src/asm/aarch64.rs26
-rw-r--r--compiler/rustc_target/src/asm/arm.rs6
-rw-r--r--compiler/rustc_target/src/asm/avr.rs6
-rw-r--r--compiler/rustc_target/src/asm/bpf.rs6
-rw-r--r--compiler/rustc_target/src/asm/csky.rs6
-rw-r--r--compiler/rustc_target/src/asm/hexagon.rs6
-rw-r--r--compiler/rustc_target/src/asm/loongarch.rs6
-rw-r--r--compiler/rustc_target/src/asm/m68k.rs6
-rw-r--r--compiler/rustc_target/src/asm/mips.rs6
-rw-r--r--compiler/rustc_target/src/asm/mod.rs20
-rw-r--r--compiler/rustc_target/src/asm/msp430.rs6
-rw-r--r--compiler/rustc_target/src/asm/nvptx.rs6
-rw-r--r--compiler/rustc_target/src/asm/powerpc.rs6
-rw-r--r--compiler/rustc_target/src/asm/riscv.rs6
-rw-r--r--compiler/rustc_target/src/asm/s390x.rs6
-rw-r--r--compiler/rustc_target/src/asm/spirv.rs6
-rw-r--r--compiler/rustc_target/src/asm/wasm.rs6
-rw-r--r--compiler/rustc_target/src/asm/x86.rs34
-rw-r--r--compiler/rustc_target/src/spec/mod.rs4
-rw-r--r--compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs29
-rw-r--r--compiler/rustc_trait_selection/messages.ftl9
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/mod.rs15
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs42
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs7
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs90
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs189
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs38
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs45
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs18
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs53
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs4
-rw-r--r--compiler/rustc_transmute/src/layout/tree.rs44
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs2
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs12
-rw-r--r--compiler/rustc_type_ir/src/flags.rs2
-rw-r--r--compiler/rustc_type_ir/src/ty_kind.rs10
-rw-r--r--compiler/stable_mir/src/compiler_interface.rs10
-rw-r--r--compiler/stable_mir/src/lib.rs6
-rw-r--r--compiler/stable_mir/src/mir/alloc.rs4
-rw-r--r--compiler/stable_mir/src/mir/body.rs40
-rw-r--r--compiler/stable_mir/src/mir/mono.rs6
-rw-r--r--compiler/stable_mir/src/mir/pretty.rs521
-rw-r--r--compiler/stable_mir/src/target.rs2
-rw-r--r--compiler/stable_mir/src/ty.rs8
-rw-r--r--config.example.toml2
-rw-r--r--library/alloc/src/collections/btree/map.rs5
-rw-r--r--library/alloc/src/collections/btree/navigate.rs6
-rw-r--r--library/alloc/src/collections/btree/node/tests.rs6
-rw-r--r--library/alloc/src/collections/btree/set.rs6
-rw-r--r--library/alloc/src/sync.rs2
-rw-r--r--library/alloc/src/vec/in_place_collect.rs168
-rw-r--r--library/alloc/src/vec/mod.rs7
-rw-r--r--library/alloc/tests/vec.rs41
-rw-r--r--library/core/src/alloc/global.rs9
-rw-r--r--library/core/src/char/convert.rs2
-rw-r--r--library/core/src/hint.rs5
-rw-r--r--library/core/src/intrinsics.rs244
-rw-r--r--library/core/src/intrinsics/simd.rs2
-rw-r--r--library/core/src/iter/traits/marker.rs1
-rw-r--r--library/core/src/lib.rs4
-rw-r--r--library/core/src/macros/mod.rs16
-rw-r--r--library/core/src/mem/mod.rs60
-rw-r--r--library/core/src/num/nonzero.rs5
-rw-r--r--library/core/src/ops/index_range.rs5
-rw-r--r--library/core/src/option.rs92
-rw-r--r--library/core/src/panic/panic_info.rs5
-rw-r--r--library/core/src/panicking.rs4
-rw-r--r--library/core/src/pin.rs14
-rw-r--r--library/core/src/prelude/v1.rs8
-rw-r--r--library/core/src/ptr/alignment.rs4
-rw-r--r--library/core/src/ptr/const_ptr.rs2
-rw-r--r--library/core/src/ptr/mod.rs54
-rw-r--r--library/core/src/ptr/non_null.rs21
-rw-r--r--library/core/src/slice/index.rs2
-rw-r--r--library/core/src/slice/mod.rs10
-rw-r--r--library/core/src/slice/raw.rs16
-rw-r--r--library/core/src/str/traits.rs2
-rw-r--r--library/core/src/ub_checks.rs158
-rw-r--r--library/panic_unwind/src/emcc.rs2
-rw-r--r--library/portable-simd/.github/workflows/ci.yml5
-rw-r--r--library/portable-simd/Cargo.lock3
-rw-r--r--library/portable-simd/crates/core_simd/src/lib.rs12
-rw-r--r--library/portable-simd/crates/core_simd/src/masks.rs6
-rw-r--r--library/portable-simd/crates/core_simd/src/swizzle_dyn.rs8
-rw-r--r--library/portable-simd/crates/core_simd/src/vector.rs244
-rw-r--r--library/portable-simd/crates/core_simd/src/vendor.rs2
-rw-r--r--library/portable-simd/crates/core_simd/src/vendor/arm.rs8
-rw-r--r--library/portable-simd/crates/core_simd/tests/masked_load_store.rs35
-rw-r--r--library/portable-simd/crates/core_simd/tests/swizzle_dyn.rs2
-rw-r--r--library/portable-simd/crates/std_float/Cargo.toml7
-rw-r--r--library/portable-simd/crates/std_float/src/lib.rs151
-rw-r--r--library/portable-simd/crates/std_float/tests/float.rs74
-rw-r--r--library/proc_macro/src/bridge/handle.rs4
-rw-r--r--library/std/src/alloc.rs6
-rw-r--r--library/std/src/net/test.rs4
-rw-r--r--library/std/src/os/freebsd/net.rs26
-rw-r--r--library/std/src/os/netbsd/net.rs26
-rw-r--r--library/std/src/panicking.rs10
-rw-r--r--library/std/src/prelude/v1.rs9
-rw-r--r--library/std/src/sync/condvar/tests.rs4
-rw-r--r--library/std/src/sync/mutex.rs2
-rw-r--r--library/std/src/sync/rwlock.rs2
-rw-r--r--library/std/src/sys/pal/sgx/net.rs2
-rw-r--r--library/std/src/sys/pal/uefi/helpers.rs83
-rw-r--r--library/std/src/sys/pal/uefi/os.rs8
-rw-r--r--library/std/src/sys/pal/unix/net.rs31
-rw-r--r--library/std/src/sys/pal/unix/thread_local_dtor.rs2
-rw-r--r--library/std/src/sys/pal/unix/thread_parking/pthread.rs22
-rw-r--r--library/std/src/sys/pal/unsupported/net.rs2
-rw-r--r--library/std/src/sys/pal/wasi/net.rs2
-rw-r--r--library/std/src/sys/pal/wasm/alloc.rs9
-rw-r--r--library/std/src/sys/pal/windows/pipe.rs8
-rw-r--r--library/std/src/sys/pal/xous/alloc.rs9
-rw-r--r--library/std/src/sys/pal/xous/net/tcpstream.rs2
-rw-r--r--library/std/src/sys/pal/xous/thread_local_key.rs10
-rw-r--r--library/std/src/sys/sync/mutex/xous.rs11
-rw-r--r--library/std/src/sys_common/thread_local_key.rs6
-rw-r--r--library/std/src/thread/local/tests.rs19
-rw-r--r--library/test/src/console.rs9
-rw-r--r--src/bootstrap/bootstrap.py12
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs15
-rw-r--r--src/bootstrap/src/core/download.rs15
-rw-r--r--src/bootstrap/src/lib.rs29
-rw-r--r--src/ci/docker/host-x86_64/test-various/Dockerfile4
-rw-r--r--src/doc/rustc/src/platform-support.md1
-rw-r--r--src/doc/rustc/src/platform-support/riscv32-unknown-none-elf.md6
-rw-r--r--src/doc/unstable-book/src/language-features/postfix-match.md22
-rw-r--r--src/librustdoc/clean/mod.rs39
-rw-r--r--src/librustdoc/clean/utils.rs1
-rw-r--r--src/librustdoc/doctest.rs213
-rw-r--r--src/librustdoc/lib.rs4
-rw-r--r--src/librustdoc/markdown.rs11
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs2
-rw-r--r--src/librustdoc/passes/collect_trait_impls.rs4
m---------src/llvm-project0
-rw-r--r--src/tools/build-manifest/src/main.rs1
-rw-r--r--src/tools/clippy/.github/workflows/clippy.yml10
-rw-r--r--src/tools/clippy/.github/workflows/clippy_bors.yml25
-rw-r--r--src/tools/clippy/CHANGELOG.md63
-rw-r--r--src/tools/clippy/Cargo.toml12
-rw-r--r--src/tools/clippy/book/src/development/macro_expansions.md4
-rw-r--r--src/tools/clippy/book/src/development/type_checking.md10
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md1
-rw-r--r--src/tools/clippy/clippy.toml13
-rw-r--r--src/tools/clippy/clippy_config/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_config/src/conf.rs2
-rw-r--r--src/tools/clippy/clippy_config/src/msrvs.rs1
-rw-r--r--src/tools/clippy/clippy_dev/src/update_lints.rs2
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_lints/src/assigning_clones.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs64
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/mod.rs35
-rw-r--r--src/tools/clippy/clippy_lints/src/box_default.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs41
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/collection_is_never_read.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/dbg_macro.rs51
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/markdown.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/mod.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/else_if_without_else.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/entry.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/equatable_if_let.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/must_use.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/future_not_send.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_hasher.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/integer_division_remainder_used.rs50
-rw-r--r--src/tools/clippy/clippy_lints/src/let_if_seq.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/let_underscore.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/never_loop.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/same_item_push.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs81
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/utils.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_hash_one.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_retain.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs181
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/needless_match.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/single_match.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/is_empty.rs49
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_nth.rs49
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_clone.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs143
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_collect.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/no_effect_replace.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/str_splitn.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs135
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/zst_offset.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_doc.rs64
-rw-r--r--src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_key.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_mut.rs70
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_reference.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/mutex_atomic.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_late_init.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/raw_strings.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs60
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_closure_call.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_else.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_locals.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs35
-rw-r--r--src/tools/clippy/clippy_lints/src/shadow.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/std_instead_of_core.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/crosspointer_transmute.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/wrong_transmute.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/types/mod.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/types/vec_box.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/unconditional_recursion.rs60
-rw-r--r--src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/uninhabited_references.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/mod.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_io_amount.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_peekable.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/use_self.rs59
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/vec.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/vec_init_then_push.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/wildcard_imports.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs154
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs4
-rw-r--r--src/tools/clippy/clippy_utils/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs109
-rw-r--r--src/tools/clippy/clippy_utils/src/diagnostics.rs118
-rw-r--r--src/tools/clippy/clippy_utils/src/higher.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs51
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs10
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs4
-rw-r--r--src/tools/clippy/declare_clippy_lint/Cargo.toml2
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr3
-rw-r--r--src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.fixed38
-rw-r--r--src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.rs5
-rw-r--r--src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.stderr34
-rw-r--r--src/tools/clippy/tests/ui-toml/needless_raw_string_hashes_one_allowed/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.fixed9
-rw-r--r--src/tools/clippy/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.rs9
-rw-r--r--src/tools/clippy/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.stderr40
-rw-r--r--src/tools/clippy/tests/ui/allow_attributes_without_reason.rs2
-rw-r--r--src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr4
-rw-r--r--src/tools/clippy/tests/ui/assigning_clones.fixed13
-rw-r--r--src/tools/clippy/tests/ui/assigning_clones.rs13
-rw-r--r--src/tools/clippy/tests/ui/assigning_clones.stderr32
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs43
-rw-r--r--src/tools/clippy/tests/ui/await_holding_lock.rs1
-rw-r--r--src/tools/clippy/tests/ui/await_holding_lock.stderr52
-rw-r--r--src/tools/clippy/tests/ui/bool_assert_comparison.fixed2
-rw-r--r--src/tools/clippy/tests/ui/bool_assert_comparison.rs2
-rw-r--r--src/tools/clippy/tests/ui/builtin_type_shadow.stderr1
-rw-r--r--src/tools/clippy/tests/ui/cast_lossless_bool.fixed4
-rw-r--r--src/tools/clippy/tests/ui/cast_lossless_bool.rs4
-rw-r--r--src/tools/clippy/tests/ui/cast_lossless_bool.stderr36
-rw-r--r--src/tools/clippy/tests/ui/cast_lossless_float.fixed5
-rw-r--r--src/tools/clippy/tests/ui/cast_lossless_float.rs5
-rw-r--r--src/tools/clippy/tests/ui/cast_lossless_float.stderr36
-rw-r--r--src/tools/clippy/tests/ui/cast_lossless_integer.fixed10
-rw-r--r--src/tools/clippy/tests/ui/cast_lossless_integer.rs10
-rw-r--r--src/tools/clippy/tests/ui/cast_lossless_integer.stderr50
-rw-r--r--src/tools/clippy/tests/ui/const_is_empty.rs174
-rw-r--r--src/tools/clippy/tests/ui/const_is_empty.stderr161
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-12491.fixed7
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-12491.rs8
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-12491.stderr19
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6179.rs2
-rw-r--r--src/tools/clippy/tests/ui/dbg_macro/dbg_macro.fixed111
-rw-r--r--src/tools/clippy/tests/ui/dbg_macro/dbg_macro.rs20
-rw-r--r--src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr108
-rw-r--r--src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.rs12
-rw-r--r--src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.stderr71
-rw-r--r--src/tools/clippy/tests/ui/doc/issue_10262.fixed12
-rw-r--r--src/tools/clippy/tests/ui/doc/issue_10262.rs12
-rw-r--r--src/tools/clippy/tests/ui/doc/issue_10262.stderr15
-rw-r--r--src/tools/clippy/tests/ui/duplicated_attributes.rs17
-rw-r--r--src/tools/clippy/tests/ui/duplicated_attributes.stderr123
-rw-r--r--src/tools/clippy/tests/ui/else_if_without_else.rs68
-rw-r--r--src/tools/clippy/tests/ui/else_if_without_else.stderr30
-rw-r--r--src/tools/clippy/tests/ui/empty_docs.rs17
-rw-r--r--src/tools/clippy/tests/ui/empty_docs.stderr18
-rw-r--r--src/tools/clippy/tests/ui/empty_line_after_doc_comments.rs2
-rw-r--r--src/tools/clippy/tests/ui/empty_line_after_outer_attribute.rs2
-rw-r--r--src/tools/clippy/tests/ui/entry.fixed10
-rw-r--r--src/tools/clippy/tests/ui/entry.rs10
-rw-r--r--src/tools/clippy/tests/ui/entry.stderr23
-rw-r--r--src/tools/clippy/tests/ui/integer_division_remainder_used.rs41
-rw-r--r--src/tools/clippy/tests/ui/integer_division_remainder_used.stderr59
-rw-r--r--src/tools/clippy/tests/ui/iter_nth.fixed60
-rw-r--r--src/tools/clippy/tests/ui/iter_nth.rs3
-rw-r--r--src/tools/clippy/tests/ui/iter_nth.stderr48
-rw-r--r--src/tools/clippy/tests/ui/len_zero.fixed8
-rw-r--r--src/tools/clippy/tests/ui/len_zero.rs8
-rw-r--r--src/tools/clippy/tests/ui/len_zero.stderr46
-rw-r--r--src/tools/clippy/tests/ui/let_if_seq.rs11
-rw-r--r--src/tools/clippy/tests/ui/let_if_seq.stderr8
-rw-r--r--src/tools/clippy/tests/ui/manual_let_else.rs3
-rw-r--r--src/tools/clippy/tests/ui/manual_let_else.stderr62
-rw-r--r--src/tools/clippy/tests/ui/manual_retain.fixed2
-rw-r--r--src/tools/clippy/tests/ui/manual_retain.rs2
-rw-r--r--src/tools/clippy/tests/ui/manual_retain.stderr76
-rw-r--r--src/tools/clippy/tests/ui/manual_unwrap_or.fixed7
-rw-r--r--src/tools/clippy/tests/ui/manual_unwrap_or.rs7
-rw-r--r--src/tools/clippy/tests/ui/manual_unwrap_or.stderr28
-rw-r--r--src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed19
-rw-r--r--src/tools/clippy/tests/ui/manual_unwrap_or_default.rs40
-rw-r--r--src/tools/clippy/tests/ui/manual_unwrap_or_default.stderr56
-rw-r--r--src/tools/clippy/tests/ui/map_clone.fixed16
-rw-r--r--src/tools/clippy/tests/ui/map_clone.rs16
-rw-r--r--src/tools/clippy/tests/ui/map_clone.stderr30
-rw-r--r--src/tools/clippy/tests/ui/match_result_ok.fixed2
-rw-r--r--src/tools/clippy/tests/ui/match_result_ok.rs2
-rw-r--r--src/tools/clippy/tests/ui/missing_doc.rs12
-rw-r--r--src/tools/clippy/tests/ui/missing_doc.stderr26
-rw-r--r--src/tools/clippy/tests/ui/mixed_attributes_style.rs1
-rw-r--r--src/tools/clippy/tests/ui/mixed_attributes_style.stderr6
-rw-r--r--src/tools/clippy/tests/ui/mut_mut.rs6
-rw-r--r--src/tools/clippy/tests/ui/mut_mut.stderr18
-rw-r--r--src/tools/clippy/tests/ui/needless_bitwise_bool.fixed1
-rw-r--r--src/tools/clippy/tests/ui/needless_bitwise_bool.rs1
-rw-r--r--src/tools/clippy/tests/ui/needless_bitwise_bool.stderr2
-rw-r--r--src/tools/clippy/tests/ui/needless_return.fixed7
-rw-r--r--src/tools/clippy/tests/ui/needless_return.rs7
-rw-r--r--src/tools/clippy/tests/ui/no_effect_replace.rs2
-rw-r--r--src/tools/clippy/tests/ui/no_effect_replace.stderr16
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.fixed3
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.rs3
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.stderr50
-rw-r--r--src/tools/clippy/tests/ui/option_option.rs4
-rw-r--r--src/tools/clippy/tests/ui/option_option.stderr26
-rw-r--r--src/tools/clippy/tests/ui/read_zero_byte_vec.rs6
-rw-r--r--src/tools/clippy/tests/ui/redundant_as_str.fixed1
-rw-r--r--src/tools/clippy/tests/ui/redundant_as_str.rs1
-rw-r--r--src/tools/clippy/tests/ui/redundant_as_str.stderr4
-rw-r--r--src/tools/clippy/tests/ui/rename.fixed1
-rw-r--r--src/tools/clippy/tests/ui/rename.rs1
-rw-r--r--src/tools/clippy/tests/ui/rename.stderr116
-rw-r--r--src/tools/clippy/tests/ui/single_match.fixed5
-rw-r--r--src/tools/clippy/tests/ui/single_match.rs5
-rw-r--r--src/tools/clippy/tests/ui/single_match.stderr36
-rw-r--r--src/tools/clippy/tests/ui/single_match_else.fixed1
-rw-r--r--src/tools/clippy/tests/ui/single_match_else.rs1
-rw-r--r--src/tools/clippy/tests/ui/single_match_else.stderr18
-rw-r--r--src/tools/clippy/tests/ui/std_instead_of_core.fixed2
-rw-r--r--src/tools/clippy/tests/ui/std_instead_of_core.stderr8
-rw-r--r--src/tools/clippy/tests/ui/unconditional_recursion.rs50
-rw-r--r--src/tools/clippy/tests/ui/unconditional_recursion.stderr136
-rw-r--r--src/tools/clippy/tests/ui/unused_enumerate_index.fixed50
-rw-r--r--src/tools/clippy/tests/ui/unused_enumerate_index.rs50
-rw-r--r--src/tools/clippy/tests/ui/unused_enumerate_index.stderr78
-rw-r--r--src/tools/clippy/tests/ui/unused_io_amount.rs5
-rw-r--r--src/tools/clippy/tests/ui/unused_peekable.rs6
-rw-r--r--src/tools/clippy/tests/ui/use_self.fixed18
-rw-r--r--src/tools/clippy/tests/ui/use_self.rs16
-rw-r--r--src/tools/clippy/tests/ui/use_self.stderr92
-rw-r--r--src/tools/clippy/tests/ui/zero_repeat_side_effects.fixed60
-rw-r--r--src/tools/clippy/tests/ui/zero_repeat_side_effects.rs60
-rw-r--r--src/tools/clippy/tests/ui/zero_repeat_side_effects.stderr77
-rw-r--r--src/tools/clippy/triagebot.toml2
-rw-r--r--src/tools/compiletest/src/runtest.rs27
-rw-r--r--src/tools/miri/.github/workflows/ci.yml2
-rw-r--r--src/tools/miri/bench-cargo-miri/range-iteration/Cargo.lock (renamed from src/tools/miri/bench-cargo-miri/invalidate/Cargo.lock)2
-rw-r--r--src/tools/miri/bench-cargo-miri/range-iteration/Cargo.toml (renamed from src/tools/miri/bench-cargo-miri/invalidate/Cargo.toml)2
-rw-r--r--src/tools/miri/bench-cargo-miri/range-iteration/src/main.rs (renamed from src/tools/miri/bench-cargo-miri/invalidate/src/main.rs)3
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/bin/miri.rs20
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs21
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs15
-rw-r--r--src/tools/miri/src/concurrency/data_race.rs141
-rw-r--r--src/tools/miri/src/concurrency/vector_clock.rs62
-rw-r--r--src/tools/miri/src/diagnostics.rs8
-rw-r--r--src/tools/miri/src/lib.rs1
-rw-r--r--src/tools/miri/src/machine.rs24
-rw-r--r--src/tools/miri/src/shims/intrinsics/simd.rs48
-rw-r--r--src/tools/miri/src/shims/unix/linux/fd/epoll.rs2
-rw-r--r--src/tools/miri/src/shims/unix/linux/fd/event.rs4
-rw-r--r--src/tools/miri/src/shims/x86/mod.rs13
-rw-r--r--src/tools/miri/src/shims/x86/sse2.rs6
-rw-r--r--src/tools/miri/test-cargo-miri/src/lib.rs18
-rw-r--r--src/tools/miri/test-cargo-miri/test.default.stdout.ref6
-rw-r--r--src/tools/miri/test-cargo-miri/test.filter.stdout.ref2
-rw-r--r--src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs2
-rw-r--r--src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr7
-rw-r--r--src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr7
-rw-r--r--src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.rs19
-rw-r--r--src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr20
-rw-r--r--src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.rs19
-rw-r--r--src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.stderr20
-rw-r--r--src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.rs2
-rw-r--r--src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr7
-rw-r--r--src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs2
-rw-r--r--src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr7
-rw-r--r--src/tools/miri/tests/pass/intptrcast.rs26
-rw-r--r--src/tools/miri/tests/pass/intrinsics-x86-pause-without-sse2.rs25
-rw-r--r--src/tools/miri/tests/pass/intrinsics-x86-sse2.rs5
-rw-r--r--src/tools/miri/tests/pass/main_fn.rs5
-rw-r--r--src/tools/miri/tests/pass/portable-simd.rs18
-rw-r--r--src/tools/run-make-support/Cargo.toml1
-rw-r--r--src/tools/run-make-support/src/lib.rs42
-rw-r--r--src/tools/rustfmt/src/expr.rs8
-rw-r--r--src/tools/rustfmt/src/matches.rs33
-rw-r--r--src/tools/rustfmt/src/patterns.rs8
-rw-r--r--src/tools/rustfmt/tests/source/postfix-match/pf-match.rs20
-rw-r--r--src/tools/rustfmt/tests/target/postfix-match/pf-match.rs20
-rw-r--r--src/tools/tidy/src/ui_tests.rs5
-rw-r--r--tests/assembly/option-nonzero-eq.rs27
-rw-r--r--tests/assembly/targets/targets-elf.rs3
-rw-r--r--tests/assembly/x86_64-typed-swap.rs53
-rw-r--r--tests/codegen/intrinsics/typed_swap.rs78
-rw-r--r--tests/codegen/option-niche-eq.rs (renamed from tests/codegen/option-nonzero-eq.rs)43
-rw-r--r--tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs50
-rw-r--r--tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs6
-rw-r--r--tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs2
-rw-r--r--tests/codegen/sanitizer/cfi/normalize-integers.rs6
-rw-r--r--tests/codegen/swap-small-types.rs5
-rw-r--r--tests/coverage/let_else_loop.cov-map30
-rw-r--r--tests/coverage/let_else_loop.coverage35
-rw-r--r--tests/coverage/let_else_loop.rs33
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff6
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff6
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff6
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff6
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff6
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff6
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff6
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff6
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs1
-rw-r--r--tests/mir-opt/funky_arms.rs1
-rw-r--r--tests/mir-opt/inline/unchecked_shifts.rs1
-rw-r--r--tests/mir-opt/inline/unwrap_unchecked.rs3
-rw-r--r--tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff6
-rw-r--r--tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff6
-rw-r--r--tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir6
-rw-r--r--tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir6
-rw-r--r--tests/mir-opt/inline_coroutine_body.rs28
-rw-r--r--tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff281
-rw-r--r--tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff341
-rw-r--r--tests/mir-opt/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff56
-rw-r--r--tests/mir-opt/instrument_coverage_cleanup.main.InstrumentCoverage.diff53
-rw-r--r--tests/mir-opt/instrument_coverage_cleanup.rs22
-rw-r--r--tests/mir-opt/pre-codegen/duplicate_switch_targets.rs1
-rw-r--r--tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir6
-rw-r--r--tests/mir-opt/pre-codegen/mem_replace.rs2
-rw-r--r--tests/mir-opt/pre-codegen/slice_index.rs1
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.rs1
-rw-r--r--tests/pretty/postfix-match.rs21
-rw-r--r--tests/run-make-fulldeps/obtain-borrowck/driver.rs2
-rw-r--r--tests/run-make/compiler-builtins/rmake.rs142
-rw-r--r--tests/run-make/rustdoc-test-args/foo.rs3
-rw-r--r--tests/run-make/rustdoc-test-args/rmake.rs18
-rw-r--r--tests/rustdoc-ui/invalid_associated_const.rs1
-rw-r--r--tests/rustdoc-ui/invalid_associated_const.stderr10
-rw-r--r--tests/rustdoc-ui/issue-102467.rs1
-rw-r--r--tests/rustdoc-ui/issue-102467.stderr10
-rw-r--r--tests/rustdoc-ui/issues/issue-96287.rs1
-rw-r--r--tests/rustdoc-ui/issues/issue-96287.stderr14
-rw-r--r--tests/ui/asm/aarch64/type-check-3.stderr40
-rw-r--r--tests/ui/asm/bad-template.aarch64.stderr4
-rw-r--r--tests/ui/asm/bad-template.x86_64.stderr4
-rw-r--r--tests/ui/asm/x86_64/type-check-3.stderr16
-rw-r--r--tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs14
-rw-r--r--tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr42
-rw-r--r--tests/ui/associated-consts/issue-102335-const.rs1
-rw-r--r--tests/ui/associated-consts/issue-102335-const.stderr10
-rw-r--r--tests/ui/associated-inherent-types/issue-109299-1.rs6
-rw-r--r--tests/ui/associated-inherent-types/issue-109299-1.stderr15
-rw-r--r--tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid-2.rs18
-rw-r--r--tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid-2.stderr13
-rw-r--r--tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid.rs18
-rw-r--r--tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid.stderr14
-rw-r--r--tests/ui/associated-type-bounds/dont-imply-atb-in-closure-inference.rs21
-rw-r--r--tests/ui/associated-type-bounds/duplicate.rs9
-rw-r--r--tests/ui/associated-type-bounds/duplicate.stderr186
-rw-r--r--tests/ui/associated-type-bounds/issue-102335-ty.rs1
-rw-r--r--tests/ui/associated-type-bounds/issue-102335-ty.stderr10
-rw-r--r--tests/ui/associated-type-bounds/issue-99828.rs1
-rw-r--r--tests/ui/associated-type-bounds/issue-99828.stderr14
-rw-r--r--tests/ui/async-await/future-sizes/async-awaiting-fut.stdout14
-rw-r--r--tests/ui/async-await/future-sizes/large-arg.stdout6
-rw-r--r--tests/ui/async-await/in-trait/return-not-existing-pair.rs3
-rw-r--r--tests/ui/async-await/in-trait/return-not-existing-pair.stderr15
-rw-r--r--tests/ui/async-await/in-trait/unconstrained-impl-region.rs1
-rw-r--r--tests/ui/async-await/in-trait/unconstrained-impl-region.stderr21
-rw-r--r--tests/ui/async-await/issues/issue-65159.rs1
-rw-r--r--tests/ui/async-await/issues/issue-65159.stderr16
-rw-r--r--tests/ui/async-await/send-bound-async-closure.rs3
-rw-r--r--tests/ui/borrowck/ice-mutability-error-slicing-121807.rs27
-rw-r--r--tests/ui/borrowck/ice-mutability-error-slicing-121807.stderr53
-rw-r--r--tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs4
-rw-r--r--tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr38
-rw-r--r--tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.rs26
-rw-r--r--tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.stderr42
-rw-r--r--tests/ui/cfg/cfg-false-feature.stderr24
-rw-r--r--tests/ui/const-generics/generic_const_exprs/ice-generics_of-no-entry-found-for-key-113017.rs13
-rw-r--r--tests/ui/const-generics/generic_const_exprs/ice-generics_of-no-entry-found-for-key-113017.stderr19
-rw-r--r--tests/ui/const-generics/generic_const_exprs/ice-predicates-of-no-entry-found-for-key-119275.rs18
-rw-r--r--tests/ui/const-generics/generic_const_exprs/ice-predicates-of-no-entry-found-for-key-119275.stderr46
-rw-r--r--tests/ui/const-generics/generic_const_exprs/issue-109141.rs1
-rw-r--r--tests/ui/const-generics/generic_const_exprs/issue-109141.stderr21
-rw-r--r--tests/ui/const-generics/generic_const_exprs/poly-const-uneval-ice-106423.rs57
-rw-r--r--tests/ui/const-generics/ice-unexpected-inference-var-122549.rs29
-rw-r--r--tests/ui/const-generics/ice-unexpected-inference-var-122549.stderr67
-rw-r--r--tests/ui/const-generics/late-bound-vars/late-bound-in-return-issue-77357.stderr43
-rw-r--r--tests/ui/const-generics/min_const_generics/macro-fail.rs1
-rw-r--r--tests/ui/const-generics/min_const_generics/macro-fail.stderr24
-rw-r--r--tests/ui/const-generics/occurs-check/unify-fixpoint.rs5
-rw-r--r--tests/ui/const-generics/occurs-check/unify-fixpoint.stderr2
-rw-r--r--tests/ui/const-generics/transmute-fail.rs75
-rw-r--r--tests/ui/const-generics/transmute-fail.stderr91
-rw-r--r--tests/ui/const-generics/transmute.rs69
-rw-r--r--tests/ui/const_prop/ice-type-mismatch-when-copying-112824.rs20
-rw-r--r--tests/ui/const_prop/ice-type-mismatch-when-copying-112824.stderr29
-rw-r--r--tests/ui/consts/missing_span_in_backtrace.stderr2
-rw-r--r--tests/ui/consts/required-consts/collect-in-called-fn.noopt.stderr8
-rw-r--r--tests/ui/consts/required-consts/collect-in-called-fn.opt.stderr8
-rw-r--r--tests/ui/consts/required-consts/collect-in-called-fn.rs1
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-closure.noopt.stderr23
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-closure.opt.stderr23
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-closure.rs30
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-drop.noopt.stderr6
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-drop.opt.stderr20
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-drop.rs11
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.noopt.stderr20
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.opt.stderr20
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.rs49
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.noopt.stderr20
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.opt.stderr20
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.rs30
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.noopt.stderr20
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.opt.stderr20
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.rs37
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-fn.noopt.stderr8
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-fn.opt.stderr23
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-fn.rs11
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.noopt.stderr20
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.opt.stderr20
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.rs34
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-fnptr.noopt.stderr23
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-fnptr.opt.stderr23
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-fnptr.rs33
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-forget.rs4
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-move.noopt.stderr6
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-move.opt.stderr20
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-move.rs11
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-vtable.noopt.stderr10
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-vtable.opt.stderr23
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-vtable.rs16
-rw-r--r--tests/ui/consts/required-consts/interpret-in-const-called-fn.noopt.stderr6
-rw-r--r--tests/ui/consts/required-consts/interpret-in-const-called-fn.opt.stderr6
-rw-r--r--tests/ui/consts/required-consts/interpret-in-const-called-fn.rs1
-rw-r--r--tests/ui/consts/required-consts/interpret-in-promoted.noopt.stderr6
-rw-r--r--tests/ui/consts/required-consts/interpret-in-promoted.opt.stderr6
-rw-r--r--tests/ui/consts/required-consts/interpret-in-promoted.rs1
-rw-r--r--tests/ui/consts/required-consts/interpret-in-static.noopt.stderr6
-rw-r--r--tests/ui/consts/required-consts/interpret-in-static.opt.stderr6
-rw-r--r--tests/ui/consts/required-consts/interpret-in-static.rs1
-rw-r--r--tests/ui/coroutine/gen_block_is_fused_iter.rs21
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs45
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr193
-rw-r--r--tests/ui/drop/norm-ice-106444.rs16
-rw-r--r--tests/ui/error-codes/E0637.rs4
-rw-r--r--tests/ui/error-codes/E0637.stderr20
-rw-r--r--tests/ui/feature-gates/feature-gate-deref_patterns.rs9
-rw-r--r--tests/ui/feature-gates/feature-gate-deref_patterns.stderr13
-rw-r--r--tests/ui/feature-gates/feature-gate-postfix_match.rs17
-rw-r--r--tests/ui/feature-gates/feature-gate-postfix_match.stderr23
-rw-r--r--tests/ui/generic-associated-types/issue-102335-gat.rs1
-rw-r--r--tests/ui/generic-associated-types/issue-102335-gat.stderr10
-rw-r--r--tests/ui/generic-associated-types/issue-80433.rs2
-rw-r--r--tests/ui/generic-associated-types/issue-80433.stderr17
-rw-r--r--tests/ui/generic-associated-types/issue-81712-cyclic-traits.rs1
-rw-r--r--tests/ui/generic-associated-types/issue-81712-cyclic-traits.stderr19
-rw-r--r--tests/ui/generics/generic-type-less-params-with-defaults.rs16
-rw-r--r--tests/ui/generics/generic-type-less-params-with-defaults.stderr36
-rw-r--r--tests/ui/higher-ranked/structually-relate-aliases.rs17
-rw-r--r--tests/ui/higher-ranked/structually-relate-aliases.stderr27
-rw-r--r--tests/ui/impl-not-adjacent-to-type.rs1
-rw-r--r--tests/ui/impl-trait/fresh-lifetime-from-bare-trait-obj-114664.rs2
-rw-r--r--tests/ui/impl-trait/fresh-lifetime-from-bare-trait-obj-114664.stderr16
-rw-r--r--tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs30
-rw-r--r--tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.stderr31
-rw-r--r--tests/ui/impl-trait/impl-fn-hrtb-bounds.rs3
-rw-r--r--tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr39
-rw-r--r--tests/ui/impl-trait/impl-fn-parsing-ambiguities.rs1
-rw-r--r--tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr13
-rw-r--r--tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.rs17
-rw-r--r--tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.stderr71
-rw-r--r--tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs1
-rw-r--r--tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr10
-rw-r--r--tests/ui/impl-trait/issues/issue-92305.rs1
-rw-r--r--tests/ui/impl-trait/issues/issue-92305.stderr14
-rw-r--r--tests/ui/impl-trait/nested-rpit-hrtb.rs3
-rw-r--r--tests/ui/impl-trait/nested-rpit-hrtb.stderr30
-rw-r--r--tests/ui/impl-trait/opaque-used-in-extraneous-argument.rs1
-rw-r--r--tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr19
-rw-r--r--tests/ui/impl-trait/recursive-ice-101862.rs12
-rw-r--r--tests/ui/impl-trait/recursive-ice-101862.stderr24
-rw-r--r--tests/ui/impl-trait/stranded-opaque.rs1
-rw-r--r--tests/ui/impl-trait/stranded-opaque.stderr10
-rw-r--r--tests/ui/inference/ice-cannot-relate-region-109178.rs14
-rw-r--r--tests/ui/inference/ice-cannot-relate-region-109178.stderr21
-rw-r--r--tests/ui/inference/ice-ifer-var-leaked-out-of-rollback-122098.rs25
-rw-r--r--tests/ui/inference/ice-ifer-var-leaked-out-of-rollback-122098.stderr72
-rw-r--r--tests/ui/inference/issue-107090.rs2
-rw-r--r--tests/ui/inference/issue-107090.stderr17
-rw-r--r--tests/ui/inference/str-as-char.stderr12
-rw-r--r--tests/ui/issues/issue-10412.rs1
-rw-r--r--tests/ui/issues/issue-10412.stderr26
-rw-r--r--tests/ui/issues/issue-17361.rs2
-rw-r--r--tests/ui/issues/issue-23589.stderr4
-rw-r--r--tests/ui/issues/issue-27942.stderr24
-rw-r--r--tests/ui/issues/issue-87199.rs1
-rw-r--r--tests/ui/issues/issue-87199.stderr12
-rw-r--r--tests/ui/lexer/lex-bad-char-literals-2.stderr4
-rw-r--r--tests/ui/lexer/lex-bad-char-literals-3.stderr8
-rw-r--r--tests/ui/lexer/lex-bad-char-literals-5.stderr8
-rw-r--r--tests/ui/lexer/lex-bad-char-literals-6.stderr12
-rw-r--r--tests/ui/lexer/lex-bad-str-literal-as-char-1.fixed6
-rw-r--r--tests/ui/lexer/lex-bad-str-literal-as-char-1.rs6
-rw-r--r--tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr20
-rw-r--r--tests/ui/lexer/lex-bad-str-literal-as-char-2.fixed4
-rw-r--r--tests/ui/lexer/lex-bad-str-literal-as-char-2.rs4
-rw-r--r--tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr13
-rw-r--r--tests/ui/lexer/lex-bad-str-literal-as-char-3.rs7
-rw-r--r--tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2015.stderr14
-rw-r--r--tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2018.stderr14
-rw-r--r--tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr14
-rw-r--r--tests/ui/lifetimes/could-not-resolve-issue-121503.rs3
-rw-r--r--tests/ui/lifetimes/could-not-resolve-issue-121503.stderr18
-rw-r--r--tests/ui/lifetimes/issue-26638.rs1
-rw-r--r--tests/ui/lifetimes/issue-26638.stderr25
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.rs2
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr18
-rw-r--r--tests/ui/lint/dead-code/pub-field-in-priv-mod.rs11
-rw-r--r--tests/ui/lint/dead-code/pub-field-in-priv-mod.stderr16
-rw-r--r--tests/ui/lint/lint-qualification.fixed1
-rw-r--r--tests/ui/lint/lint-qualification.rs1
-rw-r--r--tests/ui/lint/unused/unused-associated-item.rs21
-rw-r--r--tests/ui/match/postfix-match/pf-match-chain.rs16
-rw-r--r--tests/ui/match/postfix-match/pf-match-exhaustiveness.rs7
-rw-r--r--tests/ui/match/postfix-match/pf-match-exhaustiveness.stderr21
-rw-r--r--tests/ui/match/postfix-match/pf-match-types.rs15
-rw-r--r--tests/ui/match/postfix-match/pf-match-types.stderr21
-rw-r--r--tests/ui/match/postfix-match/postfix-match.rs62
-rw-r--r--tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr19
-rw-r--r--tests/ui/nll/ice-106874.rs48
-rw-r--r--tests/ui/nll/ice-106874.stderr90
-rw-r--r--tests/ui/nll/issue-54189.rs1
-rw-r--r--tests/ui/nll/issue-54189.stderr10
-rw-r--r--tests/ui/nll/user-annotations/adt-nullary-enums.stderr21
-rw-r--r--tests/ui/nll/user-annotations/region-error-ice-109072.rs1
-rw-r--r--tests/ui/nll/user-annotations/region-error-ice-109072.stderr11
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.rs1
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.stderr18
-rw-r--r--tests/ui/panics/panic-in-message-fmt.rs25
-rw-r--r--tests/ui/panics/panic-in-message-fmt.run.stderr2
-rw-r--r--tests/ui/parser/attribute/attr-bad-meta-4.rs12
-rw-r--r--tests/ui/parser/attribute/attr-bad-meta-4.stderr25
-rw-r--r--tests/ui/parser/issues/issue-64732.rs2
-rw-r--r--tests/ui/parser/issues/issue-64732.stderr6
-rw-r--r--tests/ui/parser/parser-ice-ed2021-await-105210.rs10
-rw-r--r--tests/ui/parser/parser-ice-ed2021-await-105210.stderr34
-rw-r--r--tests/ui/parser/unicode-character-literal.fixed4
-rw-r--r--tests/ui/parser/unicode-character-literal.rs4
-rw-r--r--tests/ui/parser/unicode-character-literal.stderr8
-rw-r--r--tests/ui/pattern/deref-patterns/typeck.rs31
-rw-r--r--tests/ui/print_type_sizes/async.stdout2
-rw-r--r--tests/ui/privacy/suggest-making-field-public.fixed2
-rw-r--r--tests/ui/privacy/suggest-making-field-public.rs2
-rw-r--r--tests/ui/raw-ref-op/const-eval-compare-ice-105047.rs15
-rw-r--r--tests/ui/raw-ref-op/const-eval-compare-ice-105047.stderr31
-rw-r--r--tests/ui/raw-ref-op/raw-ref-temp.stderr8
-rw-r--r--tests/ui/reachable/expr_type.stderr1
-rw-r--r--tests/ui/return/return-impl-trait-bad.stderr4
-rw-r--r--tests/ui/return/return-impl-trait.stderr2
-rw-r--r--tests/ui/return/return-ty-mismatch-note.rs21
-rw-r--r--tests/ui/return/return-ty-mismatch-note.stderr36
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.stderr10
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.rs6
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.stderr14
-rw-r--r--tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs18
-rw-r--r--tests/ui/specialization/broken-mir-drop-glue-107228.rs28
-rw-r--r--tests/ui/stable-mir-print/basic_function.rs13
-rw-r--r--tests/ui/stable-mir-print/basic_function.stdout266
-rw-r--r--tests/ui/str/str-as-char.stderr4
-rw-r--r--tests/ui/suggestions/clone-on-unconstrained-borrowed-type-param.stderr1
-rw-r--r--tests/ui/suggestions/issue-85347.rs3
-rw-r--r--tests/ui/suggestions/issue-85347.stderr27
-rw-r--r--tests/ui/suggestions/issue-86667.rs2
-rw-r--r--tests/ui/suggestions/issue-86667.stderr22
-rw-r--r--tests/ui/suggestions/lifetimes/explicit-lifetime-suggestion-in-proper-span-issue-121267.rs12
-rw-r--r--tests/ui/suggestions/lifetimes/explicit-lifetime-suggestion-in-proper-span-issue-121267.stderr20
-rw-r--r--tests/ui/suggestions/missing-lifetime-specifier.rs10
-rw-r--r--tests/ui/suggestions/missing-lifetime-specifier.stderr228
-rw-r--r--tests/ui/suggestions/types/into-inference-needs-type.rs15
-rw-r--r--tests/ui/suggestions/types/into-inference-needs-type.stderr19
-rw-r--r--tests/ui/trait-bounds/restrict-assoc-type-of-generic-bound.stderr1
-rw-r--r--tests/ui/traits/alias/self-in-generics.rs2
-rw-r--r--tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs1
-rw-r--r--tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr29
-rw-r--r--tests/ui/traits/impl-of-supertrait-has-wrong-lifetime-parameters.stderr12
-rw-r--r--tests/ui/traits/matching-lifetimes.stderr24
-rw-r--r--tests/ui/traits/next-solver/dont-canonicalize-re-error.rs28
-rw-r--r--tests/ui/traits/next-solver/dont-canonicalize-re-error.stderr21
-rw-r--r--tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs15
-rw-r--r--tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr33
-rw-r--r--tests/ui/traits/span-bug-issue-121414.rs3
-rw-r--r--tests/ui/traits/span-bug-issue-121414.stderr21
-rw-r--r--tests/ui/traits/suggest-fully-qualified-closure.rs2
-rw-r--r--tests/ui/traits/suggest-fully-qualified-closure.stderr8
-rw-r--r--tests/ui/transmute/transmute-zst-generics.rs34
-rw-r--r--tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.rs36
-rw-r--r--tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.stderr25
-rw-r--r--tests/ui/type-alias-impl-trait/hkl_forbidden4.rs25
-rw-r--r--tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr34
-rw-r--r--tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.rs52
-rw-r--r--tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr9
-rw-r--r--tests/ui/type-alias-impl-trait/not_well_formed.fixed19
-rw-r--r--tests/ui/type-alias-impl-trait/not_well_formed.rs6
-rw-r--r--tests/ui/type-alias-impl-trait/not_well_formed.stderr14
-rw-r--r--tests/ui/type-alias-impl-trait/underef-index-out-of-bounds-121472.rs16
-rw-r--r--tests/ui/type-alias-impl-trait/underef-index-out-of-bounds-121472.stderr23
-rw-r--r--tests/ui/type/type-parameter-names.stderr1
-rw-r--r--tests/ui/type/type-params-in-different-spaces-3.stderr1
-rw-r--r--tests/ui/typeck/escaping_bound_vars.rs3
-rw-r--r--tests/ui/typeck/escaping_bound_vars.stderr47
-rw-r--r--tests/ui/typeck/issue-13853.stderr1
-rw-r--r--tests/ui/typeck/issue-91267.stderr2
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-region.rs1
-rw-r--r--tests/ui/unboxed-closures/unboxed-closure-sugar-region.stderr20
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-type-mismatch-closure-from-another-scope.stderr6
-rw-r--r--tests/ui/underscore-lifetime/underscore-lifetime-binders.rs1
-rw-r--r--tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr10
-rw-r--r--tests/ui/union/union-macro.rs1
-rw-r--r--tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs31
-rw-r--r--tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr228
-rw-r--r--tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.rs1
-rw-r--r--tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr17
-rw-r--r--triagebot.toml8
1098 files changed, 17846 insertions, 7182 deletions
diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml
index c182f3245e5..d7a31c8e80f 100644
--- a/.github/workflows/dependencies.yml
+++ b/.github/workflows/dependencies.yml
@@ -42,7 +42,7 @@ jobs:
 
           # Exit with error if open and S-waiting-on-bors
           if [[ "$STATE" == "OPEN" && "$WAITING_ON_BORS" == "true" ]]; then
-            exit 1
+            gh run cancel ${{ github.run_id }}
           fi
 
   update:
@@ -65,7 +65,10 @@ jobs:
 
       - name: cargo update
         # Remove first line that always just says "Updating crates.io index"
-        run: cargo update 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
+        # If there are no changes, cancel the job here
+        run: |
+          cargo update 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
+          git status --porcelain | grep -q Cargo.lock || gh run cancel ${{ github.run_id }}
       - name: upload Cargo.lock artifact for use in PR
         uses: actions/upload-artifact@v3
         with:
@@ -131,7 +134,7 @@ jobs:
           # Exit with error if PR is closed
           STATE=$(gh pr view cargo_update --repo $GITHUB_REPOSITORY --json state --jq '.state')
           if [[ "$STATE" != "OPEN" ]]; then
-            exit 1
+            gh run cancel ${{ github.run_id }}
           fi
 
           gh pr edit cargo_update --title "${PR_TITLE}" --body-file body.md --repo $GITHUB_REPOSITORY
diff --git a/.mailmap b/.mailmap
index f37ac7609e0..0d96f5f3d4f 100644
--- a/.mailmap
+++ b/.mailmap
@@ -259,6 +259,7 @@ James Hinshelwood <jameshinshelwood1@gmail.com> <james.hinshelwood@bigpayme.com>
 James Miller <bladeon@gmail.com> <james@aatch.net>
 James Perry <james.austin.perry@gmail.com>
 James Sanderson <zofrex@gmail.com>
+Jan-Erik Rediger <janerik@fnordig.de> <badboy@archlinux.us>
 Jaro Fietz <jaro.fietz@gmx.de>
 Jason Fager <jfager@gmail.com>
 Jason Liquorish <jason@liquori.sh> <Bassetts@users.noreply.github.com>
diff --git a/Cargo.lock b/Cargo.lock
index 3110f32ade9..b8fe1ebaf80 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -214,7 +214,7 @@ version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9792d37ca5173d7e7f4fe453739a0671d0557915a030a383d6b866476bbc3e71"
 dependencies = [
- "object",
+ "object 0.32.2",
 ]
 
 [[package]]
@@ -281,7 +281,7 @@ dependencies = [
  "cfg-if",
  "libc",
  "miniz_oxide",
- "object",
+ "object 0.32.2",
  "rustc-demangle",
 ]
 
@@ -574,7 +574,7 @@ checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
 
 [[package]]
 name = "clippy"
-version = "0.1.78"
+version = "0.1.79"
 dependencies = [
  "anstream",
  "clippy_config",
@@ -602,7 +602,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_config"
-version = "0.1.78"
+version = "0.1.79"
 dependencies = [
  "rustc-semver",
  "serde",
@@ -625,7 +625,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_lints"
-version = "0.1.78"
+version = "0.1.79"
 dependencies = [
  "arrayvec",
  "cargo_metadata 0.18.1",
@@ -650,7 +650,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_utils"
-version = "0.1.78"
+version = "0.1.79"
 dependencies = [
  "arrayvec",
  "clippy_config",
@@ -971,7 +971,7 @@ checksum = "a0afaad2b26fa326569eb264b1363e8ae3357618c43982b3f285f0774ce76b69"
 
 [[package]]
 name = "declare_clippy_lint"
-version = "0.1.78"
+version = "0.1.79"
 dependencies = [
  "itertools 0.12.1",
  "quote",
@@ -2205,7 +2205,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
 dependencies = [
  "cfg-if",
- "windows-targets 0.52.4",
+ "windows-targets 0.48.5",
 ]
 
 [[package]]
@@ -2636,11 +2636,22 @@ dependencies = [
  "memchr",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
- "ruzstd",
+ "ruzstd 0.5.0",
  "wasmparser",
 ]
 
 [[package]]
+name = "object"
+version = "0.34.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7090bae93f8585aad99e595b7073c5de9ba89fbd6b4e9f0cdd7a10177273ac8"
+dependencies = [
+ "flate2",
+ "memchr",
+ "ruzstd 0.6.0",
+]
+
+[[package]]
 name = "odht"
 version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3323,6 +3334,7 @@ dependencies = [
 name = "run_make_support"
 version = "0.0.0"
 dependencies = [
+ "object 0.34.0",
  "wasmparser",
 ]
 
@@ -3634,7 +3646,7 @@ dependencies = [
  "itertools 0.12.1",
  "libc",
  "measureme",
- "object",
+ "object 0.32.2",
  "rustc-demangle",
  "rustc_ast",
  "rustc_attr",
@@ -3670,7 +3682,7 @@ dependencies = [
  "itertools 0.12.1",
  "jobserver",
  "libc",
- "object",
+ "object 0.32.2",
  "pathdiff",
  "regex",
  "rustc_arena",
@@ -3686,6 +3698,7 @@ dependencies = [
  "rustc_macros",
  "rustc_metadata",
  "rustc_middle",
+ "rustc_monomorphize",
  "rustc_query_system",
  "rustc_serialize",
  "rustc_session",
@@ -4236,6 +4249,7 @@ name = "rustc_middle"
 version = "0.0.0"
 dependencies = [
  "bitflags 2.4.2",
+ "derivative",
  "either",
  "field-offset",
  "gsgdt",
@@ -4440,6 +4454,8 @@ dependencies = [
  "rustc_target",
  "smallvec",
  "tracing",
+ "tracing-subscriber",
+ "tracing-tree",
 ]
 
 [[package]]
@@ -4627,7 +4643,7 @@ name = "rustc_target"
 version = "0.0.0"
 dependencies = [
  "bitflags 2.4.2",
- "object",
+ "object 0.32.2",
  "rustc_abi",
  "rustc_data_structures",
  "rustc_feature",
@@ -4895,6 +4911,17 @@ dependencies = [
 ]
 
 [[package]]
+name = "ruzstd"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5174a470eeb535a721ae9fdd6e291c2411a906b96592182d05217591d5c5cf7b"
+dependencies = [
+ "byteorder",
+ "derive_more",
+ "twox-hash",
+]
+
+[[package]]
 name = "ryu"
 version = "1.0.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5197,7 +5224,7 @@ dependencies = [
  "hermit-abi",
  "libc",
  "miniz_oxide",
- "object",
+ "object 0.32.2",
  "panic_abort",
  "panic_unwind",
  "profiler_builtins",
@@ -5514,7 +5541,7 @@ checksum = "4db52ee8fec06e119b692ef3dd2c4cf621a99204c1b8c47407870ed050305b9b"
 dependencies = [
  "gimli",
  "hashbrown",
- "object",
+ "object 0.32.2",
  "tracing",
 ]
 
diff --git a/Cargo.toml b/Cargo.toml
index 5dd315ef2f7..e12c968e205 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -66,15 +66,6 @@ exclude = [
 ]
 
 [profile.release.package.compiler_builtins]
-# The compiler-builtins crate cannot reference libcore, and its own CI will
-# verify that this is the case. This requires, however, that the crate is built
-# without overflow checks and debug assertions. Forcefully disable debug
-# assertions and overflow checks here which should ensure that even if these
-# assertions are enabled for libstd we won't enable them for compiler_builtins
-# which should ensure we still link everything correctly.
-debug-assertions = false
-overflow-checks = false
-
 # For compiler-builtins we always use a high number of codegen units.
 # The goal here is to place every single intrinsic into its own object
 # file to avoid symbol clashes with the system libgcc if possible. Note
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index d0e8b86b71d..915cb386075 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -303,10 +303,6 @@ impl TraitBoundModifiers {
     };
 }
 
-/// The AST represents all type param bounds as types.
-/// `typeck::collect::compute_bounds` matches these against
-/// the "special" built-in traits (see `middle::lang_items`) and
-/// detects `Copy`, `Send` and `Sync`.
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub enum GenericBound {
     Trait(PolyTraitRef, TraitBoundModifiers),
@@ -621,7 +617,9 @@ impl Pat {
             | PatKind::Or(s) => s.iter().for_each(|p| p.walk(it)),
 
             // Trivial wrappers over inner patterns.
-            PatKind::Box(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => s.walk(it),
+            PatKind::Box(s) | PatKind::Deref(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => {
+                s.walk(it)
+            }
 
             // These patterns do not contain subpatterns, skip.
             PatKind::Wild
@@ -792,6 +790,9 @@ pub enum PatKind {
     /// A `box` pattern.
     Box(P<Pat>),
 
+    /// A `deref` pattern (currently `deref!()` macro-based syntax).
+    Deref(P<Pat>),
+
     /// A reference pattern (e.g., `&mut (a, b)`).
     Ref(P<Pat>, Mutability),
 
@@ -1436,7 +1437,7 @@ pub enum ExprKind {
     /// `'label: loop { block }`
     Loop(P<Block>, Option<Label>, Span),
     /// A `match` block.
-    Match(P<Expr>, ThinVec<Arm>),
+    Match(P<Expr>, ThinVec<Arm>, MatchKind),
     /// A closure (e.g., `move |a, b, c| a + b + c`).
     Closure(Box<Closure>),
     /// A block (`'label: { ... }`).
@@ -1761,6 +1762,15 @@ pub enum StrStyle {
     Raw(u8),
 }
 
+/// The kind of match expression
+#[derive(Clone, Copy, Encodable, Decodable, Debug, PartialEq)]
+pub enum MatchKind {
+    /// match expr { ... }
+    Prefix,
+    /// expr.match { ... }
+    Postfix,
+}
+
 /// A literal in a meta item.
 #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
 pub struct MetaItemLit {
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 83468c5f101..7337b969242 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -1295,6 +1295,7 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
             fields.flat_map_in_place(|field| vis.flat_map_pat_field(field));
         }
         PatKind::Box(inner) => vis.visit_pat(inner),
+        PatKind::Deref(inner) => vis.visit_pat(inner),
         PatKind::Ref(inner, _mutbl) => vis.visit_pat(inner),
         PatKind::Range(e1, e2, Spanned { span: _, node: _ }) => {
             visit_opt(e1, |e| vis.visit_expr(e));
@@ -1424,7 +1425,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
             visit_opt(label, |label| vis.visit_label(label));
             vis.visit_span(span);
         }
-        ExprKind::Match(expr, arms) => {
+        ExprKind::Match(expr, arms, _kind) => {
             vis.visit_expr(expr);
             arms.flat_map_in_place(|arm| vis.flat_map_arm(arm));
         }
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index c17020ed663..f49eb2f22c5 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -105,7 +105,7 @@ impl Lit {
         }
     }
 
-    /// Keep this in sync with `Token::can_begin_literal_or_bool` excluding unary negation.
+    /// Keep this in sync with `Token::can_begin_literal_maybe_minus` excluding unary negation.
     pub fn from_token(token: &Token) -> Option<Lit> {
         match token.uninterpolate().kind {
             Ident(name, IdentIsRaw::No) if name.is_bool_lit() => Some(Lit::new(Bool, name, None)),
@@ -664,7 +664,7 @@ impl Token {
     }
 
     /// Returns `true` if the token is an interpolated path.
-    fn is_path(&self) -> bool {
+    fn is_whole_path(&self) -> bool {
         if let Interpolated(nt) = &self.kind
             && let NtPath(..) = &nt.0
         {
@@ -710,7 +710,7 @@ impl Token {
     pub fn is_path_start(&self) -> bool {
         self == &ModSep
             || self.is_qpath_start()
-            || self.is_path()
+            || self.is_whole_path()
             || self.is_path_segment_keyword()
             || self.is_ident() && !self.is_reserved_ident()
     }
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index adc3056cc29..239735456ad 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -28,18 +28,7 @@ use smallvec::{smallvec, SmallVec};
 use std::borrow::Cow;
 use std::{cmp, fmt, iter};
 
-/// When the main Rust parser encounters a syntax-extension invocation, it
-/// parses the arguments to the invocation as a token tree. This is a very
-/// loose structure, such that all sorts of different AST fragments can
-/// be passed to syntax extensions using a uniform type.
-///
-/// If the syntax extension is an MBE macro, it will attempt to match its
-/// LHS token tree against the provided token tree, and if it finds a
-/// match, will transcribe the RHS token tree, splicing in any captured
-/// `macro_parser::matched_nonterminals` into the `SubstNt`s it finds.
-///
-/// The RHS of an MBE macro is the only place `SubstNt`s are substituted.
-/// Nothing special happens to misnamed or misplaced `SubstNt`s.
+/// Part of a `TokenStream`.
 #[derive(Debug, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
 pub enum TokenTree {
     /// A single token. Should never be `OpenDelim` or `CloseDelim`, because
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 825f8dad8e4..18986fb7504 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -480,7 +480,7 @@ pub fn walk_use_tree<'a, V: Visitor<'a>>(
     try_visit!(visitor.visit_path(&use_tree.prefix, id));
     match use_tree.kind {
         UseTreeKind::Simple(rename) => {
-            // The extra IDs are handled during HIR lowering.
+            // The extra IDs are handled during AST lowering.
             visit_opt!(visitor, visit_ident, rename);
         }
         UseTreeKind::Glob => {}
@@ -576,7 +576,10 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res
             try_visit!(visitor.visit_path(path, pattern.id));
             walk_list!(visitor, visit_pat_field, fields);
         }
-        PatKind::Box(subpattern) | PatKind::Ref(subpattern, _) | PatKind::Paren(subpattern) => {
+        PatKind::Box(subpattern)
+        | PatKind::Deref(subpattern)
+        | PatKind::Ref(subpattern, _)
+        | PatKind::Paren(subpattern) => {
             try_visit!(visitor.visit_pat(subpattern));
         }
         PatKind::Ident(_, ident, optional_subpattern) => {
@@ -920,7 +923,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
             visit_opt!(visitor, visit_label, opt_label);
             try_visit!(visitor.visit_block(block));
         }
-        ExprKind::Match(subexpression, arms) => {
+        ExprKind::Match(subexpression, arms, _kind) => {
             try_visit!(visitor.visit_expr(subexpression));
             walk_list!(visitor, visit_arm, arms);
         }
diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs
index 11a66fe87c9..eef6e8280af 100644
--- a/compiler/rustc_ast_lowering/src/block.rs
+++ b/compiler/rustc_ast_lowering/src/block.rs
@@ -81,7 +81,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         (self.arena.alloc_from_iter(stmts), expr)
     }
 
-    fn lower_local(&mut self, l: &Local) -> &'hir hir::Local<'hir> {
+    fn lower_local(&mut self, l: &Local) -> &'hir hir::LetStmt<'hir> {
         let ty = l
             .ty
             .as_ref()
@@ -97,7 +97,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let span = self.lower_span(l.span);
         let source = hir::LocalSource::Normal;
         self.lower_attrs(hir_id, &l.attrs);
-        self.arena.alloc(hir::Local { hir_id, ty, pat, init, els, span, source })
+        self.arena.alloc(hir::LetStmt { hir_id, ty, pat, init, els, span, source })
     }
 
     fn lower_block_check_mode(&mut self, b: &BlockCheckMode) -> hir::BlockCheckMode {
diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs
index 4e1c477a3d7..e26a65c1f29 100644
--- a/compiler/rustc_ast_lowering/src/delegation.rs
+++ b/compiler/rustc_ast_lowering/src/delegation.rs
@@ -29,11 +29,12 @@
 //! item id (`item_id`) in case of impl trait or path resolution id (`path_id`) otherwise.
 //!
 //! Since we do not have a proper way to obtain function type information by path resolution
-//! in AST, we mark each function parameter type as `InferDelegation` and inherit it in `AstConv`.
+//! in AST, we mark each function parameter type as `InferDelegation` and inherit it during
+//! HIR ty lowering.
 //!
 //! Similarly generics, predicates and header are set to the "default" values.
 //! In case of discrepancy with callee function the `NotSupportedDelegation` error will
-//! also be emitted in `AstConv`.
+//! also be emitted during HIR ty lowering.
 
 use crate::{ImplTraitPosition, ResolverAstLoweringExt};
 
@@ -129,7 +130,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
     ) -> &'hir hir::FnDecl<'hir> {
         let args_count = if let Some(local_sig_id) = sig_id.as_local() {
             // Map may be filled incorrectly due to recursive delegation.
-            // Error will be emmited later in astconv.
+            // Error will be emitted later during HIR ty lowering.
             self.resolver.fn_parameter_counts.get(&local_sig_id).cloned().unwrap_or_default()
         } else {
             self.tcx.fn_arg_names(sig_id).len()
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 41f7418ddde..389cf4e3132 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -157,7 +157,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     hir::ExprKind::AddrOf(*k, *m, ohs)
                 }
                 ExprKind::Let(pat, scrutinee, span, is_recovered) => {
-                    hir::ExprKind::Let(self.arena.alloc(hir::Let {
+                    hir::ExprKind::Let(self.arena.alloc(hir::LetExpr {
                         span: self.lower_span(*span),
                         pat: self.lower_pat(pat),
                         ty: None,
@@ -181,10 +181,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     )
                 }),
                 ExprKind::TryBlock(body) => self.lower_expr_try_block(body),
-                ExprKind::Match(expr, arms) => hir::ExprKind::Match(
+                ExprKind::Match(expr, arms, kind) => hir::ExprKind::Match(
                     self.lower_expr(expr),
                     self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))),
-                    hir::MatchSource::Normal,
+                    match kind {
+                        MatchKind::Prefix => hir::MatchSource::Normal,
+                        MatchKind::Postfix => hir::MatchSource::Postfix,
+                    },
                 ),
                 ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr),
                 ExprKind::Closure(box Closure {
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index 9078b1f889c..a1164008d0d 100644
--- a/compiler/rustc_ast_lowering/src/index.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -302,8 +302,8 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
         });
     }
 
-    fn visit_local(&mut self, l: &'hir Local<'hir>) {
-        self.insert(l.span, l.hir_id, Node::Local(l));
+    fn visit_local(&mut self, l: &'hir LetStmt<'hir>) {
+        self.insert(l.span, l.hir_id, Node::LetStmt(l));
         self.with_parent(l.hir_id, |this| {
             intravisit::walk_local(this, l);
         })
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 2d03c854bd0..c9786328565 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1427,8 +1427,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
         // Error if `?Trait` bounds in where clauses don't refer directly to type parameters.
         // Note: we used to clone these bounds directly onto the type parameter (and avoid lowering
         // these into hir when we lower thee where clauses), but this makes it quite difficult to
-        // keep track of the Span info. Now, `add_implicitly_sized` in `AstConv` checks both param bounds and
-        // where clauses for `?Sized`.
+        // keep track of the Span info. Now, `<dyn HirTyLowerer>::add_implicit_sized_bound`
+        // checks both param bounds and where clauses for `?Sized`.
         for pred in &generics.where_clause.predicates {
             let WherePredicate::BoundPredicate(bound_pred) = pred else {
                 continue;
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 6a7ee936f66..b5b98659e2f 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -55,7 +55,9 @@ use rustc_errors::{DiagArgFromDisplay, DiagCtxt, StashKey};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
 use rustc_hir::def_id::{LocalDefId, LocalDefIdMap, CRATE_DEF_ID, LOCAL_CRATE};
-use rustc_hir::{ConstArg, GenericArg, ItemLocalMap, ParamName, TraitCandidate};
+use rustc_hir::{
+    ConstArg, GenericArg, ItemLocalMap, MissingLifetimeKind, ParamName, TraitCandidate,
+};
 use rustc_index::{Idx, IndexSlice, IndexVec};
 use rustc_macros::extension;
 use rustc_middle::span_bug;
@@ -797,7 +799,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             LifetimeRes::Param { .. } => {
                 (hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit)
             }
-            LifetimeRes::Fresh { param, .. } => {
+            LifetimeRes::Fresh { param, kind, .. } => {
                 // Late resolution delegates to us the creation of the `LocalDefId`.
                 let _def_id = self.create_def(
                     self.current_hir_id_owner.def_id,
@@ -808,7 +810,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 );
                 debug!(?_def_id);
 
-                (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
+                (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided(kind))
             }
             LifetimeRes::Static | LifetimeRes::Error => return None,
             res => panic!(
@@ -1605,13 +1607,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
         for lifetime in captured_lifetimes_to_duplicate {
             let res = self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error);
-            let old_def_id = match res {
-                LifetimeRes::Param { param: old_def_id, binder: _ } => old_def_id,
+            let (old_def_id, missing_kind) = match res {
+                LifetimeRes::Param { param: old_def_id, binder: _ } => (old_def_id, None),
 
-                LifetimeRes::Fresh { param, binder: _ } => {
+                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
+                        (old_def_id, Some(kind))
                     } else {
                         self.dcx()
                             .span_delayed_bug(lifetime.ident.span, "no def-id for fresh lifetime");
@@ -1651,6 +1653,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     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.
@@ -1668,27 +1671,33 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             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)| {
-                    let hir_id = this.lower_node_id(new_node_id);
-                    let (name, kind) = if ident.name == kw::UnderscoreLifetime {
-                        (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
-                    } else {
-                        (hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit)
-                    };
+            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,
-                    }
-                }),
-            );
+                        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);
@@ -2332,7 +2341,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             debug_assert!(!a.is_empty());
             self.attrs.insert(hir_id.local_id, a);
         }
-        let local = hir::Local {
+        let local = hir::LetStmt {
             hir_id,
             init,
             pat,
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index 469cdac11e4..8631d90be81 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -91,6 +91,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     PatKind::Box(inner) => {
                         break hir::PatKind::Box(self.lower_pat(inner));
                     }
+                    PatKind::Deref(inner) => {
+                        break hir::PatKind::Deref(self.lower_pat(inner));
+                    }
                     PatKind::Ref(inner, mutbl) => {
                         break hir::PatKind::Ref(self.lower_pat(inner), *mutbl);
                     }
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 2c396a64789..bb83f4c0f0e 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -564,6 +564,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
     gate_all!(generic_const_items, "generic const items are experimental");
     gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented");
     gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
+    gate_all!(postfix_match, "postfix match is experimental");
 
     if !visitor.features.never_patterns {
         if let Some(spans) = spans.get(&sym::never_patterns) {
@@ -607,13 +608,13 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
         };
     }
 
+    gate_all_legacy_dont_use!(box_patterns, "box pattern syntax is experimental");
     gate_all_legacy_dont_use!(trait_alias, "trait aliases are experimental");
     // Despite being a new feature, `where T: Trait<Assoc(): Sized>`, which is RTN syntax now,
     // used to be gated under associated_type_bounds, which are right above, so RTN needs to
     // be too.
     gate_all_legacy_dont_use!(return_type_notation, "return type notation is experimental");
     gate_all_legacy_dont_use!(decl_macro, "`macro` is experimental");
-    gate_all_legacy_dont_use!(box_patterns, "box pattern syntax is experimental");
     gate_all_legacy_dont_use!(
         exclusive_range_pattern,
         "exclusive range pattern syntax is experimental"
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index c50878e32a4..a70daf1b644 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1626,6 +1626,12 @@ impl<'a> State<'a> {
                 self.word("box ");
                 self.print_pat(inner);
             }
+            PatKind::Deref(inner) => {
+                self.word("deref!");
+                self.popen();
+                self.print_pat(inner);
+                self.pclose();
+            }
             PatKind::Ref(inner, mutbl) => {
                 self.word("&");
                 if mutbl.is_mut() {
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index 433ef03b6e5..8bd8b6ac144 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -1,6 +1,6 @@
 use crate::pp::Breaks::Inconsistent;
 use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
-use ast::ForLoopKind;
+use ast::{ForLoopKind, MatchKind};
 use itertools::{Itertools, Position};
 use rustc_ast::ptr::P;
 use rustc_ast::token;
@@ -589,12 +589,22 @@ impl<'a> State<'a> {
                 self.word_nbsp("loop");
                 self.print_block_with_attrs(blk, attrs);
             }
-            ast::ExprKind::Match(expr, arms) => {
+            ast::ExprKind::Match(expr, arms, match_kind) => {
                 self.cbox(0);
                 self.ibox(0);
-                self.word_nbsp("match");
-                self.print_expr_as_cond(expr);
-                self.space();
+
+                match match_kind {
+                    MatchKind::Prefix => {
+                        self.word_nbsp("match");
+                        self.print_expr_as_cond(expr);
+                        self.space();
+                    }
+                    MatchKind::Postfix => {
+                        self.print_expr_as_cond(expr);
+                        self.word_nbsp(".match");
+                    }
+                }
+
                 self.bopen();
                 self.print_inner_attributes_no_trailing_hardbreak(attrs);
                 for arm in arms {
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 0109f188772..35bd7d37992 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -622,7 +622,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
                     // FIXME: We make sure that this is a normal top-level binding,
                     // but we could suggest `todo!()` for all uninitalized bindings in the pattern pattern
-                    if let hir::StmtKind::Let(hir::Local { span, ty, init: None, pat, .. }) =
+                    if let hir::StmtKind::Let(hir::LetStmt { span, ty, init: None, pat, .. }) =
                         &ex.kind
                         && let hir::PatKind::Binding(..) = pat.kind
                         && span.contains(self.decl_span)
@@ -716,7 +716,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 .copied()
                 .find_map(find_fn_kind_from_did),
             ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => tcx
-                .explicit_item_bounds(def_id)
+                .explicit_item_super_predicates(def_id)
                 .iter_instantiated_copied(tcx, args)
                 .find_map(|(clause, span)| find_fn_kind_from_did((clause, span))),
             ty::Closure(_, args) => match args.as_closure().kind() {
@@ -800,7 +800,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         for (_, node) in tcx.hir().parent_iter(expr.hir_id) {
             let e = match node {
                 hir::Node::Expr(e) => e,
-                hir::Node::Local(hir::Local { els: Some(els), .. }) => {
+                hir::Node::LetStmt(hir::LetStmt { els: Some(els), .. }) => {
                     let mut finder = BreakFinder { found_breaks: vec![], found_continues: vec![] };
                     finder.visit_block(els);
                     if !finder.found_breaks.is_empty() {
@@ -2124,7 +2124,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 hir::intravisit::walk_expr(self, e);
             }
 
-            fn visit_local(&mut self, local: &'hir hir::Local<'hir>) {
+            fn visit_local(&mut self, local: &'hir hir::LetStmt<'hir>) {
                 if let hir::Pat { kind: hir::PatKind::Binding(_, hir_id, _ident, _), .. } =
                     local.pat
                     && let Some(init) = local.init
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 914f68a38b4..11561539f6d 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -366,7 +366,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     Some(variant.fields[field].name.to_string())
                 }
                 ty::Tuple(_) => Some(field.index().to_string()),
-                ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
+                ty::Ref(_, ty, _) | ty::RawPtr(ty, _) => {
                     self.describe_field_from_ty(ty, field, variant_index, including_tuple_field)
                 }
                 ty::Array(ty, _) | ty::Slice(ty) => {
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 36c2723b66d..2aeea1dd341 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -558,7 +558,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     hir::intravisit::walk_stmt(self, stmt);
                     let expr = match stmt.kind {
                         hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr) => expr,
-                        hir::StmtKind::Let(hir::Local { init: Some(expr), .. }) => expr,
+                        hir::StmtKind::Let(hir::LetStmt { init: Some(expr), .. }) => expr,
                         _ => {
                             return;
                         }
@@ -737,7 +737,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             && let body = self.infcx.tcx.hir().body(body_id)
             && let Some(hir_id) = (BindingFinder { span: pat_span }).visit_body(body).break_value()
             && let node = self.infcx.tcx.hir_node(hir_id)
-            && let hir::Node::Local(hir::Local {
+            && let hir::Node::LetStmt(hir::LetStmt {
                 pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. },
                 ..
             })
@@ -1170,7 +1170,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 };
 
                 if let Some(hir_id) = hir_id
-                    && let hir::Node::Local(local) = self.infcx.tcx.hir_node(hir_id)
+                    && let hir::Node::LetStmt(local) = self.infcx.tcx.hir_node(hir_id)
                 {
                     let tables = self.infcx.tcx.typeck(def_id.as_local().unwrap());
                     if let Some(clone_trait) = self.infcx.tcx.lang_items().clone_trait()
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index c06bf94a6fd..c92fccc959f 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -503,10 +503,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             ty::VarianceDiagInfo::None => {}
             ty::VarianceDiagInfo::Invariant { ty, param_index } => {
                 let (desc, note) = match ty.kind() {
-                    ty::RawPtr(ty_mut) => {
-                        assert_eq!(ty_mut.mutbl, rustc_hir::Mutability::Mut);
+                    ty::RawPtr(ty, mutbl) => {
+                        assert_eq!(*mutbl, rustc_hir::Mutability::Mut);
                         (
-                            format!("a mutable pointer to `{}`", ty_mut.ty),
+                            format!("a mutable pointer to `{}`", ty),
                             "mutable pointers are invariant over their type parameter".to_string(),
                         )
                     }
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 08199068020..cda61360404 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -555,8 +555,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                     search_stack.push((*elem_ty, elem_hir_ty));
                 }
 
-                (ty::RawPtr(mut_ty), hir::TyKind::Ptr(mut_hir_ty)) => {
-                    search_stack.push((mut_ty.ty, &mut_hir_ty.ty));
+                (ty::RawPtr(mut_ty, _), hir::TyKind::Ptr(mut_hir_ty)) => {
+                    search_stack.push((*mut_ty, &mut_hir_ty.ty));
                 }
 
                 _ => {
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 9f4f88b2b93..4a5ba441878 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -1649,7 +1649,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     | ty::Str
                     | ty::Array(_, _)
                     | ty::Slice(_)
-                    | ty::RawPtr(_)
+                    | ty::RawPtr(_, _)
                     | ty::Ref(_, _, _)
                     | ty::FnDef(_, _)
                     | ty::FnPtr(_)
@@ -2284,8 +2284,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                                     }
                                 }
                             }
-                            ty::RawPtr(tnm) => {
-                                match tnm.mutbl {
+                            ty::RawPtr(_, mutbl) => {
+                                match mutbl {
                                     // `*const` raw pointers are not mutable
                                     hir::Mutability::Not => Err(place),
                                     // `*mut` raw pointers are always mutable, regardless of
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index c3800a1f1f2..54c516c960c 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -2065,7 +2065,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 from_closure: constraint.from_closure,
                 cause: ObligationCause::new(constraint.span, CRATE_DEF_ID, cause_code.clone()),
                 variance_info: constraint.variance_info,
-                outlives_constraint: *constraint,
             })
             .collect();
         debug!("categorized_path={:#?}", categorized_path);
@@ -2294,5 +2293,4 @@ pub struct BlameConstraint<'tcx> {
     pub from_closure: bool,
     pub cause: ObligationCause<'tcx>,
     pub variance_info: ty::VarianceDiagInfo<'tcx>,
-    pub outlives_constraint: OutlivesConstraint<'tcx>,
 }
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index bea9be24028..d5875a226fe 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -192,6 +192,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                         .find(|ur_vid| self.eval_equal(vid, **ur_vid))
                         .and_then(|ur_vid| self.definitions[*ur_vid].external_name)
                         .unwrap_or(infcx.tcx.lifetimes.re_erased),
+                    ty::RePlaceholder(_) => ty::Region::new_error_with_message(
+                        infcx.tcx,
+                        concrete_type.span,
+                        "hidden type contains placeholders, we don't support higher kinded opaques yet",
+                    ),
                     _ => region,
                 });
             debug!(?universal_concrete_type);
@@ -434,10 +439,6 @@ fn check_opaque_type_parameter_valid(
     // Only check the parent generics, which will ignore any of the
     // duplicated lifetime args that come from reifying late-bounds.
     for (i, arg) in opaque_type_key.args.iter().take(parent_generics.count()).enumerate() {
-        if let Err(guar) = arg.error_reported() {
-            return Err(guar);
-        }
-
         let arg_is_param = match arg.unpack() {
             GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
             GenericArgKind::Lifetime(lt) if is_ty_alias => {
diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
index a673c4c2aca..f28b786e4f7 100644
--- a/compiler/rustc_borrowck/src/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -82,7 +82,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     ) {
         self.prove_predicate(
             ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Trait(
-                ty::TraitPredicate { trait_ref, polarity: ty::ImplPolarity::Positive },
+                ty::TraitPredicate { trait_ref, polarity: ty::PredicatePolarity::Positive },
             ))),
             locations,
             category,
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index acda2a7524c..a206aac0467 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -2000,7 +2000,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     ConstraintCategory::SizedBound,
                 );
             }
-            &Rvalue::NullaryOp(NullOp::UbCheck(_), _) => {}
+            &Rvalue::NullaryOp(NullOp::UbChecks, _) => {}
 
             Rvalue::ShallowInitBox(operand, ty) => {
                 self.check_operand(operand, location);
@@ -2157,15 +2157,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     }
 
                     CastKind::PointerCoercion(PointerCoercion::MutToConstPointer) => {
-                        let ty::RawPtr(ty::TypeAndMut { ty: ty_from, mutbl: hir::Mutability::Mut }) =
-                            op.ty(body, tcx).kind()
+                        let ty::RawPtr(ty_from, hir::Mutability::Mut) = op.ty(body, tcx).kind()
                         else {
                             span_mirbug!(self, rvalue, "unexpected base type for cast {:?}", ty,);
                             return;
                         };
-                        let ty::RawPtr(ty::TypeAndMut { ty: ty_to, mutbl: hir::Mutability::Not }) =
-                            ty.kind()
-                        else {
+                        let ty::RawPtr(ty_to, hir::Mutability::Not) = ty.kind() else {
                             span_mirbug!(self, rvalue, "unexpected target type for cast {:?}", ty,);
                             return;
                         };
@@ -2190,12 +2187,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         let ty_from = op.ty(body, tcx);
 
                         let opt_ty_elem_mut = match ty_from.kind() {
-                            ty::RawPtr(ty::TypeAndMut { mutbl: array_mut, ty: array_ty }) => {
-                                match array_ty.kind() {
-                                    ty::Array(ty_elem, _) => Some((ty_elem, *array_mut)),
-                                    _ => None,
-                                }
-                            }
+                            ty::RawPtr(array_ty, array_mut) => match array_ty.kind() {
+                                ty::Array(ty_elem, _) => Some((ty_elem, *array_mut)),
+                                _ => None,
+                            },
                             _ => None,
                         };
 
@@ -2210,9 +2205,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         };
 
                         let (ty_to, ty_to_mut) = match ty.kind() {
-                            ty::RawPtr(ty::TypeAndMut { mutbl: ty_to_mut, ty: ty_to }) => {
-                                (ty_to, *ty_to_mut)
-                            }
+                            ty::RawPtr(ty_to, ty_to_mut) => (ty_to, *ty_to_mut),
                             _ => {
                                 span_mirbug!(
                                     self,
@@ -2413,7 +2406,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 let ty_left = left.ty(body, tcx);
                 match ty_left.kind() {
                     // Types with regions are comparable if they have a common super-type.
-                    ty::RawPtr(_) | ty::FnPtr(_) => {
+                    ty::RawPtr(_, _) | ty::FnPtr(_) => {
                         let ty_right = right.ty(body, tcx);
                         let common_ty = self.infcx.next_ty_var(TypeVariableOrigin {
                             kind: TypeVariableOriginKind::MiscVariable,
diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs
index 56c56b2704b..92efeab08eb 100644
--- a/compiler/rustc_builtin_macros/src/assert/context.rs
+++ b/compiler/rustc_builtin_macros/src/assert/context.rs
@@ -245,7 +245,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
             ExprKind::Let(_, local_expr, _, _) => {
                 self.manage_cond_expr(local_expr);
             }
-            ExprKind::Match(local_expr, _) => {
+            ExprKind::Match(local_expr, ..) => {
                 self.manage_cond_expr(local_expr);
             }
             ExprKind::MethodCall(call) => {
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
index 6eccd67f8af..60dbdf8b544 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
@@ -132,7 +132,7 @@ fn cs_partial_cmp(
                 // Reference: https://github.com/rust-lang/rust/pull/103659#issuecomment-1328126354
 
                 if !tag_then_data
-                    && let ExprKind::Match(_, arms) = &mut expr1.kind
+                    && let ExprKind::Match(_, arms, _) = &mut expr1.kind
                     && let Some(last) = arms.last_mut()
                     && let PatKind::Wild = last.pat.kind
                 {
diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs
index b11a1b6cda1..03acd7f489f 100644
--- a/compiler/rustc_builtin_macros/src/deriving/debug.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs
@@ -2,8 +2,7 @@ use crate::deriving::generic::ty::*;
 use crate::deriving::generic::*;
 use crate::deriving::path_std;
 
-use ast::EnumDef;
-use rustc_ast::{self as ast, MetaItem};
+use rustc_ast::{self as ast, EnumDef, MetaItem};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::Span;
@@ -52,7 +51,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
 
     let (ident, vdata, fields) = match substr.fields {
         Struct(vdata, fields) => (substr.type_ident, *vdata, fields),
-        EnumMatching(_, _, v, fields) => (v.ident, &v.data, fields),
+        EnumMatching(_, v, fields) => (v.ident, &v.data, fields),
         AllFieldlessEnum(enum_def) => return show_fieldless_enum(cx, span, enum_def, substr),
         EnumTag(..) | StaticStruct(..) | StaticEnum(..) => {
             cx.dcx().span_bug(span, "nonsensical .fields in `#[derive(Debug)]`")
diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
index 14d93a8cc23..d939f8c7aeb 100644
--- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
@@ -226,7 +226,7 @@ fn encodable_substructure(
             BlockOrExpr::new_expr(expr)
         }
 
-        EnumMatching(idx, _, variant, fields) => {
+        EnumMatching(idx, variant, fields) => {
             // We're not generating an AST that the borrow checker is expecting,
             // so we need to generate a unique local variable to take the
             // mutable loan out on, otherwise we get conflicts which don't
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 3cb3e30daa7..afa73b672da 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -310,10 +310,10 @@ pub enum SubstructureFields<'a> {
     /// variants has any fields).
     AllFieldlessEnum(&'a ast::EnumDef),
 
-    /// Matching variants of the enum: variant index, variant count, ast::Variant,
+    /// Matching variants of the enum: variant index, ast::Variant,
     /// fields: the field name is only non-`None` in the case of a struct
     /// variant.
-    EnumMatching(usize, usize, &'a ast::Variant, Vec<FieldInfo>),
+    EnumMatching(usize, &'a ast::Variant, Vec<FieldInfo>),
 
     /// The tag of an enum. The first field is a `FieldInfo` for the tags, as
     /// if they were fields. The second field is the expression to combine the
@@ -1272,7 +1272,7 @@ impl<'a> MethodDef<'a> {
                     trait_,
                     type_ident,
                     nonselflike_args,
-                    &EnumMatching(0, 1, &variants[0], Vec::new()),
+                    &EnumMatching(0, &variants[0], Vec::new()),
                 );
             }
         }
@@ -1318,7 +1318,7 @@ impl<'a> MethodDef<'a> {
                 // expressions for referencing every field of every
                 // Self arg, assuming all are instances of VariantK.
                 // Build up code associated with such a case.
-                let substructure = EnumMatching(index, variants.len(), variant, fields);
+                let substructure = EnumMatching(index, variant, fields);
                 let arm_expr = self
                     .call_substructure_method(
                         cx,
@@ -1346,7 +1346,7 @@ impl<'a> MethodDef<'a> {
                         trait_,
                         type_ident,
                         nonselflike_args,
-                        &EnumMatching(0, variants.len(), v, Vec::new()),
+                        &EnumMatching(0, v, Vec::new()),
                     )
                     .into_expr(cx, span),
                 )
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index f344dbcd10c..554dac0852f 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -49,7 +49,6 @@ mod log_syntax;
 mod source_util;
 mod test;
 mod trace_macros;
-mod type_ascribe;
 mod util;
 
 pub mod asm;
@@ -99,7 +98,6 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
         std_panic: edition_panic::expand_panic,
         stringify: source_util::expand_stringify,
         trace_macros: trace_macros::expand_trace_macros,
-        type_ascribe: type_ascribe::expand_type_ascribe,
         unreachable: edition_panic::expand_unreachable,
         // tidy-alphabetical-end
     }
diff --git a/compiler/rustc_builtin_macros/src/type_ascribe.rs b/compiler/rustc_builtin_macros/src/type_ascribe.rs
deleted file mode 100644
index f3e66ffc759..00000000000
--- a/compiler/rustc_builtin_macros/src/type_ascribe.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-use rustc_ast::ptr::P;
-use rustc_ast::tokenstream::TokenStream;
-use rustc_ast::{token, Expr, ExprKind, Ty};
-use rustc_errors::PResult;
-use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
-use rustc_span::Span;
-
-pub fn expand_type_ascribe(
-    cx: &mut ExtCtxt<'_>,
-    span: Span,
-    tts: TokenStream,
-) -> MacroExpanderResult<'static> {
-    let (expr, ty) = match parse_ascribe(cx, tts) {
-        Ok(parsed) => parsed,
-        Err(err) => {
-            let guar = err.emit();
-            return ExpandResult::Ready(DummyResult::any(span, guar));
-        }
-    };
-
-    let asc_expr = cx.expr(span, ExprKind::Type(expr, ty));
-
-    ExpandResult::Ready(MacEager::expr(asc_expr))
-}
-
-fn parse_ascribe<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P<Expr>, P<Ty>)> {
-    let mut parser = cx.new_parser_from_tts(stream);
-
-    let expr = parser.parse_expr()?;
-    parser.expect(&token::Comma)?;
-
-    let ty = parser.parse_ty()?;
-
-    Ok((expr, ty))
-}
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 6e846d721f2..b0af421008a 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -8,8 +8,11 @@ use std::borrow::Cow;
 
 use cranelift_codegen::ir::SigRef;
 use cranelift_module::ModuleError;
+use rustc_codegen_ssa::errors::CompilerBuiltinsCannotCall;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::ty::layout::FnAbiOf;
+use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization;
 use rustc_session::Session;
 use rustc_span::source_map::Spanned;
 use rustc_target::abi::call::{Conv, FnAbi};
@@ -372,6 +375,17 @@ pub(crate) fn codegen_terminator_call<'tcx>(
             ty::Instance::expect_resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, fn_args)
                 .polymorphize(fx.tcx);
 
+        if is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx, instance) {
+            if target.is_some() {
+                let caller = with_no_trimmed_paths!(fx.tcx.def_path_str(fx.instance.def_id()));
+                let callee = with_no_trimmed_paths!(fx.tcx.def_path_str(def_id));
+                fx.tcx.dcx().emit_err(CompilerBuiltinsCannotCall { caller, callee });
+            } else {
+                fx.bcx.ins().trap(TrapCode::User(0));
+                return;
+            }
+        }
+
         if fx.tcx.symbol_name(instance).name.starts_with("llvm.") {
             crate::intrinsics::codegen_llvm_intrinsic_call(
                 fx,
@@ -663,11 +677,7 @@ pub(crate) fn codegen_drop<'tcx>(
 
                 let arg_value = drop_place.place_ref(
                     fx,
-                    fx.layout_of(Ty::new_ref(
-                        fx.tcx,
-                        fx.tcx.lifetimes.re_erased,
-                        TypeAndMut { ty, mutbl: crate::rustc_hir::Mutability::Mut },
-                    )),
+                    fx.layout_of(Ty::new_mut_ref(fx.tcx, fx.tcx.lifetimes.re_erased, ty)),
                 );
                 let arg_value = adjust_arg_for_abi(fx, arg_value, &fn_abi.args[0], true);
 
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 2415c2c90b2..dbce6d165d2 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -8,6 +8,7 @@ use rustc_index::IndexVec;
 use rustc_middle::ty::adjustment::PointerCoercion;
 use rustc_middle::ty::layout::FnAbiOf;
 use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization;
 
 use crate::constant::ConstantCx;
 use crate::debuginfo::FunctionDebugContext;
@@ -779,7 +780,7 @@ fn codegen_stmt<'tcx>(
                         NullOp::OffsetOf(fields) => {
                             layout.offset_of_subfield(fx, fields.iter()).bytes()
                         }
-                        NullOp::UbCheck(_) => {
+                        NullOp::UbChecks => {
                             let val = fx.tcx.sess.opts.debug_assertions;
                             let val = CValue::by_val(
                                 fx.bcx.ins().iconst(types::I8, i64::try_from(val).unwrap()),
@@ -999,6 +1000,12 @@ fn codegen_panic_inner<'tcx>(
     let def_id = fx.tcx.require_lang_item(lang_item, span);
 
     let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx);
+
+    if is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx, instance) {
+        fx.bcx.ins().trap(TrapCode::User(0));
+        return;
+    }
+
     let symbol_name = fx.tcx.symbol_name(instance).name;
 
     fx.lib_call(
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index 7e29d407a1f..a7c3d68ff8c 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -69,7 +69,7 @@ fn clif_type_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<types::Typ
             FloatTy::F128 => unimplemented!("f16_f128"),
         },
         ty::FnPtr(_) => pointer_ty(tcx),
-        ty::RawPtr(TypeAndMut { ty: pointee_ty, mutbl: _ }) | ty::Ref(_, pointee_ty, _) => {
+        ty::RawPtr(pointee_ty, _) | ty::Ref(_, pointee_ty, _) => {
             if has_ptr_meta(tcx, *pointee_ty) {
                 return None;
             } else {
@@ -89,7 +89,7 @@ fn clif_pair_type_from_ty<'tcx>(
         ty::Tuple(types) if types.len() == 2 => {
             (clif_type_from_ty(tcx, types[0])?, clif_type_from_ty(tcx, types[1])?)
         }
-        ty::RawPtr(TypeAndMut { ty: pointee_ty, mutbl: _ }) | ty::Ref(_, pointee_ty, _) => {
+        ty::RawPtr(pointee_ty, _) | ty::Ref(_, pointee_ty, _) => {
             if has_ptr_meta(tcx, *pointee_ty) {
                 (pointer_ty(tcx), pointer_ty(tcx))
             } else {
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index 7e2e1f7c6ac..a59a39074f8 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -21,6 +21,7 @@ extern crate rustc_hir;
 extern crate rustc_incremental;
 extern crate rustc_index;
 extern crate rustc_metadata;
+extern crate rustc_monomorphize;
 extern crate rustc_session;
 extern crate rustc_span;
 extern crate rustc_target;
diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs
index 7b61dc64cb1..f33bacb99a3 100644
--- a/compiler/rustc_codegen_cranelift/src/unsize.rs
+++ b/compiler/rustc_codegen_cranelift/src/unsize.rs
@@ -70,10 +70,8 @@ fn unsize_ptr<'tcx>(
 ) -> (Value, Value) {
     match (&src_layout.ty.kind(), &dst_layout.ty.kind()) {
         (&ty::Ref(_, a, _), &ty::Ref(_, b, _))
-        | (&ty::Ref(_, a, _), &ty::RawPtr(ty::TypeAndMut { ty: b, .. }))
-        | (&ty::RawPtr(ty::TypeAndMut { ty: a, .. }), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => {
-            (src, unsized_info(fx, *a, *b, old_info))
-        }
+        | (&ty::Ref(_, a, _), &ty::RawPtr(b, _))
+        | (&ty::RawPtr(a, _), &ty::RawPtr(b, _)) => (src, unsized_info(fx, *a, *b, old_info)),
         (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
             assert_eq!(def_a, def_b);
 
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index f016e6950d4..fc5b88a54fe 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -865,15 +865,10 @@ pub(crate) fn assert_assignable<'tcx>(
         return;
     }
     match (from_ty.kind(), to_ty.kind()) {
-        (ty::Ref(_, a, _), ty::Ref(_, b, _))
-        | (
-            ty::RawPtr(TypeAndMut { ty: a, mutbl: _ }),
-            ty::RawPtr(TypeAndMut { ty: b, mutbl: _ }),
-        ) => {
+        (ty::Ref(_, a, _), ty::Ref(_, b, _)) | (ty::RawPtr(a, _), ty::RawPtr(b, _)) => {
             assert_assignable(fx, *a, *b, limit - 1);
         }
-        (ty::Ref(_, a, _), ty::RawPtr(TypeAndMut { ty: b, mutbl: _ }))
-        | (ty::RawPtr(TypeAndMut { ty: a, mutbl: _ }), ty::Ref(_, b, _)) => {
+        (ty::Ref(_, a, _), ty::RawPtr(b, _)) | (ty::RawPtr(a, _), ty::Ref(_, b, _)) => {
             assert_assignable(fx, *a, *b, limit - 1);
         }
         (ty::FnPtr(_), ty::FnPtr(_)) => {
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs
index 8f643c7db72..9e6cf3e34df 100644
--- a/compiler/rustc_codegen_gcc/src/context.rs
+++ b/compiler/rustc_codegen_gcc/src/context.rs
@@ -110,6 +110,7 @@ pub struct CodegenCx<'gcc, 'tcx> {
     local_gen_sym_counter: Cell<usize>,
 
     eh_personality: Cell<Option<RValue<'gcc>>>,
+    #[cfg(feature="master")]
     pub rust_try_fn: Cell<Option<(Type<'gcc>, Function<'gcc>)>>,
 
     pub pointee_infos: RefCell<FxHashMap<(Ty<'tcx>, Size), Option<PointeeInfo>>>,
@@ -121,6 +122,7 @@ pub struct CodegenCx<'gcc, 'tcx> {
     /// FIXME(antoyo): fix the rustc API to avoid having this hack.
     pub structs_as_pointer: RefCell<FxHashSet<RValue<'gcc>>>,
 
+    #[cfg(feature="master")]
     pub cleanup_blocks: RefCell<FxHashSet<Block<'gcc>>>,
 }
 
@@ -325,9 +327,11 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
             struct_types: Default::default(),
             local_gen_sym_counter: Cell::new(0),
             eh_personality: Cell::new(None),
+            #[cfg(feature="master")]
             rust_try_fn: Cell::new(None),
             pointee_infos: Default::default(),
             structs_as_pointer: Default::default(),
+            #[cfg(feature="master")]
             cleanup_blocks: Default::default(),
         };
         // TODO(antoyo): instead of doing this, add SsizeT to libgccjit.
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
index e9af34059a0..60361a44c2d 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
@@ -796,16 +796,16 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
 
         // This counts how many pointers
         fn ptr_count(t: Ty<'_>) -> usize {
-            match t.kind() {
-                ty::RawPtr(p) => 1 + ptr_count(p.ty),
+            match *t.kind() {
+                ty::RawPtr(p_ty, _) => 1 + ptr_count(p_ty),
                 _ => 0,
             }
         }
 
         // Non-ptr type
         fn non_ptr(t: Ty<'_>) -> Ty<'_> {
-            match t.kind() {
-                ty::RawPtr(p) => non_ptr(p.ty),
+            match *t.kind() {
+                ty::RawPtr(p_ty, _) => non_ptr(p_ty),
                 _ => t,
             }
         }
@@ -814,8 +814,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
         // to the element type of the first argument
         let (_, element_ty0) = arg_tys[0].simd_size_and_type(bx.tcx());
         let (_, element_ty1) = arg_tys[1].simd_size_and_type(bx.tcx());
-        let (pointer_count, underlying_ty) = match element_ty1.kind() {
-            ty::RawPtr(p) if p.ty == in_elem => (ptr_count(element_ty1), non_ptr(element_ty1)),
+        let (pointer_count, underlying_ty) = match *element_ty1.kind() {
+            ty::RawPtr(p_ty, _) if p_ty == in_elem => (ptr_count(element_ty1), non_ptr(element_ty1)),
             _ => {
                 require!(
                     false,
@@ -910,16 +910,16 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
 
         // This counts how many pointers
         fn ptr_count(t: Ty<'_>) -> usize {
-            match t.kind() {
-                ty::RawPtr(p) => 1 + ptr_count(p.ty),
+            match *t.kind() {
+                ty::RawPtr(p_ty, _) => 1 + ptr_count(p_ty),
                 _ => 0,
             }
         }
 
         // Non-ptr type
         fn non_ptr(t: Ty<'_>) -> Ty<'_> {
-            match t.kind() {
-                ty::RawPtr(p) => non_ptr(p.ty),
+            match *t.kind() {
+                ty::RawPtr(p_ty, _) => non_ptr(p_ty),
                 _ => t,
             }
         }
@@ -929,8 +929,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
         let (_, element_ty0) = arg_tys[0].simd_size_and_type(bx.tcx());
         let (_, element_ty1) = arg_tys[1].simd_size_and_type(bx.tcx());
         let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx());
-        let (pointer_count, underlying_ty) = match element_ty1.kind() {
-            ty::RawPtr(p) if p.ty == in_elem && p.mutbl == hir::Mutability::Mut => {
+        let (pointer_count, underlying_ty) = match *element_ty1.kind() {
+            ty::RawPtr(p_ty, mutbl) if p_ty == in_elem && mutbl == hir::Mutability::Mut => {
                 (ptr_count(element_ty1), non_ptr(element_ty1))
             }
             _ => {
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 649ff9df2cc..df9f066e58a 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -27,9 +27,7 @@ use rustc_session::config::{CrateType, DebugInfo, PAuthKey, PacRet};
 use rustc_session::Session;
 use rustc_span::source_map::Spanned;
 use rustc_span::Span;
-use rustc_target::abi::{
-    call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx,
-};
+use rustc_target::abi::{call::FnAbi, HasDataLayout, TargetDataLayout, VariantIdx};
 use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel};
 use smallvec::SmallVec;
 
@@ -83,7 +81,6 @@ pub struct CodegenCx<'ll, 'tcx> {
     /// Mapping of scalar types to llvm types.
     pub scalar_lltypes: RefCell<FxHashMap<Ty<'tcx>, &'ll Type>>,
 
-    pub pointee_infos: RefCell<FxHashMap<(Ty<'tcx>, Size), Option<PointeeInfo>>>,
     pub isize_ty: &'ll Type,
 
     pub coverage_cx: Option<coverageinfo::CrateCoverageContext<'ll, 'tcx>>,
@@ -450,7 +447,6 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
             compiler_used_statics: RefCell::new(Vec::new()),
             type_lowering: Default::default(),
             scalar_lltypes: Default::default(),
-            pointee_infos: Default::default(),
             isize_ty,
             coverage_cx,
             dbg_cx,
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index 133084b7c12..54f4bc06340 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -85,14 +85,6 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
 
         let bx = self;
 
-        match coverage.kind {
-            // Marker statements have no effect during codegen,
-            // so return early and don't create `func_coverage`.
-            CoverageKind::SpanMarker | CoverageKind::BlockMarker { .. } => return,
-            // Match exhaustively to ensure that newly-added kinds are classified correctly.
-            CoverageKind::CounterIncrement { .. } | CoverageKind::ExpressionUsed { .. } => {}
-        }
-
         let Some(function_coverage_info) =
             bx.tcx.instance_mir(instance.def).function_coverage_info.as_deref()
         else {
@@ -109,7 +101,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
         let Coverage { kind } = coverage;
         match *kind {
             CoverageKind::SpanMarker | CoverageKind::BlockMarker { .. } => unreachable!(
-                "unexpected marker statement {kind:?} should have caused an early return"
+                "marker statement {kind:?} should have been removed by CleanupPostBorrowck"
             ),
             CoverageKind::CounterIncrement { id } => {
                 func_coverage.mark_counter_id_seen(id);
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 5782b156335..3c76df11e3f 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -452,7 +452,7 @@ pub fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll D
         ty::Slice(_) | ty::Str => build_slice_type_di_node(cx, t, unique_type_id),
         ty::Dynamic(..) => build_dyn_type_di_node(cx, t, unique_type_id),
         ty::Foreign(..) => build_foreign_type_di_node(cx, t, unique_type_id),
-        ty::RawPtr(ty::TypeAndMut { ty: pointee_type, .. }) | ty::Ref(_, pointee_type, _) => {
+        ty::RawPtr(pointee_type, _) | ty::Ref(_, pointee_type, _) => {
             build_pointer_or_reference_di_node(cx, t, pointee_type, unique_type_id)
         }
         // Some `Box` are newtyped pointers, make debuginfo aware of that.
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 71b69a94e99..2409b2e78d7 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -1483,7 +1483,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
                 v.normalize(bx.target_spec().pointer_width).bit_width().unwrap()
             ),
             ty::Float(v) => format!("v{}f{}", vec_len, v.bit_width()),
-            ty::RawPtr(_) => format!("v{}p0", vec_len),
+            ty::RawPtr(_, _) => format!("v{}p0", vec_len),
             _ => unreachable!(),
         }
     }
@@ -1493,7 +1493,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
             ty::Int(v) => cx.type_int_from_ty(v),
             ty::Uint(v) => cx.type_uint_from_ty(v),
             ty::Float(v) => cx.type_float_from_ty(v),
-            ty::RawPtr(_) => cx.type_ptr(),
+            ty::RawPtr(_, _) => cx.type_ptr(),
             _ => unreachable!(),
         };
         cx.type_vector(elem_ty, vec_len)
@@ -1548,8 +1548,8 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
 
         require!(
             matches!(
-                element_ty1.kind(),
-                ty::RawPtr(p) if p.ty == in_elem && p.ty.kind() == element_ty0.kind()
+                *element_ty1.kind(),
+                ty::RawPtr(p_ty, _) if p_ty == in_elem && p_ty.kind() == element_ty0.kind()
             ),
             InvalidMonomorphization::ExpectedElementType {
                 span,
@@ -1654,8 +1654,8 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
 
         require!(
             matches!(
-                pointer_ty.kind(),
-                ty::RawPtr(p) if p.ty == values_elem && p.ty.kind() == values_elem.kind()
+                *pointer_ty.kind(),
+                ty::RawPtr(p_ty, _) if p_ty == values_elem && p_ty.kind() == values_elem.kind()
             ),
             InvalidMonomorphization::ExpectedElementType {
                 span,
@@ -1746,8 +1746,8 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
         // The second argument must be a mutable pointer type matching the element type
         require!(
             matches!(
-                pointer_ty.kind(),
-                ty::RawPtr(p) if p.ty == values_elem && p.ty.kind() == values_elem.kind() && p.mutbl.is_mut()
+                *pointer_ty.kind(),
+                ty::RawPtr(p_ty, p_mutbl) if p_ty == values_elem && p_ty.kind() == values_elem.kind() && p_mutbl.is_mut()
             ),
             InvalidMonomorphization::ExpectedElementType {
                 span,
@@ -1843,9 +1843,9 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
 
         require!(
             matches!(
-                element_ty1.kind(),
-                ty::RawPtr(p)
-                    if p.ty == in_elem && p.mutbl.is_mut() && p.ty.kind() == element_ty0.kind()
+                *element_ty1.kind(),
+                ty::RawPtr(p_ty, p_mutbl)
+                    if p_ty == in_elem && p_mutbl.is_mut() && p_ty.kind() == element_ty0.kind()
             ),
             InvalidMonomorphization::ExpectedElementType {
                 span,
@@ -2074,8 +2074,8 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
         );
 
         match in_elem.kind() {
-            ty::RawPtr(p) => {
-                let metadata = p.ty.ptr_metadata_ty(bx.tcx, |ty| {
+            ty::RawPtr(p_ty, _) => {
+                let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| {
                     bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
                 });
                 require!(
@@ -2088,8 +2088,8 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
             }
         }
         match out_elem.kind() {
-            ty::RawPtr(p) => {
-                let metadata = p.ty.ptr_metadata_ty(bx.tcx, |ty| {
+            ty::RawPtr(p_ty, _) => {
+                let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| {
                     bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
                 });
                 require!(
@@ -2120,7 +2120,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
         );
 
         match in_elem.kind() {
-            ty::RawPtr(_) => {}
+            ty::RawPtr(_, _) => {}
             _ => {
                 return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: in_elem })
             }
@@ -2152,7 +2152,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
             _ => return_error!(InvalidMonomorphization::ExpectedUsize { span, name, ty: in_elem }),
         }
         match out_elem.kind() {
-            ty::RawPtr(_) => {}
+            ty::RawPtr(_, _) => {}
             _ => {
                 return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: out_elem })
             }
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index 7851b9e8e03..baf10622a6d 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -25,6 +25,7 @@ rustc_index = { path = "../rustc_index" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_metadata = { path = "../rustc_metadata" }
 rustc_middle = { path = "../rustc_middle" }
+rustc_monomorphize = { path = "../rustc_monomorphize" }
 rustc_query_system = { path = "../rustc_query_system" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index 5ba66d1be43..d159fe58d3e 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -16,6 +16,9 @@ codegen_ssa_cgu_not_recorded =
 
 codegen_ssa_check_installed_visual_studio = please ensure that Visual Studio 2017 or later, or Build Tools for Visual Studio were installed with the Visual C++ option.
 
+codegen_ssa_compiler_builtins_cannot_call =
+    `compiler_builtins` cannot call functions through upstream monomorphizations; encountered invalid call from `{$caller}` to `{$callee}`
+
 codegen_ssa_copy_path = could not copy {$from} to {$to}: {$error}
 
 codegen_ssa_copy_path_buf = unable to copy {$source_file} to {$output_path}: {$error}
diff --git a/compiler/rustc_codegen_ssa/src/back/command.rs b/compiler/rustc_codegen_ssa/src/back/command.rs
index 9b0ba34135c..3a89be89951 100644
--- a/compiler/rustc_codegen_ssa/src/back/command.rs
+++ b/compiler/rustc_codegen_ssa/src/back/command.rs
@@ -100,12 +100,6 @@ impl Command {
             Program::Lld(ref p, flavor) => {
                 let mut c = process::Command::new(p);
                 c.arg("-flavor").arg(flavor.as_str());
-                if let LldFlavor::Wasm = flavor {
-                    // LLVM expects host-specific formatting for @file
-                    // arguments, but we always generate posix formatted files
-                    // at this time. Indicate as such.
-                    c.arg("--rsp-quoting=posix");
-                }
                 c
             }
         };
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index f5e8d5fc92a..c8b8594c0dd 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -785,7 +785,7 @@ fn link_natively<'a>(
     let mut i = 0;
     loop {
         i += 1;
-        prog = sess.time("run_linker", || exec_linker(sess, &cmd, out_filename, tmpdir));
+        prog = sess.time("run_linker", || exec_linker(sess, &cmd, out_filename, flavor, tmpdir));
         let Ok(ref output) = prog else {
             break;
         };
@@ -1576,6 +1576,7 @@ fn exec_linker(
     sess: &Session,
     cmd: &Command,
     out_filename: &Path,
+    flavor: LinkerFlavor,
     tmpdir: &Path,
 ) -> io::Result<Output> {
     // When attempting to spawn the linker we run a risk of blowing out the
@@ -1584,9 +1585,9 @@ fn exec_linker(
     //
     // Here we attempt to handle errors from the OS saying "your list of
     // arguments is too big" by reinvoking the linker again with an `@`-file
-    // that contains all the arguments. The theory is that this is then
-    // accepted on all linkers and the linker will read all its options out of
-    // there instead of looking at the command line.
+    // that contains all the arguments (aka 'response' files).
+    // The theory is that this is then accepted on all linkers and the linker
+    // will read all its options out of there instead of looking at the command line.
     if !cmd.very_likely_to_exceed_some_spawn_limit() {
         match cmd.command().stdout(Stdio::piped()).stderr(Stdio::piped()).spawn() {
             Ok(child) => {
@@ -1606,8 +1607,12 @@ fn exec_linker(
     let mut args = String::new();
     for arg in cmd2.take_args() {
         args.push_str(
-            &Escape { arg: arg.to_str().unwrap(), is_like_msvc: sess.target.is_like_msvc }
-                .to_string(),
+            &Escape {
+                arg: arg.to_str().unwrap(),
+                // LLD also uses MSVC-like parsing for @-files by default when running on windows hosts
+                is_like_msvc: sess.target.is_like_msvc || (cfg!(windows) && flavor.uses_lld()),
+            }
+            .to_string(),
         );
         args.push('\n');
     }
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index c316d19e041..13809ef72ec 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -193,8 +193,8 @@ pub fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 ) -> (Bx::Value, Bx::Value) {
     debug!("unsize_ptr: {:?} => {:?}", src_ty, dst_ty);
     match (src_ty.kind(), dst_ty.kind()) {
-        (&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(ty::TypeAndMut { ty: b, .. }))
-        | (&ty::RawPtr(ty::TypeAndMut { ty: a, .. }), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => {
+        (&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(b, _))
+        | (&ty::RawPtr(a, _), &ty::RawPtr(b, _)) => {
             assert_eq!(bx.cx().type_is_sized(a), old_info.is_none());
             (src, unsized_info(bx, a, b, old_info))
         }
diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs
index 44a2434238d..71fca403def 100644
--- a/compiler/rustc_codegen_ssa/src/common.rs
+++ b/compiler/rustc_codegen_ssa/src/common.rs
@@ -2,6 +2,7 @@
 
 use rustc_hir::LangItem;
 use rustc_middle::mir;
+use rustc_middle::ty::Instance;
 use rustc_middle::ty::{self, layout::TyAndLayout, Ty, TyCtxt};
 use rustc_span::Span;
 
@@ -120,11 +121,11 @@ pub fn build_langcall<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     bx: &Bx,
     span: Option<Span>,
     li: LangItem,
-) -> (Bx::FnAbiOfResult, Bx::Value) {
+) -> (Bx::FnAbiOfResult, Bx::Value, Instance<'tcx>) {
     let tcx = bx.tcx();
     let def_id = tcx.require_lang_item(li, span);
     let instance = ty::Instance::mono(tcx, def_id);
-    (bx.fn_abi_of_instance(instance, ty::List::empty()), bx.get_fn_addr(instance))
+    (bx.fn_abi_of_instance(instance, ty::List::empty()), bx.get_fn_addr(instance), instance)
 }
 
 // To avoid UB from LLVM, these two functions mask RHS with an
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index fcd7fa9247b..64448441acb 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -138,7 +138,7 @@ fn push_debuginfo_type_name<'tcx>(
                 output.push(')');
             }
         }
-        ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl }) => {
+        ty::RawPtr(inner_type, mutbl) => {
             if cpp_like_debuginfo {
                 match mutbl {
                     Mutability::Not => output.push_str("ptr_const$<"),
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index 3572ee301c8..b843d1bdf23 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -1030,3 +1030,10 @@ pub struct FailedToGetLayout<'tcx> {
 pub struct ErrorCreatingRemarkDir {
     pub error: std::io::Error,
 }
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_compiler_builtins_cannot_call)]
+pub struct CompilerBuiltinsCannotCall {
+    pub caller: String,
+    pub callee: String,
+}
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 02e7bb05b77..dcc27a4f0e5 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -5,6 +5,7 @@ use super::{CachedLlbb, FunctionCx, LocalRef};
 
 use crate::base;
 use crate::common::{self, IntPredicate};
+use crate::errors::CompilerBuiltinsCannotCall;
 use crate::meth;
 use crate::traits::*;
 use crate::MemFlags;
@@ -16,6 +17,7 @@ use rustc_middle::mir::{self, AssertKind, BasicBlock, SwitchTargets, UnwindTermi
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
 use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
 use rustc_middle::ty::{self, Instance, Ty};
+use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization;
 use rustc_session::config::OptLevel;
 use rustc_span::{source_map::Spanned, sym, Span};
 use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode, Reg};
@@ -157,8 +159,28 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
         destination: Option<(ReturnDest<'tcx, Bx::Value>, mir::BasicBlock)>,
         mut unwind: mir::UnwindAction,
         copied_constant_arguments: &[PlaceRef<'tcx, <Bx as BackendTypes>::Value>],
+        instance: Option<Instance<'tcx>>,
         mergeable_succ: bool,
     ) -> MergingSucc {
+        let tcx = bx.tcx();
+        if let Some(instance) = instance {
+            if is_call_from_compiler_builtins_to_upstream_monomorphization(tcx, instance) {
+                if destination.is_some() {
+                    let caller = with_no_trimmed_paths!(tcx.def_path_str(fx.instance.def_id()));
+                    let callee = with_no_trimmed_paths!(tcx.def_path_str(instance.def_id()));
+                    tcx.dcx().emit_err(CompilerBuiltinsCannotCall { caller, callee });
+                } else {
+                    info!(
+                        "compiler_builtins call to diverging function {:?} replaced with abort",
+                        instance.def_id()
+                    );
+                    bx.abort();
+                    bx.unreachable();
+                    return MergingSucc::False;
+                }
+            }
+        }
+
         // If there is a cleanup block and the function we're calling can unwind, then
         // do an invoke, otherwise do a call.
         let fn_ty = bx.fn_decl_backend_type(fn_abi);
@@ -480,6 +502,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         let ty = location.ty(self.mir, bx.tcx()).ty;
         let ty = self.monomorphize(ty);
         let drop_fn = Instance::resolve_drop_in_place(bx.tcx(), ty);
+        let instance = drop_fn.clone();
 
         if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def {
             // we don't actually need to drop anything.
@@ -582,6 +605,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             Some((ReturnDest::Nothing, target)),
             unwind,
             &[],
+            Some(instance),
             mergeable_succ,
         )
     }
@@ -658,10 +682,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             }
         };
 
-        let (fn_abi, llfn) = common::build_langcall(bx, Some(span), lang_item);
+        let (fn_abi, llfn, instance) = common::build_langcall(bx, Some(span), lang_item);
 
         // Codegen the actual panic invoke/call.
-        let merging_succ = helper.do_call(self, bx, fn_abi, llfn, &args, None, unwind, &[], false);
+        let merging_succ =
+            helper.do_call(self, bx, fn_abi, llfn, &args, None, unwind, &[], Some(instance), false);
         assert_eq!(merging_succ, MergingSucc::False);
         MergingSucc::False
     }
@@ -677,7 +702,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         self.set_debug_loc(bx, terminator.source_info);
 
         // Obtain the panic entry point.
-        let (fn_abi, llfn) = common::build_langcall(bx, Some(span), reason.lang_item());
+        let (fn_abi, llfn, instance) = common::build_langcall(bx, Some(span), reason.lang_item());
 
         // Codegen the actual panic invoke/call.
         let merging_succ = helper.do_call(
@@ -689,6 +714,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             None,
             mir::UnwindAction::Unreachable,
             &[],
+            Some(instance),
             false,
         );
         assert_eq!(merging_succ, MergingSucc::False);
@@ -738,7 +764,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 let msg = bx.const_str(&msg_str);
 
                 // Obtain the panic entry point.
-                let (fn_abi, llfn) =
+                let (fn_abi, llfn, instance) =
                     common::build_langcall(bx, Some(source_info.span), LangItem::PanicNounwind);
 
                 // Codegen the actual panic invoke/call.
@@ -751,6 +777,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     target.as_ref().map(|bb| (ReturnDest::Nothing, *bb)),
                     unwind,
                     &[],
+                    Some(instance),
                     mergeable_succ,
                 )
             } else {
@@ -798,6 +825,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             ty::FnPtr(_) => (None, Some(callee.immediate())),
             _ => bug!("{} is not callable", callee.layout.ty),
         };
+
         let def = instance.map(|i| i.def);
 
         if let Some(ty::InstanceDef::DropGlue(_, None)) = def {
@@ -1106,6 +1134,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             destination,
             unwind,
             &copied_constant_arguments,
+            instance,
             mergeable_succ,
         )
     }
@@ -1664,11 +1693,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
         self.set_debug_loc(&mut bx, mir::SourceInfo::outermost(self.mir.span));
 
-        let (fn_abi, fn_ptr) = common::build_langcall(&bx, None, reason.lang_item());
-        let fn_ty = bx.fn_decl_backend_type(fn_abi);
+        let (fn_abi, fn_ptr, instance) = common::build_langcall(&bx, None, reason.lang_item());
+        if is_call_from_compiler_builtins_to_upstream_monomorphization(bx.tcx(), instance) {
+            bx.abort();
+        } else {
+            let fn_ty = bx.fn_decl_backend_type(fn_abi);
 
-        let llret = bx.call(fn_ty, None, Some(fn_abi), fn_ptr, &[], funclet.as_ref());
-        bx.apply_attrs_to_cleanup_callsite(llret);
+            let llret = bx.call(fn_ty, None, Some(fn_abi), fn_ptr, &[], funclet.as_ref());
+            bx.apply_attrs_to_cleanup_callsite(llret);
+        }
 
         bx.unreachable();
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index 48f3f4f2522..0387c430d32 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -414,10 +414,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 calculate_debuginfo_offset(bx, var.projection, base);
 
             // Create a variable which will be a pointer to the actual value
-            let ptr_ty = Ty::new_ptr(
-                bx.tcx(),
-                ty::TypeAndMut { mutbl: mir::Mutability::Mut, ty: place.layout.ty },
-            );
+            let ptr_ty = Ty::new_mut_ptr(bx.tcx(), place.layout.ty);
             let ptr_layout = bx.layout_of(ptr_ty);
             let alloca = PlaceRef::alloca(bx, ptr_layout);
             bx.set_var_name(alloca.llval, &(var.name.to_string() + ".dbg.spill"));
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 5532ff6e6a5..3e6cf0ece29 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -9,6 +9,7 @@ use crate::traits::*;
 use crate::MemFlags;
 
 use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_session::config::OptLevel;
 use rustc_span::{sym, Span};
 use rustc_target::abi::{
     call::{FnAbi, PassMode},
@@ -75,6 +76,29 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         let name = bx.tcx().item_name(def_id);
         let name_str = name.as_str();
 
+        // If we're swapping something that's *not* an `OperandValue::Ref`,
+        // then we can do it directly and avoid the alloca.
+        // Otherwise, we'll let the fallback MIR body take care of it.
+        if let sym::typed_swap = name {
+            let pointee_ty = fn_args.type_at(0);
+            let pointee_layout = bx.layout_of(pointee_ty);
+            if !bx.is_backend_ref(pointee_layout)
+                // But if we're not going to optimize, trying to use the fallback
+                // body just makes things worse, so don't bother.
+                || bx.sess().opts.optimize == OptLevel::No
+                // NOTE(eddyb) SPIR-V's Logical addressing model doesn't allow for arbitrary
+                // reinterpretation of values as (chunkable) byte arrays, and the loop in the
+                // block optimization in `ptr::swap_nonoverlapping` is hard to rewrite back
+                // into the (unoptimized) direct swapping implementation, so we disable it.
+                || bx.sess().target.arch == "spirv"
+            {
+                let x_place = PlaceRef::new_sized(args[0].immediate(), pointee_layout);
+                let y_place = PlaceRef::new_sized(args[1].immediate(), pointee_layout);
+                bx.typed_place_swap(x_place, y_place);
+                return Ok(());
+            }
+        }
+
         let llret_ty = bx.backend_type(bx.layout_of(ret_ty));
         let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout);
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 8159f76b421..0e8c4abf212 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -572,20 +572,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
             mir::Rvalue::Ref(_, bk, place) => {
                 let mk_ref = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| {
-                    Ty::new_ref(
-                        tcx,
-                        tcx.lifetimes.re_erased,
-                        ty::TypeAndMut { ty, mutbl: bk.to_mutbl_lossy() },
-                    )
+                    Ty::new_ref(tcx, tcx.lifetimes.re_erased, ty, bk.to_mutbl_lossy())
                 };
                 self.codegen_place_to_pointer(bx, place, mk_ref)
             }
 
             mir::Rvalue::CopyForDeref(place) => self.codegen_operand(bx, &Operand::Copy(place)),
             mir::Rvalue::AddressOf(mutability, place) => {
-                let mk_ptr = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| {
-                    Ty::new_ptr(tcx, ty::TypeAndMut { ty, mutbl: mutability })
-                };
+                let mk_ptr =
+                    move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| Ty::new_ptr(tcx, ty, mutability);
                 self.codegen_place_to_pointer(bx, place, mk_ptr)
             }
 
@@ -685,8 +680,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         let val = layout.offset_of_subfield(bx.cx(), fields.iter()).bytes();
                         bx.cx().const_usize(val)
                     }
-                    mir::NullOp::UbCheck(_) => {
-                        // In codegen, we want to check for language UB and library UB
+                    mir::NullOp::UbChecks => {
                         let val = bx.tcx().sess.opts.debug_assertions;
                         bx.cx().const_bool(val)
                     }
diff --git a/compiler/rustc_codegen_ssa/src/size_of_val.rs b/compiler/rustc_codegen_ssa/src/size_of_val.rs
index 087836ca37d..e2e95cede60 100644
--- a/compiler/rustc_codegen_ssa/src/size_of_val.rs
+++ b/compiler/rustc_codegen_ssa/src/size_of_val.rs
@@ -62,7 +62,8 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
             let msg = bx.const_str(&msg_str);
 
             // Obtain the panic entry point.
-            let (fn_abi, llfn) = common::build_langcall(bx, None, LangItem::PanicNounwind);
+            let (fn_abi, llfn, _instance) =
+                common::build_langcall(bx, None, LangItem::PanicNounwind);
 
             // Generate the call.
             // Cannot use `do_call` since we don't have a MIR terminator so we can't create a `TerminationCodegenHelper`.
diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs
index e6d42c596d2..e8b9490d401 100644
--- a/compiler/rustc_codegen_ssa/src/traits/backend.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs
@@ -21,7 +21,6 @@ use rustc_session::{
 };
 use rustc_span::symbol::Symbol;
 use rustc_target::abi::call::FnAbi;
-use rustc_target::spec::Target;
 
 use std::fmt;
 
@@ -70,12 +69,6 @@ pub trait CodegenBackend {
     fn print_passes(&self) {}
     fn print_version(&self) {}
 
-    /// If this plugin provides additional builtin targets, provide the one enabled by the options here.
-    /// Be careful: this is called *before* init() is called.
-    fn target_override(&self, _opts: &config::Options) -> Option<Target> {
-        None
-    }
-
     /// The metadata loader used to load rlib and dylib metadata.
     ///
     /// Alternative codegen backends may want to use different rlib or dylib formats than the
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index 36f37e3791b..7bc9dee3a89 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -1,22 +1,24 @@
 use super::abi::AbiBuilderMethods;
 use super::asm::AsmBuilderMethods;
+use super::consts::ConstMethods;
 use super::coverageinfo::CoverageInfoBuilderMethods;
 use super::debuginfo::DebugInfoBuilderMethods;
 use super::intrinsic::IntrinsicCallMethods;
 use super::misc::MiscMethods;
-use super::type_::{ArgAbiMethods, BaseTypeMethods};
+use super::type_::{ArgAbiMethods, BaseTypeMethods, LayoutTypeMethods};
 use super::{HasCodegen, StaticBuilderMethods};
 
 use crate::common::{
     AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope, TypeKind,
 };
-use crate::mir::operand::OperandRef;
+use crate::mir::operand::{OperandRef, OperandValue};
 use crate::mir::place::PlaceRef;
 use crate::MemFlags;
 
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
 use rustc_middle::ty::layout::{HasParamEnv, TyAndLayout};
 use rustc_middle::ty::Ty;
+use rustc_session::config::OptLevel;
 use rustc_span::Span;
 use rustc_target::abi::call::FnAbi;
 use rustc_target::abi::{Abi, Align, Scalar, Size, WrappingRange};
@@ -267,6 +269,54 @@ pub trait BuilderMethods<'a, 'tcx>:
         flags: MemFlags,
     );
 
+    /// *Typed* copy for non-overlapping places.
+    ///
+    /// Has a default implementation in terms of `memcpy`, but specific backends
+    /// can override to do something smarter if possible.
+    ///
+    /// (For example, typed load-stores with alias metadata.)
+    fn typed_place_copy(
+        &mut self,
+        dst: PlaceRef<'tcx, Self::Value>,
+        src: PlaceRef<'tcx, Self::Value>,
+    ) {
+        debug_assert!(src.llextra.is_none());
+        debug_assert!(dst.llextra.is_none());
+        debug_assert_eq!(dst.layout.size, src.layout.size);
+        if self.sess().opts.optimize == OptLevel::No && self.is_backend_immediate(dst.layout) {
+            // If we're not optimizing, the aliasing information from `memcpy`
+            // isn't useful, so just load-store the value for smaller code.
+            let temp = self.load_operand(src);
+            temp.val.store(self, dst);
+        } else if !dst.layout.is_zst() {
+            let bytes = self.const_usize(dst.layout.size.bytes());
+            self.memcpy(dst.llval, dst.align, src.llval, src.align, bytes, MemFlags::empty());
+        }
+    }
+
+    /// *Typed* swap for non-overlapping places.
+    ///
+    /// Avoids `alloca`s for Immediates and ScalarPairs.
+    ///
+    /// FIXME: Maybe do something smarter for Ref types too?
+    /// For now, the `typed_swap` intrinsic just doesn't call this for those
+    /// cases (in non-debug), preferring the fallback body instead.
+    fn typed_place_swap(
+        &mut self,
+        left: PlaceRef<'tcx, Self::Value>,
+        right: PlaceRef<'tcx, Self::Value>,
+    ) {
+        let mut temp = self.load_operand(left);
+        if let OperandValue::Ref(..) = temp.val {
+            // The SSA value isn't stand-alone, so we need to copy it elsewhere
+            let alloca = PlaceRef::alloca(self, left.layout);
+            self.typed_place_copy(alloca, left);
+            temp = self.load_operand(alloca);
+        }
+        self.typed_place_copy(left, right);
+        temp.val.store(self, right);
+    }
+
     fn select(
         &mut self,
         cond: Self::Value,
diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs
index 72cce43a3fa..555833759eb 100644
--- a/compiler/rustc_codegen_ssa/src/traits/type_.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs
@@ -120,6 +120,20 @@ pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> {
         immediate: bool,
     ) -> Self::Type;
 
+    /// A type that produces an [`OperandValue::Ref`] when loaded.
+    ///
+    /// AKA one that's not a ZST, not `is_backend_immediate`, and
+    /// not `is_backend_scalar_pair`. For such a type, a
+    /// [`load_operand`] doesn't actually `load` anything.
+    ///
+    /// [`OperandValue::Ref`]: crate::mir::operand::OperandValue::Ref
+    /// [`load_operand`]: super::BuilderMethods::load_operand
+    fn is_backend_ref(&self, layout: TyAndLayout<'tcx>) -> bool {
+        !(layout.is_zst()
+            || self.is_backend_immediate(layout)
+            || self.is_backend_scalar_pair(layout))
+    }
+
     /// A type that can be used in a [`super::BuilderMethods::load`] +
     /// [`super::BuilderMethods::store`] pair to implement a *typed* copy,
     /// such as a MIR `*_0 = *_1`.
diff --git a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs
new file mode 100644
index 00000000000..ba2e2a1e353
--- /dev/null
+++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs
@@ -0,0 +1,193 @@
+use crate::interpret::{self, HasStaticRootDefId, ImmTy, Immediate, InterpCx, PointerArithmetic};
+use rustc_middle::mir::interpret::{AllocId, ConstAllocation, InterpResult};
+use rustc_middle::mir::*;
+use rustc_middle::query::TyCtxtAt;
+use rustc_middle::ty;
+use rustc_middle::ty::layout::TyAndLayout;
+use rustc_span::def_id::DefId;
+
+/// Macro for machine-specific `InterpError` without allocation.
+/// (These will never be shown to the user, but they help diagnose ICEs.)
+pub macro throw_machine_stop_str($($tt:tt)*) {{
+    // We make a new local type for it. The type itself does not carry any information,
+    // but its vtable (for the `MachineStopType` trait) does.
+    #[derive(Debug)]
+    struct Zst;
+    // Printing this type shows the desired string.
+    impl std::fmt::Display for Zst {
+        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+            write!(f, $($tt)*)
+        }
+    }
+
+    impl rustc_middle::mir::interpret::MachineStopType for Zst {
+        fn diagnostic_message(&self) -> rustc_errors::DiagMessage {
+            self.to_string().into()
+        }
+
+        fn add_args(
+            self: Box<Self>,
+            _: &mut dyn FnMut(rustc_errors::DiagArgName, rustc_errors::DiagArgValue),
+        ) {}
+    }
+    throw_machine_stop!(Zst)
+}}
+
+pub struct DummyMachine;
+
+impl HasStaticRootDefId for DummyMachine {
+    fn static_def_id(&self) -> Option<rustc_hir::def_id::LocalDefId> {
+        None
+    }
+}
+
+impl<'mir, 'tcx: 'mir> interpret::Machine<'mir, 'tcx> for DummyMachine {
+    interpret::compile_time_machine!(<'mir, 'tcx>);
+    type MemoryKind = !;
+    const PANIC_ON_ALLOC_FAIL: bool = true;
+
+    #[inline(always)]
+    fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+        false // no reason to enforce alignment
+    }
+
+    fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool {
+        false
+    }
+
+    fn before_access_global(
+        _tcx: TyCtxtAt<'tcx>,
+        _machine: &Self,
+        _alloc_id: AllocId,
+        alloc: ConstAllocation<'tcx>,
+        _static_def_id: Option<DefId>,
+        is_write: bool,
+    ) -> InterpResult<'tcx> {
+        if is_write {
+            throw_machine_stop_str!("can't write to global");
+        }
+
+        // If the static allocation is mutable, then we can't const prop it as its content
+        // might be different at runtime.
+        if alloc.inner().mutability.is_mut() {
+            throw_machine_stop_str!("can't access mutable globals in ConstProp");
+        }
+
+        Ok(())
+    }
+
+    fn find_mir_or_eval_fn(
+        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
+        _instance: ty::Instance<'tcx>,
+        _abi: rustc_target::spec::abi::Abi,
+        _args: &[interpret::FnArg<'tcx, Self::Provenance>],
+        _destination: &interpret::MPlaceTy<'tcx, Self::Provenance>,
+        _target: Option<BasicBlock>,
+        _unwind: UnwindAction,
+    ) -> interpret::InterpResult<'tcx, Option<(&'mir Body<'tcx>, ty::Instance<'tcx>)>> {
+        unimplemented!()
+    }
+
+    fn panic_nounwind(
+        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
+        _msg: &str,
+    ) -> interpret::InterpResult<'tcx> {
+        unimplemented!()
+    }
+
+    fn call_intrinsic(
+        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
+        _instance: ty::Instance<'tcx>,
+        _args: &[interpret::OpTy<'tcx, Self::Provenance>],
+        _destination: &interpret::MPlaceTy<'tcx, Self::Provenance>,
+        _target: Option<BasicBlock>,
+        _unwind: UnwindAction,
+    ) -> interpret::InterpResult<'tcx> {
+        unimplemented!()
+    }
+
+    fn assert_panic(
+        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
+        _msg: &rustc_middle::mir::AssertMessage<'tcx>,
+        _unwind: UnwindAction,
+    ) -> interpret::InterpResult<'tcx> {
+        unimplemented!()
+    }
+
+    fn binary_ptr_op(
+        ecx: &InterpCx<'mir, 'tcx, Self>,
+        bin_op: BinOp,
+        left: &interpret::ImmTy<'tcx, Self::Provenance>,
+        right: &interpret::ImmTy<'tcx, Self::Provenance>,
+    ) -> interpret::InterpResult<'tcx, (ImmTy<'tcx, Self::Provenance>, bool)> {
+        use rustc_middle::mir::BinOp::*;
+        Ok(match bin_op {
+            Eq | Ne | Lt | Le | Gt | Ge => {
+                // Types can differ, e.g. fn ptrs with different `for`.
+                assert_eq!(left.layout.abi, right.layout.abi);
+                let size = ecx.pointer_size();
+                // Just compare the bits. ScalarPairs are compared lexicographically.
+                // We thus always compare pairs and simply fill scalars up with 0.
+                // If the pointer has provenance, `to_bits` will return `Err` and we bail out.
+                let left = match **left {
+                    Immediate::Scalar(l) => (l.to_bits(size)?, 0),
+                    Immediate::ScalarPair(l1, l2) => (l1.to_bits(size)?, l2.to_bits(size)?),
+                    Immediate::Uninit => panic!("we should never see uninit data here"),
+                };
+                let right = match **right {
+                    Immediate::Scalar(r) => (r.to_bits(size)?, 0),
+                    Immediate::ScalarPair(r1, r2) => (r1.to_bits(size)?, r2.to_bits(size)?),
+                    Immediate::Uninit => panic!("we should never see uninit data here"),
+                };
+                let res = match bin_op {
+                    Eq => left == right,
+                    Ne => left != right,
+                    Lt => left < right,
+                    Le => left <= right,
+                    Gt => left > right,
+                    Ge => left >= right,
+                    _ => bug!(),
+                };
+                (ImmTy::from_bool(res, *ecx.tcx), false)
+            }
+
+            // Some more operations are possible with atomics.
+            // The return value always has the provenance of the *left* operand.
+            Add | Sub | BitOr | BitAnd | BitXor => {
+                throw_machine_stop_str!("pointer arithmetic is not handled")
+            }
+
+            _ => span_bug!(ecx.cur_span(), "Invalid operator on pointers: {:?}", bin_op),
+        })
+    }
+
+    fn expose_ptr(
+        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
+        _ptr: interpret::Pointer<Self::Provenance>,
+    ) -> interpret::InterpResult<'tcx> {
+        unimplemented!()
+    }
+
+    fn init_frame_extra(
+        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
+        _frame: interpret::Frame<'mir, 'tcx, Self::Provenance>,
+    ) -> interpret::InterpResult<
+        'tcx,
+        interpret::Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>,
+    > {
+        unimplemented!()
+    }
+
+    fn stack<'a>(
+        _ecx: &'a InterpCx<'mir, 'tcx, Self>,
+    ) -> &'a [interpret::Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>] {
+        // Return an empty stack instead of panicking, as `cur_span` uses it to evaluate constants.
+        &[]
+    }
+
+    fn stack_mut<'a>(
+        _ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
+    ) -> &'a mut Vec<interpret::Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>> {
+        unimplemented!()
+    }
+}
diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs
index d0d6adbfad0..8efc67bcb0c 100644
--- a/compiler/rustc_const_eval/src/const_eval/mod.rs
+++ b/compiler/rustc_const_eval/src/const_eval/mod.rs
@@ -2,17 +2,20 @@
 
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::InterpErrorInfo;
-use rustc_middle::query::TyCtxtAt;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::query::{Key, TyCtxtAt};
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_target::abi::VariantIdx;
 
-use crate::interpret::format_interp_error;
+use crate::interpret::{format_interp_error, InterpCx};
 
+mod dummy_machine;
 mod error;
 mod eval_queries;
 mod fn_queries;
 mod machine;
 mod valtrees;
 
+pub use dummy_machine::*;
 pub use error::*;
 pub use eval_queries::*;
 pub use fn_queries::*;
@@ -75,3 +78,21 @@ pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>(
 
     Some(mir::DestructuredConstant { variant, fields })
 }
+
+/// Computes the tag (if any) for a given type and variant.
+#[instrument(skip(tcx), level = "debug")]
+pub fn tag_for_variant_provider<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    (ty, variant_index): (Ty<'tcx>, VariantIdx),
+) -> Option<ty::ScalarInt> {
+    assert!(ty.is_enum());
+
+    let ecx = InterpCx::new(
+        tcx,
+        ty.default_span(tcx),
+        ty::ParamEnv::reveal_all(),
+        crate::const_eval::DummyMachine,
+    );
+
+    ecx.tag_for_variant(ty, variant_index).unwrap().map(|(tag, _tag_field)| tag)
+}
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index d3428d27d52..d91ad3fcab1 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -98,7 +98,7 @@ fn const_to_valtree_inner<'tcx>(
             Ok(ty::ValTree::Leaf(val.assert_int()))
         }
 
-        ty::RawPtr(_) => {
+        ty::RawPtr(_, _) => {
             // Not all raw pointers are allowed, as we cannot properly test them for
             // equality at compile-time (see `ptr_guaranteed_cmp`).
             // However we allow those that are just integers in disguise.
@@ -278,7 +278,7 @@ pub fn valtree_to_const_value<'tcx>(
             assert!(valtree.unwrap_branch().is_empty());
             mir::ConstValue::ZeroSized
         }
-        ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char | ty::RawPtr(_) => {
+        ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char | ty::RawPtr(_, _) => {
             match valtree {
                 ty::ValTree::Leaf(scalar_int) => mir::ConstValue::Scalar(Scalar::Int(scalar_int)),
                 ty::ValTree::Branch(_) => bug!(
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index 2cebea9d145..bbf11f169f9 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -6,7 +6,7 @@ use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar};
 use rustc_middle::mir::CastKind;
 use rustc_middle::ty::adjustment::PointerCoercion;
 use rustc_middle::ty::layout::{IntegerExt, LayoutOf, TyAndLayout};
-use rustc_middle::ty::{self, FloatTy, Ty, TypeAndMut};
+use rustc_middle::ty::{self, FloatTy, Ty};
 use rustc_target::abi::Integer;
 use rustc_type_ir::TyKind::*;
 
@@ -230,7 +230,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         src: &ImmTy<'tcx, M::Provenance>,
         cast_to: TyAndLayout<'tcx>,
     ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
-        assert_matches!(src.layout.ty.kind(), ty::RawPtr(_) | ty::FnPtr(_));
+        assert_matches!(src.layout.ty.kind(), ty::RawPtr(_, _) | ty::FnPtr(_));
         assert!(cast_to.ty.is_integral());
 
         let scalar = src.to_scalar();
@@ -248,7 +248,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         cast_to: TyAndLayout<'tcx>,
     ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
         assert!(src.layout.ty.is_integral());
-        assert_matches!(cast_to.ty.kind(), ty::RawPtr(_));
+        assert_matches!(cast_to.ty.kind(), ty::RawPtr(_, _));
 
         // First cast to usize.
         let scalar = src.to_scalar();
@@ -435,10 +435,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     ) -> InterpResult<'tcx> {
         trace!("Unsizing {:?} of type {} into {}", *src, src.layout.ty, cast_ty.ty);
         match (&src.layout.ty.kind(), &cast_ty.ty.kind()) {
-            (&ty::Ref(_, s, _), &ty::Ref(_, c, _) | &ty::RawPtr(TypeAndMut { ty: c, .. }))
-            | (&ty::RawPtr(TypeAndMut { ty: s, .. }), &ty::RawPtr(TypeAndMut { ty: c, .. })) => {
-                self.unsize_into_ptr(src, dest, *s, *c)
-            }
+            (&ty::Ref(_, s, _), &ty::Ref(_, c, _) | &ty::RawPtr(c, _))
+            | (&ty::RawPtr(s, _), &ty::RawPtr(c, _)) => self.unsize_into_ptr(src, dest, *s, *c),
             (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
                 assert_eq!(def_a, def_b); // implies same number of fields
 
diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs
index 6d4f6d0cb3c..704f597cfdb 100644
--- a/compiler/rustc_const_eval/src/interpret/discriminant.rs
+++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs
@@ -2,7 +2,7 @@
 
 use rustc_middle::mir;
 use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt};
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, ScalarInt, Ty};
 use rustc_target::abi::{self, TagEncoding};
 use rustc_target::abi::{VariantIdx, Variants};
 
@@ -28,78 +28,27 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             throw_ub!(UninhabitedEnumVariantWritten(variant_index))
         }
 
-        match dest.layout().variants {
-            abi::Variants::Single { index } => {
-                assert_eq!(index, variant_index);
-            }
-            abi::Variants::Multiple {
-                tag_encoding: TagEncoding::Direct,
-                tag: tag_layout,
-                tag_field,
-                ..
-            } => {
+        match self.tag_for_variant(dest.layout().ty, variant_index)? {
+            Some((tag, tag_field)) => {
                 // No need to validate that the discriminant here because the
-                // `TyAndLayout::for_variant()` call earlier already checks the variant is valid.
-
-                let discr_val = dest
-                    .layout()
-                    .ty
-                    .discriminant_for_variant(*self.tcx, variant_index)
-                    .unwrap()
-                    .val;
-
-                // raw discriminants for enums are isize or bigger during
-                // their computation, but the in-memory tag is the smallest possible
-                // representation
-                let size = tag_layout.size(self);
-                let tag_val = size.truncate(discr_val);
-
+                // `TyAndLayout::for_variant()` call earlier already checks the
+                // variant is valid.
                 let tag_dest = self.project_field(dest, tag_field)?;
-                self.write_scalar(Scalar::from_uint(tag_val, size), &tag_dest)?;
+                self.write_scalar(tag, &tag_dest)
             }
-            abi::Variants::Multiple {
-                tag_encoding:
-                    TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start },
-                tag: tag_layout,
-                tag_field,
-                ..
-            } => {
-                // No need to validate that the discriminant here because the
-                // `TyAndLayout::for_variant()` call earlier already checks the variant is valid.
-
-                if variant_index != untagged_variant {
-                    let variants_start = niche_variants.start().as_u32();
-                    let variant_index_relative = variant_index
-                        .as_u32()
-                        .checked_sub(variants_start)
-                        .expect("overflow computing relative variant idx");
-                    // We need to use machine arithmetic when taking into account `niche_start`:
-                    // tag_val = variant_index_relative + niche_start_val
-                    let tag_layout = self.layout_of(tag_layout.primitive().to_int_ty(*self.tcx))?;
-                    let niche_start_val = ImmTy::from_uint(niche_start, tag_layout);
-                    let variant_index_relative_val =
-                        ImmTy::from_uint(variant_index_relative, tag_layout);
-                    let tag_val = self.wrapping_binary_op(
-                        mir::BinOp::Add,
-                        &variant_index_relative_val,
-                        &niche_start_val,
-                    )?;
-                    // Write result.
-                    let niche_dest = self.project_field(dest, tag_field)?;
-                    self.write_immediate(*tag_val, &niche_dest)?;
-                } else {
-                    // The untagged variant is implicitly encoded simply by having a value that is
-                    // outside the niche variants. But what if the data stored here does not
-                    // actually encode this variant? That would be bad! So let's double-check...
-                    let actual_variant = self.read_discriminant(&dest.to_op(self)?)?;
-                    if actual_variant != variant_index {
-                        throw_ub!(InvalidNichedEnumVariantWritten { enum_ty: dest.layout().ty });
-                    }
+            None => {
+                // No need to write the tag here, because an untagged variant is
+                // implicitly encoded. For `Niche`-optimized enums, this works by
+                // simply by having a value that is outside the niche variants.
+                // But what if the data stored here does not actually encode
+                // this variant? That would be bad! So let's double-check...
+                let actual_variant = self.read_discriminant(&dest.to_op(self)?)?;
+                if actual_variant != variant_index {
+                    throw_ub!(InvalidNichedEnumVariantWritten { enum_ty: dest.layout().ty });
                 }
+                Ok(())
             }
         }
-
-        Ok(())
     }
 
     /// Read discriminant, return the runtime value as well as the variant index.
@@ -277,4 +226,79 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         };
         Ok(ImmTy::from_scalar(discr_value, discr_layout))
     }
+
+    /// Computes how to write the tag of a given variant of enum `ty`:
+    /// - `None` means that nothing needs to be done as the variant is encoded implicitly
+    /// - `Some((val, field_idx))` means that the given integer value needs to be stored at the
+    ///   given field index.
+    pub(crate) fn tag_for_variant(
+        &self,
+        ty: Ty<'tcx>,
+        variant_index: VariantIdx,
+    ) -> InterpResult<'tcx, Option<(ScalarInt, usize)>> {
+        match self.layout_of(ty)?.variants {
+            abi::Variants::Single { index } => {
+                assert_eq!(index, variant_index);
+                Ok(None)
+            }
+
+            abi::Variants::Multiple {
+                tag_encoding: TagEncoding::Direct,
+                tag: tag_layout,
+                tag_field,
+                ..
+            } => {
+                // raw discriminants for enums are isize or bigger during
+                // their computation, but the in-memory tag is the smallest possible
+                // representation
+                let discr = self.discriminant_for_variant(ty, variant_index)?;
+                let discr_size = discr.layout.size;
+                let discr_val = discr.to_scalar().to_bits(discr_size)?;
+                let tag_size = tag_layout.size(self);
+                let tag_val = tag_size.truncate(discr_val);
+                let tag = ScalarInt::try_from_uint(tag_val, tag_size).unwrap();
+                Ok(Some((tag, tag_field)))
+            }
+
+            abi::Variants::Multiple {
+                tag_encoding: TagEncoding::Niche { untagged_variant, .. },
+                ..
+            } if untagged_variant == variant_index => {
+                // The untagged variant is implicitly encoded simply by having a
+                // value that is outside the niche variants.
+                Ok(None)
+            }
+
+            abi::Variants::Multiple {
+                tag_encoding:
+                    TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start },
+                tag: tag_layout,
+                tag_field,
+                ..
+            } => {
+                assert!(variant_index != untagged_variant);
+                let variants_start = niche_variants.start().as_u32();
+                let variant_index_relative = variant_index
+                    .as_u32()
+                    .checked_sub(variants_start)
+                    .expect("overflow computing relative variant idx");
+                // We need to use machine arithmetic when taking into account `niche_start`:
+                // tag_val = variant_index_relative + niche_start_val
+                let tag_layout = self.layout_of(tag_layout.primitive().to_int_ty(*self.tcx))?;
+                let niche_start_val = ImmTy::from_uint(niche_start, tag_layout);
+                let variant_index_relative_val =
+                    ImmTy::from_uint(variant_index_relative, tag_layout);
+                let tag = self
+                    .wrapping_binary_op(
+                        mir::BinOp::Add,
+                        &variant_index_relative_val,
+                        &niche_start_val,
+                    )?
+                    .to_scalar()
+                    .try_to_int()
+                    .unwrap();
+                Ok(Some((tag, tag_field)))
+            }
+        }
+    }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 748c7dce5a3..a8478f721c7 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -21,8 +21,8 @@ use rustc_span::symbol::{sym, Symbol};
 use rustc_target::abi::Size;
 
 use super::{
-    util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx, MPlaceTy, Machine, OpTy,
-    Pointer,
+    memory::MemoryKind, util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx,
+    MPlaceTy, Machine, OpTy, Pointer,
 };
 
 use crate::fluent_generated as fluent;
@@ -79,7 +79,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
             | ty::Str
             | ty::Array(_, _)
             | ty::Slice(_)
-            | ty::RawPtr(_)
+            | ty::RawPtr(_, _)
             | ty::Ref(_, _, _)
             | ty::FnDef(_, _)
             | ty::FnPtr(_)
@@ -414,6 +414,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let result = self.raw_eq_intrinsic(&args[0], &args[1])?;
                 self.write_scalar(result, dest)?;
             }
+            sym::typed_swap => {
+                self.typed_swap_intrinsic(&args[0], &args[1])?;
+            }
 
             sym::vtable_size => {
                 let ptr = self.read_pointer(&args[0])?;
@@ -607,6 +610,24 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         self.mem_copy(src, dst, size, nonoverlapping)
     }
 
+    /// Does a *typed* swap of `*left` and `*right`.
+    fn typed_swap_intrinsic(
+        &mut self,
+        left: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
+        right: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
+    ) -> InterpResult<'tcx> {
+        let left = self.deref_pointer(left)?;
+        let right = self.deref_pointer(right)?;
+        debug_assert_eq!(left.layout, right.layout);
+        let kind = MemoryKind::Stack;
+        let temp = self.allocate(left.layout, kind)?;
+        self.copy_op(&left, &temp)?;
+        self.copy_op(&right, &left)?;
+        self.copy_op(&temp, &right)?;
+        self.deallocate_ptr(temp.ptr(), None, kind)?;
+        Ok(())
+    }
+
     pub(crate) fn write_bytes_intrinsic(
         &mut self,
         dst: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index a6ca4b2e0de..9b1d9cf932b 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -1159,11 +1159,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         };
 
         // Side-step AllocRef and directly access the underlying bytes more efficiently.
-        // (We are staying inside the bounds here so all is good.)
+        // (We are staying inside the bounds here and all bytes do get overwritten so all is good.)
         let alloc_id = alloc_ref.alloc_id;
         let bytes = alloc_ref
             .alloc
-            .get_bytes_mut(&alloc_ref.tcx, alloc_ref.range)
+            .get_bytes_unchecked_for_overwrite(&alloc_ref.tcx, alloc_ref.range)
             .map_err(move |e| e.to_interp_error(alloc_id))?;
         // `zip` would stop when the first iterator ends; we want to definitely
         // cover all of `bytes`.
@@ -1184,6 +1184,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         self.mem_copy_repeatedly(src, dest, size, 1, nonoverlapping)
     }
 
+    /// Performs `num_copies` many copies of `size` many bytes from `src` to `dest + i*size` (where
+    /// `i` is the index of the copy).
+    ///
+    /// Either `nonoverlapping` must be true or `num_copies` must be 1; doing repeated copies that
+    /// may overlap is not supported.
     pub fn mem_copy_repeatedly(
         &mut self,
         src: Pointer<Option<M::Provenance>>,
@@ -1245,8 +1250,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             (dest_alloc_id, dest_prov),
             dest_range,
         )?;
+        // Yes we do overwrite all bytes in `dest_bytes`.
         let dest_bytes = dest_alloc
-            .get_bytes_mut_ptr(&tcx, dest_range)
+            .get_bytes_unchecked_for_overwrite_ptr(&tcx, dest_range)
             .map_err(|e| e.to_interp_error(dest_alloc_id))?
             .as_mut_ptr();
 
@@ -1280,6 +1286,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     }
                 }
             }
+            if num_copies > 1 {
+                assert!(nonoverlapping, "multi-copy only supported in non-overlapping mode");
+            }
 
             let size_in_bytes = size.bytes_usize();
             // For particularly large arrays (where this is perf-sensitive) it's common that
@@ -1292,6 +1301,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             } else if src_alloc_id == dest_alloc_id {
                 let mut dest_ptr = dest_bytes;
                 for _ in 0..num_copies {
+                    // Here we rely on `src` and `dest` being non-overlapping if there is more than
+                    // one copy.
                     ptr::copy(src_bytes, dest_ptr, size_in_bytes);
                     dest_ptr = dest_ptr.add(size_in_bytes);
                 }
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 54bac70da38..9114ffff6fd 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -258,17 +258,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                         let val = layout.offset_of_subfield(self, fields.iter()).bytes();
                         Scalar::from_target_usize(val, self)
                     }
-                    mir::NullOp::UbCheck(kind) => {
-                        // We want to enable checks for library UB, because the interpreter doesn't
-                        // know about those on its own.
-                        // But we want to disable checks for language UB, because the interpreter
-                        // has its own better checks for that.
-                        let should_check = match kind {
-                            mir::UbKind::LibraryUb => self.tcx.sess.opts.debug_assertions,
-                            mir::UbKind::LanguageUb => false,
-                        };
-                        Scalar::from_bool(should_check)
-                    }
+                    mir::NullOp::UbChecks => Scalar::from_bool(self.tcx.sess.opts.debug_assertions),
                 };
                 self.write_scalar(val, &dest)?;
             }
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index 82fb7ff1840..c0e27e86d50 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -375,7 +375,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             // We cannot use `builtin_deref` here since we need to reject `Box<T, MyAlloc>`.
             Ok(Some(match ty.kind() {
                 ty::Ref(_, ty, _) => *ty,
-                ty::RawPtr(mt) => mt.ty,
+                ty::RawPtr(ty, _) => *ty,
                 // We only accept `Box` with the default allocator.
                 _ if ty.is_box_global(*self.tcx) => ty.boxed_ty(),
                 _ => return Ok(None),
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index 1e7ee208af1..633caf8d092 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -40,6 +40,7 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 
 pub fn provide(providers: &mut Providers) {
     const_eval::provide(providers);
+    providers.tag_for_variant = const_eval::tag_for_variant_provider;
     providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider;
     providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider;
     providers.eval_static_initializer = const_eval::eval_static_initializer_provider;
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index a93e8138aa4..da8e28d0298 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -558,7 +558,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
             Rvalue::Cast(_, _, _) => {}
 
             Rvalue::NullaryOp(
-                NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_) | NullOp::UbCheck(_),
+                NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_) | NullOp::UbChecks,
                 _,
             ) => {}
             Rvalue::ShallowInitBox(_, _) => {}
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 68270dab284..1664475f52a 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -4,6 +4,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_index::bit_set::BitSet;
 use rustc_index::IndexVec;
 use rustc_infer::traits::Reveal;
+use rustc_middle::mir::coverage::CoverageKind;
 use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
@@ -84,7 +85,7 @@ impl<'tcx> MirPass<'tcx> for Validator {
         cfg_checker.check_cleanup_control_flow();
 
         // Also run the TypeChecker.
-        for (location, msg) in validate_types(tcx, self.mir_phase, param_env, body) {
+        for (location, msg) in validate_types(tcx, self.mir_phase, param_env, body, body) {
             cfg_checker.fail(location, msg);
         }
 
@@ -345,11 +346,21 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
                     self.fail(location, format!("explicit `{kind:?}` is forbidden"));
                 }
             }
+            StatementKind::Coverage(coverage) => {
+                let kind = &coverage.kind;
+                if self.mir_phase >= MirPhase::Analysis(AnalysisPhase::PostCleanup)
+                    && let CoverageKind::BlockMarker { .. } | CoverageKind::SpanMarker { .. } = kind
+                {
+                    self.fail(
+                        location,
+                        format!("{kind:?} should have been removed after analysis"),
+                    );
+                }
+            }
             StatementKind::Assign(..)
             | StatementKind::StorageLive(_)
             | StatementKind::StorageDead(_)
             | StatementKind::Intrinsic(_)
-            | StatementKind::Coverage(_)
             | StatementKind::ConstEvalCounter
             | StatementKind::PlaceMention(..)
             | StatementKind::Nop => {}
@@ -530,19 +541,25 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
 
 /// A faster version of the validation pass that only checks those things which may break when
 /// instantiating any generic parameters.
+///
+/// `caller_body` is used to detect cycles in MIR inlining and MIR validation before
+/// `optimized_mir` is available.
 pub fn validate_types<'tcx>(
     tcx: TyCtxt<'tcx>,
     mir_phase: MirPhase,
     param_env: ty::ParamEnv<'tcx>,
     body: &Body<'tcx>,
+    caller_body: &Body<'tcx>,
 ) -> Vec<(Location, String)> {
-    let mut type_checker = TypeChecker { body, tcx, param_env, mir_phase, failures: Vec::new() };
+    let mut type_checker =
+        TypeChecker { body, caller_body, tcx, param_env, mir_phase, failures: Vec::new() };
     type_checker.visit_body(body);
     type_checker.failures
 }
 
 struct TypeChecker<'a, 'tcx> {
     body: &'a Body<'tcx>,
+    caller_body: &'a Body<'tcx>,
     tcx: TyCtxt<'tcx>,
     param_env: ParamEnv<'tcx>,
     mir_phase: MirPhase,
@@ -694,8 +711,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                     }
                     &ty::Coroutine(def_id, args) => {
                         let f_ty = if let Some(var) = parent_ty.variant_index {
-                            let gen_body = if def_id == self.body.source.def_id() {
-                                self.body
+                            // If we're currently validating an inlined copy of this body,
+                            // then it will no longer be parameterized over the original
+                            // args of the coroutine. Otherwise, we prefer to use this body
+                            // since we may be in the process of computing this MIR in the
+                            // first place.
+                            let gen_body = if def_id == self.caller_body.source.def_id() {
+                                self.caller_body
                             } else {
                                 self.tcx.optimized_mir(def_id)
                             };
@@ -1157,7 +1179,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
             Rvalue::Repeat(_, _)
             | Rvalue::ThreadLocalRef(_)
             | Rvalue::AddressOf(_, _)
-            | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::UbCheck(_), _)
+            | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::UbChecks, _)
             | Rvalue::Discriminant(_) => {}
         }
         self.super_rvalue(rvalue, location);
diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs
index 2b80623ab45..f3db7d4cd42 100644
--- a/compiler/rustc_const_eval/src/util/type_name.rs
+++ b/compiler/rustc_const_eval/src/util/type_name.rs
@@ -33,7 +33,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
             | ty::Str
             | ty::Array(_, _)
             | ty::Slice(_)
-            | ty::RawPtr(_)
+            | ty::RawPtr(_, _)
             | ty::Ref(_, _, _)
             | ty::FnPtr(_)
             | ty::Never
diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs
index 32202ac3ede..eab6d8168ca 100644
--- a/compiler/rustc_data_structures/src/sync.rs
+++ b/compiler/rustc_data_structures/src/sync.rs
@@ -20,6 +20,7 @@
 //! | ----------------------- | ------------------- | ------------------------------- |
 //! | `Lrc<T>`                | `rc::Rc<T>`         | `sync::Arc<T>`                  |
 //! |` Weak<T>`               | `rc::Weak<T>`       | `sync::Weak<T>`                 |
+//! | `LRef<'a, T>` [^2]      | `&'a mut T`         | `&'a T`                         |
 //! |                         |                     |                                 |
 //! | `AtomicBool`            | `Cell<bool>`        | `atomic::AtomicBool`            |
 //! | `AtomicU32`             | `Cell<u32>`         | `atomic::AtomicU32`             |
@@ -38,7 +39,7 @@
 //! of a `RefCell`. This is appropriate when interior mutability is not
 //! required.
 //!
-//! [^2] `MTLockRef` is a typedef.
+//! [^2] `MTRef`, `MTLockRef` are type aliases.
 
 pub use crate::marker::*;
 use std::collections::HashMap;
@@ -208,7 +209,7 @@ cfg_match! {
 
         use std::cell::RefCell as InnerRwLock;
 
-        pub type MTLockRef<'a, T> = &'a mut MTLock<T>;
+        pub type LRef<'a, T> = &'a mut T;
 
         #[derive(Debug, Default)]
         pub struct MTLock<T>(T);
@@ -274,7 +275,7 @@ cfg_match! {
         pub use std::sync::Arc as Lrc;
         pub use std::sync::Weak as Weak;
 
-        pub type MTLockRef<'a, T> = &'a MTLock<T>;
+        pub type LRef<'a, T> = &'a T;
 
         #[derive(Debug, Default)]
         pub struct MTLock<T>(Lock<T>);
@@ -314,6 +315,8 @@ cfg_match! {
     }
 }
 
+pub type MTLockRef<'a, T> = LRef<'a, MTLock<T>>;
+
 #[derive(Default)]
 #[cfg_attr(parallel_compiler, repr(align(64)))]
 pub struct CacheAligned<T>(pub T);
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 938f9f0beaa..716e31080dd 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -890,7 +890,7 @@ pub fn version_at_macro_invocation(
         let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
         let opts = config::Options::default();
         let sysroot = filesearch::materialize_sysroot(opts.maybe_sysroot.clone());
-        let target = config::build_target_config(early_dcx, &opts, None, &sysroot);
+        let target = config::build_target_config(early_dcx, &opts, &sysroot);
 
         get_codegen_backend(early_dcx, &sysroot, backend_name, &target).print_version();
     }
@@ -1100,7 +1100,7 @@ pub fn describe_flag_categories(early_dcx: &EarlyDiagCtxt, matches: &Matches) ->
 
         let opts = config::Options::default();
         let sysroot = filesearch::materialize_sysroot(opts.maybe_sysroot.clone());
-        let target = config::build_target_config(early_dcx, &opts, None, &sysroot);
+        let target = config::build_target_config(early_dcx, &opts, &sysroot);
 
         get_codegen_backend(early_dcx, &sysroot, backend_name, &target).print_passes();
         return true;
diff --git a/compiler/rustc_driver_impl/src/signal_handler.rs b/compiler/rustc_driver_impl/src/signal_handler.rs
index deca1082221..441219eec90 100644
--- a/compiler/rustc_driver_impl/src/signal_handler.rs
+++ b/compiler/rustc_driver_impl/src/signal_handler.rs
@@ -1,6 +1,7 @@
 //! Signal handler for rustc
 //! Primarily used to extract a backtrace from stack overflow
 
+use rustc_interface::util::{DEFAULT_STACK_SIZE, STACK_SIZE};
 use std::alloc::{alloc, Layout};
 use std::{fmt, mem, ptr};
 
@@ -100,7 +101,10 @@ extern "C" fn print_stack_trace(_: libc::c_int) {
         written += 1;
     }
     raw_errln!("note: we would appreciate a report at https://github.com/rust-lang/rust");
-    written += 1;
+    // get the current stack size WITHOUT blocking and double it
+    let new_size = STACK_SIZE.get().copied().unwrap_or(DEFAULT_STACK_SIZE) * 2;
+    raw_errln!("help: you can increase rustc's stack size by setting RUST_MIN_STACK={new_size}");
+    written += 2;
     if written > 24 {
         // We probably just scrolled the earlier "we got SIGSEGV" message off the terminal
         raw_errln!("note: backtrace dumped due to SIGSEGV! resuming signal");
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index 1f0488130b2..fdd1a87cae8 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -33,6 +33,9 @@ expand_duplicate_matcher_binding = duplicate matcher binding
 expand_expected_comma_in_list =
     expected token: `,`
 
+expand_expected_paren_or_brace =
+    expected `(` or `{"{"}`, found `{$token}`
+
 expand_explain_doc_comment_inner =
     inner doc comments expand to `#![doc = "..."]`, which is what this macro attempted to match
 
diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs
index e71047f94fa..30559871b4e 100644
--- a/compiler/rustc_expand/src/build.rs
+++ b/compiler/rustc_expand/src/build.rs
@@ -1,6 +1,6 @@
 use crate::base::ExtCtxt;
 use rustc_ast::ptr::P;
-use rustc_ast::{self as ast, AttrVec, BlockCheckMode, Expr, LocalKind, PatKind, UnOp};
+use rustc_ast::{self as ast, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, PatKind, UnOp};
 use rustc_ast::{attr, token, util::literal};
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -524,7 +524,7 @@ impl<'a> ExtCtxt<'a> {
     }
 
     pub fn expr_match(&self, span: Span, arg: P<ast::Expr>, arms: ThinVec<ast::Arm>) -> P<Expr> {
-        self.expr(span, ast::ExprKind::Match(arg, arms))
+        self.expr(span, ast::ExprKind::Match(arg, arms, MatchKind::Prefix))
     }
 
     pub fn expr_if(
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index fe901603c73..21ce5e1d81e 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -448,3 +448,11 @@ pub struct InvalidFragmentSpecifier {
     pub fragment: Ident,
     pub help: String,
 }
+
+#[derive(Diagnostic)]
+#[diag(expand_expected_paren_or_brace)]
+pub struct ExpectedParenOrBrace<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub token: Cow<'a, str>,
+}
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index ac5136539c3..a31be05ccc4 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -392,12 +392,7 @@ pub(super) fn count_metavar_decls(matcher: &[TokenTree]) -> usize {
 #[derive(Debug, Clone)]
 pub(crate) enum NamedMatch {
     MatchedSeq(Vec<NamedMatch>),
-
-    // A metavar match of type `tt`.
-    MatchedTokenTree(rustc_ast::tokenstream::TokenTree),
-
-    // A metavar match of any type other than `tt`.
-    MatchedNonterminal(Lrc<(Nonterminal, rustc_span::Span)>),
+    MatchedSingle(ParseNtResult<Lrc<(Nonterminal, Span)>>),
 }
 
 /// Performs a token equality check, ignoring syntax context (that is, an unhygienic comparison)
@@ -691,11 +686,11 @@ impl TtParser {
                             }
                             Ok(nt) => nt,
                         };
-                        let m = match nt {
-                            ParseNtResult::Nt(nt) => MatchedNonterminal(Lrc::new((nt, span))),
-                            ParseNtResult::Tt(tt) => MatchedTokenTree(tt),
-                        };
-                        mp.push_match(next_metavar, seq_depth, m);
+                        mp.push_match(
+                            next_metavar,
+                            seq_depth,
+                            MatchedSingle(nt.map_nt(|nt| (Lrc::new((nt, span))))),
+                        );
                         mp.idx += 1;
                     } else {
                         unreachable!()
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 3f29d7f7465..7099f1b0d35 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -5,7 +5,7 @@ use crate::mbe;
 use crate::mbe::diagnostics::{annotate_doc_comment, parse_failure_msg};
 use crate::mbe::macro_check;
 use crate::mbe::macro_parser::{Error, ErrorReported, Failure, Success, TtParser};
-use crate::mbe::macro_parser::{MatchedSeq, MatchedTokenTree, MatcherLoc};
+use crate::mbe::macro_parser::{MatcherLoc, NamedMatch::*};
 use crate::mbe::transcribe::transcribe;
 
 use ast::token::IdentIsRaw;
@@ -22,7 +22,7 @@ use rustc_lint_defs::builtin::{
     RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
 };
 use rustc_lint_defs::BuiltinLintDiag;
-use rustc_parse::parser::{Parser, Recovery};
+use rustc_parse::parser::{ParseNtResult, Parser, Recovery};
 use rustc_session::parse::ParseSess;
 use rustc_session::Session;
 use rustc_span::edition::Edition;
@@ -479,7 +479,7 @@ pub fn compile_declarative_macro(
         MatchedSeq(s) => s
             .iter()
             .map(|m| {
-                if let MatchedTokenTree(tt) = m {
+                if let MatchedSingle(ParseNtResult::Tt(tt)) = m {
                     let tt = mbe::quoted::parse(
                         &TokenStream::new(vec![tt.clone()]),
                         true,
@@ -505,7 +505,7 @@ pub fn compile_declarative_macro(
         MatchedSeq(s) => s
             .iter()
             .map(|m| {
-                if let MatchedTokenTree(tt) = m {
+                if let MatchedSingle(ParseNtResult::Tt(tt)) = m {
                     return mbe::quoted::parse(
                         &TokenStream::new(vec![tt.clone()]),
                         false,
diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs
index 5fd3716743b..06c1612ddba 100644
--- a/compiler/rustc_expand/src/mbe/quoted.rs
+++ b/compiler/rustc_expand/src/mbe/quoted.rs
@@ -194,9 +194,11 @@ fn parse_tree<'a>(
                             }
                             Delimiter::Parenthesis => {}
                             _ => {
-                                let tok = pprust::token_kind_to_string(&token::OpenDelim(delim));
-                                let msg = format!("expected `(` or `{{`, found `{tok}`");
-                                sess.dcx().span_err(delim_span.entire(), msg);
+                                let token = pprust::token_kind_to_string(&token::OpenDelim(delim));
+                                sess.dcx().emit_err(errors::ExpectedParenOrBrace {
+                                    span: delim_span.entire(),
+                                    token,
+                                });
                             }
                         }
                     }
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index 8fcd468e34b..dad83984c8b 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -3,14 +3,14 @@ use crate::errors::{
     CountRepetitionMisplaced, MetaVarExprUnrecognizedVar, MetaVarsDifSeqMatchers, MustRepeatOnce,
     NoSyntaxVarsExprRepeat, VarStillRepeating,
 };
-use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, MatchedTokenTree, NamedMatch};
+use crate::mbe::macro_parser::{NamedMatch, NamedMatch::*};
 use crate::mbe::{self, KleeneOp, MetaVarExpr};
 use rustc_ast::mut_visit::{self, MutVisitor};
 use rustc_ast::token::{self, Delimiter, Token, TokenKind};
 use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::Diag;
-use rustc_errors::{pluralize, PResult};
+use rustc_errors::{pluralize, Diag, PResult};
+use rustc_parse::parser::ParseNtResult;
 use rustc_span::hygiene::{LocalExpnId, Transparency};
 use rustc_span::symbol::{sym, Ident, MacroRulesNormalizedIdent};
 use rustc_span::{with_metavar_spans, Span, SyntaxContext};
@@ -250,26 +250,25 @@ pub(super) fn transcribe<'a>(
                 // the meta-var.
                 let ident = MacroRulesNormalizedIdent::new(original_ident);
                 if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) {
-                    match cur_matched {
-                        MatchedTokenTree(tt) => {
+                    let tt = match cur_matched {
+                        MatchedSingle(ParseNtResult::Tt(tt)) => {
                             // `tt`s are emitted into the output stream directly as "raw tokens",
                             // without wrapping them into groups.
-                            let tt = maybe_use_metavar_location(cx, &stack, sp, tt, &mut marker);
-                            result.push(tt);
+                            maybe_use_metavar_location(cx, &stack, sp, tt, &mut marker)
                         }
-                        MatchedNonterminal(nt) => {
+                        MatchedSingle(ParseNtResult::Nt(nt)) => {
                             // Other variables are emitted into the output stream as groups with
                             // `Delimiter::Invisible` to maintain parsing priorities.
                             // `Interpolated` is currently used for such groups in rustc parser.
                             marker.visit_span(&mut sp);
-                            result
-                                .push(TokenTree::token_alone(token::Interpolated(nt.clone()), sp));
+                            TokenTree::token_alone(token::Interpolated(nt.clone()), sp)
                         }
                         MatchedSeq(..) => {
                             // We were unable to descend far enough. This is an error.
                             return Err(cx.dcx().create_err(VarStillRepeating { span: sp, ident }));
                         }
-                    }
+                    };
+                    result.push(tt)
                 } else {
                     // If we aren't able to match the meta-var, we push it back into the result but
                     // with modified syntax context. (I believe this supports nested macros).
@@ -424,7 +423,7 @@ fn lookup_cur_matched<'a>(
     interpolations.get(&ident).map(|mut matched| {
         for &(idx, _) in repeats {
             match matched {
-                MatchedTokenTree(_) | MatchedNonterminal(_) => break,
+                MatchedSingle(_) => break,
                 MatchedSeq(ads) => matched = ads.get(idx).unwrap(),
             }
         }
@@ -514,7 +513,7 @@ fn lockstep_iter_size(
             let name = MacroRulesNormalizedIdent::new(*name);
             match lookup_cur_matched(name, interpolations, repeats) {
                 Some(matched) => match matched {
-                    MatchedTokenTree(_) | MatchedNonterminal(_) => LockstepIterSize::Unconstrained,
+                    MatchedSingle(_) => LockstepIterSize::Unconstrained,
                     MatchedSeq(ads) => LockstepIterSize::Constraint(ads.len(), name),
                 },
                 _ => LockstepIterSize::Unconstrained,
@@ -557,7 +556,7 @@ fn count_repetitions<'a>(
     // (or at the top-level of `matched` if no depth is given).
     fn count<'a>(depth_curr: usize, depth_max: usize, matched: &NamedMatch) -> PResult<'a, usize> {
         match matched {
-            MatchedTokenTree(_) | MatchedNonterminal(_) => Ok(1),
+            MatchedSingle(_) => Ok(1),
             MatchedSeq(named_matches) => {
                 if depth_curr == depth_max {
                     Ok(named_matches.len())
@@ -571,7 +570,7 @@ fn count_repetitions<'a>(
     /// Maximum depth
     fn depth(counter: usize, matched: &NamedMatch) -> usize {
         match matched {
-            MatchedTokenTree(_) | MatchedNonterminal(_) => counter,
+            MatchedSingle(_) => counter,
             MatchedSeq(named_matches) => {
                 let rslt = counter + 1;
                 if let Some(elem) = named_matches.first() { depth(rslt, elem) } else { rslt }
@@ -599,7 +598,7 @@ fn count_repetitions<'a>(
         }
     }
 
-    if let MatchedTokenTree(_) | MatchedNonterminal(_) = matched {
+    if let MatchedSingle(_) = matched {
         return Err(cx.dcx().create_err(CountRepetitionMisplaced { span: sp.entire() }));
     }
 
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index d4d7833cb21..22cf50fce7f 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -597,9 +597,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
 
     rustc_attr!(
-        rustc_never_type_mode, Normal, template!(NameValueStr: "fallback_to_unit|fallback_to_niko|fallback_to_never|no_fallback"), ErrorFollowing,
+        rustc_never_type_options,
+        Normal,
+        template!(List: r#"/*opt*/ fallback = "unit|niko|never|no""#),
+        ErrorFollowing,
         EncodeCrossCrate::No,
-        "`rustc_never_type_fallback` is used to experiment with never type fallback and work on \
+        "`rustc_never_type_options` is used to experiment with never type fallback and work on \
          never type stabilization, and will never be stable"
     ),
 
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index a3b13c4d907..8d72f4924d6 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -436,6 +436,8 @@ declare_features! (
     (unstable, deprecated_safe, "1.61.0", Some(94978)),
     /// Allows having using `suggestion` in the `#[deprecated]` attribute.
     (unstable, deprecated_suggestion, "1.61.0", Some(94785)),
+    /// Allows deref patterns.
+    (incomplete, deref_patterns, "CURRENT_RUSTC_VERSION", Some(87121)),
     /// Controls errors in trait implementations.
     (unstable, do_not_recommend, "1.67.0", Some(51992)),
     /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
@@ -557,6 +559,8 @@ declare_features! (
     (unstable, offset_of_nested, "1.77.0", Some(120140)),
     /// Allows using `#[optimize(X)]`.
     (unstable, optimize_attribute, "1.34.0", Some(54882)),
+    /// Allows postfix match `expr.match { ... }`
+    (unstable, postfix_match, "CURRENT_RUSTC_VERSION", Some(121618)),
     /// Allows macro attributes on expressions, statements and non-inline modules.
     (unstable, proc_macro_hygiene, "1.30.0", Some(54727)),
     /// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions.
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index 1810193c16b..e8cecb1930f 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -810,6 +810,8 @@ pub enum LifetimeRes {
         param: NodeId,
         /// Id of the introducing place. See `Param`.
         binder: NodeId,
+        /// Kind of elided lifetime
+        kind: hir::MissingLifetimeKind,
     },
     /// This variant is used for anonymous lifetimes that we did not resolve during
     /// late resolution. Those lifetimes will be inferred by typechecking.
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index ca5d2930e82..cc0ab05d422 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -428,10 +428,6 @@ pub enum TraitBoundModifier {
     MaybeConst,
 }
 
-/// The AST represents all type param bounds as types.
-/// `typeck::collect::compute_bounds` matches these against
-/// the "special" built-in traits (see `middle::lang_items`) and
-/// detects `Copy`, `Send` and `Sync`.
 #[derive(Clone, Copy, Debug, HashStable_Generic)]
 pub enum GenericBound<'hir> {
     Trait(PolyTraitRef<'hir>, TraitBoundModifier),
@@ -456,6 +452,18 @@ impl GenericBound<'_> {
 
 pub type GenericBounds<'hir> = &'hir [GenericBound<'hir>];
 
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable_Generic, Debug)]
+pub enum MissingLifetimeKind {
+    /// An explicit `'_`.
+    Underscore,
+    /// An elided lifetime `&' ty`.
+    Ampersand,
+    /// An elided lifetime in brackets with written brackets.
+    Comma,
+    /// An elided lifetime with elided brackets.
+    Brackets,
+}
+
 #[derive(Copy, Clone, Debug, HashStable_Generic)]
 pub enum LifetimeParamKind {
     // Indicates that the lifetime definition was explicitly declared (e.g., in
@@ -464,7 +472,7 @@ pub enum LifetimeParamKind {
 
     // Indication that the lifetime was elided (e.g., in both cases in
     // `fn foo(x: &u8) -> &'_ u8 { x }`).
-    Elided,
+    Elided(MissingLifetimeKind),
 
     // Indication that the lifetime name was somehow in error.
     Error,
@@ -512,7 +520,7 @@ impl<'hir> GenericParam<'hir> {
     ///
     /// See `lifetime_to_generic_param` in `rustc_ast_lowering` for more information.
     pub fn is_elided_lifetime(&self) -> bool {
-        matches!(self.kind, GenericParamKind::Lifetime { kind: LifetimeParamKind::Elided })
+        matches!(self.kind, GenericParamKind::Lifetime { kind: LifetimeParamKind::Elided(_) })
     }
 }
 
@@ -1003,7 +1011,7 @@ impl<'hir> Pat<'hir> {
         use PatKind::*;
         match self.kind {
             Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => true,
-            Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_short_(it),
+            Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_short_(it),
             Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)),
             TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)),
             Slice(before, slice, after) => {
@@ -1030,7 +1038,7 @@ impl<'hir> Pat<'hir> {
         use PatKind::*;
         match self.kind {
             Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => {}
-            Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_(it),
+            Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_(it),
             Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)),
             TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)),
             Slice(before, slice, after) => {
@@ -1173,6 +1181,9 @@ pub enum PatKind<'hir> {
     /// A `box` pattern.
     Box(&'hir Pat<'hir>),
 
+    /// A `deref` pattern (currently `deref!()` macro-based syntax).
+    Deref(&'hir Pat<'hir>),
+
     /// A reference pattern (e.g., `&mut (a, b)`).
     Ref(&'hir Pat<'hir>, Mutability),
 
@@ -1209,7 +1220,7 @@ pub struct Stmt<'hir> {
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
 pub enum StmtKind<'hir> {
     /// A local (`let`) binding.
-    Let(&'hir Local<'hir>),
+    Let(&'hir LetStmt<'hir>),
 
     /// An item binding.
     Item(ItemId),
@@ -1223,7 +1234,7 @@ pub enum StmtKind<'hir> {
 
 /// Represents a `let` statement (i.e., `let <pat>:<ty> = <init>;`).
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
-pub struct Local<'hir> {
+pub struct LetStmt<'hir> {
     pub pat: &'hir Pat<'hir>,
     /// Type annotation, if any (otherwise the type will be inferred).
     pub ty: Option<&'hir Ty<'hir>>,
@@ -1253,13 +1264,13 @@ pub struct Arm<'hir> {
     pub body: &'hir Expr<'hir>,
 }
 
-/// Represents a `let <pat>[: <ty>] = <expr>` expression (not a [`Local`]), occurring in an `if-let`
+/// Represents a `let <pat>[: <ty>] = <expr>` expression (not a [`LetStmt`]), occurring in an `if-let`
 /// or `let-else`, evaluating to a boolean. Typically the pattern is refutable.
 ///
 /// In an `if let`, imagine it as `if (let <pat> = <expr>) { ... }`; in a let-else, it is part of
 /// the desugaring to if-let. Only let-else supports the type annotation at present.
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
-pub struct Let<'hir> {
+pub struct LetExpr<'hir> {
     pub span: Span,
     pub pat: &'hir Pat<'hir>,
     pub ty: Option<&'hir Ty<'hir>>,
@@ -1845,14 +1856,14 @@ pub enum ExprKind<'hir> {
     /// Wraps the expression in a terminating scope.
     /// This makes it semantically equivalent to `{ let _t = expr; _t }`.
     ///
-    /// This construct only exists to tweak the drop order in HIR lowering.
+    /// This construct only exists to tweak the drop order in AST lowering.
     /// An example of that is the desugaring of `for` loops.
     DropTemps(&'hir Expr<'hir>),
     /// A `let $pat = $expr` expression.
     ///
-    /// These are not `Local` and only occur as expressions.
+    /// These are not [`LetStmt`] and only occur as expressions.
     /// The `let Some(x) = foo()` in `if let Some(x) = foo()` is an example of `Let(..)`.
-    Let(&'hir Let<'hir>),
+    Let(&'hir LetExpr<'hir>),
     /// An `if` block, with an optional else block.
     ///
     /// I.e., `if <expr> { <expr> } else { <expr> }`.
@@ -2004,6 +2015,8 @@ pub enum LocalSource {
 pub enum MatchSource {
     /// A `match _ { .. }`.
     Normal,
+    /// A `expr.match { .. }`.
+    Postfix,
     /// A desugared `for _ in _ { .. }` loop.
     ForLoopDesugar,
     /// A desugared `?` operator.
@@ -2020,6 +2033,7 @@ impl MatchSource {
         use MatchSource::*;
         match self {
             Normal => "match",
+            Postfix => ".match",
             ForLoopDesugar => "for",
             TryDesugar(_) => "?",
             AwaitDesugar => ".await",
@@ -2278,7 +2292,7 @@ pub enum ImplItemKind<'hir> {
 /// Bind a type to an associated type (i.e., `A = Foo`).
 ///
 /// Bindings like `A: Debug` are represented as a special type `A =
-/// $::Debug` that is understood by the astconv code.
+/// $::Debug` that is understood by the HIR ty lowering code.
 ///
 /// FIXME(alexreg): why have a separate type for the binding case,
 /// wouldn't it be better to make the `ty` field an enum like the
@@ -3515,7 +3529,7 @@ pub enum Node<'hir> {
     PatField(&'hir PatField<'hir>),
     Arm(&'hir Arm<'hir>),
     Block(&'hir Block<'hir>),
-    Local(&'hir Local<'hir>),
+    LetStmt(&'hir LetStmt<'hir>),
     /// `Ctor` refers to the constructor of an enum variant or struct. Only tuple or unit variants
     /// with synthesized constructors.
     Ctor(&'hir VariantData<'hir>),
@@ -3571,7 +3585,7 @@ impl<'hir> Node<'hir> {
             | Node::Ctor(..)
             | Node::Pat(..)
             | Node::Arm(..)
-            | Node::Local(..)
+            | Node::LetStmt(..)
             | Node::Crate(..)
             | Node::Ty(..)
             | Node::TraitRef(..)
@@ -3743,7 +3757,7 @@ impl<'hir> Node<'hir> {
         expect_pat_field,     &'hir PatField<'hir>,     Node::PatField(n),     n;
         expect_arm,           &'hir Arm<'hir>,          Node::Arm(n),          n;
         expect_block,         &'hir Block<'hir>,        Node::Block(n),        n;
-        expect_local,         &'hir Local<'hir>,        Node::Local(n),        n;
+        expect_let_stmt,      &'hir LetStmt<'hir>,      Node::LetStmt(n),      n;
         expect_ctor,          &'hir VariantData<'hir>,  Node::Ctor(n),         n;
         expect_lifetime,      &'hir Lifetime,           Node::Lifetime(n),     n;
         expect_generic_param, &'hir GenericParam<'hir>, Node::GenericParam(n), n;
@@ -3773,7 +3787,7 @@ mod size_asserts {
     static_assert_size!(ImplItemKind<'_>, 40);
     static_assert_size!(Item<'_>, 88);
     static_assert_size!(ItemKind<'_>, 56);
-    static_assert_size!(Local<'_>, 64);
+    static_assert_size!(LetStmt<'_>, 64);
     static_assert_size!(Param<'_>, 32);
     static_assert_size!(Pat<'_>, 72);
     static_assert_size!(Path<'_>, 40);
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 186bb234a45..8c44f21a57b 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -320,7 +320,7 @@ pub trait Visitor<'v>: Sized {
     fn visit_foreign_item(&mut self, i: &'v ForeignItem<'v>) -> Self::Result {
         walk_foreign_item(self, i)
     }
-    fn visit_local(&mut self, l: &'v Local<'v>) -> Self::Result {
+    fn visit_local(&mut self, l: &'v LetStmt<'v>) -> Self::Result {
         walk_local(self, l)
     }
     fn visit_block(&mut self, b: &'v Block<'v>) -> Self::Result {
@@ -606,7 +606,7 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(
     V::Result::output()
 }
 
-pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local<'v>) -> V::Result {
+pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v LetStmt<'v>) -> V::Result {
     // Intentionally visiting the expr first - the initialization expr
     // dominates the local's definition.
     visit_opt!(visitor, visit_expr, local.init);
@@ -660,7 +660,9 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V:
         PatKind::Tuple(tuple_elements, _) => {
             walk_list!(visitor, visit_pat, tuple_elements);
         }
-        PatKind::Box(ref subpattern) | PatKind::Ref(ref subpattern, _) => {
+        PatKind::Box(ref subpattern)
+        | PatKind::Deref(ref subpattern)
+        | PatKind::Ref(ref subpattern, _) => {
             try_visit!(visitor.visit_pat(subpattern));
         }
         PatKind::Binding(_, _hir_id, ident, ref optional_subpattern) => {
@@ -753,7 +755,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
         ExprKind::DropTemps(ref subexpression) => {
             try_visit!(visitor.visit_expr(subexpression));
         }
-        ExprKind::Let(Let { span: _, pat, ty, init, is_recovered: _ }) => {
+        ExprKind::Let(LetExpr { span: _, pat, ty, init, is_recovered: _ }) => {
             // match the visit order in walk_local
             try_visit!(visitor.visit_expr(init));
             try_visit!(visitor.visit_pat(pat));
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 5118bf5c3b7..dbf86f5cf74 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -214,6 +214,7 @@ language_item_table! {
     FnOnceOutput,            sym::fn_once_output,      fn_once_output,             Target::AssocTy,        GenericRequirement::None;
 
     Iterator,                sym::iterator,            iterator_trait,             Target::Trait,          GenericRequirement::Exact(0);
+    FusedIterator,           sym::fused_iterator,      fused_iterator_trait,       Target::Trait,          GenericRequirement::Exact(0);
     Future,                  sym::future_trait,        future_trait,               Target::Trait,          GenericRequirement::Exact(0);
     AsyncIterator,           sym::async_iterator,      async_iterator_trait,       Target::Trait,          GenericRequirement::Exact(0);
 
diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs
index b69f679880d..d5465bb5dd5 100644
--- a/compiler/rustc_hir_analysis/src/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/bounds.rs
@@ -1,5 +1,5 @@
-//! Bounds are restrictions applied to some types after they've been converted into the
-//! `ty` form from the HIR.
+//! Bounds are restrictions applied to some types after they've been lowered from the HIR to the
+//! [`rustc_middle::ty`] form.
 
 use rustc_hir::LangItem;
 use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
@@ -42,7 +42,7 @@ impl<'tcx> Bounds<'tcx> {
         tcx: TyCtxt<'tcx>,
         trait_ref: ty::PolyTraitRef<'tcx>,
         span: Span,
-        polarity: ty::ImplPolarity,
+        polarity: ty::PredicatePolarity,
     ) {
         self.push_trait_bound_inner(tcx, trait_ref, span, polarity);
     }
@@ -52,7 +52,7 @@ impl<'tcx> Bounds<'tcx> {
         tcx: TyCtxt<'tcx>,
         trait_ref: ty::PolyTraitRef<'tcx>,
         span: Span,
-        polarity: ty::ImplPolarity,
+        polarity: ty::PredicatePolarity,
     ) {
         self.clauses.push((
             trait_ref
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index d1fed13ee9f..1286a724e95 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -382,8 +382,8 @@ fn check_opaque_meets_bounds<'tcx>(
         Ok(()) => {}
         Err(ty_err) => {
             // Some types may be left "stranded" if they can't be reached
-            // from an astconv'd bound but they're mentioned in the HIR. This
-            // will happen, e.g., when a nested opaque is inside of a non-
+            // from a lowered rustc_middle bound but they're mentioned in the HIR.
+            // This will happen, e.g., when a nested opaque is inside of a non-
             // existent associated type, like `impl Trait<Missing = impl Trait>`.
             // See <tests/ui/impl-trait/stranded-opaque.rs>.
             let ty_err = ty_err.to_string(tcx);
@@ -499,7 +499,7 @@ fn is_enum_of_nonnullable_ptr<'tcx>(
 fn check_static_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     if tcx.codegen_fn_attrs(def_id).import_linkage.is_some() {
         if match tcx.type_of(def_id).instantiate_identity().kind() {
-            ty::RawPtr(_) => false,
+            ty::RawPtr(_, _) => false,
             ty::Adt(adt_def, args) => !is_enum_of_nonnullable_ptr(tcx, *adt_def, *args),
             _ => true,
         } {
@@ -934,10 +934,13 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
         // No: char, "fat" pointers, compound types
         match e.kind() {
             ty::Param(_) => (), // pass struct<T>(T, T, T, T) through, let monomorphization catch errors
-            ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_) => (), // struct(u8, u8, u8, u8) is ok
+            ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_, _) => (), // struct(u8, u8, u8, u8) is ok
             ty::Array(t, _) if matches!(t.kind(), ty::Param(_)) => (), // pass struct<T>([T; N]) through, let monomorphization catch errors
             ty::Array(t, _clen)
-                if matches!(t.kind(), ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_)) =>
+                if matches!(
+                    t.kind(),
+                    ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_, _)
+                ) =>
             { /* struct([f32; 4]) is ok */ }
             _ => {
                 struct_span_code_err!(
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 ec9e928ce59..50f88eb970a 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -639,10 +639,9 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
         }
     }
 
-    if !unnormalized_trait_sig.output().references_error() {
-        debug_assert!(
-            !collector.types.is_empty(),
-            "expect >0 RPITITs in call to `collect_return_position_impl_trait_in_trait_tys`"
+    if !unnormalized_trait_sig.output().references_error() && collector.types.is_empty() {
+        tcx.dcx().delayed_bug(
+            "expect >0 RPITITs in call to `collect_return_position_impl_trait_in_trait_tys`",
         );
     }
 
@@ -746,7 +745,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
 
     // We may not collect all RPITITs that we see in the HIR for a trait signature
     // because an RPITIT was located within a missing item. Like if we have a sig
-    // returning `-> Missing<impl Sized>`, that gets converted to `-> [type error]`,
+    // returning `-> Missing<impl Sized>`, that gets converted to `-> {type error}`,
     // and when walking through the signature we end up never collecting the def id
     // of the `impl Sized`. Insert that here, so we don't ICE later.
     for assoc_item in tcx.associated_types_for_impl_traits_in_associated_fn(trait_m.def_id) {
@@ -1305,7 +1304,7 @@ fn compare_number_of_generics<'tcx>(
                     .iter()
                     .filter(|p| match p.kind {
                         hir::GenericParamKind::Lifetime {
-                            kind: hir::LifetimeParamKind::Elided,
+                            kind: hir::LifetimeParamKind::Elided(_),
                         } => {
                             // A fn can have an arbitrary number of extra elided lifetimes for the
                             // same signature.
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 07054c184f4..f482ae4f5fa 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -127,8 +127,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
         | sym::variant_count
         | sym::is_val_statically_known
         | sym::ptr_mask
-        | sym::check_language_ub
-        | sym::check_library_ub
+        | sym::ub_checks
         | sym::fadd_algebraic
         | sym::fsub_algebraic
         | sym::fmul_algebraic
@@ -191,7 +190,7 @@ pub fn check_intrinsic_type(
                 ty::BoundRegion { var: ty::BoundVar::from_u32(2), kind: ty::BrEnv },
             );
             let va_list_ty = tcx.type_of(did).instantiate(tcx, &[region.into()]);
-            (Ty::new_ref(tcx, env_region, ty::TypeAndMut { ty: va_list_ty, mutbl }), va_list_ty)
+            (Ty::new_ref(tcx, env_region, va_list_ty, mutbl), va_list_ty)
         })
     };
 
@@ -240,15 +239,9 @@ pub fn check_intrinsic_type(
             sym::prefetch_read_data
             | sym::prefetch_write_data
             | sym::prefetch_read_instruction
-            | sym::prefetch_write_instruction => (
-                1,
-                0,
-                vec![
-                    Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
-                    tcx.types.i32,
-                ],
-                Ty::new_unit(tcx),
-            ),
+            | sym::prefetch_write_instruction => {
+                (1, 0, vec![Ty::new_imm_ptr(tcx, param(0)), tcx.types.i32], Ty::new_unit(tcx))
+            }
             sym::needs_drop => (1, 0, vec![], tcx.types.bool),
 
             sym::type_name => (1, 0, vec![], Ty::new_static_str(tcx)),
@@ -257,28 +250,22 @@ pub fn check_intrinsic_type(
             sym::arith_offset => (
                 1,
                 0,
-                vec![
-                    Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
-                    tcx.types.isize,
-                ],
-                Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
+                vec![Ty::new_imm_ptr(tcx, param(0)), tcx.types.isize],
+                Ty::new_imm_ptr(tcx, param(0)),
             ),
             sym::ptr_mask => (
                 1,
                 0,
-                vec![
-                    Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
-                    tcx.types.usize,
-                ],
-                Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
+                vec![Ty::new_imm_ptr(tcx, param(0)), tcx.types.usize],
+                Ty::new_imm_ptr(tcx, param(0)),
             ),
 
             sym::copy | sym::copy_nonoverlapping => (
                 1,
                 0,
                 vec![
-                    Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
-                    Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }),
+                    Ty::new_imm_ptr(tcx, param(0)),
+                    Ty::new_mut_ptr(tcx, param(0)),
                     tcx.types.usize,
                 ],
                 Ty::new_unit(tcx),
@@ -287,8 +274,8 @@ pub fn check_intrinsic_type(
                 1,
                 0,
                 vec![
-                    Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }),
-                    Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
+                    Ty::new_mut_ptr(tcx, param(0)),
+                    Ty::new_imm_ptr(tcx, param(0)),
                     tcx.types.usize,
                 ],
                 Ty::new_unit(tcx),
@@ -300,11 +287,7 @@ pub fn check_intrinsic_type(
             sym::write_bytes | sym::volatile_set_memory => (
                 1,
                 0,
-                vec![
-                    Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Mut }),
-                    tcx.types.u8,
-                    tcx.types.usize,
-                ],
+                vec![Ty::new_mut_ptr(tcx, param(0)), tcx.types.u8, tcx.types.usize],
                 Ty::new_unit(tcx),
             ),
 
@@ -500,6 +483,8 @@ pub fn check_intrinsic_type(
                 (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], Ty::new_unit(tcx))
             }
 
+            sym::typed_swap => (1, 1, vec![Ty::new_mut_ptr(tcx, param(0)); 2], Ty::new_unit(tcx)),
+
             sym::discriminant_value => {
                 let assoc_items = tcx.associated_item_def_ids(
                     tcx.require_lang_item(hir::LangItem::DiscriminantKind, None),
@@ -585,7 +570,7 @@ pub fn check_intrinsic_type(
                 (0, 0, vec![Ty::new_imm_ptr(tcx, Ty::new_unit(tcx))], tcx.types.usize)
             }
 
-            sym::check_language_ub | sym::check_library_ub => (0, 1, Vec::new(), tcx.types.bool),
+            sym::ub_checks => (0, 1, Vec::new(), tcx.types.bool),
 
             sym::simd_eq
             | sym::simd_ne
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
index 9de660407d7..df4db3ec3fb 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
@@ -6,7 +6,9 @@ use rustc_session::lint;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::Symbol;
 use rustc_target::abi::FieldIdx;
-use rustc_target::asm::{InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType};
+use rustc_target::asm::{
+    InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType, ModifierInfo,
+};
 
 pub struct InlineAsmCtxt<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
@@ -62,9 +64,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
             ty::Float(FloatTy::F32) => Some(InlineAsmType::F32),
             ty::Float(FloatTy::F64) => Some(InlineAsmType::F64),
             ty::FnPtr(_) => Some(asm_ty_isize),
-            ty::RawPtr(ty::TypeAndMut { ty, mutbl: _ }) if self.is_thin_ptr_ty(ty) => {
-                Some(asm_ty_isize)
-            }
+            ty::RawPtr(ty, _) if self.is_thin_ptr_ty(ty) => Some(asm_ty_isize),
             ty::Adt(adt, args) if adt.repr().simd() => {
                 let fields = &adt.non_enum_variant().fields;
                 let elem_ty = fields[FieldIdx::from_u32(0)].ty(self.tcx, args);
@@ -253,8 +253,11 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
         }
 
         // Check whether a modifier is suggested for using this type.
-        if let Some((suggested_modifier, suggested_result)) =
-            reg_class.suggest_modifier(asm_arch, asm_ty)
+        if let Some(ModifierInfo {
+            modifier: suggested_modifier,
+            result: suggested_result,
+            size: suggested_size,
+        }) = reg_class.suggest_modifier(asm_arch, asm_ty)
         {
             // Search for any use of this operand without a modifier and emit
             // the suggestion for them.
@@ -268,8 +271,11 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                 }
             }
             if !spans.is_empty() {
-                let (default_modifier, default_result) =
-                    reg_class.default_modifier(asm_arch).unwrap();
+                let ModifierInfo {
+                    modifier: default_modifier,
+                    result: default_result,
+                    size: default_size,
+                } = reg_class.default_modifier(asm_arch).unwrap();
                 self.tcx.node_span_lint(
                     lint::builtin::ASM_SUB_REGISTER,
                     expr.hir_id,
@@ -278,10 +284,10 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                     |lint| {
                         lint.span_label(expr.span, "for this argument");
                         lint.help(format!(
-                            "use `{{{idx}:{suggested_modifier}}}` to have the register formatted as `{suggested_result}`",
+                            "use `{{{idx}:{suggested_modifier}}}` to have the register formatted as `{suggested_result}` (for {suggested_size}-bit values)",
                         ));
                         lint.help(format!(
-                            "or use `{{{idx}:{default_modifier}}}` to keep the default formatting of `{default_result}`",
+                            "or use `{{{idx}:{default_modifier}}}` to keep the default formatting of `{default_result}` (for {default_size}-bit values)",
                         ));
                     },
                 );
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 4c4ff28808e..8760901b71b 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -431,7 +431,7 @@ fn fn_sig_suggestion<'tcx>(
 
     let asyncness = if tcx.asyncness(assoc.def_id).is_async() {
         output = if let ty::Alias(_, alias_ty) = *output.kind() {
-            tcx.explicit_item_bounds(alias_ty.def_id)
+            tcx.explicit_item_super_predicates(alias_ty.def_id)
                 .iter_instantiated_copied(tcx, alias_ty.args)
                 .find_map(|(bound, _)| bound.as_projection_clause()?.no_bound_vars()?.term.ty())
                 .unwrap_or_else(|| {
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index 3c26729eff8..dcabac6d780 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -11,7 +11,7 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{Arm, Block, Expr, Local, Pat, PatKind, Stmt};
+use rustc_hir::{Arm, Block, Expr, LetStmt, Pat, PatKind, Stmt};
 use rustc_index::Idx;
 use rustc_middle::middle::region::*;
 use rustc_middle::ty::TyCtxt;
@@ -123,7 +123,7 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h
 
         for (i, statement) in blk.stmts.iter().enumerate() {
             match statement.kind {
-                hir::StmtKind::Let(hir::Local { els: Some(els), .. }) => {
+                hir::StmtKind::Let(LetStmt { els: Some(els), .. }) => {
                     // Let-else has a special lexical structure for variables.
                     // First we take a checkpoint of the current scope context here.
                     let mut prev_cx = visitor.cx;
@@ -668,7 +668,7 @@ fn resolve_local<'tcx>(
             | PatKind::TupleStruct(_, subpats, _)
             | PatKind::Tuple(subpats, _) => subpats.iter().any(|p| is_binding_pat(p)),
 
-            PatKind::Box(subpat) => is_binding_pat(subpat),
+            PatKind::Box(subpat) | PatKind::Deref(subpat) => is_binding_pat(subpat),
 
             PatKind::Ref(_, _)
             | PatKind::Binding(hir::BindingAnnotation(hir::ByRef::No, _), ..)
@@ -760,7 +760,7 @@ impl<'tcx> RegionResolutionVisitor<'tcx> {
 
     fn enter_node_scope_with_dtor(&mut self, id: hir::ItemLocalId) {
         // If node was previously marked as a terminating scope during the
-        // recursive visit of its parent node in the AST, then we need to
+        // recursive visit of its parent node in the HIR, then we need to
         // account for the destruction scope representing the scope of
         // the destructors that run immediately after it completes.
         if self.terminating_scopes.contains(&id) {
@@ -855,7 +855,7 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
     fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
         resolve_expr(self, ex);
     }
-    fn visit_local(&mut self, l: &'tcx Local<'tcx>) {
+    fn visit_local(&mut self, l: &'tcx LetStmt<'tcx>) {
         resolve_local(self, Some(l.pat), l.init)
     }
 }
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index b5377e40bfd..4fd7c870fc7 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -272,7 +272,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<()
                 }
                 Some(ty::ImplPolarity::Negative) => {
                     let ast::ImplPolarity::Negative(span) = impl_.polarity else {
-                        bug!("impl_polarity query disagrees with impl's polarity in AST");
+                        bug!("impl_polarity query disagrees with impl's polarity in HIR");
                     };
                     // FIXME(#27579): what amount of WF checking do we need for neg impls?
                     if let hir::Defaultness::Default { .. } = impl_.defaultness {
@@ -954,7 +954,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
                         hir_ty.span,
                         "using function pointers as const generic parameters is forbidden",
                     ),
-                    ty::RawPtr(_) => tcx.dcx().struct_span_err(
+                    ty::RawPtr(_, _) => tcx.dcx().struct_span_err(
                         hir_ty.span,
                         "using raw pointers as const generic parameters is forbidden",
                     ),
@@ -1322,7 +1322,7 @@ fn check_impl<'tcx>(
                     trait_ref,
                 );
                 let trait_pred =
-                    ty::TraitPredicate { trait_ref, polarity: ty::ImplPolarity::Positive };
+                    ty::TraitPredicate { trait_ref, polarity: ty::PredicatePolarity::Positive };
                 let mut obligations = traits::wf::trait_obligations(
                     wfcx.infcx,
                     wfcx.param_env,
@@ -1866,7 +1866,7 @@ fn check_variances_for_type_defn<'tcx>(
             .iter()
             .filter_map(|predicate| match predicate {
                 hir::WherePredicate::BoundPredicate(predicate) => {
-                    match icx.to_ty(predicate.bounded_ty).kind() {
+                    match icx.lower_ty(predicate.bounded_ty).kind() {
                         ty::Param(data) => Some(Parameter(data.index)),
                         _ => None,
                     }
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 8d8b13d6cb3..5e404847656 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -195,7 +195,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
         {
             Ok(())
         }
-        (&RawPtr(tm_a), &RawPtr(tm_b)) if tm_a.mutbl == tm_b.mutbl => Ok(()),
+        (&RawPtr(_, a_mutbl), &RawPtr(_, b_mutbl)) if a_mutbl == b_mutbl => Ok(()),
         (&Adt(def_a, args_a), &Adt(def_b, args_b)) if def_a.is_struct() && def_b.is_struct() => {
             if def_a != def_b {
                 let source_path = tcx.def_path_str(def_a.did());
@@ -351,14 +351,17 @@ pub fn coerce_unsized_info<'tcx>(
             check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ref(tcx, r_b, ty))
         }
 
-        (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(mt_b)) => {
-            let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
-            check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ptr(tcx, ty))
-        }
+        (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b)) => check_mutbl(
+            ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a },
+            ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b },
+            &|ty| Ty::new_imm_ptr(tcx, ty),
+        ),
 
-        (&ty::RawPtr(mt_a), &ty::RawPtr(mt_b)) => {
-            check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ptr(tcx, ty))
-        }
+        (&ty::RawPtr(ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b)) => check_mutbl(
+            ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a },
+            ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b },
+            &|ty| Ty::new_imm_ptr(tcx, ty),
+        ),
 
         (&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b))
             if def_a.is_struct() && def_b.is_struct() =>
@@ -551,7 +554,7 @@ fn infringing_fields_error(
                     }
                     if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate {
                         trait_ref,
-                        polarity: ty::ImplPolarity::Positive,
+                        polarity: ty::PredicatePolarity::Positive,
                         ..
                     })) = error_predicate.kind().skip_binder()
                     {
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index 32f31201254..067878091a7 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -162,7 +162,7 @@ impl<'tcx> InherentCollect<'tcx> {
             | ty::Str
             | ty::Array(..)
             | ty::Slice(_)
-            | ty::RawPtr(_)
+            | ty::RawPtr(_, _)
             | ty::Ref(..)
             | ty::Never
             | ty::FnPtr(_)
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index b46a67d08eb..ca8a635ab5e 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -323,7 +323,7 @@ fn emit_orphan_check_error<'tcx>(
                 let is_foreign =
                     !trait_ref.def_id.is_local() && matches!(is_target_ty, IsFirstInputType::No);
 
-                match &ty.kind() {
+                match *ty.kind() {
                     ty::Slice(_) => {
                         push_to_foreign_or_name(
                             is_foreign,
@@ -354,14 +354,14 @@ fn emit_orphan_check_error<'tcx>(
                     ty::Alias(ty::Opaque, ..) => {
                         opaque.push(errors::OnlyCurrentTraitsOpaque { span })
                     }
-                    ty::RawPtr(ptr_ty) => {
+                    ty::RawPtr(ptr_ty, mutbl) => {
                         if !self_ty.has_param() {
-                            let mut_key = ptr_ty.mutbl.prefix_str();
+                            let mut_key = mutbl.prefix_str();
                             sugg = Some(errors::OnlyCurrentTraitsPointerSugg {
                                 wrapper_span: self_ty_span,
                                 struct_span: full_impl_span.shrink_to_lo(),
                                 mut_key,
-                                ptr_ty: ptr_ty.ty,
+                                ptr_ty,
                             });
                         }
                         pointer.push(errors::OnlyCurrentTraitsPointer { span, pointer: ty });
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 5cd6862786b..a705d3bc107 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -40,9 +40,9 @@ use std::cell::Cell;
 use std::iter;
 use std::ops::Bound;
 
-use crate::astconv::AstConv;
 use crate::check::intrinsic::intrinsic_operation_unsafety;
 use crate::errors;
+use crate::hir_ty_lowering::HirTyLowerer;
 pub use type_of::test_opaque_hidden_types;
 
 mod generics_of;
@@ -61,6 +61,9 @@ pub fn provide(providers: &mut Providers) {
         type_alias_is_lazy: type_of::type_alias_is_lazy,
         item_bounds: item_bounds::item_bounds,
         explicit_item_bounds: item_bounds::explicit_item_bounds,
+        item_super_predicates: item_bounds::item_super_predicates,
+        explicit_item_super_predicates: item_bounds::explicit_item_super_predicates,
+        item_non_self_assumptions: item_bounds::item_non_self_assumptions,
         generics_of: generics_of::generics_of,
         predicates_of: predicates_of::predicates_of,
         predicates_defined_on,
@@ -85,13 +88,12 @@ pub fn provide(providers: &mut Providers) {
 
 ///////////////////////////////////////////////////////////////////////////
 
-/// Context specific to some particular item. This is what implements
-/// [`AstConv`].
+/// Context specific to some particular item. This is what implements [`HirTyLowerer`].
 ///
 /// # `ItemCtxt` vs `FnCtxt`
 ///
 /// `ItemCtxt` is primarily used to type-check item signatures and lower them
-/// from HIR to their [`ty::Ty`] representation, which is exposed using [`AstConv`].
+/// from HIR to their [`ty::Ty`] representation, which is exposed using [`HirTyLowerer`].
 /// It's also used for the bodies of items like structs where the body (the fields)
 /// are just signatures.
 ///
@@ -108,11 +110,11 @@ pub fn provide(providers: &mut Providers) {
 /// `ItemCtxt` has information about the predicates that are defined
 /// on the trait. Unfortunately, this predicate information is
 /// available in various different forms at various points in the
-/// process. So we can't just store a pointer to e.g., the AST or the
+/// process. So we can't just store a pointer to e.g., the HIR or the
 /// parsed ty form, we have to be more flexible. To this end, the
 /// `ItemCtxt` is parameterized by a `DefId` that it uses to satisfy
-/// `get_type_parameter_bounds` requests, drawing the information from
-/// the AST (`hir::Generics`), recursively.
+/// `probe_ty_param_bounds` requests, drawing the information from
+/// the HIR (`hir::Generics`), recursively.
 pub struct ItemCtxt<'tcx> {
     tcx: TyCtxt<'tcx>,
     item_def_id: LocalDefId,
@@ -274,7 +276,7 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
-        convert_item(self.tcx, item.item_id());
+        lower_item(self.tcx, item.item_id());
         reject_placeholder_type_signatures_in_item(self.tcx, item);
         intravisit::walk_item(self, item);
     }
@@ -312,12 +314,12 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
     }
 
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
-        convert_trait_item(self.tcx, trait_item.trait_item_id());
+        lower_trait_item(self.tcx, trait_item.trait_item_id());
         intravisit::walk_trait_item(self, trait_item);
     }
 
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
-        convert_impl_item(self.tcx, impl_item.impl_item_id());
+        lower_impl_item(self.tcx, impl_item.impl_item_id());
         intravisit::walk_impl_item(self, impl_item);
     }
 }
@@ -341,8 +343,8 @@ impl<'tcx> ItemCtxt<'tcx> {
         ItemCtxt { tcx, item_def_id, tainted_by_errors: Cell::new(None) }
     }
 
-    pub fn to_ty(&self, ast_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
-        self.astconv().ast_ty_to_ty(ast_ty)
+    pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
+        self.lowerer().lower_ty(hir_ty)
     }
 
     pub fn hir_id(&self) -> hir::HirId {
@@ -361,7 +363,7 @@ impl<'tcx> ItemCtxt<'tcx> {
     }
 }
 
-impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
+impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
@@ -370,23 +372,14 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
         self.item_def_id.to_def_id()
     }
 
-    fn get_type_parameter_bounds(
-        &self,
-        span: Span,
-        def_id: LocalDefId,
-        assoc_name: Ident,
-    ) -> ty::GenericPredicates<'tcx> {
-        self.tcx.at(span).type_param_predicates((self.item_def_id, def_id, assoc_name))
+    fn allow_infer(&self) -> bool {
+        false
     }
 
     fn re_infer(&self, _: Option<&ty::GenericParamDef>, _: Span) -> Option<ty::Region<'tcx>> {
         None
     }
 
-    fn allow_ty_infer(&self) -> bool {
-        false
-    }
-
     fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
         Ty::new_error_with_message(self.tcx(), span, "bad placeholder type")
     }
@@ -401,7 +394,16 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
         ty::Const::new_error_with_message(self.tcx(), ty, span, "bad placeholder constant")
     }
 
-    fn projected_ty_from_poly_trait_ref(
+    fn probe_ty_param_bounds(
+        &self,
+        span: Span,
+        def_id: LocalDefId,
+        assoc_name: Ident,
+    ) -> ty::GenericPredicates<'tcx> {
+        self.tcx.at(span).type_param_predicates((self.item_def_id, def_id, assoc_name))
+    }
+
+    fn lower_assoc_ty(
         &self,
         span: Span,
         item_def_id: DefId,
@@ -409,7 +411,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
         poly_trait_ref: ty::PolyTraitRef<'tcx>,
     ) -> Ty<'tcx> {
         if let Some(trait_ref) = poly_trait_ref.no_bound_vars() {
-            let item_args = self.astconv().create_args_for_associated_item(
+            let item_args = self.lowerer().lower_generic_args_of_assoc_item(
                 span,
                 item_def_id,
                 item_segment,
@@ -494,10 +496,6 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
         ty.ty_adt_def()
     }
 
-    fn set_tainted_by_errors(&self, err: ErrorGuaranteed) {
-        self.tainted_by_errors.set(Some(err));
-    }
-
     fn record_ty(&self, _hir_id: hir::HirId, _ty: Ty<'tcx>, _span: Span) {
         // There's no place to record types from signatures?
     }
@@ -505,6 +503,10 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
     fn infcx(&self) -> Option<&InferCtxt<'tcx>> {
         None
     }
+
+    fn set_tainted_by_errors(&self, err: ErrorGuaranteed) {
+        self.tainted_by_errors.set(Some(err));
+    }
 }
 
 /// Synthesize a new lifetime name that doesn't clash with any of the lifetimes already present.
@@ -544,9 +546,10 @@ fn get_new_lifetime_name<'tcx>(
     (1..).flat_map(a_to_z_repeat_n).find(|lt| !existing_lifetimes.contains(lt.as_str())).unwrap()
 }
 
-fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
+#[instrument(level = "debug", skip_all)]
+fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
     let it = tcx.hir().item(item_id);
-    debug!("convert: item {} with id {}", it.ident, it.hir_id());
+    debug!(item = %it.ident, id = %it.hir_id());
     let def_id = item_id.owner_id.def_id;
 
     match &it.kind {
@@ -588,7 +591,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
             tcx.ensure().generics_of(def_id);
             tcx.ensure().type_of(def_id);
             tcx.ensure().predicates_of(def_id);
-            convert_enum_variant_types(tcx, def_id.to_def_id());
+            lower_enum_variant_types(tcx, def_id.to_def_id());
         }
         hir::ItemKind::Impl { .. } => {
             tcx.ensure().generics_of(def_id);
@@ -622,7 +625,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
             }
 
             if let Some(ctor_def_id) = struct_def.ctor_def_id() {
-                convert_variant_ctor(tcx, ctor_def_id);
+                lower_variant_ctor(tcx, ctor_def_id);
             }
         }
 
@@ -633,7 +636,9 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
             tcx.ensure().generics_of(def_id);
             tcx.ensure().predicates_of(def_id);
             tcx.ensure().explicit_item_bounds(def_id);
+            tcx.ensure().explicit_item_super_predicates(def_id);
             tcx.ensure().item_bounds(def_id);
+            tcx.ensure().item_super_predicates(def_id);
         }
 
         hir::ItemKind::TyAlias(..) => {
@@ -663,7 +668,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
     }
 }
 
-fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
+fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
     let trait_item = tcx.hir().trait_item(trait_item_id);
     let def_id = trait_item_id.owner_id;
     tcx.ensure().generics_of(def_id);
@@ -689,6 +694,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
 
         hir::TraitItemKind::Type(_, Some(_)) => {
             tcx.ensure().item_bounds(def_id);
+            tcx.ensure().item_super_predicates(def_id);
             tcx.ensure().type_of(def_id);
             // Account for `type T = _;`.
             let mut visitor = HirPlaceholderCollector::default();
@@ -698,6 +704,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
 
         hir::TraitItemKind::Type(_, None) => {
             tcx.ensure().item_bounds(def_id);
+            tcx.ensure().item_super_predicates(def_id);
             // #74612: Visit and try to find bad placeholders
             // even if there is no concrete type.
             let mut visitor = HirPlaceholderCollector::default();
@@ -710,7 +717,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
     tcx.ensure().predicates_of(def_id);
 }
 
-fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
+fn lower_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
     let def_id = impl_item_id.owner_id;
     tcx.ensure().generics_of(def_id);
     tcx.ensure().type_of(def_id);
@@ -739,13 +746,13 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
     }
 }
 
-fn convert_variant_ctor(tcx: TyCtxt<'_>, def_id: LocalDefId) {
+fn lower_variant_ctor(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     tcx.ensure().generics_of(def_id);
     tcx.ensure().type_of(def_id);
     tcx.ensure().predicates_of(def_id);
 }
 
-fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
+fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
     let def = tcx.adt_def(def_id);
     let repr_type = def.repr().discr_type();
     let initial = repr_type.initial_discriminant(tcx);
@@ -778,10 +785,9 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
             tcx.ensure().predicates_of(f.did);
         }
 
-        // Convert the ctor, if any. This also registers the variant as
-        // an item.
+        // Lower the ctor, if any. This also registers the variant as an item.
         if let Some(ctor_def_id) = variant.ctor_def_id() {
-            convert_variant_ctor(tcx, ctor_def_id.expect_local());
+            lower_variant_ctor(tcx, ctor_def_id.expect_local());
         }
     }
 }
@@ -968,7 +974,7 @@ impl<'tcx> FieldUniquenessCheckContext<'tcx> {
     }
 }
 
-fn convert_variant(
+fn lower_variant(
     tcx: TyCtxt<'_>,
     variant_did: Option<LocalDefId>,
     ident: Ident,
@@ -1053,7 +1059,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
                     };
                     distance_from_explicit += 1;
 
-                    convert_variant(
+                    lower_variant(
                         tcx,
                         Some(v.def_id),
                         v.ident,
@@ -1073,7 +1079,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
                 ItemKind::Struct(..) => AdtKind::Struct,
                 _ => AdtKind::Union,
             };
-            let variants = std::iter::once(convert_variant(
+            let variants = std::iter::once(lower_variant(
                 tcx,
                 None,
                 item.ident,
@@ -1277,7 +1283,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<
             if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) = tcx.parent_hir_node(hir_id)
                 && i.of_trait.is_some()
             {
-                icx.astconv().ty_of_fn(
+                icx.lowerer().lower_fn_ty(
                     hir_id,
                     sig.header.unsafety,
                     sig.header.abi,
@@ -1294,9 +1300,14 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<
             kind: TraitItemKind::Fn(FnSig { header, decl, span: _ }, _),
             generics,
             ..
-        }) => {
-            icx.astconv().ty_of_fn(hir_id, header.unsafety, header.abi, decl, Some(generics), None)
-        }
+        }) => icx.lowerer().lower_fn_ty(
+            hir_id,
+            header.unsafety,
+            header.abi,
+            decl,
+            Some(generics),
+            None,
+        ),
 
         ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(fn_decl, _, _), .. }) => {
             let abi = tcx.hir().get_foreign_abi(hir_id);
@@ -1364,7 +1375,7 @@ fn infer_return_ty_for_fn_sig<'tcx>(
             // recursive function definition to leak out into the fn sig.
             let mut should_recover = false;
 
-            if let Some(ret_ty) = ret_ty.make_suggestable(tcx, false) {
+            if let Some(ret_ty) = ret_ty.make_suggestable(tcx, false, None) {
                 diag.span_suggestion(
                     ty.span,
                     "replace with the correct return type",
@@ -1404,7 +1415,7 @@ fn infer_return_ty_for_fn_sig<'tcx>(
                 ))
             }
         }
-        None => icx.astconv().ty_of_fn(
+        None => icx.lowerer().lower_fn_ty(
             hir_id,
             sig.header.unsafety,
             sig.header.abi,
@@ -1442,7 +1453,7 @@ fn suggest_impl_trait<'tcx>(
             let ty::Tuple(types) = *args_tuple.kind() else {
                 return None;
             };
-            let types = types.make_suggestable(tcx, false)?;
+            let types = types.make_suggestable(tcx, false, None)?;
             let maybe_ret =
                 if item_ty.is_unit() { String::new() } else { format!(" -> {item_ty}") };
             Some(format!(
@@ -1500,7 +1511,7 @@ fn suggest_impl_trait<'tcx>(
         // FIXME(compiler-errors): We may benefit from resolving regions here.
         if ocx.select_where_possible().is_empty()
             && let item_ty = infcx.resolve_vars_if_possible(item_ty)
-            && let Some(item_ty) = item_ty.make_suggestable(tcx, false)
+            && let Some(item_ty) = item_ty.make_suggestable(tcx, false, None)
             && let Some(sugg) = formatter(
                 tcx,
                 infcx.resolve_vars_if_possible(args),
@@ -1522,19 +1533,19 @@ fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::ImplTrai
     impl_
         .of_trait
         .as_ref()
-        .map(|ast_trait_ref| {
-            let selfty = tcx.type_of(def_id).instantiate_identity();
+        .map(|hir_trait_ref| {
+            let self_ty = tcx.type_of(def_id).instantiate_identity();
 
             let trait_ref = if let Some(ErrorGuaranteed { .. }) = check_impl_constness(
                 tcx,
                 tcx.is_const_trait_impl_raw(def_id.to_def_id()),
-                ast_trait_ref,
+                hir_trait_ref,
             ) {
                 // we have a const impl, but for a trait without `#[const_trait]`, so
                 // without the host param. If we continue with the HIR trait ref, we get
                 // ICEs for generic arg count mismatch. We do a little HIR editing to
-                // make astconv happy.
-                let mut path_segments = ast_trait_ref.path.segments.to_vec();
+                // make HIR ty lowering happy.
+                let mut path_segments = hir_trait_ref.path.segments.to_vec();
                 let last_segment = path_segments.len() - 1;
                 let mut args = *path_segments[last_segment].args();
                 let last_arg = args.args.len() - 1;
@@ -1542,19 +1553,19 @@ fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::ImplTrai
                 args.args = &args.args[..args.args.len() - 1];
                 path_segments[last_segment].args = Some(tcx.hir_arena.alloc(args));
                 let path = hir::Path {
-                    span: ast_trait_ref.path.span,
-                    res: ast_trait_ref.path.res,
+                    span: hir_trait_ref.path.span,
+                    res: hir_trait_ref.path.res,
                     segments: tcx.hir_arena.alloc_slice(&path_segments),
                 };
-                let trait_ref = tcx.hir_arena.alloc(hir::TraitRef { path: tcx.hir_arena.alloc(path), hir_ref_id: ast_trait_ref.hir_ref_id });
-                icx.astconv().instantiate_mono_trait_ref(trait_ref, selfty)
+                let trait_ref = tcx.hir_arena.alloc(hir::TraitRef { path: tcx.hir_arena.alloc(path), hir_ref_id: hir_trait_ref.hir_ref_id });
+                icx.lowerer().lower_impl_trait_ref(trait_ref, self_ty)
             } else {
-                icx.astconv().instantiate_mono_trait_ref(ast_trait_ref, selfty)
+                icx.lowerer().lower_impl_trait_ref(hir_trait_ref, self_ty)
             };
             ty::ImplTraitHeader {
                 trait_ref: ty::EarlyBinder::bind(trait_ref),
                 unsafety: impl_.unsafety,
-                polarity: polarity_of_impl(tcx, def_id,  impl_, item.span)
+                polarity: polarity_of_impl(tcx, def_id, impl_, item.span)
             }
         })
 }
@@ -1562,20 +1573,20 @@ fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::ImplTrai
 fn check_impl_constness(
     tcx: TyCtxt<'_>,
     is_const: bool,
-    ast_trait_ref: &hir::TraitRef<'_>,
+    hir_trait_ref: &hir::TraitRef<'_>,
 ) -> Option<ErrorGuaranteed> {
     if !is_const {
         return None;
     }
 
-    let trait_def_id = ast_trait_ref.trait_def_id()?;
+    let trait_def_id = hir_trait_ref.trait_def_id()?;
     if tcx.has_attr(trait_def_id, sym::const_trait) {
         return None;
     }
 
     let trait_name = tcx.item_name(trait_def_id).to_string();
     Some(tcx.dcx().emit_err(errors::ConstImplForNonConstTrait {
-        trait_ref_span: ast_trait_ref.path.span,
+        trait_ref_span: hir_trait_ref.path.span,
         trait_name,
         local_trait_span:
             trait_def_id.as_local().map(|_| tcx.def_span(trait_def_id).shrink_to_lo()),
@@ -1671,19 +1682,19 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
     };
     let hir_id = tcx.local_def_id_to_hir_id(def_id);
     let fty =
-        ItemCtxt::new(tcx, def_id).astconv().ty_of_fn(hir_id, unsafety, abi, decl, None, None);
+        ItemCtxt::new(tcx, def_id).lowerer().lower_fn_ty(hir_id, unsafety, abi, decl, None, None);
 
     // Feature gate SIMD types in FFI, since I am not sure that the
     // ABIs are handled at all correctly. -huonw
     if abi != abi::Abi::RustIntrinsic && !tcx.features().simd_ffi {
-        let check = |ast_ty: &hir::Ty<'_>, ty: Ty<'_>| {
+        let check = |hir_ty: &hir::Ty<'_>, ty: Ty<'_>| {
             if ty.is_simd() {
                 let snip = tcx
                     .sess
                     .source_map()
-                    .span_to_snippet(ast_ty.span)
+                    .span_to_snippet(hir_ty.span)
                     .map_or_else(|_| String::new(), |s| format!(" `{s}`"));
-                tcx.dcx().emit_err(errors::SIMDFFIHighlyExperimental { span: ast_ty.span, snip });
+                tcx.dcx().emit_err(errors::SIMDFFIHighlyExperimental { span: hir_ty.span, snip });
             }
         };
         for (input, ty) in iter::zip(decl.inputs, fty.inputs().skip_binder()) {
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index bc6abc53cad..4d6a02f50bf 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -218,8 +218,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
         Deny,
     }
 
-    let no_generics = hir::Generics::empty();
-    let ast_generics = node.generics().unwrap_or(no_generics);
+    let hir_generics = node.generics().unwrap_or(hir::Generics::empty());
     let (opt_self, allow_defaults) = match node {
         Node::Item(item) => {
             match item.kind {
@@ -275,13 +274,13 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
         generics.parent_count + generics.params.len()
     });
 
-    let mut params: Vec<_> = Vec::with_capacity(ast_generics.params.len() + has_self as usize);
+    let mut params: Vec<_> = Vec::with_capacity(hir_generics.params.len() + has_self as usize);
 
     if let Some(opt_self) = opt_self {
         params.push(opt_self);
     }
 
-    let early_lifetimes = super::early_bound_lifetimes_from_generics(tcx, ast_generics);
+    let early_lifetimes = super::early_bound_lifetimes_from_generics(tcx, hir_generics);
     params.extend(early_lifetimes.enumerate().map(|(i, param)| ty::GenericParamDef {
         name: param.name.ident().name,
         index: own_start + i as u32,
@@ -302,7 +301,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
     const TYPE_DEFAULT_NOT_ALLOWED: &'static str = "defaults for type parameters are only allowed in \
     `struct`, `enum`, `type`, or `trait` definitions";
 
-    params.extend(ast_generics.params.iter().filter_map(|param| match param.kind {
+    params.extend(hir_generics.params.iter().filter_map(|param| match param.kind {
         GenericParamKind::Lifetime { .. } => None,
         GenericParamKind::Type { default, synthetic, .. } => {
             if default.is_some() {
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 78c390d0924..f1b14adcb7a 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -1,5 +1,6 @@
 use super::ItemCtxt;
-use crate::astconv::{AstConv, PredicateFilter};
+use crate::hir_ty_lowering::{HirTyLowerer, PredicateFilter};
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir as hir;
 use rustc_infer::traits::util;
 use rustc_middle::ty::GenericArgs;
@@ -17,8 +18,9 @@ use rustc_span::Span;
 fn associated_type_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
     assoc_item_def_id: LocalDefId,
-    ast_bounds: &'tcx [hir::GenericBound<'tcx>],
+    hir_bounds: &'tcx [hir::GenericBound<'tcx>],
     span: Span,
+    filter: PredicateFilter,
 ) -> &'tcx [(ty::Clause<'tcx>, Span)] {
     let item_ty = Ty::new_projection(
         tcx,
@@ -27,9 +29,9 @@ fn associated_type_bounds<'tcx>(
     );
 
     let icx = ItemCtxt::new(tcx, assoc_item_def_id);
-    let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, PredicateFilter::All);
+    let mut bounds = icx.lowerer().lower_mono_bounds(item_ty, hir_bounds, filter);
     // Associated types are implicitly sized unless a `?Sized` bound is found
-    icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span);
+    icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
 
     let trait_def_id = tcx.local_parent(assoc_item_def_id);
     let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id);
@@ -60,15 +62,16 @@ fn associated_type_bounds<'tcx>(
 fn opaque_type_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
     opaque_def_id: LocalDefId,
-    ast_bounds: &'tcx [hir::GenericBound<'tcx>],
+    hir_bounds: &'tcx [hir::GenericBound<'tcx>],
     item_ty: Ty<'tcx>,
     span: Span,
+    filter: PredicateFilter,
 ) -> &'tcx [(ty::Clause<'tcx>, Span)] {
     ty::print::with_reduced_queries!({
         let icx = ItemCtxt::new(tcx, opaque_def_id);
-        let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, PredicateFilter::All);
+        let mut bounds = icx.lowerer().lower_mono_bounds(item_ty, hir_bounds, filter);
         // Opaque types are implicitly sized unless a `?Sized` bound is found
-        icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span);
+        icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
         debug!(?bounds);
 
         tcx.arena.alloc_from_iter(bounds.clauses())
@@ -79,6 +82,21 @@ pub(super) fn explicit_item_bounds(
     tcx: TyCtxt<'_>,
     def_id: LocalDefId,
 ) -> ty::EarlyBinder<&'_ [(ty::Clause<'_>, Span)]> {
+    explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::All)
+}
+
+pub(super) fn explicit_item_super_predicates(
+    tcx: TyCtxt<'_>,
+    def_id: LocalDefId,
+) -> ty::EarlyBinder<&'_ [(ty::Clause<'_>, Span)]> {
+    explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::SelfOnly)
+}
+
+pub(super) fn explicit_item_bounds_with_filter(
+    tcx: TyCtxt<'_>,
+    def_id: LocalDefId,
+    filter: PredicateFilter,
+) -> ty::EarlyBinder<&'_ [(ty::Clause<'_>, Span)]> {
     match tcx.opt_rpitit_info(def_id.to_def_id()) {
         // RPITIT's bounds are the same as opaque type bounds, but with
         // a projection self type.
@@ -95,6 +113,7 @@ pub(super) fn explicit_item_bounds(
                     ty::GenericArgs::identity_for_item(tcx, def_id),
                 ),
                 item.span,
+                filter,
             ));
         }
         Some(ty::ImplTraitInTraitData::Impl { .. }) => span_bug!(
@@ -109,7 +128,7 @@ pub(super) fn explicit_item_bounds(
             kind: hir::TraitItemKind::Type(bounds, _),
             span,
             ..
-        }) => associated_type_bounds(tcx, def_id, bounds, *span),
+        }) => associated_type_bounds(tcx, def_id, bounds, *span, filter),
         hir::Node::Item(hir::Item {
             kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, in_trait: false, .. }),
             span,
@@ -117,10 +136,10 @@ pub(super) fn explicit_item_bounds(
         }) => {
             let args = GenericArgs::identity_for_item(tcx, def_id);
             let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);
-            opaque_type_bounds(tcx, def_id, bounds, item_ty, *span)
+            opaque_type_bounds(tcx, def_id, bounds, item_ty, *span, filter)
         }
-        // Since RPITITs are astconv'd as projections in `ast_ty_to_ty`, when we're asking
-        // for the item bounds of the *opaques* in a trait's default method signature, we
+        // Since RPITITs are lowered as projections in `<dyn HirTyLowerer>::lower_ty`, when we're
+        // asking for the item bounds of the *opaques* in a trait's default method signature, we
         // need to map these projections back to opaques.
         hir::Node::Item(hir::Item {
             kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, in_trait: true, origin, .. }),
@@ -135,7 +154,7 @@ pub(super) fn explicit_item_bounds(
             let args = GenericArgs::identity_for_item(tcx, def_id);
             let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);
             tcx.arena.alloc_slice(
-                &opaque_type_bounds(tcx, def_id, bounds, item_ty, *span)
+                &opaque_type_bounds(tcx, def_id, bounds, item_ty, *span, filter)
                     .to_vec()
                     .fold_with(&mut AssocTyToOpaque { tcx, fn_def_id: fn_def_id.to_def_id() }),
             )
@@ -155,6 +174,31 @@ pub(super) fn item_bounds(
     })
 }
 
+pub(super) fn item_super_predicates(
+    tcx: TyCtxt<'_>,
+    def_id: DefId,
+) -> ty::EarlyBinder<&'_ ty::List<ty::Clause<'_>>> {
+    tcx.explicit_item_super_predicates(def_id).map_bound(|bounds| {
+        tcx.mk_clauses_from_iter(
+            util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound)).filter_only_self(),
+        )
+    })
+}
+
+pub(super) fn item_non_self_assumptions(
+    tcx: TyCtxt<'_>,
+    def_id: DefId,
+) -> ty::EarlyBinder<&'_ ty::List<ty::Clause<'_>>> {
+    let all_bounds: FxIndexSet<_> = tcx.item_bounds(def_id).skip_binder().iter().collect();
+    let own_bounds: FxIndexSet<_> =
+        tcx.item_super_predicates(def_id).skip_binder().iter().collect();
+    if all_bounds.len() == own_bounds.len() {
+        ty::EarlyBinder::bind(ty::List::empty())
+    } else {
+        ty::EarlyBinder::bind(tcx.mk_clauses_from_iter(all_bounds.difference(&own_bounds).copied()))
+    }
+}
+
 struct AssocTyToOpaque<'tcx> {
     tcx: TyCtxt<'tcx>,
     fn_def_id: DefId,
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 66c9fb93500..efd3ceebe6c 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -1,7 +1,7 @@
-use crate::astconv::{AstConv, OnlySelfBounds, PredicateFilter};
 use crate::bounds::Bounds;
 use crate::collect::ItemCtxt;
 use crate::constrained_generic_params as cgp;
+use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter};
 use hir::{HirId, Node};
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir as hir;
@@ -123,7 +123,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
     // Preserving the order of insertion is important here so as not to break UI tests.
     let mut predicates: FxIndexSet<(ty::Clause<'_>, Span)> = FxIndexSet::default();
 
-    let ast_generics = node.generics().unwrap_or(NO_GENERICS);
+    let hir_generics = node.generics().unwrap_or(NO_GENERICS);
     if let Node::Item(item) = node {
         match item.kind {
             ItemKind::Impl(impl_) => {
@@ -149,8 +149,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
     // like `trait Foo: A + B + C`.
     if let Some(self_bounds) = is_trait {
         predicates.extend(
-            icx.astconv()
-                .compute_bounds(tcx.types.self_param, self_bounds, PredicateFilter::All)
+            icx.lowerer()
+                .lower_mono_bounds(tcx.types.self_param, self_bounds, PredicateFilter::All)
                 .clauses(),
         );
     }
@@ -170,19 +170,19 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
     // Collect the predicates that were written inline by the user on each
     // type parameter (e.g., `<T: Foo>`). Also add `ConstArgHasType` predicates
     // for each const parameter.
-    for param in ast_generics.params {
+    for param in hir_generics.params {
         match param.kind {
             // We already dealt with early bound lifetimes above.
             GenericParamKind::Lifetime { .. } => (),
             GenericParamKind::Type { .. } => {
-                let param_ty = icx.astconv().hir_id_to_bound_ty(param.hir_id);
+                let param_ty = icx.lowerer().lower_ty_param(param.hir_id);
                 let mut bounds = Bounds::default();
                 // Params are implicitly sized unless a `?Sized` bound is found
-                icx.astconv().add_implicitly_sized(
+                icx.lowerer().add_sized_bound(
                     &mut bounds,
                     param_ty,
                     &[],
-                    Some((param.def_id, ast_generics.predicates)),
+                    Some((param.def_id, hir_generics.predicates)),
                     param.span,
                 );
                 trace!(?bounds);
@@ -194,7 +194,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                     .type_of(param.def_id.to_def_id())
                     .no_bound_vars()
                     .expect("const parameters cannot be generic");
-                let ct = icx.astconv().hir_id_to_bound_const(param.hir_id, ct_ty);
+                let ct = icx.lowerer().lower_const_param(param.hir_id, ct_ty);
                 predicates.insert((
                     ty::ClauseKind::ConstArgHasType(ct, ct_ty).to_predicate(tcx),
                     param.span,
@@ -205,10 +205,10 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
 
     trace!(?predicates);
     // Add in the bounds that appear in the where-clause.
-    for predicate in ast_generics.predicates {
+    for predicate in hir_generics.predicates {
         match predicate {
             hir::WherePredicate::BoundPredicate(bound_pred) => {
-                let ty = icx.to_ty(bound_pred.bounded_ty);
+                let ty = icx.lower_ty(bound_pred.bounded_ty);
                 let bound_vars = tcx.late_bound_vars(bound_pred.hir_id);
                 // Keep the type around in a dummy predicate, in case of no bounds.
                 // That way, `where Ty:` is not a complete noop (see #53696) and `Ty`
@@ -232,7 +232,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                 }
 
                 let mut bounds = Bounds::default();
-                icx.astconv().add_bounds(
+                icx.lowerer().lower_poly_bounds(
                     ty,
                     bound_pred.bounds.iter(),
                     &mut bounds,
@@ -243,11 +243,11 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
             }
 
             hir::WherePredicate::RegionPredicate(region_pred) => {
-                let r1 = icx.astconv().ast_region_to_region(region_pred.lifetime, None);
+                let r1 = icx.lowerer().lower_lifetime(region_pred.lifetime, None);
                 predicates.extend(region_pred.bounds.iter().map(|bound| {
                     let (r2, span) = match bound {
                         hir::GenericBound::Outlives(lt) => {
-                            (icx.astconv().ast_region_to_region(lt, None), lt.ident.span)
+                            (icx.lowerer().lower_lifetime(lt, None), lt.ident.span)
                         }
                         bound => {
                             span_bug!(
@@ -542,8 +542,8 @@ pub(super) fn explicit_predicates_of<'tcx>(
 }
 
 /// Ensures that the super-predicates of the trait with a `DefId`
-/// of `trait_def_id` are converted and stored. This also ensures that
-/// the transitive super-predicates are converted.
+/// of `trait_def_id` are lowered and stored. This also ensures that
+/// the transitive super-predicates are lowered.
 pub(super) fn super_predicates_of(
     tcx: TyCtxt<'_>,
     trait_def_id: LocalDefId,
@@ -574,8 +574,8 @@ pub(super) fn implied_predicates_of(
 }
 
 /// Ensures that the super-predicates of the trait with a `DefId`
-/// of `trait_def_id` are converted and stored. This also ensures that
-/// the transitive super-predicates are converted.
+/// of `trait_def_id` are lowered and stored. This also ensures that
+/// the transitive super-predicates are lowered.
 pub(super) fn implied_predicates_with_filter(
     tcx: TyCtxt<'_>,
     trait_def_id: DefId,
@@ -601,9 +601,9 @@ pub(super) fn implied_predicates_with_filter(
     let icx = ItemCtxt::new(tcx, trait_def_id);
 
     let self_param_ty = tcx.types.self_param;
-    let superbounds = icx.astconv().compute_bounds(self_param_ty, bounds, filter);
+    let superbounds = icx.lowerer().lower_mono_bounds(self_param_ty, bounds, filter);
 
-    let where_bounds_that_match = icx.type_parameter_bounds_in_generics(
+    let where_bounds_that_match = icx.probe_ty_param_bounds_in_generics(
         generics,
         item.owner_id.def_id,
         self_param_ty,
@@ -615,7 +615,7 @@ pub(super) fn implied_predicates_with_filter(
         &*tcx.arena.alloc_from_iter(superbounds.clauses().chain(where_bounds_that_match));
     debug!(?implied_bounds);
 
-    // Now require that immediate supertraits are converted, which will, in
+    // Now require that immediate supertraits are lowered, which will, in
     // turn, reach indirect supertraits, so we detect cycles now instead of
     // overflowing during elaboration. Same for implied predicates, which
     // make sure we walk into associated type bounds.
@@ -624,7 +624,7 @@ pub(super) fn implied_predicates_with_filter(
             for &(pred, span) in implied_bounds {
                 debug!("superbound: {:?}", pred);
                 if let ty::ClauseKind::Trait(bound) = pred.kind().skip_binder()
-                    && bound.polarity == ty::ImplPolarity::Positive
+                    && bound.polarity == ty::PredicatePolarity::Positive
                 {
                     tcx.at(span).super_predicates_of(bound.def_id());
                 }
@@ -634,7 +634,7 @@ pub(super) fn implied_predicates_with_filter(
             for &(pred, span) in implied_bounds {
                 debug!("superbound: {:?}", pred);
                 if let ty::ClauseKind::Trait(bound) = pred.kind().skip_binder()
-                    && bound.polarity == ty::ImplPolarity::Positive
+                    && bound.polarity == ty::PredicatePolarity::Positive
                 {
                     tcx.at(span).implied_predicates_of(bound.def_id());
                 }
@@ -656,7 +656,7 @@ pub(super) fn type_param_predicates(
     use rustc_hir::*;
     use rustc_middle::ty::Ty;
 
-    // In the AST, bounds can derive from two places. Either
+    // In the HIR, bounds can derive from two places. Either
     // written inline like `<T: Foo>` or in a where-clause like
     // `where T: Foo`.
 
@@ -676,7 +676,7 @@ pub(super) fn type_param_predicates(
     let mut result = parent
         .map(|parent| {
             let icx = ItemCtxt::new(tcx, parent);
-            icx.get_type_parameter_bounds(DUMMY_SP, def_id, assoc_name)
+            icx.probe_ty_param_bounds(DUMMY_SP, def_id, assoc_name)
         })
         .unwrap_or_default();
     let mut extend = None;
@@ -684,7 +684,7 @@ pub(super) fn type_param_predicates(
     let item_hir_id = tcx.local_def_id_to_hir_id(item_def_id);
 
     let hir_node = tcx.hir_node(item_hir_id);
-    let Some(ast_generics) = hir_node.generics() else { return result };
+    let Some(hir_generics) = hir_node.generics() else { return result };
     if let Node::Item(item) = hir_node
         && let ItemKind::Trait(..) = item.kind
         // Implied `Self: Trait` and supertrait bounds.
@@ -696,8 +696,8 @@ pub(super) fn type_param_predicates(
 
     let icx = ItemCtxt::new(tcx, item_def_id);
     let extra_predicates = extend.into_iter().chain(
-        icx.type_parameter_bounds_in_generics(
-            ast_generics,
+        icx.probe_ty_param_bounds_in_generics(
+            hir_generics,
             def_id,
             ty,
             PredicateFilter::SelfThatDefines(assoc_name),
@@ -714,21 +714,22 @@ pub(super) fn type_param_predicates(
 }
 
 impl<'tcx> ItemCtxt<'tcx> {
-    /// Finds bounds from `hir::Generics`. This requires scanning through the
-    /// AST. We do this to avoid having to convert *all* the bounds, which
-    /// would create artificial cycles. Instead, we can only convert the
-    /// bounds for a type parameter `X` if `X::Foo` is used.
-    #[instrument(level = "trace", skip(self, ast_generics))]
-    fn type_parameter_bounds_in_generics(
+    /// Finds bounds from `hir::Generics`.
+    ///
+    /// This requires scanning through the HIR.
+    /// We do this to avoid having to lower *all* the bounds, which would create artificial cycles.
+    /// Instead, we can only lower the bounds for a type parameter `X` if `X::Foo` is used.
+    #[instrument(level = "trace", skip(self, hir_generics))]
+    fn probe_ty_param_bounds_in_generics(
         &self,
-        ast_generics: &'tcx hir::Generics<'tcx>,
+        hir_generics: &'tcx hir::Generics<'tcx>,
         param_def_id: LocalDefId,
         ty: Ty<'tcx>,
         filter: PredicateFilter,
     ) -> Vec<(ty::Clause<'tcx>, Span)> {
         let mut bounds = Bounds::default();
 
-        for predicate in ast_generics.predicates {
+        for predicate in hir_generics.predicates {
             let hir::WherePredicate::BoundPredicate(predicate) = predicate else {
                 continue;
             };
@@ -750,13 +751,13 @@ impl<'tcx> ItemCtxt<'tcx> {
             let bound_ty = if predicate.is_param_bound(param_def_id.to_def_id()) {
                 ty
             } else if matches!(filter, PredicateFilter::All) {
-                self.to_ty(predicate.bounded_ty)
+                self.lower_ty(predicate.bounded_ty)
             } else {
                 continue;
             };
 
             let bound_vars = self.tcx.late_bound_vars(predicate.hir_id);
-            self.astconv().add_bounds(
+            self.lowerer().lower_poly_bounds(
                 bound_ty,
                 predicate.bounds.iter().filter(|bound| {
                     assoc_name
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 86b075a84a7..27a26cfe474 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -1917,18 +1917,18 @@ fn is_late_bound_map(
     ///
     /// If we conservatively considered `'a` unconstrained then we could break users who had written code before
     /// we started correctly handling aliases. If we considered `'a` constrained then it would become late bound
-    /// causing an error during astconv as the `'a` is not constrained by the input type `<() as Trait<'a>>::Assoc`
+    /// causing an error during HIR ty lowering as the `'a` is not constrained by the input type `<() as Trait<'a>>::Assoc`
     /// but appears in the output type `<() as Trait<'a>>::Assoc`.
     ///
     /// We must therefore "look into" the `Alias` to see whether we should consider `'a` constrained or not.
     ///
     /// See #100508 #85533 #47511 for additional context
-    struct ConstrainedCollectorPostAstConv {
+    struct ConstrainedCollectorPostHirTyLowering {
         arg_is_constrained: Box<[bool]>,
     }
 
     use ty::Ty;
-    impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ConstrainedCollectorPostAstConv {
+    impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ConstrainedCollectorPostHirTyLowering {
         fn visit_ty(&mut self, t: Ty<'tcx>) {
             match t.kind() {
                 ty::Param(param_ty) => {
@@ -1970,10 +1970,10 @@ fn is_late_bound_map(
                     None,
                     hir::Path { res: Res::Def(DefKind::TyAlias, alias_def), segments, span },
                 )) => {
-                    // See comments on `ConstrainedCollectorPostAstConv` for why this arm does not just consider
-                    // args to be unconstrained.
+                    // See comments on `ConstrainedCollectorPostHirTyLowering` for why this arm does not
+                    // just consider args to be unconstrained.
                     let generics = self.tcx.generics_of(alias_def);
-                    let mut walker = ConstrainedCollectorPostAstConv {
+                    let mut walker = ConstrainedCollectorPostHirTyLowering {
                         arg_is_constrained: vec![false; generics.params.len()].into_boxed_slice(),
                     };
                     walker.visit_ty(self.tcx.type_of(alias_def).instantiate_identity());
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index fd86f2dd1b1..722def2563c 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -47,7 +47,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
             let ty = tcx.fold_regions(ty, |r, _| {
                 if r.is_erased() { ty::Region::new_error_misc(tcx) } else { r }
             });
-            let (ty, opt_sugg) = if let Some(ty) = ty.make_suggestable(tcx, false) {
+            let (ty, opt_sugg) = if let Some(ty) = ty.make_suggestable(tcx, false, None) {
                 (ty, Some((span, Applicability::MachineApplicable)))
             } else {
                 (ty, None)
@@ -97,10 +97,10 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
         // I believe this match arm is only needed for GAT but I am not 100% sure - BoxyUwU
         Node::Ty(hir_ty @ hir::Ty { kind: TyKind::Path(QPath::TypeRelative(_, segment)), .. }) => {
             // Find the Item containing the associated type so we can create an ItemCtxt.
-            // Using the ItemCtxt convert the HIR for the unresolved assoc type into a
+            // Using the ItemCtxt lower the HIR for the unresolved assoc type into a
             // ty which is a fully resolved projection.
-            // For the code example above, this would mean converting Self::Assoc<3>
-            // into a ty::Alias(ty::Projection, <Self as Foo>::Assoc<3>)
+            // For the code example above, this would mean lowering `Self::Assoc<3>`
+            // to a ty::Alias(ty::Projection, `<Self as Foo>::Assoc<3>`).
             let item_def_id = tcx
                 .hir()
                 .parent_owner_iter(hir_id)
@@ -108,7 +108,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
                 .unwrap()
                 .0
                 .def_id;
-            let ty = ItemCtxt::new(tcx, item_def_id).to_ty(hir_ty);
+            let ty = ItemCtxt::new(tcx, item_def_id).lower_ty(hir_ty);
 
             // Iterate through the generics of the projection to find the one that corresponds to
             // the def_id that this query was called with. We filter to only type and const args here
@@ -369,8 +369,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
                         )
                     })
                 })
-                .unwrap_or_else(|| icx.to_ty(ty)),
-            TraitItemKind::Type(_, Some(ty)) => icx.to_ty(ty),
+                .unwrap_or_else(|| icx.lower_ty(ty)),
+            TraitItemKind::Type(_, Some(ty)) => icx.lower_ty(ty),
             TraitItemKind::Type(_, None) => {
                 span_bug!(item.span, "associated type missing default");
             }
@@ -392,7 +392,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
                         "associated constant",
                     )
                 } else {
-                    icx.to_ty(ty)
+                    icx.lower_ty(ty)
                 }
             }
             ImplItemKind::Type(ty) => {
@@ -400,7 +400,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
                     check_feature_inherent_assoc_ty(tcx, item.span);
                 }
 
-                icx.to_ty(ty)
+                icx.lower_ty(ty)
             }
         },
 
@@ -416,17 +416,17 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
                         "static variable",
                     )
                 } else {
-                    icx.to_ty(ty)
+                    icx.lower_ty(ty)
                 }
             }
             ItemKind::Const(ty, _, body_id) => {
                 if ty.is_suggestable_infer_ty() {
                     infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident, "constant")
                 } else {
-                    icx.to_ty(ty)
+                    icx.lower_ty(ty)
                 }
             }
-            ItemKind::TyAlias(self_ty, _) => icx.to_ty(self_ty),
+            ItemKind::TyAlias(self_ty, _) => icx.lower_ty(self_ty),
             ItemKind::Impl(hir::Impl { self_ty, .. }) => match self_ty.find_self_aliases() {
                 spans if spans.len() > 0 => {
                     let guar = tcx
@@ -434,7 +434,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
                         .emit_err(crate::errors::SelfInImplSelf { span: spans.into(), note: () });
                     Ty::new_error(tcx, guar)
                 }
-                _ => icx.to_ty(*self_ty),
+                _ => icx.lower_ty(*self_ty),
             },
             ItemKind::Fn(..) => {
                 let args = ty::GenericArgs::identity_for_item(tcx, def_id);
@@ -466,7 +466,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
                 let args = ty::GenericArgs::identity_for_item(tcx, def_id);
                 Ty::new_fn_def(tcx, def_id.to_def_id(), args)
             }
-            ForeignItemKind::Static(t, _) => icx.to_ty(t),
+            ForeignItemKind::Static(t, _) => icx.lower_ty(t),
             ForeignItemKind::Type => Ty::new_foreign(tcx, def_id.to_def_id()),
         },
 
@@ -480,7 +480,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
             }
         },
 
-        Node::Field(field) => icx.to_ty(field.ty),
+        Node::Field(field) => icx.lower_ty(field.ty),
 
         Node::Expr(&Expr { kind: ExprKind::Closure { .. }, .. }) => {
             tcx.typeck(def_id).node_type(hir_id)
@@ -495,7 +495,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
 
         Node::GenericParam(param) => match &param.kind {
             GenericParamKind::Type { default: Some(ty), .. }
-            | GenericParamKind::Const { ty, .. } => icx.to_ty(ty),
+            | GenericParamKind::Const { ty, .. } => icx.lower_ty(ty),
             x => bug!("unexpected non-type Node::GenericParam: {:?}", x),
         },
 
@@ -587,7 +587,7 @@ fn infer_placeholder_type<'a>(
                     suggestions.clear();
                 }
 
-                if let Some(ty) = ty.make_suggestable(tcx, false) {
+                if let Some(ty) = ty.make_suggestable(tcx, false, None) {
                     err.span_suggestion(
                         span,
                         format!("provide a type for the {kind}"),
@@ -606,7 +606,7 @@ fn infer_placeholder_type<'a>(
             let mut diag = bad_placeholder(tcx, vec![span], kind);
 
             if !ty.references_error() {
-                if let Some(ty) = ty.make_suggestable(tcx, false) {
+                if let Some(ty) = ty.make_suggestable(tcx, false, None) {
                     diag.span_suggestion(
                         span,
                         "replace with the correct type",
diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
index 3067e2d0b71..11bd3e5282d 100644
--- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -12,17 +12,19 @@ use rustc_trait_selection::traits;
 use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
 use smallvec::SmallVec;
 
-use crate::astconv::{AstConv, OnlySelfBounds, PredicateFilter};
 use crate::bounds::Bounds;
 use crate::errors;
+use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter};
 
-impl<'tcx> dyn AstConv<'tcx> + '_ {
-    /// Sets `implicitly_sized` to true on `Bounds` if necessary
-    pub(crate) fn add_implicitly_sized(
+impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
+    /// Add a `Sized` bound to the `bounds` if appropriate.
+    ///
+    /// Doesn't add the bound if the HIR bounds contain any of `Sized`, `?Sized` or `!Sized`.
+    pub(crate) fn add_sized_bound(
         &self,
         bounds: &mut Bounds<'tcx>,
         self_ty: Ty<'tcx>,
-        ast_bounds: &'tcx [hir::GenericBound<'tcx>],
+        hir_bounds: &'tcx [hir::GenericBound<'tcx>],
         self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
         span: Span,
     ) {
@@ -33,9 +35,9 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
 
         // Try to find an unbound in bounds.
         let mut unbounds: SmallVec<[_; 1]> = SmallVec::new();
-        let mut search_bounds = |ast_bounds: &'tcx [hir::GenericBound<'tcx>]| {
-            for ab in ast_bounds {
-                let hir::GenericBound::Trait(ptr, modifier) = ab else {
+        let mut search_bounds = |hir_bounds: &'tcx [hir::GenericBound<'tcx>]| {
+            for hir_bound in hir_bounds {
+                let hir::GenericBound::Trait(ptr, modifier) = hir_bound else {
                     continue;
                 };
                 match modifier {
@@ -58,7 +60,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                 }
             }
         };
-        search_bounds(ast_bounds);
+        search_bounds(hir_bounds);
         if let Some((self_ty, where_clause)) = self_ty_where_predicates {
             for clause in where_clause {
                 if let hir::WherePredicate::BoundPredicate(pred) = clause
@@ -101,51 +103,57 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         }
     }
 
-    /// This helper takes a *converted* parameter type (`param_ty`)
-    /// and an *unconverted* list of bounds:
+    /// Lower HIR bounds into `bounds` given the self type `param_ty` and the overarching late-bound vars if any.
+    ///
+    /// ### Examples
     ///
-    /// ```text
-    /// fn foo<T: Debug>
-    ///        ^  ^^^^^ `ast_bounds` parameter, in HIR form
-    ///        |
-    ///        `param_ty`, in ty form
+    /// ```ignore (illustrative)
+    /// fn foo<T>() where for<'a> T: Trait<'a> + Copy {}
+    /// //                ^^^^^^^ ^  ^^^^^^^^^^^^^^^^ `hir_bounds`, in HIR form
+    /// //                |       |
+    /// //                |       `param_ty`, in ty form
+    /// //                `bound_vars`, in ty form
+    ///
+    /// fn bar<T>() where T: for<'a> Trait<'a> + Copy {} // no overarching `bound_vars` here!
+    /// //                ^  ^^^^^^^^^^^^^^^^^^^^^^^^ `hir_bounds`, in HIR form
+    /// //                |
+    /// //                `param_ty`, in ty form
     /// ```
     ///
-    /// It adds these `ast_bounds` into the `bounds` structure.
+    /// ### A Note on Binders
     ///
-    /// **A note on binders:** there is an implied binder around
-    /// `param_ty` and `ast_bounds`. See `instantiate_poly_trait_ref`
-    /// for more details.
-    #[instrument(level = "debug", skip(self, ast_bounds, bounds))]
-    pub(crate) fn add_bounds<'hir, I: Iterator<Item = &'hir hir::GenericBound<'tcx>>>(
+    /// There is an implied binder around `param_ty` and `hir_bounds`.
+    /// See `lower_poly_trait_ref` for more details.
+    #[instrument(level = "debug", skip(self, hir_bounds, bounds))]
+    pub(crate) fn lower_poly_bounds<'hir, I: Iterator<Item = &'hir hir::GenericBound<'tcx>>>(
         &self,
         param_ty: Ty<'tcx>,
-        ast_bounds: I,
+        hir_bounds: I,
         bounds: &mut Bounds<'tcx>,
         bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
         only_self_bounds: OnlySelfBounds,
     ) where
         'tcx: 'hir,
     {
-        for ast_bound in ast_bounds {
-            match ast_bound {
+        for hir_bound in hir_bounds {
+            match hir_bound {
                 hir::GenericBound::Trait(poly_trait_ref, modifier) => {
                     let (constness, polarity) = match modifier {
                         hir::TraitBoundModifier::Const => {
-                            (ty::BoundConstness::Const, ty::ImplPolarity::Positive)
+                            (ty::BoundConstness::Const, ty::PredicatePolarity::Positive)
                         }
                         hir::TraitBoundModifier::MaybeConst => {
-                            (ty::BoundConstness::ConstIfConst, ty::ImplPolarity::Positive)
+                            (ty::BoundConstness::ConstIfConst, ty::PredicatePolarity::Positive)
                         }
                         hir::TraitBoundModifier::None => {
-                            (ty::BoundConstness::NotConst, ty::ImplPolarity::Positive)
+                            (ty::BoundConstness::NotConst, ty::PredicatePolarity::Positive)
                         }
                         hir::TraitBoundModifier::Negative => {
-                            (ty::BoundConstness::NotConst, ty::ImplPolarity::Negative)
+                            (ty::BoundConstness::NotConst, ty::PredicatePolarity::Negative)
                         }
                         hir::TraitBoundModifier::Maybe => continue,
                     };
-                    let _ = self.instantiate_poly_trait_ref(
+                    let _ = self.lower_poly_trait_ref(
                         &poly_trait_ref.trait_ref,
                         poly_trait_ref.span,
                         constness,
@@ -156,7 +164,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                     );
                 }
                 hir::GenericBound::Outlives(lifetime) => {
-                    let region = self.ast_region_to_region(lifetime, None);
+                    let region = self.lower_lifetime(lifetime, None);
                     bounds.push_region_bound(
                         self.tcx(),
                         ty::Binder::bind_with_vars(
@@ -170,26 +178,19 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         }
     }
 
-    /// Translates a list of bounds from the HIR into the `Bounds` data structure.
-    /// The self-type for the bounds is given by `param_ty`.
+    /// Lower HIR bounds into `bounds` given the self type `param_ty` and *no* overarching late-bound vars.
     ///
-    /// Example:
+    /// ### Example
     ///
     /// ```ignore (illustrative)
     /// fn foo<T: Bar + Baz>() { }
-    /// //     ^  ^^^^^^^^^ ast_bounds
+    /// //     ^  ^^^^^^^^^ hir_bounds
     /// //     param_ty
     /// ```
-    ///
-    /// The `sized_by_default` parameter indicates if, in this context, the `param_ty` should be
-    /// considered `Sized` unless there is an explicit `?Sized` bound. This would be true in the
-    /// example above, but is not true in supertrait listings like `trait Foo: Bar + Baz`.
-    ///
-    /// `span` should be the declaration size of the parameter.
-    pub(crate) fn compute_bounds(
+    pub(crate) fn lower_mono_bounds(
         &self,
         param_ty: Ty<'tcx>,
-        ast_bounds: &[hir::GenericBound<'tcx>],
+        hir_bounds: &[hir::GenericBound<'tcx>],
         filter: PredicateFilter,
     ) -> Bounds<'tcx> {
         let mut bounds = Bounds::default();
@@ -201,9 +202,9 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => OnlySelfBounds(true),
         };
 
-        self.add_bounds(
+        self.lower_poly_bounds(
             param_ty,
-            ast_bounds.iter().filter(|bound| match filter {
+            hir_bounds.iter().filter(|bound| match filter {
                 PredicateFilter::All
                 | PredicateFilter::SelfOnly
                 | PredicateFilter::SelfAndAssociatedTypeBounds => true,
@@ -227,14 +228,16 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         bounds
     }
 
-    /// Given an HIR binding like `Item = Foo` or `Item: Foo`, pushes the corresponding predicates
-    /// onto `bounds`.
+    /// Lower an associated item binding from HIR into `bounds`.
+    ///
+    /// ### A Note on Binders
     ///
-    /// **A note on binders:** given something like `T: for<'a> Iterator<Item = &'a u32>`, the
-    /// `trait_ref` here will be `for<'a> T: Iterator`. The `binding` data however is from *inside*
-    /// the binder (e.g., `&'a u32`) and hence may reference bound regions.
+    /// Given something like `T: for<'a> Iterator<Item = &'a u32>`,
+    /// the `trait_ref` here will be `for<'a> T: Iterator`.
+    /// The `binding` data however is from *inside* the binder
+    /// (e.g., `&'a u32`) and hence may reference bound regions.
     #[instrument(level = "debug", skip(self, bounds, dup_bindings, path_span))]
-    pub(super) fn add_predicates_for_ast_type_binding(
+    pub(super) fn lower_assoc_item_binding(
         &self,
         hir_ref_id: hir::HirId,
         trait_ref: ty::PolyTraitRef<'tcx>,
@@ -244,22 +247,6 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         path_span: Span,
         only_self_bounds: OnlySelfBounds,
     ) -> Result<(), ErrorGuaranteed> {
-        // Given something like `U: SomeTrait<T = X>`, we want to produce a
-        // predicate like `<U as SomeTrait>::T = X`. This is somewhat
-        // subtle in the event that `T` is defined in a supertrait of
-        // `SomeTrait`, because in that case we need to upcast.
-        //
-        // That is, consider this case:
-        //
-        // ```
-        // trait SubTrait: SuperTrait<i32> { }
-        // trait SuperTrait<A> { type T; }
-        //
-        // ... B: SubTrait<T = foo> ...
-        // ```
-        //
-        // We want to produce `<B as SuperTrait<i32>>::T == foo`.
-
         let tcx = self.tcx();
 
         let assoc_kind = if binding.gen_args.parenthesized
@@ -272,7 +259,15 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             ty::AssocKind::Type
         };
 
-        let candidate = if self.trait_defines_associated_item_named(
+        // Given something like `U: Trait<T = X>`, we want to produce a predicate like
+        // `<U as Trait>::T = X`.
+        // This is somewhat subtle in the event that `T` is defined in a supertrait of `Trait`,
+        // because in that case we need to upcast. I.e., we want to produce
+        // `<B as SuperTrait<i32>>::T == X` for `B: SubTrait<T = X>` where
+        //
+        //     trait SubTrait: SuperTrait<i32> {}
+        //     trait SuperTrait<A> { type T; }
+        let candidate = if self.probe_trait_that_defines_assoc_item(
             trait_ref.def_id(),
             assoc_kind,
             binding.ident,
@@ -282,7 +277,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         } else {
             // Otherwise, we have to walk through the supertraits to find
             // one that does define it.
-            self.one_bound_for_assoc_item(
+            self.probe_single_bound_for_assoc_item(
                 || traits::supertraits(tcx, trait_ref),
                 trait_ref.skip_binder().print_only_trait_name(),
                 None,
@@ -417,7 +412,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                     infer_args: false,
                 };
 
-                let alias_args = self.create_args_for_associated_item(
+                let alias_args = self.lower_generic_args_of_assoc_item(
                     path_span,
                     assoc_item.def_id,
                     &item_segment,
@@ -449,9 +444,11 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                     span: binding.span,
                 }));
             }
+            // Lower an equality constraint like `Item = u32` as found in HIR bound `T: Iterator<Item = u32>`
+            // to a projection predicate: `<T as Iterator>::Item = u32`.
             hir::TypeBindingKind::Equality { term } => {
                 let term = match term {
-                    hir::Term::Ty(ty) => self.ast_ty_to_ty(ty).into(),
+                    hir::Term::Ty(ty) => self.lower_ty(ty).into(),
                     hir::Term::Const(ct) => ty::Const::from_anon_const(tcx, ct.def_id).into(),
                 };
 
@@ -490,10 +487,6 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                     },
                 );
 
-                // "Desugar" a constraint like `T: Iterator<Item = u32>` this to
-                // the "projection predicate" for:
-                //
-                // `<T as Iterator>::Item = u32`
                 bounds.push_projection_bound(
                     tcx,
                     projection_ty
@@ -501,22 +494,18 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                     binding.span,
                 );
             }
-            hir::TypeBindingKind::Constraint { bounds: ast_bounds } => {
-                // "Desugar" a constraint like `T: Iterator<Item: Debug>` to
-                //
-                // `<T as Iterator>::Item: Debug`
-                //
-                // Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty`
-                // parameter to have a skipped binder.
-                //
-                // NOTE: If `only_self_bounds` is true, do NOT expand this associated
-                // type bound into a trait predicate, since we only want to add predicates
-                // for the `Self` type.
+            // Lower a constraint like `Item: Debug` as found in HIR bound `T: Iterator<Item: Debug>`
+            // to a bound involving a projection: `<T as Iterator>::Item: Debug`.
+            hir::TypeBindingKind::Constraint { bounds: hir_bounds } => {
+                // NOTE: If `only_self_bounds` is true, do NOT expand this associated type bound into
+                // a trait predicate, since we only want to add predicates for the `Self` type.
                 if !only_self_bounds.0 {
+                    // Calling `skip_binder` is okay, because `lower_bounds` expects the `param_ty`
+                    // parameter to have a skipped binder.
                     let param_ty = Ty::new_alias(tcx, ty::Projection, projection_ty.skip_binder());
-                    self.add_bounds(
+                    self.lower_poly_bounds(
                         param_ty,
-                        ast_bounds.iter(),
+                        hir_bounds.iter(),
                         bounds,
                         projection_ty.bound_vars(),
                         only_self_bounds,
@@ -565,7 +554,7 @@ fn check_assoc_const_binding_type<'tcx>(
     let mut guar = ty.visit_with(&mut collector).break_value();
 
     let ty_note = ty
-        .make_suggestable(tcx, false)
+        .make_suggestable(tcx, false, None)
         .map(|ty| crate::errors::TyOfAssocConstBindingNote { assoc_const, ty });
 
     let enclosing_item_owner_id = tcx
diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index 68896768e8d..ca2e14ee359 100644
--- a/compiler/rustc_hir_analysis/src/astconv/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -1,9 +1,9 @@
-use crate::astconv::AstConv;
 use crate::errors::{
     self, AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
     ParenthesizedFnTraitExpansion,
 };
 use crate::fluent_generated as fluent;
+use crate::hir_ty_lowering::HirTyLowerer;
 use crate::traits::error_reporting::report_object_safety_error;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::sorted_map::SortedMap;
@@ -22,7 +22,7 @@ use rustc_span::symbol::{sym, Ident};
 use rustc_span::{Span, Symbol, DUMMY_SP};
 use rustc_trait_selection::traits::object_safety_violations_for_assoc_item;
 
-impl<'tcx> dyn AstConv<'tcx> + '_ {
+impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     /// On missing type parameters, emit an E0393 error and provide a structured suggestion using
     /// the type parameter's name as a placeholder.
     pub(crate) fn complain_about_missing_type_params(
@@ -311,7 +311,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         // FIXME(associated_const_equality): This has quite a few false positives and negatives.
         let wrap_in_braces_sugg = if let Some(binding) = binding
             && let hir::TypeBindingKind::Equality { term: hir::Term::Ty(hir_ty) } = binding.kind
-            && let ty = self.ast_ty_to_ty(hir_ty)
+            && let ty = self.lower_ty(hir_ty)
             && (ty.is_enum() || ty.references_error())
             && tcx.features().associated_const_equality
         {
@@ -349,7 +349,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         })
     }
 
-    pub(super) fn report_ambiguous_associated_type(
+    pub(super) fn report_ambiguous_assoc_ty(
         &self,
         span: Span,
         types: &[String],
@@ -458,7 +458,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         reported
     }
 
-    pub(crate) fn complain_about_ambiguous_inherent_assoc_type(
+    pub(crate) fn complain_about_ambiguous_inherent_assoc_ty(
         &self,
         name: Ident,
         candidates: Vec<DefId>,
@@ -471,14 +471,14 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             "multiple applicable items in scope"
         );
         err.span_label(name.span, format!("multiple `{name}` found"));
-        self.note_ambiguous_inherent_assoc_type(&mut err, candidates, span);
+        self.note_ambiguous_inherent_assoc_ty(&mut err, candidates, span);
         let reported = err.emit();
         self.set_tainted_by_errors(reported);
         reported
     }
 
     // FIXME(fmease): Heavily adapted from `rustc_hir_typeck::method::suggest`. Deduplicate.
-    fn note_ambiguous_inherent_assoc_type(
+    fn note_ambiguous_inherent_assoc_ty(
         &self,
         err: &mut Diag<'_>,
         candidates: Vec<DefId>,
@@ -521,7 +521,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
     }
 
     // FIXME(inherent_associated_types): Find similarly named associated types and suggest them.
-    pub(crate) fn complain_about_inherent_assoc_type_not_found(
+    pub(crate) fn complain_about_inherent_assoc_ty_not_found(
         &self,
         name: Ident,
         self_ty: Ty<'tcx>,
@@ -697,7 +697,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
     /// reasonable suggestion on how to write it. For the case of multiple associated types in the
     /// same trait bound have the same name (as they come from different supertraits), we instead
     /// emit a generic note suggesting using a `where` clause to constraint instead.
-    pub(crate) fn complain_about_missing_associated_types(
+    pub(crate) fn complain_about_missing_assoc_tys(
         &self,
         associated_types: FxIndexMap<Span, FxIndexSet<DefId>>,
         potential_assoc_types: Vec<Span>,
@@ -1027,7 +1027,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
 }
 
 /// Emits an error regarding forbidden type binding associations
-pub fn prohibit_assoc_ty_binding(
+pub fn prohibit_assoc_item_binding(
     tcx: TyCtxt<'_>,
     span: Span,
     segment: Option<(&hir::PathSegment<'_>, Span)>,
diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
index 42e303c10ea..d340a08ee79 100644
--- a/compiler/rustc_hir_analysis/src/astconv/generics.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
@@ -1,7 +1,7 @@
 use super::IsMethodCall;
-use crate::astconv::{
-    errors::prohibit_assoc_ty_binding, CreateInstantiationsForGenericArgsCtxt, ExplicitLateBound,
-    GenericArgCountMismatch, GenericArgCountResult, GenericArgPosition,
+use crate::hir_ty_lowering::{
+    errors::prohibit_assoc_item_binding, ExplicitLateBound, GenericArgCountMismatch,
+    GenericArgCountResult, GenericArgPosition, GenericArgsLowerer,
 };
 use crate::structured_errors::{GenericArgsInfo, StructuredDiag, WrongNumberOfGenericArgs};
 use rustc_ast::ast::ParamKindOrd;
@@ -143,24 +143,22 @@ fn generic_arg_mismatch_err(
     err.emit()
 }
 
-/// Creates the relevant generic arguments
-/// corresponding to a set of generic parameters. This is a
-/// rather complex function. Let us try to explain the role
+/// Lower generic arguments from the HIR to the [`rustc_middle::ty`] representation.
+///
+/// This is a rather complex function. Let us try to explain the role
 /// of each of its parameters:
 ///
-/// To start, we are given the `def_id` of the thing whose generic
-/// parameters we are instantiating, and a partial set of
-/// arguments `parent_args`. In general, the generic arguments
-/// for an item begin with arguments for all the "parents" of
-/// that item -- e.g., for a method it might include the
-/// parameters from the impl.
+/// To start, we are given the `def_id` of the thing whose generic parameters we
+/// are creating, and a partial set of arguments `parent_args`. In general,
+/// the generic arguments for an item begin with arguments for all the "parents"
+/// of that item -- e.g., for a method it might include the parameters from the impl.
 ///
 /// Therefore, the method begins by walking down these parents,
 /// starting with the outermost parent and proceed inwards until
 /// it reaches `def_id`. For each parent `P`, it will check `parent_args`
 /// first to see if the parent's arguments are listed in there. If so,
-/// we can append those and move on. Otherwise, it invokes the
-/// three callback functions:
+/// we can append those and move on. Otherwise, it uses the provided
+/// [`GenericArgsLowerer`] `ctx` which has the following methods:
 ///
 /// - `args_for_def_id`: given the `DefId` `P`, supplies back the
 ///   generic arguments that were given to that parent from within
@@ -168,18 +166,18 @@ fn generic_arg_mismatch_err(
 ///   might refer to the trait `Foo`, and the arguments might be
 ///   `[T]`. The boolean value indicates whether to infer values
 ///   for arguments whose values were not explicitly provided.
-/// - `provided_kind`: given the generic parameter and the value from `args_for_def_id`,
-///   instantiate a `GenericArg`.
-/// - `inferred_kind`: if no parameter was provided, and inference is enabled, then
-///   creates a suitable inference variable.
-pub fn create_args_for_parent_generic_args<'tcx: 'a, 'a>(
+/// - `provided_kind`: given the generic parameter and the value
+///   from `args_for_def_id`, creating a `GenericArg`.
+/// - `inferred_kind`: if no parameter was provided, and inference
+///   is enabled, then creates a suitable inference variable.
+pub fn lower_generic_args<'tcx: 'a, 'a>(
     tcx: TyCtxt<'tcx>,
     def_id: DefId,
     parent_args: &[ty::GenericArg<'tcx>],
     has_self: bool,
     self_ty: Option<Ty<'tcx>>,
     arg_count: &GenericArgCountResult,
-    ctx: &mut impl CreateInstantiationsForGenericArgsCtxt<'a, 'tcx>,
+    ctx: &mut impl GenericArgsLowerer<'a, 'tcx>,
 ) -> GenericArgsRef<'tcx> {
     // Collect the segments of the path; we need to instantiate arguments
     // for parameters throughout the entire path (wherever there are
@@ -456,7 +454,7 @@ pub(crate) fn check_generic_arg_count(
     if gen_pos != GenericArgPosition::Type
         && let Some(b) = gen_args.bindings.first()
     {
-        prohibit_assoc_ty_binding(tcx, b.span, None);
+        prohibit_assoc_item_binding(tcx, b.span, None);
     }
 
     let explicit_late_bound =
diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
index b421a33ba29..80be563686a 100644
--- a/compiler/rustc_hir_analysis/src/astconv/lint.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
@@ -6,9 +6,9 @@ use rustc_lint_defs::{builtin::BARE_TRAIT_OBJECTS, Applicability};
 use rustc_span::Span;
 use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
 
-use super::AstConv;
+use super::HirTyLowerer;
 
-impl<'tcx> dyn AstConv<'tcx> + '_ {
+impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     /// Make sure that we are in the condition to suggest the blanket implementation.
     pub(super) fn maybe_lint_blanket_trait_impl<G: EmissionGuarantee>(
         &self,
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index a912d7f578d..b865bf976b5 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -1,6 +1,17 @@
-//! Conversion from AST representation of types to the `ty.rs` representation.
-//! The main routine here is `ast_ty_to_ty()`; each use is parameterized by an
-//! instance of `AstConv`.
+//! HIR ty lowering: Lowers type-system entities[^1] from the [HIR][hir] to
+//! the [`rustc_middle::ty`] representation.
+//!
+//! Not to be confused with *AST lowering* which lowers AST constructs to HIR ones
+//! or with *THIR* / *MIR* *lowering* / *building* which lowers HIR *bodies*
+//! (i.e., “executable code”) to THIR / MIR.
+//!
+//! Most lowering routines are defined on [`dyn HirTyLowerer`](HirTyLowerer) directly,
+//! like the main routine of this module, `lower_ty`.
+//!
+//! This module used to be called `astconv`.
+//!
+//! [^1]: This includes types, lifetimes / regions, constants in type positions,
+//! trait references and bounds.
 
 mod bounds;
 mod errors;
@@ -8,11 +19,11 @@ pub mod generics;
 mod lint;
 mod object_safety;
 
-use crate::astconv::errors::prohibit_assoc_ty_binding;
-use crate::astconv::generics::{check_generic_arg_count, create_args_for_parent_generic_args};
 use crate::bounds::Bounds;
 use crate::collect::HirPlaceholderCollector;
 use crate::errors::AmbiguousLifetimeBound;
+use crate::hir_ty_lowering::errors::prohibit_assoc_item_binding;
+use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
 use crate::middle::resolve_bound_vars as rbv;
 use crate::require_c_abi_if_c_variadic;
 use rustc_ast::TraitObjectSyntax;
@@ -43,8 +54,9 @@ use rustc_trait_selection::traits::{self, ObligationCtxt};
 use std::fmt::Display;
 use std::slice;
 
+/// A path segment that is semantically allowed to have generic arguments.
 #[derive(Debug)]
-pub struct PathSeg(pub DefId, pub usize);
+pub struct GenericPathSegment(pub DefId, pub usize);
 
 #[derive(Copy, Clone, Debug)]
 pub struct OnlySelfBounds(pub bool);
@@ -67,40 +79,26 @@ pub enum PredicateFilter {
     SelfAndAssociatedTypeBounds,
 }
 
-pub trait AstConv<'tcx> {
+/// A context which can lower type-system entities from the [HIR][hir] to
+/// the [`rustc_middle::ty`] representation.
+///
+/// This trait used to be called `AstConv`.
+pub trait HirTyLowerer<'tcx> {
     fn tcx(&self) -> TyCtxt<'tcx>;
 
+    /// Returns the [`DefId`] of the overarching item whose constituents get lowered.
     fn item_def_id(&self) -> DefId;
 
-    /// Returns predicates in scope of the form `X: Foo<T>`, where `X`
-    /// is a type parameter `X` with the given id `def_id` and T
-    /// matches `assoc_name`. This is a subset of the full set of
-    /// predicates.
-    ///
-    /// This is used for one specific purpose: resolving "short-hand"
-    /// associated type references like `T::Item`. In principle, we
-    /// would do that by first getting the full set of predicates in
-    /// scope and then filtering down to find those that apply to `T`,
-    /// but this can lead to cycle errors. The problem is that we have
-    /// to do this resolution *in order to create the predicates in
-    /// the first place*. Hence, we have this "special pass".
-    fn get_type_parameter_bounds(
-        &self,
-        span: Span,
-        def_id: LocalDefId,
-        assoc_name: Ident,
-    ) -> ty::GenericPredicates<'tcx>;
+    /// Returns `true` if the current context allows the use of inference variables.
+    fn allow_infer(&self) -> bool;
 
-    /// Returns the lifetime to use when a lifetime is omitted (and not elided).
+    /// Returns the region to use when a lifetime is omitted (and not elided).
     fn re_infer(&self, param: Option<&ty::GenericParamDef>, span: Span)
     -> Option<ty::Region<'tcx>>;
 
     /// Returns the type to use when a type is omitted.
     fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx>;
 
-    /// Returns `true` if `_` is allowed in type signatures in the current context.
-    fn allow_ty_infer(&self) -> bool;
-
     /// Returns the const to use when a const is omitted.
     fn ct_infer(
         &self,
@@ -109,14 +107,40 @@ pub trait AstConv<'tcx> {
         span: Span,
     ) -> Const<'tcx>;
 
-    /// Projecting an associated type from a (potentially)
-    /// higher-ranked trait reference is more complicated, because of
-    /// the possibility of late-bound regions appearing in the
-    /// associated type binding. This is not legal in function
-    /// signatures for that reason. In a function body, we can always
-    /// handle it because we can use inference variables to remove the
-    /// late-bound regions.
-    fn projected_ty_from_poly_trait_ref(
+    /// Probe bounds in scope where the bounded type coincides with the given type parameter.
+    ///
+    /// Rephrased, this returns bounds of the form `T: Trait`, where `T` is a type parameter
+    /// with the given `def_id`. This is a subset of the full set of bounds.
+    ///
+    /// This method may use the given `assoc_name` to disregard bounds whose trait reference
+    /// doesn't define an associated item with the provided name.
+    ///
+    /// This is used for one specific purpose: Resolving “short-hand” associated type references
+    /// like `T::Item` where `T` is a type parameter. In principle, we would do that by first
+    /// getting the full set of predicates in scope and then filtering down to find those that
+    /// apply to `T`, but this can lead to cycle errors. The problem is that we have to do this
+    /// resolution *in order to create the predicates in the first place*.
+    /// Hence, we have this “special pass”.
+    fn probe_ty_param_bounds(
+        &self,
+        span: Span,
+        def_id: LocalDefId,
+        assoc_name: Ident,
+    ) -> ty::GenericPredicates<'tcx>;
+
+    /// Lower an associated type to a projection.
+    ///
+    /// This method has to be defined by the concrete lowering context because
+    /// dealing with higher-ranked trait references depends on its capabilities:
+    ///
+    /// If the context can make use of type inference, it can simply instantiate
+    /// any late-bound vars bound by the trait reference with inference variables.
+    /// If it doesn't support type inference, there is nothing reasonable it can
+    /// do except reject the associated type.
+    ///
+    /// The canonical example of this is associated type `T::P` where `T` is a type
+    /// param constrained by `T: for<'a> Trait<'a>` and where `Trait` defines `P`.
+    fn lower_assoc_ty(
         &self,
         span: Span,
         item_def_id: DefId,
@@ -125,28 +149,35 @@ pub trait AstConv<'tcx> {
     ) -> Ty<'tcx>;
 
     /// Returns `AdtDef` if `ty` is an ADT.
-    /// Note that `ty` might be a projection type that needs normalization.
+    ///
+    /// Note that `ty` might be a alias type that needs normalization.
     /// This used to get the enum variants in scope of the type.
     /// For example, `Self::A` could refer to an associated type
     /// or to an enum variant depending on the result of this function.
     fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>>;
 
-    /// Invoked when we encounter an error from some prior pass
-    /// (e.g., resolve) that is translated into a ty-error. This is
-    /// used to help suppress derived errors typeck might otherwise
-    /// report.
-    fn set_tainted_by_errors(&self, e: ErrorGuaranteed);
-
+    /// Record the lowered type of a HIR node in this context.
     fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span);
 
-    fn astconv(&self) -> &dyn AstConv<'tcx>
+    /// The inference context of the lowering context if applicable.
+    fn infcx(&self) -> Option<&InferCtxt<'tcx>>;
+
+    /// Taint the context with errors.
+    ///
+    /// Invoke this when you encounter an error from some prior pass like name resolution.
+    /// This is used to help suppress derived errors typeck might otherwise report.
+    fn set_tainted_by_errors(&self, e: ErrorGuaranteed);
+
+    /// Convenience method for coercing the lowering context into a trait object type.
+    ///
+    /// Most lowering routines are defined on the trait object type directly
+    /// necessitating a coercion step from the concrete lowering context.
+    fn lowerer(&self) -> &dyn HirTyLowerer<'tcx>
     where
         Self: Sized,
     {
         self
     }
-
-    fn infcx(&self) -> Option<&InferCtxt<'tcx>>;
 }
 
 /// New-typed boolean indicating whether explicit late-bound lifetimes
@@ -197,7 +228,11 @@ pub struct GenericArgCountResult {
     pub correct: Result<(), GenericArgCountMismatch>,
 }
 
-pub trait CreateInstantiationsForGenericArgsCtxt<'a, 'tcx> {
+/// A context which can lower HIR's [`GenericArg`] to `rustc_middle`'s [`ty::GenericArg`].
+///
+/// Its only consumer is [`generics::lower_generic_args`].
+/// Read its documentation to learn more.
+pub trait GenericArgsLowerer<'a, 'tcx> {
     fn args_for_def_id(&mut self, def_id: DefId) -> (Option<&'a GenericArgs<'tcx>>, bool);
 
     fn provided_kind(
@@ -214,9 +249,10 @@ pub trait CreateInstantiationsForGenericArgsCtxt<'a, 'tcx> {
     ) -> ty::GenericArg<'tcx>;
 }
 
-impl<'tcx> dyn AstConv<'tcx> + '_ {
+impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
+    /// Lower a lifetime from the HIR to our internal notion of a lifetime called a *region*.
     #[instrument(level = "debug", skip(self), ret)]
-    pub fn ast_region_to_region(
+    pub fn lower_lifetime(
         &self,
         lifetime: &hir::Lifetime,
         def: Option<&ty::GenericParamDef>,
@@ -271,15 +307,13 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         }
     }
 
-    /// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`,
-    /// returns an appropriate set of generic arguments for this particular reference to `I`.
-    pub fn ast_path_args_for_ty(
+    pub fn lower_generic_args_of_path_segment(
         &self,
         span: Span,
         def_id: DefId,
         item_segment: &hir::PathSegment<'tcx>,
     ) -> GenericArgsRef<'tcx> {
-        let (args, _) = self.create_args_for_ast_path(
+        let (args, _) = self.lower_generic_args_of_path(
             span,
             def_id,
             &[],
@@ -288,20 +322,19 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             ty::BoundConstness::NotConst,
         );
         if let Some(b) = item_segment.args().bindings.first() {
-            prohibit_assoc_ty_binding(self.tcx(), b.span, Some((item_segment, span)));
+            prohibit_assoc_item_binding(self.tcx(), b.span, Some((item_segment, span)));
         }
-
         args
     }
 
-    /// Given the type/lifetime/const arguments provided to some path (along with
-    /// an implicit `Self`, if this is a trait reference), returns the complete
-    /// set of generic arguments. This may involve applying defaulted type parameters.
+    /// Lower the generic arguments provided to some path.
     ///
-    /// Constraints on associated types are not converted here but
-    /// separately in `add_predicates_for_ast_type_binding`.
+    /// If this is a trait reference, you also need to pass the self type `self_ty`.
+    /// The lowering process may involve applying defaulted type parameters.
     ///
-    /// Example:
+    /// Associated item bindings are not handled here!
+    ///
+    /// ### Example
     ///
     /// ```ignore (illustrative)
     ///    T: std::ops::Index<usize, Output = u32>
@@ -328,7 +361,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
     /// type itself: `['a]`. The returned `GenericArgsRef` concatenates these two
     /// lists: `[Vec<u8>, u8, 'a]`.
     #[instrument(level = "debug", skip(self, span), ret)]
-    fn create_args_for_ast_path(
+    fn lower_generic_args_of_path(
         &self,
         span: Span,
         def_id: DefId,
@@ -343,7 +376,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
 
         let tcx = self.tcx();
         let generics = tcx.generics_of(def_id);
-        debug!("generics: {:?}", generics);
+        debug!(?generics);
 
         if generics.has_self {
             if generics.parent.is_some() {
@@ -381,8 +414,8 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             return (tcx.mk_args(parent_args), arg_count);
         }
 
-        struct InstantiationsForAstPathCtxt<'a, 'tcx> {
-            astconv: &'a dyn AstConv<'tcx>,
+        struct GenericArgsCtxt<'a, 'tcx> {
+            lowerer: &'a dyn HirTyLowerer<'tcx>,
             def_id: DefId,
             generic_args: &'a GenericArgs<'tcx>,
             span: Span,
@@ -390,9 +423,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             infer_args: bool,
         }
 
-        impl<'a, 'tcx> CreateInstantiationsForGenericArgsCtxt<'a, 'tcx>
-            for InstantiationsForAstPathCtxt<'a, 'tcx>
-        {
+        impl<'a, 'tcx> GenericArgsLowerer<'a, 'tcx> for GenericArgsCtxt<'a, 'tcx> {
             fn args_for_def_id(&mut self, did: DefId) -> (Option<&'a GenericArgs<'tcx>>, bool) {
                 if did == self.def_id {
                     (Some(self.generic_args), self.infer_args)
@@ -407,7 +438,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                 param: &ty::GenericParamDef,
                 arg: &GenericArg<'tcx>,
             ) -> ty::GenericArg<'tcx> {
-                let tcx = self.astconv.tcx();
+                let tcx = self.lowerer.tcx();
 
                 let mut handle_ty_args = |has_default, ty: &hir::Ty<'tcx>| {
                     if has_default {
@@ -426,17 +457,17 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                             },
                         );
                     }
-                    if let (hir::TyKind::Infer, false) = (&ty.kind, self.astconv.allow_ty_infer()) {
+                    if let (hir::TyKind::Infer, false) = (&ty.kind, self.lowerer.allow_infer()) {
                         self.inferred_params.push(ty.span);
                         Ty::new_misc_error(tcx).into()
                     } else {
-                        self.astconv.ast_ty_to_ty(ty).into()
+                        self.lowerer.lower_ty(ty).into()
                     }
                 };
 
                 match (&param.kind, arg) {
                     (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
-                        self.astconv.ast_region_to_region(lt, Some(param)).into()
+                        self.lowerer.lower_lifetime(lt, Some(param)).into()
                     }
                     (&GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => {
                         handle_ty_args(has_default, ty)
@@ -455,8 +486,8 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                             .type_of(param.def_id)
                             .no_bound_vars()
                             .expect("const parameter types cannot be generic");
-                        if self.astconv.allow_ty_infer() {
-                            self.astconv.ct_infer(ty, Some(param), inf.span).into()
+                        if self.lowerer.allow_infer() {
+                            self.lowerer.ct_infer(ty, Some(param), inf.span).into()
                         } else {
                             self.inferred_params.push(inf.span);
                             ty::Const::new_misc_error(tcx, ty).into()
@@ -475,10 +506,10 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                 param: &ty::GenericParamDef,
                 infer_args: bool,
             ) -> ty::GenericArg<'tcx> {
-                let tcx = self.astconv.tcx();
+                let tcx = self.lowerer.tcx();
                 match param.kind {
                     GenericParamDefKind::Lifetime => self
-                        .astconv
+                        .lowerer
                         .re_infer(Some(param), self.span)
                         .unwrap_or_else(|| {
                             debug!(?param, "unelided lifetime in signature");
@@ -504,7 +535,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                             }
                             tcx.at(self.span).type_of(param.def_id).instantiate(tcx, args).into()
                         } else if infer_args {
-                            self.astconv.ty_infer(Some(param), self.span).into()
+                            self.lowerer.ty_infer(Some(param), self.span).into()
                         } else {
                             // We've already errored above about the mismatch.
                             Ty::new_misc_error(tcx).into()
@@ -526,7 +557,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                                 .into()
                         } else {
                             if infer_args {
-                                self.astconv.ct_infer(ty, Some(param), self.span).into()
+                                self.lowerer.ct_infer(ty, Some(param), self.span).into()
                             } else {
                                 // We've already errored above about the mismatch.
                                 ty::Const::new_misc_error(tcx, ty).into()
@@ -537,8 +568,8 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             }
         }
 
-        let mut args_ctx = InstantiationsForAstPathCtxt {
-            astconv: self,
+        let mut args_ctx = GenericArgsCtxt {
+            lowerer: self,
             def_id,
             span,
             generic_args: segment.args(),
@@ -557,7 +588,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             arg_count.correct =
                 Err(GenericArgCountMismatch { reported: Some(e), invalid_args: vec![] });
         }
-        let args = create_args_for_parent_generic_args(
+        let args = lower_generic_args(
             tcx,
             def_id,
             parent_args,
@@ -570,18 +601,16 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         (args, arg_count)
     }
 
-    pub fn create_args_for_associated_item(
+    #[instrument(level = "debug", skip_all)]
+    pub fn lower_generic_args_of_assoc_item(
         &self,
         span: Span,
         item_def_id: DefId,
         item_segment: &hir::PathSegment<'tcx>,
         parent_args: GenericArgsRef<'tcx>,
     ) -> GenericArgsRef<'tcx> {
-        debug!(
-            "create_args_for_associated_item(span: {:?}, item_def_id: {:?}, item_segment: {:?}",
-            span, item_def_id, item_segment
-        );
-        let (args, _) = self.create_args_for_ast_path(
+        debug!(?span, ?item_def_id, ?item_segment);
+        let (args, _) = self.lower_generic_args_of_path(
             span,
             item_def_id,
             parent_args,
@@ -589,28 +618,23 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             None,
             ty::BoundConstness::NotConst,
         );
-
         if let Some(b) = item_segment.args().bindings.first() {
-            prohibit_assoc_ty_binding(self.tcx(), b.span, Some((item_segment, span)));
+            prohibit_assoc_item_binding(self.tcx(), b.span, Some((item_segment, span)));
         }
-
         args
     }
 
-    /// Instantiates the path for the given trait reference, assuming that it's
-    /// bound to a valid trait type. Returns the `DefId` of the defining trait.
-    /// The type _cannot_ be a type other than a trait type.
+    /// Lower a trait reference as found in an impl header as the implementee.
     ///
-    /// If the `projections` argument is `None`, then assoc type bindings like `Foo<T = X>`
-    /// are disallowed. Otherwise, they are pushed onto the vector given.
-    pub fn instantiate_mono_trait_ref(
+    /// The self type `self_ty` is the implementer of the trait.
+    pub fn lower_impl_trait_ref(
         &self,
         trait_ref: &hir::TraitRef<'tcx>,
         self_ty: Ty<'tcx>,
     ) -> ty::TraitRef<'tcx> {
-        self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
+        self.prohibit_generic_args(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
 
-        self.ast_path_to_mono_trait_ref(
+        self.lower_mono_trait_ref(
             trait_ref.path.span,
             trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()),
             self_ty,
@@ -620,32 +644,36 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         )
     }
 
-    /// Given a trait bound like `Debug`, applies that trait bound the given self-type to construct
-    /// a full trait reference. The resulting trait reference is returned. This may also generate
-    /// auxiliary bounds, which are added to `bounds`.
+    /// Lower a polymorphic trait reference given a self type into `bounds`.
     ///
-    /// Example:
+    /// *Polymorphic* in the sense that it may bind late-bound vars.
     ///
-    /// ```ignore (illustrative)
-    /// poly_trait_ref = Iterator<Item = u32>
-    /// self_ty = Foo
-    /// ```
+    /// This may generate auxiliary bounds if the trait reference contains associated item bindings.
+    ///
+    /// ### Example
+    ///
+    /// Given the trait ref `Iterator<Item = u32>` and the self type `Ty`, this will add the
     ///
-    /// this would return `Foo: Iterator` and add `<Foo as Iterator>::Item = u32` into `bounds`.
+    /// 1. *trait predicate* `<Ty as Iterator>` (known as `Foo: Iterator` in surface syntax) and the
+    /// 2. *projection predicate* `<Ty as Iterator>::Item = u32`
+    ///
+    /// to `bounds`.
+    ///
+    /// ### A Note on Binders
+    ///
+    /// Against our usual convention, there is an implied binder around the `self_ty` and the
+    /// `trait_ref` here. So they may reference late-bound vars.
     ///
-    /// **A note on binders:** against our usual convention, there is an implied binder around
-    /// the `self_ty` and `poly_trait_ref` parameters here. So they may reference bound regions.
     /// If for example you had `for<'a> Foo<'a>: Bar<'a>`, then the `self_ty` would be `Foo<'a>`
-    /// where `'a` is a bound region at depth 0. Similarly, the `poly_trait_ref` would be
-    /// `Bar<'a>`. The returned poly-trait-ref will have this binder instantiated explicitly,
-    /// however.
+    /// where `'a` is a bound region at depth 0. Similarly, the `trait_ref` would be `Bar<'a>`.
+    /// The lowered poly-trait-ref will track this binder explicitly, however.
     #[instrument(level = "debug", skip(self, span, constness, bounds))]
-    pub(crate) fn instantiate_poly_trait_ref(
+    pub(crate) fn lower_poly_trait_ref(
         &self,
         trait_ref: &hir::TraitRef<'tcx>,
         span: Span,
         constness: ty::BoundConstness,
-        polarity: ty::ImplPolarity,
+        polarity: ty::PredicatePolarity,
         self_ty: Ty<'tcx>,
         bounds: &mut Bounds<'tcx>,
         only_self_bounds: OnlySelfBounds,
@@ -653,10 +681,10 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise());
         let trait_segment = trait_ref.path.segments.last().unwrap();
 
-        self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
+        self.prohibit_generic_args(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
         self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false);
 
-        let (generic_args, arg_count) = self.create_args_for_ast_path(
+        let (generic_args, arg_count) = self.lower_generic_args_of_path(
             trait_ref.path.span,
             trait_def_id,
             &[],
@@ -682,7 +710,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             // Don't register additional associated type bounds for negative bounds,
             // since we should have emitten an error for them earlier, and they will
             // not be well-formed!
-            if polarity == ty::ImplPolarity::Negative {
+            if polarity != ty::PredicatePolarity::Positive {
                 assert!(
                     self.tcx().dcx().has_errors().is_some(),
                     "negative trait bounds should not have bindings",
@@ -691,7 +719,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             }
 
             // Specify type to assert that error was already reported in `Err` case.
-            let _: Result<_, ErrorGuaranteed> = self.add_predicates_for_ast_type_binding(
+            let _: Result<_, ErrorGuaranteed> = self.lower_assoc_item_binding(
                 trait_ref.hir_ref_id,
                 poly_trait_ref,
                 binding,
@@ -706,19 +734,22 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         arg_count
     }
 
-    fn ast_path_to_mono_trait_ref(
+    /// Lower a monomorphic trait reference given a self type while prohibiting associated item bindings.
+    ///
+    /// *Monomorphic* in the sense that it doesn't bind any late-bound vars.
+    fn lower_mono_trait_ref(
         &self,
         span: Span,
         trait_def_id: DefId,
         self_ty: Ty<'tcx>,
         trait_segment: &hir::PathSegment<'tcx>,
         is_impl: bool,
-        // FIXME(effects) move all host param things in astconv to hir lowering
+        // FIXME(effects): Move all host param things in HIR ty lowering to AST lowering.
         constness: ty::BoundConstness,
     ) -> ty::TraitRef<'tcx> {
         self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
 
-        let (generic_args, _) = self.create_args_for_ast_path(
+        let (generic_args, _) = self.lower_generic_args_of_path(
             span,
             trait_def_id,
             &[],
@@ -727,12 +758,12 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             constness,
         );
         if let Some(b) = trait_segment.args().bindings.first() {
-            prohibit_assoc_ty_binding(self.tcx(), b.span, Some((trait_segment, span)));
+            prohibit_assoc_item_binding(self.tcx(), b.span, Some((trait_segment, span)));
         }
         ty::TraitRef::new(self.tcx(), trait_def_id, generic_args)
     }
 
-    fn trait_defines_associated_item_named(
+    fn probe_trait_that_defines_assoc_item(
         &self,
         trait_def_id: DefId,
         assoc_kind: ty::AssocKind,
@@ -744,14 +775,14 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             .is_some()
     }
 
-    fn ast_path_to_ty(
+    fn lower_path_segment(
         &self,
         span: Span,
         did: DefId,
         item_segment: &hir::PathSegment<'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx();
-        let args = self.ast_path_args_for_ty(span, did, item_segment);
+        let args = self.lower_generic_args_of_path_segment(span, did, item_segment);
 
         if let DefKind::TyAlias = tcx.def_kind(did)
             && tcx.type_alias_is_lazy(did)
@@ -766,30 +797,27 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         }
     }
 
-    // Search for a bound on a type parameter which includes the associated item
-    // given by `assoc_name`. `ty_param_def_id` is the `DefId` of the type parameter
-    // This function will fail if there are no suitable bounds or there is
-    // any ambiguity.
-    fn find_bound_for_assoc_item(
+    /// Search for a trait bound on a type parameter whose trait defines the associated type given by `assoc_name`.
+    ///
+    /// This fails if there is no such bound in the list of candidates or if there are multiple
+    /// candidates in which case it reports ambiguity.
+    ///
+    /// `ty_param_def_id` is the `LocalDefId` of the type parameter.
+    #[instrument(level = "debug", skip_all, ret)]
+    fn probe_single_ty_param_bound_for_assoc_ty(
         &self,
         ty_param_def_id: LocalDefId,
         assoc_name: Ident,
         span: Span,
     ) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed> {
+        debug!(?ty_param_def_id, ?assoc_name, ?span);
         let tcx = self.tcx();
 
-        debug!(
-            "find_bound_for_assoc_item(ty_param_def_id={:?}, assoc_name={:?}, span={:?})",
-            ty_param_def_id, assoc_name, span,
-        );
-
-        let predicates =
-            &self.get_type_parameter_bounds(span, ty_param_def_id, assoc_name).predicates;
-
-        debug!("find_bound_for_assoc_item: predicates={:#?}", predicates);
+        let predicates = &self.probe_ty_param_bounds(span, ty_param_def_id, assoc_name).predicates;
+        debug!("predicates={:#?}", predicates);
 
         let param_name = tcx.hir().ty_param_name(ty_param_def_id);
-        self.one_bound_for_assoc_item(
+        self.probe_single_bound_for_assoc_item(
             || {
                 traits::transitive_bounds_that_define_assoc_item(
                     tcx,
@@ -808,10 +836,12 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         )
     }
 
-    // Checks that `bounds` contains exactly one element and reports appropriate
-    // errors otherwise.
+    /// Search for a single trait bound whose trait defines the associated item given by `assoc_name`.
+    ///
+    /// This fails if there is no such bound in the list of candidates or if there are multiple
+    /// candidates in which case it reports ambiguity.
     #[instrument(level = "debug", skip(self, all_candidates, ty_param_name, binding), ret)]
-    fn one_bound_for_assoc_item<I>(
+    fn probe_single_bound_for_assoc_item<I>(
         &self,
         all_candidates: impl Fn() -> I,
         ty_param_name: impl Display,
@@ -827,7 +857,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         let tcx = self.tcx();
 
         let mut matching_candidates = all_candidates().filter(|r| {
-            self.trait_defines_associated_item_named(r.def_id(), assoc_kind, assoc_name)
+            self.probe_trait_that_defines_assoc_item(r.def_id(), assoc_kind, assoc_name)
         });
 
         let Some(bound) = matching_candidates.next() else {
@@ -886,7 +916,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                         match binding.kind {
                             hir::TypeBindingKind::Equality { term } => {
                                 let term: ty::Term<'_> = match term {
-                                    hir::Term::Ty(ty) => self.ast_ty_to_ty(ty).into(),
+                                    hir::Term::Ty(ty) => self.lower_ty(ty).into(),
                                     hir::Term::Const(ct) => {
                                         ty::Const::from_anon_const(tcx, ct.def_id).into()
                                     }
@@ -932,16 +962,35 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         Ok(bound)
     }
 
-    // Create a type from a path to an associated type or to an enum variant.
-    // For a path `A::B::C::D`, `qself_ty` and `qself_def` are the type and def for `A::B::C`
-    // and item_segment is the path segment for `D`. We return a type and a def for
-    // the whole path.
-    // Will fail except for `T::A` and `Self::A`; i.e., if `qself_ty`/`qself_def` are not a type
-    // parameter or `Self`.
+    /// Lower a [type-relative] path referring to an associated type or to an enum variant.
+    ///
+    /// If the path refers to an enum variant and `permit_variants` holds,
+    /// the returned type is simply the provided self type `qself_ty`.
+    ///
+    /// A path like `A::B::C::D` is understood as `<A::B::C>::D`. I.e.,
+    /// `qself_ty` / `qself` is `A::B::C` and `assoc_segment` is `D`.
+    /// We return the lowered type and the `DefId` for the whole path.
+    ///
+    /// We only support associated type paths whose self type is a type parameter or a `Self`
+    /// type alias (in a trait impl) like `T::Ty` (where `T` is a ty param) or `Self::Ty`.
+    /// We **don't** support paths whose self type is an arbitrary type like `Struct::Ty` where
+    /// struct `Struct` impls an in-scope trait that defines an associated type called `Ty`.
+    /// For the latter case, we report ambiguity.
+    /// While desirable to support, the implemention would be non-trivial. Tracked in [#22519].
+    ///
+    /// At the time of writing, *inherent associated types* are also resolved here. This however
+    /// is [problematic][iat]. A proper implementation would be as non-trivial as the one
+    /// described in the previous paragraph and their modeling of projections would likely be
+    /// very similar in nature.
+    ///
+    /// [type-relative]: hir::QPath::TypeRelative
+    /// [#22519]: https://github.com/rust-lang/rust/issues/22519
+    /// [iat]: https://github.com/rust-lang/rust/issues/8995#issuecomment-1569208403
+    //
     // NOTE: When this function starts resolving `Trait::AssocTy` successfully
     // it should also start reporting the `BARE_TRAIT_OBJECTS` lint.
-    #[instrument(level = "debug", skip(self, hir_ref_id, span, qself, assoc_segment), fields(assoc_ident=?assoc_segment.ident), ret)]
-    pub fn associated_path_to_ty(
+    #[instrument(level = "debug", skip_all, ret)]
+    pub fn lower_assoc_path(
         &self,
         hir_ref_id: hir::HirId,
         span: Span,
@@ -950,7 +999,9 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         assoc_segment: &hir::PathSegment<'tcx>,
         permit_variants: bool,
     ) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
+        debug!(%qself_ty, ?assoc_segment.ident);
         let tcx = self.tcx();
+
         let assoc_ident = assoc_segment.ident;
         let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
             path.res
@@ -969,7 +1020,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                 if let Some(variant_def) = variant_def {
                     if permit_variants {
                         tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
-                        self.prohibit_generics(slice::from_ref(assoc_segment).iter(), |err| {
+                        self.prohibit_generic_args(slice::from_ref(assoc_segment).iter(), |err| {
                             err.note("enum variants can't have type parameters");
                             let type_name = tcx.item_name(adt_def.did());
                             let msg = format!(
@@ -1069,7 +1120,8 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                 }
             }
 
-            if let Some((ty, did)) = self.lookup_inherent_assoc_ty(
+            // FIXME(inherent_associated_types, #106719): Support self types other than ADTs.
+            if let Some((ty, did)) = self.probe_inherent_assoc_ty(
                 assoc_ident,
                 assoc_segment,
                 adt_def.did(),
@@ -1092,7 +1144,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                     tcx.dcx().span_bug(span, "expected cycle error");
                 };
 
-                self.one_bound_for_assoc_item(
+                self.probe_single_bound_for_assoc_item(
                     || {
                         traits::supertraits(
                             tcx,
@@ -1110,7 +1162,11 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             (
                 &ty::Param(_),
                 Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did),
-            ) => self.find_bound_for_assoc_item(param_did.expect_local(), assoc_ident, span)?,
+            ) => self.probe_single_ty_param_bound_for_assoc_ty(
+                param_did.expect_local(),
+                assoc_ident,
+                span,
+            )?,
             _ => {
                 let reported = if variant_resolution.is_some() {
                     // Variant in type position
@@ -1172,7 +1228,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                         self.probe_traits_that_match_assoc_ty(qself_ty, assoc_ident);
 
                     // Don't print `ty::Error` to the user.
-                    self.report_ambiguous_associated_type(
+                    self.report_ambiguous_assoc_ty(
                         span,
                         &[qself_ty.to_string()],
                         &traits,
@@ -1185,8 +1241,8 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         };
 
         let trait_did = bound.def_id();
-        let assoc_ty_did = self.lookup_assoc_ty(assoc_ident, hir_ref_id, span, trait_did).unwrap();
-        let ty = self.projected_ty_from_poly_trait_ref(span, assoc_ty_did, assoc_segment, bound);
+        let assoc_ty_did = self.probe_assoc_ty(assoc_ident, hir_ref_id, span, trait_did).unwrap();
+        let ty = self.lower_assoc_ty(span, assoc_ty_did, assoc_segment, bound);
 
         if let Some(variant_def_id) = variant_resolution {
             tcx.node_span_lint(
@@ -1220,7 +1276,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         Ok((ty, DefKind::AssocTy, assoc_ty_did))
     }
 
-    fn lookup_inherent_assoc_ty(
+    fn probe_inherent_assoc_ty(
         &self,
         name: Ident,
         segment: &hir::PathSegment<'tcx>,
@@ -1234,8 +1290,9 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         // Don't attempt to look up inherent associated types when the feature is not enabled.
         // Theoretically it'd be fine to do so since we feature-gate their definition site.
         // However, due to current limitations of the implementation (caused by us performing
-        // selection in AstConv), IATs can lead to cycle errors (#108491, #110106) which mask the
-        // feature-gate error, needlessly confusing users that use IATs by accident (#113265).
+        // selection during HIR ty lowering instead of in the trait solver), IATs can lead to cycle
+        // errors (#108491) which mask the feature-gate error, needlessly confusing users
+        // who use IATs by accident (#113265).
         if !tcx.features().inherent_associated_types {
             return Ok(None);
         }
@@ -1243,7 +1300,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         let candidates: Vec<_> = tcx
             .inherent_impls(adt_did)?
             .iter()
-            .filter_map(|&impl_| Some((impl_, self.lookup_assoc_ty_unchecked(name, block, impl_)?)))
+            .filter_map(|&impl_| Some((impl_, self.probe_assoc_ty_unchecked(name, block, impl_)?)))
             .collect();
 
         if candidates.is_empty() {
@@ -1290,10 +1347,10 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         self.check_assoc_ty(assoc_item, name, def_scope, block, span);
 
         // FIXME(fmease): Currently creating throwaway `parent_args` to please
-        // `create_args_for_associated_item`. Modify the latter instead (or sth. similar) to
+        // `lower_generic_args_of_assoc_item`. Modify the latter instead (or sth. similar) to
         // not require the parent args logic.
         let parent_args = ty::GenericArgs::identity_for_item(tcx, impl_);
-        let args = self.create_args_for_associated_item(span, assoc_item, segment, parent_args);
+        let args = self.lower_generic_args_of_assoc_item(span, assoc_item, segment, parent_args);
         let args = tcx.mk_args_from_iter(
             std::iter::once(ty::GenericArg::from(self_ty))
                 .chain(args.into_iter().skip(parent_args.len())),
@@ -1356,7 +1413,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             .collect();
 
         match &applicable_candidates[..] {
-            &[] => Err(self.complain_about_inherent_assoc_type_not_found(
+            &[] => Err(self.complain_about_inherent_assoc_ty_not_found(
                 name,
                 self_ty,
                 candidates,
@@ -1366,7 +1423,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
 
             &[applicable_candidate] => Ok(applicable_candidate),
 
-            &[_, ..] => Err(self.complain_about_ambiguous_inherent_assoc_type(
+            &[_, ..] => Err(self.complain_about_ambiguous_inherent_assoc_ty(
                 name,
                 applicable_candidates.into_iter().map(|(_, (candidate, _))| candidate).collect(),
                 span,
@@ -1374,19 +1431,19 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         }
     }
 
-    fn lookup_assoc_ty(
+    fn probe_assoc_ty(
         &self,
         name: Ident,
         block: hir::HirId,
         span: Span,
         scope: DefId,
     ) -> Option<DefId> {
-        let (item, def_scope) = self.lookup_assoc_ty_unchecked(name, block, scope)?;
+        let (item, def_scope) = self.probe_assoc_ty_unchecked(name, block, scope)?;
         self.check_assoc_ty(item, name, def_scope, block, span);
         Some(item)
     }
 
-    fn lookup_assoc_ty_unchecked(
+    fn probe_assoc_ty_unchecked(
         &self,
         name: Ident,
         block: hir::HirId,
@@ -1491,7 +1548,9 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             .collect()
     }
 
-    fn qpath_to_ty(
+    /// Lower a qualified path to a type.
+    #[instrument(level = "debug", skip_all)]
+    fn lower_qpath(
         &self,
         span: Span,
         opt_self_ty: Option<Ty<'tcx>>,
@@ -1503,22 +1562,19 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         let tcx = self.tcx();
 
         let trait_def_id = tcx.parent(item_def_id);
-
-        debug!("qpath_to_ty: trait_def_id={:?}", trait_def_id);
+        debug!(?trait_def_id);
 
         let Some(self_ty) = opt_self_ty else {
             let path_str = tcx.def_path_str(trait_def_id);
 
             let def_id = self.item_def_id();
-
-            debug!("qpath_to_ty: self.item_def_id()={:?}", def_id);
+            debug!(item_def_id = ?def_id);
 
             let parent_def_id = def_id
                 .as_local()
                 .map(|def_id| tcx.local_def_id_to_hir_id(def_id))
                 .map(|hir_id| tcx.hir().get_parent_item(hir_id).to_def_id());
-
-            debug!("qpath_to_ty: parent_def_id={:?}", parent_def_id);
+            debug!(?parent_def_id);
 
             // If the trait in segment is the same as the trait defining the item,
             // use the `<Self as ..>` syntax in the error.
@@ -1545,7 +1601,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             // FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that
             // references the trait. Relevant for the first case in
             // `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs`
-            let reported = self.report_ambiguous_associated_type(
+            let reported = self.report_ambiguous_assoc_ty(
                 span,
                 &type_names,
                 &[path_str],
@@ -1553,27 +1609,19 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             );
             return Ty::new_error(tcx, reported);
         };
+        debug!(?self_ty);
 
-        debug!("qpath_to_ty: self_type={:?}", self_ty);
-
-        let trait_ref = self.ast_path_to_mono_trait_ref(
-            span,
-            trait_def_id,
-            self_ty,
-            trait_segment,
-            false,
-            constness,
-        );
+        let trait_ref =
+            self.lower_mono_trait_ref(span, trait_def_id, self_ty, trait_segment, false, constness);
+        debug!(?trait_ref);
 
         let item_args =
-            self.create_args_for_associated_item(span, item_def_id, item_segment, trait_ref.args);
-
-        debug!("qpath_to_ty: trait_ref={:?}", trait_ref);
+            self.lower_generic_args_of_assoc_item(span, item_def_id, item_segment, trait_ref.args);
 
         Ty::new_projection(tcx, item_def_id, item_args)
     }
 
-    pub fn prohibit_generics<'a>(
+    pub fn prohibit_generic_args<'a>(
         &self,
         segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
         extend: impl Fn(&mut Diag<'_>),
@@ -1676,25 +1724,41 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         for segment in segments {
             // Only emit the first error to avoid overloading the user with error messages.
             if let Some(b) = segment.args().bindings.first() {
-                prohibit_assoc_ty_binding(self.tcx(), b.span, None);
+                prohibit_assoc_item_binding(self.tcx(), b.span, None);
                 return true;
             }
         }
         emitted
     }
 
+    /// Probe path segments that are semantically allowed to have generic arguments.
+    ///
+    /// ### Example
+    ///
+    /// ```ignore (illustrative)
+    ///    Option::None::<()>
+    /// //         ^^^^ permitted to have generic args
+    ///
+    /// // ==> [GenericPathSegment(Option_def_id, 1)]
+    ///
+    ///    Option::<()>::None
+    /// // ^^^^^^        ^^^^ *not* permitted to have generic args
+    /// // permitted to have generic args
+    ///
+    /// // ==> [GenericPathSegment(Option_def_id, 0)]
+    /// ```
     // FIXME(eddyb, varkor) handle type paths here too, not just value ones.
-    pub fn def_ids_for_value_path_segments(
+    pub fn probe_generic_path_segments(
         &self,
         segments: &[hir::PathSegment<'_>],
         self_ty: Option<Ty<'tcx>>,
         kind: DefKind,
         def_id: DefId,
         span: Span,
-    ) -> Vec<PathSeg> {
-        // We need to extract the type parameters supplied by the user in
+    ) -> Vec<GenericPathSegment> {
+        // We need to extract the generic arguments supplied by the user in
         // the path `path`. Due to the current setup, this is a bit of a
-        // tricky-process; the problem is that resolve only tells us the
+        // tricky process; the problem is that resolve only tells us the
         // end-point of the path resolution, and not the intermediate steps.
         // Luckily, we can (at least for now) deduce the intermediate steps
         // just from the end-point.
@@ -1705,35 +1769,35 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         //
         //        struct Foo<T>(...)
         //
-        //    In this case, the parameters are declared in the type space.
+        //    In this case, the generic arguments are declared in the type space.
         //
         // 2. Reference to a constructor of an enum variant:
         //
         //        enum E<T> { Foo(...) }
         //
-        //    In this case, the parameters are defined in the type space,
+        //    In this case, the generic arguments are defined in the type space,
         //    but may be specified either on the type or the variant.
         //
-        // 3. Reference to a fn item or a free constant:
+        // 3. Reference to a free function or constant:
         //
-        //        fn foo<T>() { }
+        //        fn foo<T>() {}
         //
         //    In this case, the path will again always have the form
-        //    `a::b::foo::<T>` where only the final segment should have
-        //    type parameters. However, in this case, those parameters are
-        //    declared on a value, and hence are in the `FnSpace`.
+        //    `a::b::foo::<T>` where only the final segment should have generic
+        //    arguments. However, in this case, those arguments are declared on
+        //    a value, and hence are in the value space.
         //
-        // 4. Reference to a method or an associated constant:
+        // 4. Reference to an associated function or constant:
         //
         //        impl<A> SomeStruct<A> {
-        //            fn foo<B>(...)
+        //            fn foo<B>(...) {}
         //        }
         //
-        //    Here we can have a path like
-        //    `a::b::SomeStruct::<A>::foo::<B>`, in which case parameters
-        //    may appear in two places. The penultimate segment,
-        //    `SomeStruct::<A>`, contains parameters in TypeSpace, and the
-        //    final segment, `foo::<B>` contains parameters in fn space.
+        //    Here we can have a path like `a::b::SomeStruct::<A>::foo::<B>`,
+        //    in which case generic arguments may appear in two places. The
+        //    penultimate segment, `SomeStruct::<A>`, contains generic arguments
+        //    in the type space, and the final segment, `foo::<B>` contains
+        //    generic arguments in value space.
         //
         // The first step then is to categorize the segments appropriately.
 
@@ -1742,7 +1806,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         assert!(!segments.is_empty());
         let last = segments.len() - 1;
 
-        let mut path_segs = vec![];
+        let mut generic_segments = vec![];
 
         match kind {
             // Case 1. Reference to a struct constructor.
@@ -1753,7 +1817,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                 // Variant and struct constructors use the
                 // generics of their parent type definition.
                 let generics_def_id = generics.parent.unwrap_or(def_id);
-                path_segs.push(PathSeg(generics_def_id, last));
+                generic_segments.push(GenericPathSegment(generics_def_id, last));
             }
 
             // Case 2. Reference to a variant constructor.
@@ -1786,56 +1850,53 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                     // generics of their parent type definition.
                     (generics.parent.unwrap_or(def_id), last)
                 };
-                path_segs.push(PathSeg(generics_def_id, index));
+                generic_segments.push(GenericPathSegment(generics_def_id, index));
             }
 
             // Case 3. Reference to a top-level value.
             DefKind::Fn | DefKind::Const | DefKind::ConstParam | DefKind::Static { .. } => {
-                path_segs.push(PathSeg(def_id, last));
+                generic_segments.push(GenericPathSegment(def_id, last));
             }
 
             // Case 4. Reference to a method or associated const.
             DefKind::AssocFn | DefKind::AssocConst => {
                 if segments.len() >= 2 {
                     let generics = tcx.generics_of(def_id);
-                    path_segs.push(PathSeg(generics.parent.unwrap(), last - 1));
+                    generic_segments.push(GenericPathSegment(generics.parent.unwrap(), last - 1));
                 }
-                path_segs.push(PathSeg(def_id, last));
+                generic_segments.push(GenericPathSegment(def_id, last));
             }
 
             kind => bug!("unexpected definition kind {:?} for {:?}", kind, def_id),
         }
 
-        debug!("path_segs = {:?}", path_segs);
+        debug!(?generic_segments);
 
-        path_segs
+        generic_segments
     }
 
-    /// Check a type `Path` and convert it to a `Ty`.
-    pub fn res_to_ty(
+    /// Lower a type `Path` to a type.
+    #[instrument(level = "debug", skip_all)]
+    pub fn lower_path(
         &self,
         opt_self_ty: Option<Ty<'tcx>>,
         path: &hir::Path<'tcx>,
         hir_id: hir::HirId,
         permit_variants: bool,
     ) -> Ty<'tcx> {
+        debug!(?path.res, ?opt_self_ty, ?path.segments);
         let tcx = self.tcx();
 
-        debug!(
-            "res_to_ty(res={:?}, opt_self_ty={:?}, path_segments={:?})",
-            path.res, opt_self_ty, path.segments
-        );
-
         let span = path.span;
         match path.res {
             Res::Def(DefKind::OpaqueTy, did) => {
                 // Check for desugared `impl Trait`.
                 assert!(tcx.is_type_alias_impl_trait(did));
                 let item_segment = path.segments.split_last().unwrap();
-                self.prohibit_generics(item_segment.1.iter(), |err| {
+                self.prohibit_generic_args(item_segment.1.iter(), |err| {
                     err.note("`impl Trait` types can't have type parameters");
                 });
-                let args = self.ast_path_args_for_ty(span, did, item_segment.0);
+                let args = self.lower_generic_args_of_path_segment(span, did, item_segment.0);
                 Ty::new_opaque(tcx, did, args)
             }
             Res::Def(
@@ -1847,44 +1908,44 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                 did,
             ) => {
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generics(path.segments.split_last().unwrap().1.iter(), |_| {});
-                self.ast_path_to_ty(span, did, path.segments.last().unwrap())
+                self.prohibit_generic_args(path.segments.split_last().unwrap().1.iter(), |_| {});
+                self.lower_path_segment(span, did, path.segments.last().unwrap())
             }
             Res::Def(kind @ DefKind::Variant, def_id) if permit_variants => {
-                // Convert "variant type" as if it were a real type.
+                // Lower "variant type" as if it were a real type.
                 // The resulting `Ty` is type of the variant's enum for now.
                 assert_eq!(opt_self_ty, None);
 
-                let path_segs =
-                    self.def_ids_for_value_path_segments(path.segments, None, kind, def_id, span);
-                let generic_segs: FxHashSet<_> =
-                    path_segs.iter().map(|PathSeg(_, index)| index).collect();
-                self.prohibit_generics(
+                let generic_segments =
+                    self.probe_generic_path_segments(path.segments, None, kind, def_id, span);
+                let indices: FxHashSet<_> =
+                    generic_segments.iter().map(|GenericPathSegment(_, index)| index).collect();
+                self.prohibit_generic_args(
                     path.segments.iter().enumerate().filter_map(|(index, seg)| {
-                        if !generic_segs.contains(&index) { Some(seg) } else { None }
+                        if !indices.contains(&index) { Some(seg) } else { None }
                     }),
                     |err| {
                         err.note("enum variants can't have type parameters");
                     },
                 );
 
-                let PathSeg(def_id, index) = path_segs.last().unwrap();
-                self.ast_path_to_ty(span, *def_id, &path.segments[*index])
+                let GenericPathSegment(def_id, index) = generic_segments.last().unwrap();
+                self.lower_path_segment(span, *def_id, &path.segments[*index])
             }
             Res::Def(DefKind::TyParam, def_id) => {
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generics(path.segments.iter(), |err| {
+                self.prohibit_generic_args(path.segments.iter(), |err| {
                     if let Some(span) = tcx.def_ident_span(def_id) {
                         let name = tcx.item_name(def_id);
                         err.span_note(span, format!("type parameter `{name}` defined here"));
                     }
                 });
-                self.hir_id_to_bound_ty(hir_id)
+                self.lower_ty_param(hir_id)
             }
             Res::SelfTyParam { .. } => {
                 // `Self` in trait or type alias.
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generics(path.segments.iter(), |err| {
+                self.prohibit_generic_args(path.segments.iter(), |err| {
                     if let [hir::PathSegment { args: Some(args), ident, .. }] = &path.segments {
                         err.span_suggestion_verbose(
                             ident.span.shrink_to_hi().to(args.span_ext),
@@ -1902,7 +1963,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                 // Try to evaluate any array length constants.
                 let ty = tcx.at(span).type_of(def_id).instantiate_identity();
                 let span_of_impl = tcx.span_of_impl(def_id);
-                self.prohibit_generics(path.segments.iter(), |err| {
+                self.prohibit_generic_args(path.segments.iter(), |err| {
                     let def_id = match *ty.kind() {
                         ty::Adt(self_def, _) => self_def.did(),
                         _ => return,
@@ -2000,14 +2061,14 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             }
             Res::Def(DefKind::AssocTy, def_id) => {
                 debug_assert!(path.segments.len() >= 2);
-                self.prohibit_generics(path.segments[..path.segments.len() - 2].iter(), |_| {});
+                self.prohibit_generic_args(path.segments[..path.segments.len() - 2].iter(), |_| {});
                 // HACK: until we support `<Type as ~const Trait>`, assume all of them are.
                 let constness = if tcx.has_attr(tcx.parent(def_id), sym::const_trait) {
                     ty::BoundConstness::ConstIfConst
                 } else {
                     ty::BoundConstness::NotConst
                 };
-                self.qpath_to_ty(
+                self.lower_qpath(
                     span,
                     opt_self_ty,
                     def_id,
@@ -2018,7 +2079,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             }
             Res::PrimTy(prim_ty) => {
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generics(path.segments.iter(), |err| {
+                self.prohibit_generic_args(path.segments.iter(), |err| {
                     let name = prim_ty.name_str();
                     for segment in path.segments {
                         if let Some(args) = segment.args {
@@ -2052,9 +2113,11 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         }
     }
 
-    // Converts a hir id corresponding to a type parameter to
-    // a early-bound `ty::Param` or late-bound `ty::Bound`.
-    pub(crate) fn hir_id_to_bound_ty(&self, hir_id: hir::HirId) -> Ty<'tcx> {
+    /// Lower a type parameter from the HIR to our internal notion of a type.
+    ///
+    /// Early-bound type parameters get lowered to [`ty::Param`]
+    /// and late-bound ones to [`ty::Bound`].
+    pub(crate) fn lower_ty_param(&self, hir_id: hir::HirId) -> Ty<'tcx> {
         let tcx = self.tcx();
         match tcx.named_bound_var(hir_id) {
             Some(rbv::ResolvedArg::LateBound(debruijn, index, def_id)) => {
@@ -2077,13 +2140,11 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         }
     }
 
-    // Converts a hir id corresponding to a const parameter to
-    // a early-bound `ConstKind::Param` or late-bound `ConstKind::Bound`.
-    pub(crate) fn hir_id_to_bound_const(
-        &self,
-        hir_id: hir::HirId,
-        param_ty: Ty<'tcx>,
-    ) -> Const<'tcx> {
+    /// Lower a const parameter from the HIR to our internal notion of a constant.
+    ///
+    /// Early-bound const parameters get lowered to [`ty::ConstKind::Param`]
+    /// and late-bound ones to [`ty::ConstKind::Bound`].
+    pub(crate) fn lower_const_param(&self, hir_id: hir::HirId, param_ty: Ty<'tcx>) -> Const<'tcx> {
         let tcx = self.tcx();
         match tcx.named_bound_var(hir_id) {
             Some(rbv::ResolvedArg::EarlyBound(def_id)) => {
@@ -2103,16 +2164,14 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         }
     }
 
-    /// Parses the programmer's textual representation of a type into our
-    /// internal notion of a type.
-    pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
-        self.ast_ty_to_ty_inner(ast_ty, false, false)
+    /// Lower a type from the HIR to our internal notion of a type.
+    pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
+        self.lower_ty_common(hir_ty, false, false)
     }
 
-    /// Parses the programmer's textual representation of a type into our
-    /// internal notion of a type. This is meant to be used within a path.
-    pub fn ast_ty_to_ty_in_path(&self, ast_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
-        self.ast_ty_to_ty_inner(ast_ty, false, true)
+    /// Lower a type inside of a path from the HIR to our internal notion of a type.
+    pub fn lower_ty_in_path(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
+        self.lower_ty_common(hir_ty, false, true)
     }
 
     fn check_delegation_constraints(&self, sig_id: DefId, span: Span, emit: bool) -> bool {
@@ -2179,7 +2238,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         error_occured
     }
 
-    fn ty_from_delegation(
+    fn lower_delegation_ty(
         &self,
         sig_id: DefId,
         idx: hir::InferDelegationKind,
@@ -2213,8 +2272,8 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             sig.instantiate_identity()
         };
 
-        // Bound vars are also inherited from `sig_id`. They will be
-        // rebinded later in `ty_of_fn`.
+        // Bound vars are also inherited from `sig_id`.
+        // They will be rebound later in `lower_fn_ty`.
         let sig = sig.skip_binder();
 
         match idx {
@@ -2223,66 +2282,72 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         }
     }
 
-    /// Turns a `hir::Ty` into a `Ty`. For diagnostics' purposes we keep track of whether trait
-    /// objects are borrowed like `&dyn Trait` to avoid emitting redundant errors.
+    /// Lower a type from the HIR to our internal notion of a type given some extra data for diagnostics.
+    ///
+    /// Extra diagnostic data:
+    ///
+    /// 1. `borrowed`: Whether trait object types are borrowed like in `&dyn Trait`.
+    ///    Used to avoid emitting redundant errors.
+    /// 2. `in_path`: Whether the type appears inside of a path.
+    ///    Used to provide correct diagnostics for bare trait object types.
     #[instrument(level = "debug", skip(self), ret)]
-    fn ast_ty_to_ty_inner(
-        &self,
-        ast_ty: &hir::Ty<'tcx>,
-        borrowed: bool,
-        in_path: bool,
-    ) -> Ty<'tcx> {
+    fn lower_ty_common(&self, hir_ty: &hir::Ty<'tcx>, borrowed: bool, in_path: bool) -> Ty<'tcx> {
         let tcx = self.tcx();
 
-        let result_ty = match &ast_ty.kind {
+        let result_ty = match &hir_ty.kind {
             hir::TyKind::InferDelegation(sig_id, idx) => {
-                self.ty_from_delegation(*sig_id, *idx, ast_ty.span)
-            }
-            hir::TyKind::Slice(ty) => Ty::new_slice(tcx, self.ast_ty_to_ty(ty)),
-            hir::TyKind::Ptr(mt) => {
-                Ty::new_ptr(tcx, ty::TypeAndMut { ty: self.ast_ty_to_ty(mt.ty), mutbl: mt.mutbl })
+                self.lower_delegation_ty(*sig_id, *idx, hir_ty.span)
             }
+            hir::TyKind::Slice(ty) => Ty::new_slice(tcx, self.lower_ty(ty)),
+            hir::TyKind::Ptr(mt) => Ty::new_ptr(tcx, self.lower_ty(mt.ty), mt.mutbl),
             hir::TyKind::Ref(region, mt) => {
-                let r = self.ast_region_to_region(region, None);
+                let r = self.lower_lifetime(region, None);
                 debug!(?r);
-                let t = self.ast_ty_to_ty_inner(mt.ty, true, false);
-                Ty::new_ref(tcx, r, ty::TypeAndMut { ty: t, mutbl: mt.mutbl })
+                let t = self.lower_ty_common(mt.ty, true, false);
+                Ty::new_ref(tcx, r, t, mt.mutbl)
             }
             hir::TyKind::Never => tcx.types.never,
             hir::TyKind::Tup(fields) => {
-                Ty::new_tup_from_iter(tcx, fields.iter().map(|t| self.ast_ty_to_ty(t)))
+                Ty::new_tup_from_iter(tcx, fields.iter().map(|t| self.lower_ty(t)))
             }
             hir::TyKind::AnonAdt(item_id) => {
+                let _guard = debug_span!("AnonAdt");
+
                 let did = item_id.owner_id.def_id;
                 let adt_def = tcx.adt_def(did);
-                let generics = tcx.generics_of(did);
 
-                debug!("ast_ty_to_ty_inner(AnonAdt): generics={:?}", generics);
                 let args = ty::GenericArgs::for_item(tcx, did.to_def_id(), |param, _| {
                     tcx.mk_param_from_def(param)
                 });
-                debug!("ast_ty_to_ty_inner(AnonAdt): args={:?}", args);
+                debug!(?args);
 
                 Ty::new_adt(tcx, adt_def, tcx.mk_args(args))
             }
             hir::TyKind::BareFn(bf) => {
-                require_c_abi_if_c_variadic(tcx, bf.decl, bf.abi, ast_ty.span);
+                require_c_abi_if_c_variadic(tcx, bf.decl, bf.abi, hir_ty.span);
 
                 Ty::new_fn_ptr(
                     tcx,
-                    self.ty_of_fn(ast_ty.hir_id, bf.unsafety, bf.abi, bf.decl, None, Some(ast_ty)),
+                    self.lower_fn_ty(
+                        hir_ty.hir_id,
+                        bf.unsafety,
+                        bf.abi,
+                        bf.decl,
+                        None,
+                        Some(hir_ty),
+                    ),
                 )
             }
             hir::TyKind::TraitObject(bounds, lifetime, repr) => {
-                self.maybe_lint_bare_trait(ast_ty, in_path);
+                self.maybe_lint_bare_trait(hir_ty, in_path);
                 let repr = match repr {
                     TraitObjectSyntax::Dyn | TraitObjectSyntax::None => ty::Dyn,
                     TraitObjectSyntax::DynStar => ty::DynStar,
                 };
 
-                self.conv_object_ty_poly_trait_ref(
-                    ast_ty.span,
-                    ast_ty.hir_id,
+                self.lower_trait_object_ty(
+                    hir_ty.span,
+                    hir_ty.hir_id,
                     bounds,
                     lifetime,
                     borrowed,
@@ -2291,8 +2356,8 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             }
             hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
                 debug!(?maybe_qself, ?path);
-                let opt_self_ty = maybe_qself.as_ref().map(|qself| self.ast_ty_to_ty(qself));
-                self.res_to_ty(opt_self_ty, path, ast_ty.hir_id, false)
+                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(item_id, lifetimes, in_trait) => {
                 let opaque_ty = tcx.hir().item(item_id);
@@ -2308,21 +2373,21 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                         } else {
                             local_def_id.to_def_id()
                         };
-                        self.impl_trait_ty_to_ty(def_id, lifetimes, in_trait)
+                        self.lower_opaque_ty(def_id, lifetimes, in_trait)
                     }
                     ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
                 }
             }
             hir::TyKind::Path(hir::QPath::TypeRelative(qself, segment)) => {
                 debug!(?qself, ?segment);
-                let ty = self.ast_ty_to_ty_inner(qself, false, true);
-                self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, qself, segment, false)
+                let ty = self.lower_ty_common(qself, false, true);
+                self.lower_assoc_path(hir_ty.hir_id, hir_ty.span, ty, qself, segment, false)
                     .map(|(ty, _, _)| ty)
                     .unwrap_or_else(|guar| Ty::new_error(tcx, guar))
             }
             &hir::TyKind::Path(hir::QPath::LangItem(lang_item, span)) => {
                 let def_id = tcx.require_lang_item(lang_item, Some(span));
-                let (args, _) = self.create_args_for_ast_path(
+                let (args, _) = self.lower_generic_args_of_path(
                     span,
                     def_id,
                     &[],
@@ -2340,7 +2405,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                     }
                 };
 
-                Ty::new_array_with_const_len(tcx, self.ast_ty_to_ty(ty), length)
+                Ty::new_array_with_const_len(tcx, self.lower_ty(ty), length)
             }
             hir::TyKind::Typeof(e) => tcx.type_of(e.def_id).instantiate_identity(),
             hir::TyKind::Infer => {
@@ -2348,28 +2413,29 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                 // values in an ExprKind::Closure, or as
                 // the type of local variables. Both of these cases are
                 // handled specially and will not descend into this routine.
-                self.ty_infer(None, ast_ty.span)
+                self.ty_infer(None, hir_ty.span)
             }
             hir::TyKind::Err(guar) => Ty::new_error(tcx, *guar),
         };
 
-        self.record_ty(ast_ty.hir_id, result_ty, ast_ty.span);
+        self.record_ty(hir_ty.hir_id, result_ty, hir_ty.span);
         result_ty
     }
 
-    #[instrument(level = "debug", skip(self), ret)]
-    fn impl_trait_ty_to_ty(
+    /// 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!("impl_trait_ty_to_ty(def_id={:?}, lifetimes={:?})", def_id, lifetimes);
+        debug!(?def_id, ?lifetimes);
         let tcx = self.tcx();
 
         let generics = tcx.generics_of(def_id);
+        debug!(?generics);
 
-        debug!("impl_trait_ty_to_ty: generics={:?}", generics);
         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
@@ -2390,12 +2456,12 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                         &lifetimes[i]
                     )
                 };
-                self.ast_region_to_region(lifetime, None).into()
+                self.lower_lifetime(lifetime, None).into()
             } else {
                 tcx.mk_param_from_def(param)
             }
         });
-        debug!("impl_trait_ty_to_ty: args={:?}", args);
+        debug!(?args);
 
         if in_trait {
             Ty::new_projection(tcx, def_id, args)
@@ -2404,18 +2470,19 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         }
     }
 
-    pub fn ty_of_arg(&self, ty: &hir::Ty<'tcx>, expected_ty: Option<Ty<'tcx>>) -> Ty<'tcx> {
+    pub fn lower_arg_ty(&self, ty: &hir::Ty<'tcx>, expected_ty: Option<Ty<'tcx>>) -> Ty<'tcx> {
         match ty.kind {
             hir::TyKind::Infer if let Some(expected_ty) = expected_ty => {
                 self.record_ty(ty.hir_id, expected_ty, ty.span);
                 expected_ty
             }
-            _ => self.ast_ty_to_ty(ty),
+            _ => self.lower_ty(ty),
         }
     }
 
+    /// Lower a function type from the HIR to our internal notion of a function signature.
     #[instrument(level = "debug", skip(self, hir_id, unsafety, abi, decl, generics, hir_ty), ret)]
-    pub fn ty_of_fn(
+    pub fn lower_fn_ty(
         &self,
         hir_id: hir::HirId,
         unsafety: hir::Unsafety,
@@ -2448,7 +2515,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             .enumerate()
             .map(|(i, a)| {
                 if let hir::TyKind::Infer = a.kind
-                    && !self.allow_ty_infer()
+                    && !self.allow_infer()
                 {
                     if let Some(suggested_ty) =
                         self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i))
@@ -2464,14 +2531,14 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
 
                 // Only visit the type looking for `_` if we didn't fix the type above
                 visitor.visit_ty(a);
-                self.ty_of_arg(a, None)
+                self.lower_arg_ty(a, None)
             })
             .collect();
 
         let output_ty = match decl.output {
             hir::FnRetTy::Return(output) => {
                 if let hir::TyKind::Infer = output.kind
-                    && !self.allow_ty_infer()
+                    && !self.allow_infer()
                     && let Some(suggested_ty) =
                         self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, None)
                 {
@@ -2479,7 +2546,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                     Ty::new_error_with_message(self.tcx(), output.span, suggested_ty.to_string())
                 } else {
                     visitor.visit_ty(output);
-                    self.ast_ty_to_ty(output)
+                    self.lower_ty(output)
                 }
             }
             hir::FnRetTy::DefaultReturn(..) => Ty::new_unit(tcx),
@@ -2490,10 +2557,10 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, unsafety, abi);
         let bare_fn_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars);
 
-        if !self.allow_ty_infer() && !(visitor.0.is_empty() && infer_replacements.is_empty()) {
+        if !self.allow_infer() && !(visitor.0.is_empty() && infer_replacements.is_empty()) {
             // We always collect the spans for placeholder types when evaluating `fn`s, but we
             // only want to emit an error complaining about them if infer types (`_`) are not
-            // allowed. `allow_ty_infer` gates this behavior. We check for the presence of
+            // allowed. `allow_infer` gates this behavior. We check for the presence of
             // `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`.
 
             let mut diag = crate::collect::placeholder_type_error_diag(
@@ -2562,8 +2629,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         };
         let i = tcx.parent_hir_node(fn_hir_id).expect_item().expect_impl();
 
-        let trait_ref =
-            self.instantiate_mono_trait_ref(i.of_trait.as_ref()?, self.ast_ty_to_ty(i.self_ty));
+        let trait_ref = self.lower_impl_trait_ref(i.of_trait.as_ref()?, self.lower_ty(i.self_ty));
 
         let assoc = tcx.associated_items(trait_ref.def_id).find_by_name_and_kind(
             tcx,
@@ -2620,7 +2686,9 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
     }
 
     /// Given the bounds on an object, determines what single region bound (if any) we can
-    /// use to summarize this type. The basic idea is that we will use the bound the user
+    /// use to summarize this type.
+    ///
+    /// The basic idea is that we will use the bound the user
     /// provided, if they provided one, and otherwise search the supertypes of trait bounds
     /// for region bounds. It may be that we can derive no bound at all, in which case
     /// we return `None`.
diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs
index 70c60e39941..b5b3a9131c5 100644
--- a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs
@@ -1,6 +1,6 @@
-use crate::astconv::{GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds};
 use crate::bounds::Bounds;
 use crate::errors::TraitObjectDeclaredWithNoTraits;
+use crate::hir_ty_lowering::{GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds};
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_errors::{codes::*, struct_span_code_err};
 use rustc_hir as hir;
@@ -11,14 +11,16 @@ use rustc_middle::ty::{self, Ty};
 use rustc_middle::ty::{DynKind, ToPredicate};
 use rustc_span::Span;
 use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
-use rustc_trait_selection::traits::{self, astconv_object_safety_violations};
+use rustc_trait_selection::traits::{self, hir_ty_lowering_object_safety_violations};
 
 use smallvec::{smallvec, SmallVec};
 
-use super::AstConv;
+use super::HirTyLowerer;
 
-impl<'tcx> dyn AstConv<'tcx> + '_ {
-    pub(super) fn conv_object_ty_poly_trait_ref(
+impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
+    /// Lower a trait object type from the HIR to our internal notion of a type.
+    #[instrument(level = "debug", skip_all, ret)]
+    pub(super) fn lower_trait_object_ty(
         &self,
         span: Span,
         hir_id: hir::HirId,
@@ -37,11 +39,11 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                 correct:
                     Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }),
                 ..
-            } = self.instantiate_poly_trait_ref(
+            } = self.lower_poly_trait_ref(
                 &trait_bound.trait_ref,
                 trait_bound.span,
                 ty::BoundConstness::NotConst,
-                ty::ImplPolarity::Positive,
+                ty::PredicatePolarity::Positive,
                 dummy_self,
                 &mut bounds,
                 // True so we don't populate `bounds` with associated type bounds, even
@@ -58,7 +60,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             let bound_pred = pred.kind();
             match bound_pred.skip_binder() {
                 ty::ClauseKind::Trait(trait_pred) => {
-                    assert_eq!(trait_pred.polarity, ty::ImplPolarity::Positive);
+                    assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive);
                     trait_bounds.push((bound_pred.rebind(trait_pred.trait_ref), span));
                 }
                 ty::ClauseKind::Projection(proj) => {
@@ -133,7 +135,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         // to avoid ICEs.
         for item in &regular_traits {
             let object_safety_violations =
-                astconv_object_safety_violations(tcx, item.trait_ref().def_id());
+                hir_ty_lowering_object_safety_violations(tcx, item.trait_ref().def_id());
             if !object_safety_violations.is_empty() {
                 let reported = report_object_safety_error(
                     tcx,
@@ -156,7 +158,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         for (base_trait_ref, span) in regular_traits_refs_spans {
             let base_pred: ty::Predicate<'tcx> = base_trait_ref.to_predicate(tcx);
             for pred in traits::elaborate(tcx, [base_pred]).filter_only_self() {
-                debug!("conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", pred);
+                debug!("observing object predicate `{pred:?}`");
 
                 let bound_predicate = pred.kind();
                 match bound_predicate.skip_binder() {
@@ -231,7 +233,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             def_ids.retain(|def_id| !tcx.generics_require_sized_self(def_id));
         }
 
-        self.complain_about_missing_associated_types(
+        self.complain_about_missing_assoc_tys(
             associated_types,
             potential_assoc_types,
             hir_trait_bounds,
@@ -243,8 +245,8 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         // the bounds
         let mut duplicates = FxHashSet::default();
         auto_traits.retain(|i| duplicates.insert(i.trait_ref().def_id()));
-        debug!("regular_traits: {:?}", regular_traits);
-        debug!("auto_traits: {:?}", auto_traits);
+        debug!(?regular_traits);
+        debug!(?auto_traits);
 
         // Erase the `dummy_self` (`trait_object_dummy_self`) used above.
         let existential_trait_refs = regular_traits.iter().map(|i| {
@@ -362,11 +364,11 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
 
         // Use explicitly-specified region bound.
         let region_bound = if !lifetime.is_elided() {
-            self.ast_region_to_region(lifetime, None)
+            self.lower_lifetime(lifetime, None)
         } else {
             self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| {
                 if tcx.named_bound_var(lifetime.hir_id).is_some() {
-                    self.ast_region_to_region(lifetime, None)
+                    self.lower_lifetime(lifetime, None)
                 } else {
                     self.re_infer(None, span).unwrap_or_else(|| {
                         let err = struct_span_code_err!(
@@ -389,10 +391,8 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                 }
             })
         };
-        debug!("region_bound: {:?}", region_bound);
+        debug!(?region_bound);
 
-        let ty = Ty::new_dynamic(tcx, existential_predicates, region_bound, representation);
-        debug!("trait_object_type: {:?}", ty);
-        ty
+        Ty::new_dynamic(tcx, existential_predicates, region_bound, representation)
     }
 }
diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
index 2a9101b3808..7014b23ff07 100644
--- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
@@ -68,7 +68,7 @@ fn diagnostic_hir_wf_check<'tcx>(
             let infcx = self.tcx.infer_ctxt().build();
             let ocx = ObligationCtxt::new(&infcx);
 
-            let tcx_ty = self.icx.to_ty(ty);
+            let tcx_ty = self.icx.lower_ty(ty);
             // This visitor can walk into binders, resulting in the `tcx_ty` to
             // potentially reference escaping bound variables. We simply erase
             // those here.
@@ -163,6 +163,16 @@ fn diagnostic_hir_wf_check<'tcx>(
                 kind: hir::GenericParamKind::Type { default: Some(ty), .. },
                 ..
             }) => vec![*ty],
+            hir::Node::AnonConst(_)
+                if let Some(const_param_id) =
+                    tcx.hir().opt_const_param_default_param_def_id(hir_id)
+                    && let hir::Node::GenericParam(hir::GenericParam {
+                        kind: hir::GenericParamKind::Const { ty, .. },
+                        ..
+                    }) = tcx.hir_node_by_def_id(const_param_id) =>
+            {
+                vec![*ty]
+            }
             ref node => bug!("Unexpected node {:?}", node),
         },
         WellFormedLoc::Param { function: _, param_idx } => {
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 5fe8d1fe586..3ec5894700f 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -30,8 +30,8 @@ several major phases:
 The type checker is defined into various submodules which are documented
 independently:
 
-- astconv: converts the AST representation of types
-  into the `ty` representation.
+- hir_ty_lowering: lowers type-system entities from the [HIR][hir] to the
+  [`rustc_middle::ty`] representation.
 
 - collect: computes the types of each top-level item and enters them into
   the `tcx.types` table for later use.
@@ -82,11 +82,11 @@ extern crate rustc_middle;
 // These are used by Clippy.
 pub mod check;
 
-pub mod astconv;
 pub mod autoderef;
 mod bounds;
 mod check_unused;
 mod coherence;
+pub mod hir_ty_lowering;
 // FIXME: This module shouldn't be public.
 pub mod collect;
 mod constrained_generic_params;
@@ -211,12 +211,20 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
     Ok(())
 }
 
-/// A quasi-deprecated helper used in rustdoc and clippy to get
-/// the type from a HIR node.
-pub fn hir_ty_to_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
+/// Lower a [`hir::Ty`] to a [`Ty`].
+///
+/// <div class="warning">
+///
+/// This function is **quasi-deprecated**. It can cause ICEs if called inside of a body
+/// (of a function or constant) and especially if it contains inferred types (`_`).
+///
+/// It's used in rustdoc and Clippy.
+///
+/// </div>
+pub fn lower_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
     // In case there are any projections, etc., find the "environment"
     // def-ID that will be used to determine the traits/predicates in
     // scope. This is derived from the enclosing item-like thing.
     let env_def_id = tcx.hir().get_parent_item(hir_ty.hir_id);
-    collect::ItemCtxt::new(tcx, env_def_id.def_id).to_ty(hir_ty)
+    collect::ItemCtxt::new(tcx, env_def_id.def_id).lower_ty(hir_ty)
 }
diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
index 0f5ba26337a..dcab571eedf 100644
--- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
@@ -435,6 +435,22 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
         &self,
         num_params_to_take: usize,
     ) -> String {
+        let is_in_a_method_call = self
+            .tcx
+            .hir()
+            .parent_iter(self.path_segment.hir_id)
+            .skip(1)
+            .find_map(|(_, node)| match node {
+                hir::Node::Expr(expr) => Some(expr),
+                _ => None,
+            })
+            .is_some_and(|expr| {
+                matches!(
+                    expr.kind,
+                    hir::ExprKind::MethodCall(hir::PathSegment { args: Some(_), .. }, ..)
+                )
+            });
+
         let fn_sig = self.tcx.hir().get_if_local(self.def_id).and_then(hir::Node::fn_sig);
         let is_used_in_input = |def_id| {
             fn_sig.is_some_and(|fn_sig| {
@@ -453,14 +469,17 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
             .skip(self.params_offset + self.num_provided_type_or_const_args())
             .take(num_params_to_take)
             .map(|param| match param.kind {
-                // This is being inferred from the item's inputs, no need to set it.
-                ty::GenericParamDefKind::Type { .. } if is_used_in_input(param.def_id) => {
-                    "_".to_string()
+                // If it's in method call (turbofish), it might be inferred from the expression (e.g. `.collect::<Vec<_>>()`)
+                // If it is being inferred from the item's inputs, no need to set it.
+                ty::GenericParamDefKind::Type { .. }
+                    if is_in_a_method_call || is_used_in_input(param.def_id) =>
+                {
+                    "_"
                 }
-                _ => param.name.to_string(),
+                _ => param.name.as_str(),
             })
-            .collect::<Vec<_>>()
-            .join(", ")
+            .intersperse(", ")
+            .collect()
     }
 
     fn get_unbound_associated_types(&self) -> Vec<String> {
diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs
index 580cdb4a3a2..28c86d8019e 100644
--- a/compiler/rustc_hir_analysis/src/variance/constraints.rs
+++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs
@@ -1,6 +1,6 @@
 //! Constraint construction and representation
 //!
-//! The second pass over the AST determines the set of constraints.
+//! The second pass over the HIR determines the set of constraints.
 //! We walk the set of items and, for each member, generate new constraints.
 
 use hir::def_id::{DefId, LocalDefId};
@@ -253,8 +253,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 self.add_constraints_from_ty(current, typ, variance);
             }
 
-            ty::RawPtr(ref mt) => {
-                self.add_constraints_from_mt(current, mt, variance);
+            ty::RawPtr(ty, mutbl) => {
+                self.add_constraints_from_mt(current, &ty::TypeAndMut { ty, mutbl }, variance);
             }
 
             ty::Tuple(subtys) => {
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 34c24583947..36f59b4ac2e 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -113,7 +113,7 @@ impl<'a> State<'a> {
             // `hir_map` to reconstruct their full structure for pretty
             // printing.
             Node::Ctor(..) => panic!("cannot print isolated Ctor"),
-            Node::Local(a) => self.print_local_decl(a),
+            Node::LetStmt(a) => self.print_local_decl(a),
             Node::Crate(..) => panic!("cannot print Crate"),
             Node::WhereBoundPredicate(pred) => {
                 self.print_formal_generic_params(pred.bound_generic_params);
@@ -1387,7 +1387,7 @@ impl<'a> State<'a> {
                 // Print `}`:
                 self.bclose_maybe_open(expr.span, true);
             }
-            hir::ExprKind::Let(&hir::Let { pat, ty, init, .. }) => {
+            hir::ExprKind::Let(&hir::LetExpr { pat, ty, init, .. }) => {
                 self.print_let(pat, ty, init);
             }
             hir::ExprKind::If(test, blk, elseopt) => {
@@ -1544,7 +1544,7 @@ impl<'a> State<'a> {
         self.end()
     }
 
-    fn print_local_decl(&mut self, loc: &hir::Local<'_>) {
+    fn print_local_decl(&mut self, loc: &hir::LetStmt<'_>) {
         self.print_pat(loc.pat);
         if let Some(ty) = loc.ty {
             self.word_space(":");
@@ -1808,6 +1808,12 @@ impl<'a> State<'a> {
                     self.pclose();
                 }
             }
+            PatKind::Deref(inner) => {
+                self.word("deref!");
+                self.popen();
+                self.print_pat(inner);
+                self.pclose();
+            }
             PatKind::Ref(inner, mutbl) => {
                 let is_range_inner = matches!(inner.kind, PatKind::Range(..));
                 self.word("&");
diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index 220da19a29d..0ca958302f7 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -103,6 +103,8 @@ hir_typeck_no_associated_item = no {$item_kind} named `{$item_name}` found for {
     *[other] {" "}in the current scope
 }
 
+hir_typeck_note_caller_chooses_ty_for_ty_param = the caller chooses a type for `{$ty_param_name}` which can be different from `{$found_ty}`
+
 hir_typeck_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide
 
 hir_typeck_option_result_asref = use `{$def_path}::as_ref` to convert `{$expected_ty}` to `{$expr_ty}`
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index 4b3359858f1..9b7db9e4c8e 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -317,7 +317,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         err.note("`if` expressions without `else` evaluate to `()`");
         err.help("consider adding an `else` block that evaluates to the expected type");
         *error = true;
-        if let ExprKind::Let(hir::Let { span, pat, init, .. }) = cond_expr.kind
+        if let ExprKind::Let(hir::LetExpr { span, pat, init, .. }) = cond_expr.kind
             && let ExprKind::Block(block, _) = then_expr.kind
             // Refutability checks occur on the MIR, so we approximate it here by checking
             // if we have an enum with a single variant or a struct in the pattern.
@@ -408,7 +408,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
             }
         }
-        if let hir::Node::Local(hir::Local { ty: Some(_), pat, .. }) = node {
+        if let hir::Node::LetStmt(hir::LetStmt { ty: Some(_), pat, .. }) = node {
             return Some((pat.span, "expected because of this assignment".to_string()));
         }
         None
@@ -645,7 +645,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 for ty in [first_ty, second_ty] {
                     for (clause, _) in self
                         .tcx
-                        .explicit_item_bounds(rpit_def_id)
+                        .explicit_item_super_predicates(rpit_def_id)
                         .iter_instantiated_copied(self.tcx, args)
                     {
                         let pred = clause.kind().rebind(match clause.kind().skip_binder() {
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index b8d1eaee812..c948b6343b7 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -128,7 +128,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             | ty::Float(_)
             | ty::Array(..)
             | ty::CoroutineWitness(..)
-            | ty::RawPtr(_)
+            | ty::RawPtr(_, _)
             | ty::Ref(..)
             | ty::FnDef(..)
             | ty::FnPtr(..)
@@ -332,13 +332,9 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 let mut sugg = None;
                 let mut sugg_mutref = false;
                 if let ty::Ref(reg, cast_ty, mutbl) = *self.cast_ty.kind() {
-                    if let ty::RawPtr(TypeAndMut { ty: expr_ty, .. }) = *self.expr_ty.kind()
+                    if let ty::RawPtr(expr_ty, _) = *self.expr_ty.kind()
                         && fcx.can_coerce(
-                            Ty::new_ref(
-                                fcx.tcx,
-                                fcx.tcx.lifetimes.re_erased,
-                                TypeAndMut { ty: expr_ty, mutbl },
-                            ),
+                            Ty::new_ref(fcx.tcx, fcx.tcx.lifetimes.re_erased, expr_ty, mutbl),
                             self.cast_ty,
                         )
                     {
@@ -346,14 +342,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                     } else if let ty::Ref(expr_reg, expr_ty, expr_mutbl) = *self.expr_ty.kind()
                         && expr_mutbl == Mutability::Not
                         && mutbl == Mutability::Mut
-                        && fcx.can_coerce(
-                            Ty::new_ref(
-                                fcx.tcx,
-                                expr_reg,
-                                TypeAndMut { ty: expr_ty, mutbl: Mutability::Mut },
-                            ),
-                            self.cast_ty,
-                        )
+                        && fcx.can_coerce(Ty::new_mut_ref(fcx.tcx, expr_reg, expr_ty), self.cast_ty)
                     {
                         sugg_mutref = true;
                     }
@@ -361,19 +350,15 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                     if !sugg_mutref
                         && sugg == None
                         && fcx.can_coerce(
-                            Ty::new_ref(fcx.tcx, reg, TypeAndMut { ty: self.expr_ty, mutbl }),
+                            Ty::new_ref(fcx.tcx, reg, self.expr_ty, mutbl),
                             self.cast_ty,
                         )
                     {
                         sugg = Some((format!("&{}", mutbl.prefix_str()), false));
                     }
-                } else if let ty::RawPtr(TypeAndMut { mutbl, .. }) = *self.cast_ty.kind()
+                } else if let ty::RawPtr(_, mutbl) = *self.cast_ty.kind()
                     && fcx.can_coerce(
-                        Ty::new_ref(
-                            fcx.tcx,
-                            fcx.tcx.lifetimes.re_erased,
-                            TypeAndMut { ty: self.expr_ty, mutbl },
-                        ),
+                        Ty::new_ref(fcx.tcx, fcx.tcx.lifetimes.re_erased, self.expr_ty, mutbl),
                         self.cast_ty,
                     )
                 {
@@ -868,7 +853,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 // from a region pointer to a vector.
 
                 // Coerce to a raw pointer so that we generate AddressOf in MIR.
-                let array_ptr_type = Ty::new_ptr(fcx.tcx, m_expr);
+                let array_ptr_type = Ty::new_ptr(fcx.tcx, m_expr.ty, m_expr.mutbl);
                 fcx.coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None)
                     .unwrap_or_else(|_| {
                         bug!(
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 6e30cb02245..40555bf14eb 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -5,7 +5,7 @@ use super::{check_fn, CoroutineTypes, Expectation, FnCtxt};
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
-use rustc_hir_analysis::astconv::AstConv;
+use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes};
 use rustc_infer::infer::{InferOk, InferResult};
@@ -329,7 +329,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     expected_ty,
                     closure_kind,
                     self.tcx
-                        .explicit_item_bounds(def_id)
+                        .explicit_item_super_predicates(def_id)
                         .iter_instantiated_copied(self.tcx, args)
                         .map(|(c, s)| (c.as_predicate(), s)),
                 ),
@@ -784,7 +784,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         decl: &hir::FnDecl<'tcx>,
         closure_kind: hir::ClosureKind,
     ) -> ty::PolyFnSig<'tcx> {
-        let astconv = self.astconv();
+        let lowerer = self.lowerer();
 
         trace!("decl = {:#?}", decl);
         debug!(?closure_kind);
@@ -793,9 +793,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let bound_vars = self.tcx.late_bound_vars(hir_id);
 
         // First, convert the types that the user supplied (if any).
-        let supplied_arguments = decl.inputs.iter().map(|a| astconv.ast_ty_to_ty(a));
+        let supplied_arguments = decl.inputs.iter().map(|a| lowerer.lower_ty(a));
         let supplied_return = match decl.output {
-            hir::FnRetTy::Return(ref output) => astconv.ast_ty_to_ty(output),
+            hir::FnRetTy::Return(ref output) => lowerer.lower_ty(output),
             hir::FnRetTy::DefaultReturn(_) => match closure_kind {
                 // In the case of the async block that we create for a function body,
                 // we expect the return type of the block to match that of the enclosing
@@ -813,7 +813,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         // easily (and locally) prove that we
                         // *have* reported an
                         // error. --nikomatsakis
-                        astconv.ty_infer(None, decl.output.span())
+                        lowerer.ty_infer(None, decl.output.span())
                     })
                 }
                 // All `gen {}` and `async gen {}` must return unit.
@@ -832,7 +832,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 | hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(_))
                 | hir::ClosureKind::Closure
                 | hir::ClosureKind::CoroutineClosure(_) => {
-                    astconv.ty_infer(None, decl.output.span())
+                    lowerer.ty_infer(None, decl.output.span())
                 }
             },
         };
@@ -906,7 +906,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => self
                 .tcx
-                .explicit_item_bounds(def_id)
+                .explicit_item_super_predicates(def_id)
                 .iter_instantiated_copied(self.tcx, args)
                 .find_map(|(p, s)| get_future_output(p.as_predicate(), s))?,
             ty::Error(_) => return Some(ret_ty),
@@ -989,17 +989,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         decl: &hir::FnDecl<'tcx>,
         guar: ErrorGuaranteed,
     ) -> ty::PolyFnSig<'tcx> {
-        let astconv = self.astconv();
+        let lowerer = self.lowerer();
         let err_ty = Ty::new_error(self.tcx, guar);
 
         let supplied_arguments = decl.inputs.iter().map(|a| {
             // Convert the types that the user supplied (if any), but ignore them.
-            astconv.ast_ty_to_ty(a);
+            lowerer.lower_ty(a);
             err_ty
         });
 
         if let hir::FnRetTy::Return(ref output) = decl.output {
-            astconv.ast_ty_to_ty(output);
+            lowerer.lower_ty(output);
         }
 
         let result = ty::Binder::dummy(self.tcx.mk_fn_sig(
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 792359c9dda..3328177634b 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -41,7 +41,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::Expr;
-use rustc_hir_analysis::astconv::AstConv;
+use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult};
 use rustc_infer::traits::TraitEngine;
@@ -55,7 +55,7 @@ use rustc_middle::ty::adjustment::{
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::relate::RelateResult;
 use rustc_middle::ty::visit::TypeVisitableExt;
-use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeAndMut};
+use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt};
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::sym;
 use rustc_span::DesugaringKind;
@@ -222,8 +222,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
 
         // Examine the supertype and consider auto-borrowing.
         match *b.kind() {
-            ty::RawPtr(mt_b) => {
-                return self.coerce_unsafe_ptr(a, b, mt_b.mutbl);
+            ty::RawPtr(_, b_mutbl) => {
+                return self.coerce_unsafe_ptr(a, b, b_mutbl);
             }
             ty::Ref(r_b, _, mutbl_b) => {
                 return self.coerce_borrowed_pointer(a, b, r_b, mutbl_b);
@@ -440,10 +440,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             let derefd_ty_a = Ty::new_ref(
                 self.tcx,
                 r,
-                TypeAndMut {
-                    ty: referent_ty,
-                    mutbl: mutbl_b, // [1] above
-                },
+                referent_ty,
+                mutbl_b, // [1] above
             );
             match self.unify(derefd_ty_a, b) {
                 Ok(ok) => {
@@ -558,22 +556,18 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                     Adjustment { kind: Adjust::Deref(None), target: ty_a },
                     Adjustment {
                         kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mutbl)),
-                        target: Ty::new_ref(
-                            self.tcx,
-                            r_borrow,
-                            ty::TypeAndMut { mutbl: mutbl_b, ty: ty_a },
-                        ),
+                        target: Ty::new_ref(self.tcx, r_borrow, ty_a, mutbl_b),
                     },
                 ))
             }
-            (&ty::Ref(_, ty_a, mt_a), &ty::RawPtr(ty::TypeAndMut { mutbl: mt_b, .. })) => {
+            (&ty::Ref(_, ty_a, mt_a), &ty::RawPtr(_, mt_b)) => {
                 coerce_mutbls(mt_a, mt_b)?;
 
                 Some((
                     Adjustment { kind: Adjust::Deref(None), target: ty_a },
                     Adjustment {
                         kind: Adjust::Borrow(AutoBorrow::RawPtr(mt_b)),
-                        target: Ty::new_ptr(self.tcx, ty::TypeAndMut { mutbl: mt_b, ty: ty_a }),
+                        target: Ty::new_ptr(self.tcx, ty_a, mt_b),
                     },
                 ))
             }
@@ -984,13 +978,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
 
         let (is_ref, mt_a) = match *a.kind() {
             ty::Ref(_, ty, mutbl) => (true, ty::TypeAndMut { ty, mutbl }),
-            ty::RawPtr(mt) => (false, mt),
+            ty::RawPtr(ty, mutbl) => (false, ty::TypeAndMut { ty, mutbl }),
             _ => return self.unify_and(a, b, identity),
         };
         coerce_mutbls(mt_a.mutbl, mutbl_b)?;
 
         // Check that the types which they point at are compatible.
-        let a_unsafe = Ty::new_ptr(self.tcx, ty::TypeAndMut { mutbl: mutbl_b, ty: mt_a.ty });
+        let a_unsafe = Ty::new_ptr(self.tcx, mt_a.ty, mutbl_b);
         // Although references and unsafe ptrs have the same
         // representation, we still register an Adjust::DerefRef so that
         // regionck knows that the region for `a` must be valid here.
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 67ff412651c..564de4ab9e7 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -299,8 +299,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return false;
         };
         let (init_ty_hir_id, init) = match self.tcx.parent_hir_node(pat.hir_id) {
-            hir::Node::Local(hir::Local { ty: Some(ty), init, .. }) => (ty.hir_id, *init),
-            hir::Node::Local(hir::Local { init: Some(init), .. }) => (init.hir_id, Some(*init)),
+            hir::Node::LetStmt(hir::LetStmt { ty: Some(ty), init, .. }) => (ty.hir_id, *init),
+            hir::Node::LetStmt(hir::LetStmt { init: Some(init), .. }) => (init.hir_id, Some(*init)),
             _ => return false,
         };
         let Some(init_ty) = self.node_ty_opt(init_ty_hir_id) else {
@@ -678,7 +678,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         error: Option<TypeError<'tcx>>,
     ) {
         match (self.tcx.parent_hir_node(expr.hir_id), error) {
-            (hir::Node::Local(hir::Local { ty: Some(ty), init: Some(init), .. }), _)
+            (hir::Node::LetStmt(hir::LetStmt { ty: Some(ty), init: Some(init), .. }), _)
                 if init.hir_id == expr.hir_id =>
             {
                 // Point at `let` assignment type.
@@ -724,11 +724,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             primary_span = pat.span;
                             secondary_span = pat.span;
                             match self.tcx.parent_hir_node(pat.hir_id) {
-                                hir::Node::Local(hir::Local { ty: Some(ty), .. }) => {
+                                hir::Node::LetStmt(hir::LetStmt { ty: Some(ty), .. }) => {
                                     primary_span = ty.span;
                                     post_message = " type";
                                 }
-                                hir::Node::Local(hir::Local { init: Some(init), .. }) => {
+                                hir::Node::LetStmt(hir::LetStmt { init: Some(init), .. }) => {
                                     primary_span = init.span;
                                     post_message = " value";
                                 }
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index df21b84f92e..eee4ac5ad23 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -11,7 +11,7 @@ use rustc_middle::ty::Ty;
 use rustc_span::{
     edition::{Edition, LATEST_STABLE_EDITION},
     symbol::Ident,
-    Span,
+    Span, Symbol,
 };
 
 #[derive(Diagnostic)]
@@ -614,3 +614,10 @@ pub struct SuggestConvertViaMethod<'tcx> {
     pub expected: Ty<'tcx>,
     pub found: Ty<'tcx>,
 }
+
+#[derive(Subdiagnostic)]
+#[note(hir_typeck_note_caller_chooses_ty_for_ty_param)]
+pub struct NoteCallerChoosesTyForTyParam<'tcx> {
+    pub ty_param_name: Symbol,
+    pub found_ty: Ty<'tcx>,
+}
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 1a142f27809..f38f04fce43 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -35,8 +35,8 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ExprKind, HirId, QPath};
-use rustc_hir_analysis::astconv::AstConv as _;
 use rustc_hir_analysis::check::ty_kind_suggestion;
+use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer as _;
 use rustc_infer::infer;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::DefineOpaqueTypes;
@@ -333,7 +333,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             ExprKind::Cast(e, t) => self.check_expr_cast(e, t, expr),
             ExprKind::Type(e, t) => {
-                let ascribed_ty = self.to_ty_saving_user_provided_ty(t);
+                let ascribed_ty = self.lower_ty_saving_user_provided_ty(t);
                 let ty = self.check_expr_with_hint(e, ascribed_ty);
                 self.demand_eqtype(e.span, ascribed_ty, ty);
                 ascribed_ty
@@ -426,7 +426,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) -> Ty<'tcx> {
         let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| {
             match ty.kind() {
-                ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
+                ty::Ref(_, ty, _) | ty::RawPtr(ty, _) => {
                     if oprnd.is_syntactic_place_expr() {
                         // Places may legitimately have unsized types.
                         // For example, dereferences of a fat pointer and
@@ -442,12 +442,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let ty =
             self.check_expr_with_expectation_and_needs(oprnd, hint, Needs::maybe_mut_place(mutbl));
 
-        let tm = ty::TypeAndMut { ty, mutbl };
         match kind {
-            _ if tm.ty.references_error() => Ty::new_misc_error(self.tcx),
+            _ if ty.references_error() => Ty::new_misc_error(self.tcx),
             hir::BorrowKind::Raw => {
                 self.check_named_place_expr(oprnd);
-                Ty::new_ptr(self.tcx, tm)
+                Ty::new_ptr(self.tcx, ty, mutbl)
             }
             hir::BorrowKind::Ref => {
                 // Note: at this point, we cannot say what the best lifetime
@@ -465,7 +464,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // whose address was taken can actually be made to live as long
                 // as it needs to live.
                 let region = self.next_region_var(infer::AddrOfRegion(expr.span));
-                Ty::new_ref(self.tcx, region, tm)
+                Ty::new_ref(self.tcx, region, ty, mutbl)
             }
         }
     }
@@ -1261,7 +1260,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    pub(super) fn check_expr_let(&self, let_expr: &'tcx hir::Let<'tcx>, hir_id: HirId) -> Ty<'tcx> {
+    pub(super) fn check_expr_let(
+        &self,
+        let_expr: &'tcx hir::LetExpr<'tcx>,
+        hir_id: HirId,
+    ) -> Ty<'tcx> {
         // for let statements, this is done in check_stmt
         let init = let_expr.init;
         self.warn_if_unreachable(init.hir_id, init.span, "block in `let` expression");
@@ -1371,7 +1374,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) -> Ty<'tcx> {
         // Find the type of `e`. Supply hints based on the type we are casting to,
         // if appropriate.
-        let t_cast = self.to_ty_saving_user_provided_ty(t);
+        let t_cast = self.lower_ty_saving_user_provided_ty(t);
         let t_cast = self.resolve_vars_if_possible(t_cast);
         let t_expr = self.check_expr_with_expectation(e, ExpectCastableToType(t_cast));
         let t_expr = self.resolve_vars_if_possible(t_expr);
@@ -1448,7 +1451,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         });
         let Some((
             _,
-            hir::Node::Local(hir::Local { ty: Some(ty), .. })
+            hir::Node::LetStmt(hir::LetStmt { ty: Some(ty), .. })
             | hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _, _), .. }),
         )) = parent_node
         else {
@@ -1499,7 +1502,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expr: &'tcx hir::Expr<'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
-        let count = self.array_length_to_const(count);
+        let count = self.lower_array_length(count);
         if let Some(count) = count.try_eval_target_usize(tcx, self.param_env) {
             self.suggest_array_len(expr, count);
         }
@@ -1675,7 +1678,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expr: &hir::Expr<'_>,
         span: Span,
         variant: &'tcx ty::VariantDef,
-        ast_fields: &'tcx [hir::ExprField<'tcx>],
+        hir_fields: &'tcx [hir::ExprField<'tcx>],
         base_expr: &'tcx Option<&'tcx hir::Expr<'tcx>>,
     ) {
         let tcx = self.tcx;
@@ -1706,7 +1709,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let mut error_happened = false;
 
         // Type-check each field.
-        for (idx, field) in ast_fields.iter().enumerate() {
+        for (idx, field) in hir_fields.iter().enumerate() {
             let ident = tcx.adjust_ident(field.ident, variant.def_id);
             let field_type = if let Some((i, v_field)) = remaining_fields.remove(&ident) {
                 seen_fields.insert(ident, field.span);
@@ -1735,7 +1738,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         variant,
                         expr,
                         field,
-                        ast_fields,
+                        hir_fields,
                         adt.variant_descr(),
                     )
                 };
@@ -1750,7 +1753,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.demand_coerce_diag(field.expr, ty, field_type, None, AllowTwoPhase::No);
 
             if let Some(diag) = diag {
-                if idx == ast_fields.len() - 1 {
+                if idx == hir_fields.len() - 1 {
                     if remaining_fields.is_empty() {
                         self.suggest_fru_from_range_and_emit(field, variant, args, diag);
                     } else {
@@ -1764,7 +1767,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Make sure the programmer specified correct number of fields.
         if adt_kind == AdtKind::Union {
-            if ast_fields.len() != 1 {
+            if hir_fields.len() != 1 {
                 struct_span_code_err!(
                     tcx.dcx(),
                     span,
@@ -1901,14 +1904,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .collect();
 
             if !private_fields.is_empty() {
-                self.report_private_fields(adt_ty, span, expr.span, private_fields, ast_fields);
+                self.report_private_fields(adt_ty, span, expr.span, private_fields, hir_fields);
             } else {
                 self.report_missing_fields(
                     adt_ty,
                     span,
                     remaining_fields,
                     variant,
-                    ast_fields,
+                    hir_fields,
                     args,
                 );
             }
@@ -1945,7 +1948,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         span: Span,
         remaining_fields: UnordMap<Ident, (FieldIdx, &ty::FieldDef)>,
         variant: &'tcx ty::VariantDef,
-        ast_fields: &'tcx [hir::ExprField<'tcx>],
+        hir_fields: &'tcx [hir::ExprField<'tcx>],
         args: GenericArgsRef<'tcx>,
     ) {
         let len = remaining_fields.len();
@@ -1982,8 +1985,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         );
         err.span_label(span, format!("missing {remaining_fields_names}{truncated_fields_error}"));
 
-        if let Some(last) = ast_fields.last() {
-            self.suggest_fru_from_range_and_emit(last, variant, args, err);
+        if let Some(hir_field) = hir_fields.last() {
+            self.suggest_fru_from_range_and_emit(hir_field, variant, args, err);
         } else {
             err.emit();
         }
@@ -2682,8 +2685,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 expr,
                 Some(span),
             );
-        } else if let ty::RawPtr(ty_and_mut) = expr_t.kind()
-            && let ty::Adt(adt_def, _) = ty_and_mut.ty.kind()
+        } else if let ty::RawPtr(ptr_ty, _) = expr_t.kind()
+            && let ty::Adt(adt_def, _) = ptr_ty.kind()
             && let ExprKind::Field(base_expr, _) = expr.kind
             && adt_def.variants().len() == 1
             && adt_def
@@ -3096,7 +3099,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     cause.clone().derived_cause(
                         ty::Binder::dummy(ty::TraitPredicate {
                             trait_ref: impl_trait_ref,
-                            polarity: ty::ImplPolarity::Positive,
+                            polarity: ty::PredicatePolarity::Positive,
                         }),
                         |derived| {
                             traits::ImplDerivedObligation(Box::new(
@@ -3221,7 +3224,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     self.demand_coerce(expr, ty, fnptr_ty, None, AllowTwoPhase::No);
                 }
                 ty::Ref(_, base_ty, mutbl) => {
-                    let ptr_ty = Ty::new_ptr(self.tcx, ty::TypeAndMut { ty: base_ty, mutbl });
+                    let ptr_ty = Ty::new_ptr(self.tcx, base_ty, mutbl);
                     self.demand_coerce(expr, ty, ptr_ty, None, AllowTwoPhase::No);
                 }
                 _ => {}
@@ -3279,7 +3282,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         fields: &[Ident],
         expr: &'tcx hir::Expr<'tcx>,
     ) -> Ty<'tcx> {
-        let container = self.to_ty(container).normalized;
+        let container = self.lower_ty(container).normalized;
 
         if let Some(ident_2) = fields.get(1)
             && !self.tcx.features().offset_of_nested
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index 43e95544594..3b6accb92ae 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -245,7 +245,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
                 }
             }
 
-            hir::ExprKind::Let(hir::Let { pat, init, .. }) => {
+            hir::ExprKind::Let(hir::LetExpr { pat, init, .. }) => {
                 self.walk_local(init, pat, None, |t| t.borrow_expr(init, ty::ImmBorrow))
             }
 
@@ -371,7 +371,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
 
     fn walk_stmt(&mut self, stmt: &hir::Stmt<'_>) {
         match stmt.kind {
-            hir::StmtKind::Let(hir::Local { pat, init: Some(expr), els, .. }) => {
+            hir::StmtKind::Let(hir::LetStmt { pat, init: Some(expr), els, .. }) => {
                 self.walk_local(expr, pat, *els, |_| {})
             }
 
@@ -463,6 +463,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
                     }
                     PatKind::Or(_)
                     | PatKind::Box(_)
+                    | PatKind::Deref(_)
                     | PatKind::Ref(..)
                     | PatKind::Wild
                     | PatKind::Err(_) => {
diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index c16e941d4c5..140618e97cc 100644
--- a/compiler/rustc_hir_typeck/src/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -4,12 +4,11 @@ use rustc_data_structures::{
     graph::{iterate::DepthFirstSearch, vec_graph::VecGraph},
     unord::{UnordBag, UnordMap, UnordSet},
 };
-use rustc_hir::def_id::CRATE_DEF_ID;
 use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
 use rustc_middle::ty::{self, Ty};
-use rustc_span::sym;
 
-enum DivergingFallbackBehavior {
+#[derive(Copy, Clone)]
+pub enum DivergingFallbackBehavior {
     /// Always fallback to `()` (aka "always spontaneous decay")
     FallbackToUnit,
     /// Sometimes fallback to `!`, but mainly fallback to `()` so that most of the crates are not broken.
@@ -78,9 +77,8 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
             return false;
         }
 
-        let diverging_behavior = self.diverging_fallback_behavior();
-        let diverging_fallback =
-            self.calculate_diverging_fallback(&unresolved_variables, diverging_behavior);
+        let diverging_fallback = self
+            .calculate_diverging_fallback(&unresolved_variables, self.diverging_fallback_behavior);
 
         // We do fallback in two passes, to try to generate
         // better error messages.
@@ -94,32 +92,6 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
         fallback_occurred
     }
 
-    fn diverging_fallback_behavior(&self) -> DivergingFallbackBehavior {
-        let Some((mode, span)) = self
-            .tcx
-            .get_attr(CRATE_DEF_ID, sym::rustc_never_type_mode)
-            .map(|attr| (attr.value_str().unwrap(), attr.span))
-        else {
-            if self.tcx.features().never_type_fallback {
-                return DivergingFallbackBehavior::FallbackToNiko;
-            }
-
-            return DivergingFallbackBehavior::FallbackToUnit;
-        };
-
-        match mode {
-            sym::fallback_to_unit => DivergingFallbackBehavior::FallbackToUnit,
-            sym::fallback_to_niko => DivergingFallbackBehavior::FallbackToNiko,
-            sym::fallback_to_never => DivergingFallbackBehavior::FallbackToNever,
-            sym::no_fallback => DivergingFallbackBehavior::NoFallback,
-            _ => {
-                self.tcx.dcx().span_err(span, format!("unknown never type mode: `{mode}` (supported: `fallback_to_unit`, `fallback_to_niko`, `fallback_to_never` and `no_fallback`)"));
-
-                DivergingFallbackBehavior::FallbackToUnit
-            }
-        }
-    }
-
     fn fallback_effects(&self) -> bool {
         let unsolved_effects = self.unsolved_effects();
 
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 1d885b801d9..8e0be7c7163 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -11,12 +11,12 @@ use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ExprKind, GenericArg, Node, QPath};
-use rustc_hir_analysis::astconv::generics::{
-    check_generic_arg_count_for_call, create_args_for_parent_generic_args,
+use rustc_hir_analysis::hir_ty_lowering::generics::{
+    check_generic_arg_count_for_call, lower_generic_args,
 };
-use rustc_hir_analysis::astconv::{
-    AstConv, CreateInstantiationsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
-    GenericArgCountResult, IsMethodCall, PathSeg,
+use rustc_hir_analysis::hir_ty_lowering::{
+    ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, GenericArgsLowerer,
+    GenericPathSegment, HirTyLowerer, IsMethodCall,
 };
 use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
 use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
@@ -394,20 +394,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    pub fn to_ty(&self, ast_t: &hir::Ty<'tcx>) -> LoweredTy<'tcx> {
-        let t = self.astconv().ast_ty_to_ty(ast_t);
-        self.register_wf_obligation(t.into(), ast_t.span, traits::WellFormed(None));
-        LoweredTy::from_raw(self, ast_t.span, t)
+    pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> LoweredTy<'tcx> {
+        let ty = self.lowerer().lower_ty(hir_ty);
+        self.register_wf_obligation(ty.into(), hir_ty.span, traits::WellFormed(None));
+        LoweredTy::from_raw(self, hir_ty.span, ty)
     }
 
-    pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
-        let ty = self.to_ty(ast_ty);
-        debug!("to_ty_saving_user_provided_ty: ty={:?}", ty);
+    #[instrument(level = "debug", skip_all)]
+    pub fn lower_ty_saving_user_provided_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
+        let ty = self.lower_ty(hir_ty);
+        debug!(?ty);
 
         if Self::can_contain_user_lifetime_bounds(ty.raw) {
             let c_ty = self.canonicalize_response(UserType::Ty(ty.raw));
-            debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty);
-            self.typeck_results.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty);
+            debug!(?c_ty);
+            self.typeck_results.borrow_mut().user_provided_types_mut().insert(hir_ty.hir_id, c_ty);
         }
 
         ty.normalized
@@ -424,7 +425,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    pub fn array_length_to_const(&self, length: &hir::ArrayLen) -> ty::Const<'tcx> {
+    pub fn lower_array_length(&self, length: &hir::ArrayLen) -> ty::Const<'tcx> {
         match length {
             hir::ArrayLen::Infer(inf) => self.ct_infer(self.tcx.types.usize, None, inf.span),
             hir::ArrayLen::Body(anon_const) => {
@@ -436,20 +437,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    pub fn const_arg_to_const(
-        &self,
-        ast_c: &hir::AnonConst,
-        param_def_id: DefId,
-    ) -> ty::Const<'tcx> {
-        let did = ast_c.def_id;
+    pub fn lower_const_arg(&self, hir_ct: &hir::AnonConst, param_def_id: DefId) -> ty::Const<'tcx> {
+        let did = hir_ct.def_id;
         self.tcx.feed_anon_const_type(did, self.tcx.type_of(param_def_id));
-        let c = ty::Const::from_anon_const(self.tcx, did);
+        let ct = ty::Const::from_anon_const(self.tcx, did);
         self.register_wf_obligation(
-            c.into(),
-            self.tcx.hir().span(ast_c.hir_id),
+            ct.into(),
+            self.tcx.hir().span(hir_ct.hir_id),
             ObligationCauseCode::WellFormed(None),
         );
-        c
+        ct
     }
 
     // If the type given by the user has free regions, save it for later, since
@@ -827,12 +824,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             QPath::Resolved(ref opt_qself, path) => {
                 return (
                     path.res,
-                    opt_qself.as_ref().map(|qself| self.to_ty(qself)),
+                    opt_qself.as_ref().map(|qself| self.lower_ty(qself)),
                     path.segments,
                 );
             }
             QPath::TypeRelative(ref qself, ref segment) => {
-                // Don't use `self.to_ty`, since this will register a WF obligation.
+                // Don't use `self.lower_ty`, since this will register a WF obligation.
                 // If we're trying to call a nonexistent method on a trait
                 // (e.g. `MyTrait::missing_method`), then resolution will
                 // give us a `QPath::TypeRelative` with a trait object as
@@ -841,7 +838,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // to be object-safe.
                 // We manually call `register_wf_obligation` in the success path
                 // below.
-                let ty = self.astconv().ast_ty_to_ty_in_path(qself);
+                let ty = self.lowerer().lower_ty_in_path(qself);
                 (LoweredTy::from_raw(self, span, ty), qself, segment)
             }
             QPath::LangItem(..) => {
@@ -1119,9 +1116,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) -> (Ty<'tcx>, Res) {
         let tcx = self.tcx;
 
-        let path_segs = match res {
+        let generic_segments = match res {
             Res::Local(_) | Res::SelfCtor(_) => vec![],
-            Res::Def(kind, def_id) => self.astconv().def_ids_for_value_path_segments(
+            Res::Def(kind, def_id) => self.lowerer().probe_generic_path_segments(
                 segments,
                 self_ty.map(|ty| ty.raw),
                 kind,
@@ -1178,14 +1175,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // provided (if any) into their appropriate spaces. We'll also report
         // errors if type parameters are provided in an inappropriate place.
 
-        let generic_segs: FxHashSet<_> = path_segs.iter().map(|PathSeg(_, index)| index).collect();
-        let generics_has_err = self.astconv().prohibit_generics(
+        let indices: FxHashSet<_> =
+            generic_segments.iter().map(|GenericPathSegment(_, index)| index).collect();
+        let generics_has_err = self.lowerer().prohibit_generic_args(
             segments.iter().enumerate().filter_map(|(index, seg)| {
-                if !generic_segs.contains(&index) || is_alias_variant_ctor {
-                    Some(seg)
-                } else {
-                    None
-                }
+                if !indices.contains(&index) || is_alias_variant_ctor { Some(seg) } else { None }
             }),
             |_| {},
         );
@@ -1212,7 +1206,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let mut infer_args_for_err = FxHashSet::default();
 
         let mut explicit_late_bound = ExplicitLateBound::No;
-        for &PathSeg(def_id, index) in &path_segs {
+        for &GenericPathSegment(def_id, index) in &generic_segments {
             let seg = &segments[index];
             let generics = tcx.generics_of(def_id);
 
@@ -1233,8 +1227,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         }
 
-        let has_self =
-            path_segs.last().is_some_and(|PathSeg(def_id, _)| tcx.generics_of(*def_id).has_self);
+        let has_self = generic_segments
+            .last()
+            .is_some_and(|GenericPathSegment(def_id, _)| tcx.generics_of(*def_id).has_self);
 
         let (res, self_ctor_args) = if let Res::SelfCtor(impl_def_id) = res {
             let ty = LoweredTy::from_raw(
@@ -1294,22 +1289,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             },
         };
 
-        struct CreateCtorInstantiationsContext<'a, 'tcx> {
+        struct CtorGenericArgsCtxt<'a, 'tcx> {
             fcx: &'a FnCtxt<'a, 'tcx>,
             span: Span,
-            path_segs: &'a [PathSeg],
+            generic_segments: &'a [GenericPathSegment],
             infer_args_for_err: &'a FxHashSet<usize>,
             segments: &'tcx [hir::PathSegment<'tcx>],
         }
-        impl<'tcx, 'a> CreateInstantiationsForGenericArgsCtxt<'a, 'tcx>
-            for CreateCtorInstantiationsContext<'a, 'tcx>
-        {
+        impl<'tcx, 'a> GenericArgsLowerer<'a, 'tcx> for CtorGenericArgsCtxt<'a, 'tcx> {
             fn args_for_def_id(
                 &mut self,
                 def_id: DefId,
             ) -> (Option<&'a hir::GenericArgs<'tcx>>, bool) {
-                if let Some(&PathSeg(_, index)) =
-                    self.path_segs.iter().find(|&PathSeg(did, _)| *did == def_id)
+                if let Some(&GenericPathSegment(_, index)) =
+                    self.generic_segments.iter().find(|&GenericPathSegment(did, _)| *did == def_id)
                 {
                     // If we've encountered an `impl Trait`-related error, we're just
                     // going to infer the arguments for better error messages.
@@ -1332,13 +1325,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ) -> ty::GenericArg<'tcx> {
                 match (&param.kind, arg) {
                     (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
-                        self.fcx.astconv().ast_region_to_region(lt, Some(param)).into()
+                        self.fcx.lowerer().lower_lifetime(lt, Some(param)).into()
                     }
                     (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
-                        self.fcx.to_ty(ty).raw.into()
+                        self.fcx.lower_ty(ty).raw.into()
                     }
                     (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
-                        self.fcx.const_arg_to_const(&ct.value, param.def_id).into()
+                        self.fcx.lower_const_arg(&ct.value, param.def_id).into()
                     }
                     (GenericParamDefKind::Type { .. }, GenericArg::Infer(inf)) => {
                         self.fcx.ty_infer(Some(param), inf.span).into()
@@ -1420,17 +1413,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         let args_raw = self_ctor_args.unwrap_or_else(|| {
-            create_args_for_parent_generic_args(
+            lower_generic_args(
                 tcx,
                 def_id,
                 &[],
                 has_self,
                 self_ty.map(|s| s.raw),
                 &arg_count,
-                &mut CreateCtorInstantiationsContext {
+                &mut CtorGenericArgsCtxt {
                     fcx: self,
                     span,
-                    path_segs: &path_segs,
+                    generic_segments: &generic_segments,
                     infer_args_for_err: &infer_args_for_err,
                     segments,
                 },
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 5c56c6acd27..ebc5e11a561 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -24,9 +24,9 @@ use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::{ExprKind, Node, QPath};
-use rustc_hir_analysis::astconv::AstConv;
 use rustc_hir_analysis::check::intrinsicck::InlineAsmCtxt;
 use rustc_hir_analysis::check::potentially_plural_count;
+use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
 use rustc_hir_analysis::structured_errors::StructuredDiag;
 use rustc_index::IndexVec;
 use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt};
@@ -45,6 +45,29 @@ use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext}
 use std::iter;
 use std::mem;
 
+#[derive(Clone, Copy, Default)]
+pub enum DivergingBlockBehavior {
+    /// This is the current stable behavior:
+    ///
+    /// ```rust
+    /// {
+    ///     return;
+    /// } // block has type = !, even though we are supposedly dropping it with `;`
+    /// ```
+    #[default]
+    Never,
+
+    /// Alternative behavior:
+    ///
+    /// ```ignore (very-unstable-new-attribute)
+    /// #![rustc_never_type_options(diverging_block_default = "unit")]
+    /// {
+    ///     return;
+    /// } // block has type = (), since we are dropping `!` from `return` with `;`
+    /// ```
+    Unit,
+}
+
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(in super::super) fn check_casts(&mut self) {
         // don't hold the borrow to deferred_cast_checks while checking to avoid borrow checker errors
@@ -1371,9 +1394,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         arg: &hir::Expr<'tcx>,
         err: &mut Diag<'tcx>,
     ) {
-        if let ty::RawPtr(ty::TypeAndMut { mutbl: hir::Mutability::Mut, .. }) = expected_ty.kind()
-            && let ty::RawPtr(ty::TypeAndMut { mutbl: hir::Mutability::Not, .. }) =
-                provided_ty.kind()
+        if let ty::RawPtr(_, hir::Mutability::Mut) = expected_ty.kind()
+            && let ty::RawPtr(_, hir::Mutability::Not) = provided_ty.kind()
             && let hir::ExprKind::Call(callee, _) = arg.kind
             && let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = callee.kind
             && let Res::Def(_, def_id) = path.res
@@ -1579,7 +1601,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     /// Type check a `let` statement.
-    pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) {
+    pub fn check_decl_local(&self, local: &'tcx hir::LetStmt<'tcx>) {
         self.check_decl(local.into());
         if local.pat.is_never_pattern() {
             self.diverges.set(Diverges::Always {
@@ -1710,7 +1732,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 //
                 // #41425 -- label the implicit `()` as being the
                 // "found type" here, rather than the "expected type".
-                if !self.diverges.get().is_always() {
+                if !self.diverges.get().is_always()
+                    || matches!(self.diverging_block_behavior, DivergingBlockBehavior::Unit)
+                {
                     // #50009 -- Do not point at the entire fn block span, point at the return type
                     // span, as it is the cause of the requirement, and
                     // `consider_hint_about_removing_semicolon` will point at the last expression
@@ -1765,7 +1789,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                             [
                                                 hir::Stmt {
                                                     kind:
-                                                        hir::StmtKind::Let(hir::Local {
+                                                        hir::StmtKind::Let(hir::LetStmt {
                                                             source:
                                                                 hir::LocalSource::AssignDesugar(_),
                                                             ..
@@ -1936,16 +1960,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) -> (Res, LoweredTy<'tcx>) {
         match *qpath {
             QPath::Resolved(ref maybe_qself, path) => {
-                let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself).raw);
-                let ty = self.astconv().res_to_ty(self_ty, path, hir_id, true);
+                let self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself).raw);
+                let ty = self.lowerer().lower_path(self_ty, path, hir_id, true);
                 (path.res, LoweredTy::from_raw(self, path_span, ty))
             }
             QPath::TypeRelative(qself, segment) => {
-                let ty = self.to_ty(qself);
+                let ty = self.lower_ty(qself);
 
                 let result = self
-                    .astconv()
-                    .associated_path_to_ty(hir_id, path_span, ty.raw, qself, segment, true);
+                    .lowerer()
+                    .lower_assoc_path(hir_id, path_span, ty.raw, qself, segment, true);
                 let ty = result
                     .map(|(ty, _, _)| ty)
                     .unwrap_or_else(|guar| Ty::new_error(self.tcx(), guar));
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index 685b1af931e..efa2862177e 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -5,11 +5,14 @@ mod checks;
 mod suggestions;
 
 use crate::coercion::DynamicCoerceMany;
+use crate::fallback::DivergingFallbackBehavior;
+use crate::fn_ctxt::checks::DivergingBlockBehavior;
 use crate::{CoroutineTypes, Diverges, EnclosingBreakables, Inherited};
+use hir::def_id::CRATE_DEF_ID;
 use rustc_errors::{DiagCtxt, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir_analysis::astconv::AstConv;
+use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
 use rustc_infer::infer;
 use rustc_infer::infer::error_reporting::sub_relations::SubRelations;
 use rustc_infer::infer::error_reporting::TypeErrCtxt;
@@ -18,7 +21,7 @@ use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKin
 use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt};
 use rustc_session::Session;
 use rustc_span::symbol::Ident;
-use rustc_span::{self, Span, DUMMY_SP};
+use rustc_span::{self, sym, Span, DUMMY_SP};
 use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt};
 
 use std::cell::{Cell, RefCell};
@@ -108,6 +111,9 @@ pub struct FnCtxt<'a, 'tcx> {
     pub(super) inh: &'a Inherited<'tcx>,
 
     pub(super) fallback_has_occurred: Cell<bool>,
+
+    pub(super) diverging_fallback_behavior: DivergingFallbackBehavior,
+    pub(super) diverging_block_behavior: DivergingBlockBehavior,
 }
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -116,6 +122,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         body_id: LocalDefId,
     ) -> FnCtxt<'a, 'tcx> {
+        let (diverging_fallback_behavior, diverging_block_behavior) =
+            parse_never_type_options_attr(inh.tcx);
         FnCtxt {
             body_id,
             param_env,
@@ -131,6 +139,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }),
             inh,
             fallback_has_occurred: Cell::new(false),
+            diverging_fallback_behavior,
+            diverging_block_behavior,
         }
     }
 
@@ -202,7 +212,7 @@ impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
+impl<'a, 'tcx> HirTyLowerer<'tcx> for FnCtxt<'a, 'tcx> {
     fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
         self.tcx
     }
@@ -211,31 +221,8 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
         self.body_id.to_def_id()
     }
 
-    fn get_type_parameter_bounds(
-        &self,
-        _: Span,
-        def_id: LocalDefId,
-        _: Ident,
-    ) -> ty::GenericPredicates<'tcx> {
-        let tcx = self.tcx;
-        let item_def_id = tcx.hir().ty_param_owner(def_id);
-        let generics = tcx.generics_of(item_def_id);
-        let index = generics.param_def_id_to_index[&def_id.to_def_id()];
-        // HACK(eddyb) should get the original `Span`.
-        let span = tcx.def_span(def_id);
-        ty::GenericPredicates {
-            parent: None,
-            predicates: tcx.arena.alloc_from_iter(
-                self.param_env.caller_bounds().iter().filter_map(|predicate| {
-                    match predicate.kind().skip_binder() {
-                        ty::ClauseKind::Trait(data) if data.self_ty().is_param(index) => {
-                            Some((predicate, span))
-                        }
-                        _ => None,
-                    }
-                }),
-            ),
-        }
+    fn allow_infer(&self) -> bool {
+        true
     }
 
     fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option<ty::Region<'tcx>> {
@@ -246,10 +233,6 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
         Some(self.next_region_var(v))
     }
 
-    fn allow_ty_infer(&self) -> bool {
-        true
-    }
-
     fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
         match param {
             Some(param) => self.var_for_def(span, param).as_type().unwrap(),
@@ -282,7 +265,34 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
         }
     }
 
-    fn projected_ty_from_poly_trait_ref(
+    fn probe_ty_param_bounds(
+        &self,
+        _: Span,
+        def_id: LocalDefId,
+        _: Ident,
+    ) -> ty::GenericPredicates<'tcx> {
+        let tcx = self.tcx;
+        let item_def_id = tcx.hir().ty_param_owner(def_id);
+        let generics = tcx.generics_of(item_def_id);
+        let index = generics.param_def_id_to_index[&def_id.to_def_id()];
+        // HACK(eddyb) should get the original `Span`.
+        let span = tcx.def_span(def_id);
+        ty::GenericPredicates {
+            parent: None,
+            predicates: tcx.arena.alloc_from_iter(
+                self.param_env.caller_bounds().iter().filter_map(|predicate| {
+                    match predicate.kind().skip_binder() {
+                        ty::ClauseKind::Trait(data) if data.self_ty().is_param(index) => {
+                            Some((predicate, span))
+                        }
+                        _ => None,
+                    }
+                }),
+            ),
+        }
+    }
+
+    fn lower_assoc_ty(
         &self,
         span: Span,
         item_def_id: DefId,
@@ -295,7 +305,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
             poly_trait_ref,
         );
 
-        let item_args = self.astconv().create_args_for_associated_item(
+        let item_args = self.lowerer().lower_generic_args_of_assoc_item(
             span,
             item_def_id,
             item_segment,
@@ -318,10 +328,6 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
         }
     }
 
-    fn set_tainted_by_errors(&self, e: ErrorGuaranteed) {
-        self.infcx.set_tainted_by_errors(e)
-    }
-
     fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span) {
         // FIXME: normalization and escaping regions
         let ty = if !ty.has_escaping_bound_vars() {
@@ -345,13 +351,17 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
     fn infcx(&self) -> Option<&infer::InferCtxt<'tcx>> {
         Some(&self.infcx)
     }
+
+    fn set_tainted_by_errors(&self, e: ErrorGuaranteed) {
+        self.infcx.set_tainted_by_errors(e)
+    }
 }
 
 /// The `ty` representation of a user-provided type. Depending on the use-site
 /// we want to either use the unnormalized or the normalized form of this type.
 ///
-/// This is a bridge between the interface of `AstConv`, which outputs a raw `Ty`,
-/// and the API in this module, which expect `Ty` to be fully normalized.
+/// This is a bridge between the interface of HIR ty lowering, which outputs a raw
+/// `Ty`, and the API in this module, which expect `Ty` to be fully normalized.
 #[derive(Clone, Copy, Debug)]
 pub struct LoweredTy<'tcx> {
     /// The unnormalized type provided by the user.
@@ -374,3 +384,64 @@ impl<'tcx> LoweredTy<'tcx> {
         LoweredTy { raw, normalized }
     }
 }
+
+fn parse_never_type_options_attr(
+    tcx: TyCtxt<'_>,
+) -> (DivergingFallbackBehavior, DivergingBlockBehavior) {
+    use DivergingFallbackBehavior::*;
+
+    // Error handling is dubious here (unwraps), but that's probably fine for an internal attribute.
+    // Just don't write incorrect attributes <3
+
+    let mut fallback = None;
+    let mut block = None;
+
+    let items = tcx
+        .get_attr(CRATE_DEF_ID, sym::rustc_never_type_options)
+        .map(|attr| attr.meta_item_list().unwrap())
+        .unwrap_or_default();
+
+    for item in items {
+        if item.has_name(sym::fallback) && fallback.is_none() {
+            let mode = item.value_str().unwrap();
+            match mode {
+                sym::unit => fallback = Some(FallbackToUnit),
+                sym::niko => fallback = Some(FallbackToNiko),
+                sym::never => fallback = Some(FallbackToNever),
+                sym::no => fallback = Some(NoFallback),
+                _ => {
+                    tcx.dcx().span_err(item.span(), format!("unknown never type fallback mode: `{mode}` (supported: `unit`, `niko`, `never` and `no`)"));
+                }
+            };
+            continue;
+        }
+
+        if item.has_name(sym::diverging_block_default) && fallback.is_none() {
+            let mode = item.value_str().unwrap();
+            match mode {
+                sym::unit => block = Some(DivergingBlockBehavior::Unit),
+                sym::never => block = Some(DivergingBlockBehavior::Never),
+                _ => {
+                    tcx.dcx().span_err(item.span(), format!("unknown diverging block default: `{mode}` (supported: `unit` and `never`)"));
+                }
+            };
+            continue;
+        }
+
+        tcx.dcx().span_err(
+            item.span(),
+            format!(
+                "unknown never type option: `{}` (supported: `fallback`)",
+                item.name_or_empty()
+            ),
+        );
+    }
+
+    let fallback = fallback.unwrap_or_else(|| {
+        if tcx.features().never_type_fallback { FallbackToNiko } else { FallbackToUnit }
+    });
+
+    let block = block.unwrap_or_default();
+
+    (fallback, block)
+}
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 3f6f4cccba7..442bfd75746 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -7,7 +7,6 @@ use crate::hir::is_range_literal;
 use crate::method::probe;
 use crate::method::probe::{IsSuggestion, Mode, ProbeScope};
 use crate::rustc_middle::ty::Article;
-use crate::ty::TypeAndMut;
 use core::cmp::min;
 use core::iter;
 use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX};
@@ -21,7 +20,7 @@ use rustc_hir::{
     CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, GenericBound, HirId, Node,
     Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
 };
-use rustc_hir_analysis::astconv::AstConv;
+use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
 use rustc_infer::traits::{self};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::middle::stability::EvalResult;
@@ -318,7 +317,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             );
                             expr_id = parent_id;
                         }
-                        Node::Local(local) => {
+                        Node::LetStmt(local) => {
                             if let Some(mut ty) = local.ty {
                                 while let Some(index) = tuple_indexes.pop() {
                                     match ty.kind {
@@ -809,7 +808,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 return true;
             }
             &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => {
-                if let Some(found) = found.make_suggestable(self.tcx, false) {
+                if let Some(found) = found.make_suggestable(self.tcx, false, None) {
                     err.subdiagnostic(
                         self.dcx(),
                         errors::AddReturnTypeSuggestion::Add { span, found: found.to_string() },
@@ -877,7 +876,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // Only point to return type if the expected type is the return type, as if they
                     // are not, the expectation must have been caused by something else.
                     debug!("return type {:?}", hir_ty);
-                    let ty = self.astconv().ast_ty_to_ty(hir_ty);
+                    let ty = self.lowerer().lower_ty(hir_ty);
                     debug!("return type {:?}", ty);
                     debug!("expected type {:?}", expected);
                     let bound_vars = self.tcx.late_bound_vars(hir_ty.hir_id.owner.into());
@@ -889,7 +888,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             self.dcx(),
                             errors::ExpectedReturnTypeLabel::Other { span: hir_ty.span, expected },
                         );
-                        self.try_suggest_return_impl_trait(err, expected, ty, fn_id);
+                        self.try_suggest_return_impl_trait(err, expected, found, fn_id);
+                        self.note_caller_chooses_ty_for_ty_param(err, expected, found);
                         return true;
                     }
                 }
@@ -899,6 +899,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         false
     }
 
+    fn note_caller_chooses_ty_for_ty_param(
+        &self,
+        diag: &mut Diag<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+    ) {
+        if let ty::Param(expected_ty_as_param) = expected.kind() {
+            diag.subdiagnostic(
+                self.dcx(),
+                errors::NoteCallerChoosesTyForTyParam {
+                    ty_param_name: expected_ty_as_param.name,
+                    found_ty: found,
+                },
+            );
+        }
+    }
+
     /// check whether the return type is a generic type with a trait bound
     /// only suggest this if the generic param is not present in the arguments
     /// if this is true, hint them towards changing the return type to `impl Trait`
@@ -957,8 +974,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     bounded_ty,
                     ..
                 }) => {
-                    // FIXME: Maybe these calls to `ast_ty_to_ty` can be removed (and the ones below)
-                    let ty = self.astconv().ast_ty_to_ty(bounded_ty);
+                    // FIXME: Maybe these calls to `lower_ty` can be removed (and the ones below)
+                    let ty = self.lowerer().lower_ty(bounded_ty);
                     Some((ty, bounds))
                 }
                 _ => None,
@@ -996,7 +1013,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let all_bounds_str = all_matching_bounds_strs.join(" + ");
 
         let ty_param_used_in_fn_params = fn_parameters.iter().any(|param| {
-                let ty = self.astconv().ast_ty_to_ty( param);
+                let ty = self.lowerer().lower_ty( param);
                 matches!(ty.kind(), ty::Param(fn_param_ty_param) if expected_ty_as_param == fn_param_ty_param)
             });
 
@@ -1071,7 +1088,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let can_return = match fn_decl.output {
             hir::FnRetTy::Return(ty) => {
-                let ty = self.astconv().ast_ty_to_ty(ty);
+                let ty = self.lowerer().lower_ty(ty);
                 let bound_vars = self.tcx.late_bound_vars(fn_id);
                 let ty = self
                     .tcx
@@ -1331,7 +1348,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         //                     ++++++++++
         // since the user probably just misunderstood how `let else`
         // and `&&` work together.
-        if let Some((_, hir::Node::Local(local))) = cond_parent
+        if let Some((_, hir::Node::LetStmt(local))) = cond_parent
             && let hir::PatKind::Path(qpath) | hir::PatKind::TupleStruct(qpath, _, _) =
                 &local.pat.kind
             && let hir::QPath::Resolved(None, path) = qpath
@@ -1479,7 +1496,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expected_ty: Ty<'tcx>,
     ) -> bool {
         // Expected type needs to be a raw pointer.
-        let ty::RawPtr(ty::TypeAndMut { mutbl, .. }) = expected_ty.kind() else {
+        let ty::RawPtr(_, mutbl) = expected_ty.kind() else {
             return false;
         };
 
@@ -1731,7 +1748,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                 match self.tcx.parent_hir_node(*hir_id) {
                     // foo.clone()
-                    hir::Node::Local(hir::Local { init: Some(init), .. }) => {
+                    hir::Node::LetStmt(hir::LetStmt { init: Some(init), .. }) => {
                         self.note_type_is_not_clone_inner_expr(init)
                     }
                     // When `expr` is more complex like a tuple
@@ -1740,7 +1757,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         kind: hir::PatKind::Tuple(pats, ..),
                         ..
                     }) => {
-                        let hir::Node::Local(hir::Local { init: Some(init), .. }) =
+                        let hir::Node::LetStmt(hir::LetStmt { init: Some(init), .. }) =
                             self.tcx.parent_hir_node(*pat_hir_id)
                         else {
                             return expr;
@@ -1774,7 +1791,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     && let hir::Path { segments: [_], res: crate::Res::Local(binding), .. } =
                         call_expr_path
                     && let hir::Node::Pat(hir::Pat { hir_id, .. }) = self.tcx.hir_node(*binding)
-                    && let hir::Node::Local(hir::Local { init: Some(init), .. }) =
+                    && let hir::Node::LetStmt(hir::LetStmt { init: Some(init), .. }) =
                         self.tcx.parent_hir_node(*hir_id)
                     && let Expr {
                         kind: hir::ExprKind::Closure(hir::Closure { body: body_id, .. }),
@@ -2509,11 +2526,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     return make_sugg(sp, expr.span.lo());
                 }
             }
-            (
-                _,
-                &ty::RawPtr(TypeAndMut { ty: ty_b, mutbl: mutbl_b }),
-                &ty::Ref(_, ty_a, mutbl_a),
-            ) => {
+            (_, &ty::RawPtr(ty_b, mutbl_b), &ty::Ref(_, ty_a, mutbl_a)) => {
                 if let Some(steps) = self.deref_steps(ty_a, ty_b)
                     // Only suggest valid if dereferencing needed.
                     && steps > 0
@@ -3134,7 +3147,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let hir::Node::Pat(pat) = self.tcx.hir_node(hir_id) else {
             return;
         };
-        let hir::Node::Local(hir::Local { ty: None, init: Some(init), .. }) =
+        let hir::Node::LetStmt(hir::LetStmt { ty: None, init: Some(init), .. }) =
             self.tcx.parent_hir_node(pat.hir_id)
         else {
             return;
diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs
index 4d37f725c94..1fa799dcec7 100644
--- a/compiler/rustc_hir_typeck/src/gather_locals.rs
+++ b/compiler/rustc_hir_typeck/src/gather_locals.rs
@@ -29,7 +29,7 @@ impl<'a> DeclOrigin<'a> {
     }
 }
 
-/// A declaration is an abstraction of [hir::Local] and [hir::Let].
+/// A declaration is an abstraction of [hir::LetStmt] and [hir::LetExpr].
 ///
 /// It must have a hir_id, as this is how we connect gather_locals to the check functions.
 pub(super) struct Declaration<'a> {
@@ -41,16 +41,16 @@ pub(super) struct Declaration<'a> {
     pub origin: DeclOrigin<'a>,
 }
 
-impl<'a> From<&'a hir::Local<'a>> for Declaration<'a> {
-    fn from(local: &'a hir::Local<'a>) -> Self {
-        let hir::Local { hir_id, pat, ty, span, init, els, source: _ } = *local;
+impl<'a> From<&'a hir::LetStmt<'a>> for Declaration<'a> {
+    fn from(local: &'a hir::LetStmt<'a>) -> Self {
+        let hir::LetStmt { hir_id, pat, ty, span, init, els, source: _ } = *local;
         Declaration { hir_id, pat, ty, span, init, origin: DeclOrigin::LocalDecl { els } }
     }
 }
 
-impl<'a> From<(&'a hir::Let<'a>, hir::HirId)> for Declaration<'a> {
-    fn from((let_expr, hir_id): (&'a hir::Let<'a>, hir::HirId)) -> Self {
-        let hir::Let { pat, ty, span, init, is_recovered: _ } = *let_expr;
+impl<'a> From<(&'a hir::LetExpr<'a>, hir::HirId)> for Declaration<'a> {
+    fn from((let_expr, hir_id): (&'a hir::LetExpr<'a>, hir::HirId)) -> Self {
+        let hir::LetExpr { pat, ty, span, init, is_recovered: _ } = *let_expr;
         Declaration { hir_id, pat, ty, span, init: Some(init), origin: DeclOrigin::LetExpr }
     }
 }
@@ -93,7 +93,7 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
     fn declare(&mut self, decl: Declaration<'tcx>) {
         let local_ty = match decl.ty {
             Some(ref ty) => {
-                let o_ty = self.fcx.to_ty(ty);
+                let o_ty = self.fcx.lower_ty(ty);
 
                 let c_ty =
                     self.fcx.inh.infcx.canonicalize_user_type_annotation(UserType::Ty(o_ty.raw));
@@ -120,7 +120,7 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
 
 impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
     // Add explicitly-declared locals.
-    fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
+    fn visit_local(&mut self, local: &'tcx hir::LetStmt<'tcx>) {
         self.declare(local.into());
         intravisit::walk_local(self, local)
     }
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index d259e71f957..0b67b37df29 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -57,8 +57,8 @@ use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::{HirIdMap, Node};
-use rustc_hir_analysis::astconv::AstConv;
 use rustc_hir_analysis::check::check_abi;
+use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::traits::{ObligationCauseCode, ObligationInspector, WellFormedLoc};
 use rustc_middle::query::Providers;
@@ -178,7 +178,7 @@ fn typeck_with_fallback<'tcx>(
 
     if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
         let fn_sig = if decl.output.get_infer_ret_ty().is_some() {
-            fcx.astconv().ty_of_fn(id, header.unsafety, header.abi, decl, None, None)
+            fcx.lowerer().lower_fn_ty(id, header.unsafety, header.abi, decl, None, None)
         } else {
             tcx.fn_sig(def_id).instantiate_identity()
         };
diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs
index 9307cccf092..f5b6dd162b3 100644
--- a/compiler/rustc_hir_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs
@@ -268,11 +268,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
             adjustment::Adjust::Deref(overloaded) => {
                 // Equivalent to *expr or something similar.
                 let base = if let Some(deref) = overloaded {
-                    let ref_ty = Ty::new_ref(
-                        self.tcx(),
-                        deref.region,
-                        ty::TypeAndMut { ty: target, mutbl: deref.mutbl },
-                    );
+                    let ref_ty = Ty::new_ref(self.tcx(), deref.region, target, deref.mutbl);
                     self.cat_rvalue(expr.hir_id, ref_ty)
                 } else {
                     previous()?
@@ -479,7 +475,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         let ty::Ref(region, _, mutbl) = *base_ty.kind() else {
             span_bug!(expr.span, "cat_overloaded_place: base is not a reference");
         };
-        let ref_ty = Ty::new_ref(self.tcx(), region, ty::TypeAndMut { ty: place_ty, mutbl });
+        let ref_ty = Ty::new_ref(self.tcx(), region, place_ty, mutbl);
 
         let base = self.cat_rvalue(expr.hir_id, ref_ty);
         self.cat_deref(expr, base)
@@ -719,7 +715,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
                 self.cat_pattern_(place_with_id, subpat, op)?;
             }
 
-            PatKind::Box(subpat) | PatKind::Ref(subpat, _) => {
+            PatKind::Box(subpat) | PatKind::Ref(subpat, _) | PatKind::Deref(subpat) => {
                 // box p1, &p1, &mut p1. we can ignore the mutability of
                 // PatKind::Ref since that information is already contained
                 // in the type.
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index a580c114f26..36860e446fc 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -4,10 +4,10 @@ use crate::{callee, FnCtxt};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::GenericArg;
-use rustc_hir_analysis::astconv::generics::{
-    check_generic_arg_count_for_call, create_args_for_parent_generic_args,
+use rustc_hir_analysis::hir_ty_lowering::generics::{
+    check_generic_arg_count_for_call, lower_generic_args,
 };
-use rustc_hir_analysis::astconv::{AstConv, CreateInstantiationsForGenericArgsCtxt, IsMethodCall};
+use rustc_hir_analysis::hir_ty_lowering::{GenericArgsLowerer, HirTyLowerer, IsMethodCall};
 use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk};
 use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
@@ -188,7 +188,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
                 // Type we're wrapping in a reference, used later for unsizing
                 let base_ty = target;
 
-                target = Ty::new_ref(self.tcx, region, ty::TypeAndMut { mutbl, ty: target });
+                target = Ty::new_ref(self.tcx, region, target, mutbl);
 
                 // Method call receivers are the primary use case
                 // for two-phase borrows.
@@ -208,11 +208,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
                             base_ty
                         )
                     };
-                    target = Ty::new_ref(
-                        self.tcx,
-                        region,
-                        ty::TypeAndMut { mutbl: mutbl.into(), ty: unsized_ty },
-                    );
+                    target = Ty::new_ref(self.tcx, region, unsized_ty, mutbl.into());
                     adjustments.push(Adjustment {
                         kind: Adjust::Pointer(PointerCoercion::Unsize),
                         target,
@@ -221,9 +217,9 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
             }
             Some(probe::AutorefOrPtrAdjustment::ToConstPtr) => {
                 target = match target.kind() {
-                    &ty::RawPtr(ty::TypeAndMut { ty, mutbl }) => {
+                    &ty::RawPtr(ty, mutbl) => {
                         assert!(mutbl.is_mut());
-                        Ty::new_ptr(self.tcx, ty::TypeAndMut { mutbl: hir::Mutability::Not, ty })
+                        Ty::new_imm_ptr(self.tcx, ty)
                     }
                     other => panic!("Cannot adjust receiver type {other:?} to const ptr"),
                 };
@@ -366,14 +362,12 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
         // combining parameters from the type and those from the method.
         assert_eq!(generics.parent_count, parent_args.len());
 
-        struct MethodInstantiationsCtxt<'a, 'tcx> {
+        struct GenericArgsCtxt<'a, 'tcx> {
             cfcx: &'a ConfirmContext<'a, 'tcx>,
             pick: &'a probe::Pick<'tcx>,
             seg: &'a hir::PathSegment<'tcx>,
         }
-        impl<'a, 'tcx> CreateInstantiationsForGenericArgsCtxt<'a, 'tcx>
-            for MethodInstantiationsCtxt<'a, 'tcx>
-        {
+        impl<'a, 'tcx> GenericArgsLowerer<'a, 'tcx> for GenericArgsCtxt<'a, 'tcx> {
             fn args_for_def_id(
                 &mut self,
                 def_id: DefId,
@@ -393,13 +387,13 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
             ) -> ty::GenericArg<'tcx> {
                 match (&param.kind, arg) {
                     (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
-                        self.cfcx.fcx.astconv().ast_region_to_region(lt, Some(param)).into()
+                        self.cfcx.fcx.lowerer().lower_lifetime(lt, Some(param)).into()
                     }
                     (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
-                        self.cfcx.to_ty(ty).raw.into()
+                        self.cfcx.lower_ty(ty).raw.into()
                     }
                     (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
-                        self.cfcx.const_arg_to_const(&ct.value, param.def_id).into()
+                        self.cfcx.lower_const_arg(&ct.value, param.def_id).into()
                     }
                     (GenericParamDefKind::Type { .. }, GenericArg::Infer(inf)) => {
                         self.cfcx.ty_infer(Some(param), inf.span).into()
@@ -432,14 +426,14 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
             }
         }
 
-        let args = create_args_for_parent_generic_args(
+        let args = lower_generic_args(
             self.tcx,
             pick.item.def_id,
             parent_args,
             false,
             None,
             &arg_count_correct,
-            &mut MethodInstantiationsCtxt { cfcx: self, pick, seg },
+            &mut GenericArgsCtxt { cfcx: self, pick, seg },
         );
 
         // When the method is confirmed, the `args` includes
diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index 3b26a791f65..e9752d7a4a8 100644
--- a/compiler/rustc_hir_typeck/src/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -200,11 +200,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         if let Some(span) = result.illegal_sized_bound {
             let mut needs_mut = false;
             if let ty::Ref(region, t_type, mutability) = self_ty.kind() {
-                let trait_type = Ty::new_ref(
-                    self.tcx,
-                    *region,
-                    ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() },
-                );
+                let trait_type = Ty::new_ref(self.tcx, *region, *t_type, mutability.invert());
                 // We probe again to see if there might be a borrow mutability discrepancy.
                 match self.lookup_probe(
                     segment.ident,
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index eada5a0bc30..4e63600dbdf 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -528,7 +528,7 @@ fn method_autoderef_steps<'tcx>(
                 from_unsafe_deref: reached_raw_pointer,
                 unsize: false,
             };
-            if let ty::RawPtr(_) = ty.kind() {
+            if let ty::RawPtr(_, _) = ty.kind() {
                 // all the subsequent steps will be from_unsafe_deref
                 reached_raw_pointer = true;
             }
@@ -696,7 +696,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
             | ty::Str
             | ty::Array(..)
             | ty::Slice(_)
-            | ty::RawPtr(_)
+            | ty::RawPtr(_, _)
             | ty::Ref(..)
             | ty::Never
             | ty::Tuple(..) => self.assemble_inherent_candidates_for_incoherent_ty(raw_self_ty),
@@ -1213,7 +1213,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         // In general, during probing we erase regions.
         let region = tcx.lifetimes.re_erased;
 
-        let autoref_ty = Ty::new_ref(tcx, region, ty::TypeAndMut { ty: self_ty, mutbl });
+        let autoref_ty = Ty::new_ref(tcx, region, self_ty, mutbl);
         self.pick_method(autoref_ty, unstable_candidates).map(|r| {
             r.map(|mut pick| {
                 pick.autoderefs = step.autoderefs;
@@ -1238,12 +1238,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
             return None;
         }
 
-        let &ty::RawPtr(ty::TypeAndMut { ty, mutbl: hir::Mutability::Mut }) = self_ty.kind() else {
+        let &ty::RawPtr(ty, hir::Mutability::Mut) = self_ty.kind() else {
             return None;
         };
 
-        let const_self_ty = ty::TypeAndMut { ty, mutbl: hir::Mutability::Not };
-        let const_ptr_ty = Ty::new_ptr(self.tcx, const_self_ty);
+        let const_ptr_ty = Ty::new_imm_ptr(self.tcx, ty);
         self.pick_method(const_ptr_ty, unstable_candidates).map(|r| {
             r.map(|mut pick| {
                 pick.autoderefs = step.autoderefs;
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index c5bbcc56f86..0dcde0cdecb 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -304,11 +304,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
                 if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind() {
                     if needs_mut {
-                        let trait_type = Ty::new_ref(
-                            self.tcx,
-                            *region,
-                            ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() },
-                        );
+                        let trait_type =
+                            Ty::new_ref(self.tcx, *region, *t_type, mutability.invert());
                         let msg = format!("you need `{trait_type}` instead of `{rcvr_ty}`");
                         let mut kind = &self_expr.kind;
                         while let hir::ExprKind::AddrOf(_, _, expr)
@@ -533,7 +530,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 Applicability::MachineApplicable,
             );
         }
-        if let ty::RawPtr(_) = &rcvr_ty.kind() {
+        if let ty::RawPtr(_, _) = &rcvr_ty.kind() {
             err.note(
                 "try using `<*const T>::as_ref()` to get a reference to the \
                  type behind the pointer: https://doc.rust-lang.org/std/\
@@ -875,7 +872,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 match pred.kind().skip_binder() {
                                     ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
                                         Some(pred.def_id()) == self.tcx.lang_items().sized_trait()
-                                            && pred.polarity == ty::ImplPolarity::Positive
+                                            && pred.polarity == ty::PredicatePolarity::Positive
                                     }
                                     _ => false,
                                 }
@@ -2166,7 +2163,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         match (filename, parent_node) {
                             (
                                 FileName::Real(_),
-                                Node::Local(hir::Local {
+                                Node::LetStmt(hir::LetStmt {
                                     source: hir::LocalSource::Normal,
                                     ty,
                                     ..
@@ -2221,7 +2218,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 impl<'v> Visitor<'v> for LetVisitor {
                     type Result = ControlFlow<Option<&'v hir::Expr<'v>>>;
                     fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) -> Self::Result {
-                        if let hir::StmtKind::Let(&hir::Local { pat, init, .. }) = ex.kind
+                        if let hir::StmtKind::Let(&hir::LetStmt { pat, init, .. }) = ex.kind
                             && let Binding(_, _, ident, ..) = pat.kind
                             && ident.name == self.ident_name
                         {
@@ -3264,8 +3261,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 Colon,
                                 Nothing,
                             }
-                            let ast_generics = hir.get_generics(id.owner.def_id).unwrap();
-                            let trait_def_ids: DefIdSet = ast_generics
+                            let hir_generics = hir.get_generics(id.owner.def_id).unwrap();
+                            let trait_def_ids: DefIdSet = hir_generics
                                 .bounds_for_param(def_id)
                                 .flat_map(|bp| bp.bounds.iter())
                                 .filter_map(|bound| bound.trait_ref()?.trait_def_id())
@@ -3277,7 +3274,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 "restrict type parameter `{}` with",
                                 param.name.ident(),
                             ));
-                            let bounds_span = ast_generics.bounds_span_for_suggestions(def_id);
+                            let bounds_span = hir_generics.bounds_span_for_suggestions(def_id);
                             if rcvr_ty.is_ref() && param.is_impl_trait() && bounds_span.is_some() {
                                 err.multipart_suggestions(
                                     msg,
@@ -3367,7 +3364,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 "inherent impls can't be candidates, only trait impls can be",
                             )
                         })
-                        .filter(|header| header.polarity == ty::ImplPolarity::Negative)
+                        .filter(|header| header.polarity != ty::ImplPolarity::Positive)
                         .any(|header| {
                             let imp = header.trait_ref.instantiate_identity();
                             let imp_simp =
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index 79f574aa7fd..b17b312a797 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -508,11 +508,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         suggest_deref_binop(&mut err, *lhs_deref_ty);
                     } else {
                         let lhs_inv_mutbl = mutbl.invert();
-                        let lhs_inv_mutbl_ty = Ty::new_ref(
-                            self.tcx,
-                            *region,
-                            ty::TypeAndMut { ty: *lhs_deref_ty, mutbl: lhs_inv_mutbl },
-                        );
+                        let lhs_inv_mutbl_ty =
+                            Ty::new_ref(self.tcx, *region, *lhs_deref_ty, lhs_inv_mutbl);
 
                         suggest_different_borrow(
                             &mut err,
@@ -524,11 +521,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                         if let Ref(region, rhs_deref_ty, mutbl) = rhs_ty.kind() {
                             let rhs_inv_mutbl = mutbl.invert();
-                            let rhs_inv_mutbl_ty = Ty::new_ref(
-                                self.tcx,
-                                *region,
-                                ty::TypeAndMut { ty: *rhs_deref_ty, mutbl: rhs_inv_mutbl },
-                            );
+                            let rhs_inv_mutbl_ty =
+                                Ty::new_ref(self.tcx, *region, *rhs_deref_ty, rhs_inv_mutbl);
 
                             suggest_different_borrow(
                                 &mut err,
@@ -601,8 +595,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                             if let Some(output_def_id) = output_def_id
                                                 && let Some(trait_def_id) = trait_def_id
                                                 && self.tcx.parent(output_def_id) == trait_def_id
-                                                && let Some(output_ty) =
-                                                    output_ty.make_suggestable(self.tcx, false)
+                                                && let Some(output_ty) = output_ty
+                                                    .make_suggestable(self.tcx, false, None)
                                             {
                                                 Some(("Output", output_ty))
                                             } else {
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 491da7eb2c2..7ecd380ebeb 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -18,8 +18,7 @@ use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Ident};
-use rustc_span::Span;
-use rustc_span::{BytePos, DUMMY_SP};
+use rustc_span::{BytePos, Span, DUMMY_SP};
 use rustc_target::abi::FieldIdx;
 use rustc_trait_selection::traits::{ObligationCause, Pattern};
 use ty::VariantDef;
@@ -212,6 +211,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.check_pat_tuple(pat.span, elements, ddpos, expected, pat_info)
             }
             PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info),
+            PatKind::Deref(inner) => self.check_pat_deref(pat.span, inner, expected, pat_info),
             PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info),
             PatKind::Slice(before, slice, after) => {
                 self.check_pat_slice(pat.span, before, slice, after, expected, pat_info)
@@ -295,6 +295,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             | PatKind::TupleStruct(..)
             | PatKind::Tuple(..)
             | PatKind::Box(_)
+            | PatKind::Deref(_)
             | PatKind::Range(..)
             | PatKind::Slice(..) => AdjustMode::Peel,
             // A never pattern behaves somewhat like a literal or unit variant.
@@ -743,7 +744,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                 let ident_kind = match binding_parent {
                     hir::Node::Param(_) => "parameter",
-                    hir::Node::Local(_) => "variable",
+                    hir::Node::LetStmt(_) => "variable",
                     hir::Node::Arm(_) => "binding",
 
                     // Provide diagnostics only if the parent pattern is struct-like,
@@ -760,6 +761,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         | PatKind::Binding(..)
                         | PatKind::Path(..)
                         | PatKind::Box(..)
+                        | PatKind::Deref(_)
                         | PatKind::Ref(..)
                         | PatKind::Lit(..)
                         | PatKind::Range(..)
@@ -1975,6 +1977,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         box_ty
     }
 
+    fn check_pat_deref(
+        &self,
+        span: Span,
+        inner: &'tcx Pat<'tcx>,
+        expected: Ty<'tcx>,
+        pat_info: PatInfo<'tcx, '_>,
+    ) -> Ty<'tcx> {
+        let tcx = self.tcx;
+        // FIXME(deref_patterns): use `DerefPure` for soundness
+        // FIXME(deref_patterns): use `DerefMut` when required
+        // <expected as Deref>::Target
+        let ty = Ty::new_projection(
+            tcx,
+            tcx.require_lang_item(hir::LangItem::DerefTarget, Some(span)),
+            [expected],
+        );
+        let ty = self.normalize(span, ty);
+        let ty = self.try_structurally_resolve_type(span, ty);
+        self.check_pat(inner, ty, pat_info);
+        expected
+    }
+
     // Precondition: Pat is Ref(inner)
     fn check_pat_ref(
         &self,
@@ -2033,8 +2057,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Create a reference type with a fresh region variable.
     fn new_ref_ty(&self, span: Span, mutbl: hir::Mutability, ty: Ty<'tcx>) -> Ty<'tcx> {
         let region = self.next_region_var(infer::PatternRegion(span));
-        let mt = ty::TypeAndMut { ty, mutbl };
-        Ty::new_ref(self.tcx, region, mt)
+        Ty::new_ref(self.tcx, region, ty, mutbl)
     }
 
     fn try_resolve_slice_ty_to_array_ty(
diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs
index 6c5715b323c..f29dc39b7be 100644
--- a/compiler/rustc_hir_typeck/src/place_op.rs
+++ b/compiler/rustc_hir_typeck/src/place_op.rs
@@ -162,11 +162,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind() {
                     adjustments.push(Adjustment {
                         kind: Adjust::Borrow(AutoBorrow::Ref(*region, AutoBorrowMutability::Not)),
-                        target: Ty::new_ref(
-                            self.tcx,
-                            *region,
-                            ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: adjusted_ty },
-                        ),
+                        target: Ty::new_imm_ref(self.tcx, *region, adjusted_ty),
                     });
                 } else {
                     span_bug!(expr.span, "input to index is not a ref?");
@@ -400,11 +396,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         allow_two_phase_borrow: AllowTwoPhase::No,
                     };
                     adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(*region, mutbl));
-                    adjustment.target = Ty::new_ref(
-                        self.tcx,
-                        *region,
-                        ty::TypeAndMut { ty: source, mutbl: mutbl.into() },
-                    );
+                    adjustment.target = Ty::new_ref(self.tcx, *region, source, mutbl.into());
                 }
                 source = adjustment.target;
             }
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index b71e88a1579..e489b431e81 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -217,7 +217,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 bug!();
             };
             for stmt in block.stmts {
-                let hir::StmtKind::Let(hir::Local {
+                let hir::StmtKind::Let(hir::LetStmt {
                     init: Some(init),
                     source: hir::LocalSource::AsyncFn,
                     pat,
@@ -1719,7 +1719,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         for pointer_ty in place.deref_tys() {
             match pointer_ty.kind() {
                 // We don't capture derefs of raw ptrs
-                ty::RawPtr(_) => unreachable!(),
+                ty::RawPtr(_, _) => unreachable!(),
 
                 // Dereferencing a mut-ref allows us to mut the Place if we don't deref
                 // an immut-ref after on top of this.
@@ -1780,11 +1780,9 @@ fn apply_capture_kind_on_capture_ty<'tcx>(
 ) -> Ty<'tcx> {
     match capture_kind {
         ty::UpvarCapture::ByValue => ty,
-        ty::UpvarCapture::ByRef(kind) => Ty::new_ref(
-            tcx,
-            region.unwrap(),
-            ty::TypeAndMut { ty: ty, mutbl: kind.to_mutbl_lossy() },
-        ),
+        ty::UpvarCapture::ByRef(kind) => {
+            Ty::new_ref(tcx, region.unwrap(), ty, kind.to_mutbl_lossy())
+        }
     }
 }
 
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 0740a3fd3e9..f4516b684c3 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -351,7 +351,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
         intravisit::walk_pat(self, p);
     }
 
-    fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
+    fn visit_local(&mut self, l: &'tcx hir::LetStmt<'tcx>) {
         intravisit::walk_local(self, l);
         let var_ty = self.fcx.local_ty(l.span, l.hir_id);
         let var_ty = self.resolve(var_ty, &l.span);
diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs
index 24512dea939..5156a8d3479 100644
--- a/compiler/rustc_incremental/src/persist/dirty_clean.rs
+++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs
@@ -148,7 +148,7 @@ pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) {
 
         let crate_items = tcx.hir_crate_items(());
 
-        for id in crate_items.items() {
+        for id in crate_items.free_items() {
             dirty_clean_visitor.check_item(id.owner_id.def_id);
         }
 
diff --git a/compiler/rustc_index_macros/src/lib.rs b/compiler/rustc_index_macros/src/lib.rs
index 532cac5791e..015518ae4d6 100644
--- a/compiler/rustc_index_macros/src/lib.rs
+++ b/compiler/rustc_index_macros/src/lib.rs
@@ -34,13 +34,7 @@ mod newtype;
 #[proc_macro]
 #[cfg_attr(
     feature = "nightly",
-    allow_internal_unstable(
-        step_trait,
-        rustc_attrs,
-        trusted_step,
-        spec_option_partial_eq,
-        min_specialization
-    )
+    allow_internal_unstable(step_trait, rustc_attrs, trusted_step, min_specialization)
 )]
 pub fn newtype_index(input: TokenStream) -> TokenStream {
     newtype::newtype(input)
diff --git a/compiler/rustc_index_macros/src/newtype.rs b/compiler/rustc_index_macros/src/newtype.rs
index 0b25628b9e1..e5c2ba42483 100644
--- a/compiler/rustc_index_macros/src/newtype.rs
+++ b/compiler/rustc_index_macros/src/newtype.rs
@@ -156,32 +156,6 @@ impl Parse for Newtype {
             }
         };
 
-        let spec_partial_eq_impl = if let Lit::Int(max) = &max {
-            if let Ok(max_val) = max.base10_parse::<u32>() {
-                quote! {
-                    #gate_rustc_only
-                    impl core::option::SpecOptionPartialEq for #name {
-                        #[inline]
-                        fn eq(l: &Option<Self>, r: &Option<Self>) -> bool {
-                            if #max_val < u32::MAX {
-                                l.map(|i| i.as_u32()).unwrap_or(#max_val+1) == r.map(|i| i.as_u32()).unwrap_or(#max_val+1)
-                            } else {
-                                match (l, r) {
-                                    (Some(l), Some(r)) => r == l,
-                                    (None, None) => true,
-                                    _ => false
-                                }
-                            }
-                        }
-                    }
-                }
-            } else {
-                quote! {}
-            }
-        } else {
-            quote! {}
-        };
-
         Ok(Self(quote! {
             #(#attrs)*
             #[derive(Clone, Copy, PartialEq, Eq, Hash, #(#derive_paths),*)]
@@ -283,8 +257,6 @@ impl Parse for Newtype {
 
             #step
 
-            #spec_partial_eq_impl
-
             impl From<#name> for u32 {
                 #[inline]
                 fn from(v: #name) -> u32 {
diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl
index e44a6ae3b3f..521c65c6009 100644
--- a/compiler/rustc_infer/messages.ftl
+++ b/compiler/rustc_infer/messages.ftl
@@ -169,7 +169,7 @@ infer_lifetime_param_suggestion_elided = each elided lifetime in input position
 
 infer_meant_byte_literal = if you meant to write a byte literal, prefix with `b`
 infer_meant_char_literal = if you meant to write a `char` literal, use single quotes
-infer_meant_str_literal = if you meant to write a `str` literal, use double quotes
+infer_meant_str_literal = if you meant to write a string literal, use double quotes
 infer_mismatched_static_lifetime = incompatible lifetime on type
 infer_more_targeted = {$has_param_name ->
     [true] `{$param_name}`
diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs
index a3cf0d8e520..d0b1f2848ff 100644
--- a/compiler/rustc_infer/src/errors/mod.rs
+++ b/compiler/rustc_infer/src/errors/mod.rs
@@ -1339,15 +1339,12 @@ pub enum TypeErrorAdditionalDiags {
         span: Span,
         code: String,
     },
-    #[suggestion(
-        infer_meant_str_literal,
-        code = "\"{code}\"",
-        applicability = "machine-applicable"
-    )]
+    #[multipart_suggestion(infer_meant_str_literal, applicability = "machine-applicable")]
     MeantStrLiteral {
-        #[primary_span]
-        span: Span,
-        code: String,
+        #[suggestion_part(code = "\"")]
+        start: Span,
+        #[suggestion_part(code = "\"")]
+        end: Span,
     },
     #[suggestion(
         infer_consider_specifying_length,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 331b3b97c34..82634f7308d 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -403,8 +403,10 @@ impl<'tcx> InferCtxt<'tcx> {
         let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
         let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
 
-        self.tcx.explicit_item_bounds(def_id).iter_instantiated_copied(self.tcx, args).find_map(
-            |(predicate, _)| {
+        self.tcx
+            .explicit_item_super_predicates(def_id)
+            .iter_instantiated_copied(self.tcx, args)
+            .find_map(|(predicate, _)| {
                 predicate
                     .kind()
                     .map_bound(|kind| match kind {
@@ -417,8 +419,7 @@ impl<'tcx> InferCtxt<'tcx> {
                     })
                     .no_bound_vars()
                     .flatten()
-            },
-        )
+            })
     }
 }
 
@@ -2078,16 +2079,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 // If a string was expected and the found expression is a character literal,
                 // perhaps the user meant to write `"s"` to specify a string literal.
                 (ty::Ref(_, r, _), ty::Char) if r.is_str() => {
-                    if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
-                        if let Some(code) =
-                            code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
-                        {
-                            suggestions.push(TypeErrorAdditionalDiags::MeantStrLiteral {
-                                span,
-                                code: escape_literal(code),
-                            })
-                        }
-                    }
+                    suggestions.push(TypeErrorAdditionalDiags::MeantStrLiteral {
+                        start: span.with_hi(span.lo() + BytePos(1)),
+                        end: span.with_lo(span.hi() - BytePos(1)),
+                    })
                 }
                 // For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`,
                 // we try to suggest to add the missing `let` for `if let Some(..) = expr`
@@ -2139,7 +2134,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         // the same span as the error and the type is specified.
                         if let hir::Stmt {
                             kind:
-                                hir::StmtKind::Let(hir::Local {
+                                hir::StmtKind::Let(hir::LetStmt {
                                     init: Some(hir::Expr { span: init_span, .. }),
                                     ty: Some(array_ty),
                                     ..
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index 0686994b037..f89ed256a08 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -11,7 +11,7 @@ use rustc_hir::def::Res;
 use rustc_hir::def::{CtorOf, DefKind, Namespace};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, Local, LocalSource};
+use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, LetStmt, LocalSource};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::infer::unify_key::{
     ConstVariableOrigin, ConstVariableOriginKind, ConstVariableValue,
@@ -546,40 +546,55 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 }
             }
             InferSourceKind::FullyQualifiedMethodCall { receiver, successor, args, def_id } => {
-                let mut printer = fmt_printer(self, Namespace::ValueNS);
-                printer.print_def_path(def_id, args).unwrap();
-                let def_path = printer.into_buffer();
-
-                // We only care about whether we have to add `&` or `&mut ` for now.
-                // This is the case if the last adjustment is a borrow and the
-                // first adjustment was not a builtin deref.
-                let adjustment = match typeck_results.expr_adjustments(receiver) {
-                    [
-                        Adjustment { kind: Adjust::Deref(None), target: _ },
-                        ..,
-                        Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), target: _ },
-                    ] => "",
-                    [
-                        ..,
-                        Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mut_)), target: _ },
-                    ] => hir::Mutability::from(*mut_).ref_prefix_str(),
-                    _ => "",
-                };
+                let placeholder = Some(self.next_ty_var(TypeVariableOrigin {
+                    span: rustc_span::DUMMY_SP,
+                    kind: TypeVariableOriginKind::MiscVariable,
+                }));
+                if let Some(args) = args.make_suggestable(self.infcx.tcx, true, placeholder) {
+                    let mut printer = fmt_printer(self, Namespace::ValueNS);
+                    printer.print_def_path(def_id, args).unwrap();
+                    let def_path = printer.into_buffer();
+
+                    // We only care about whether we have to add `&` or `&mut ` for now.
+                    // This is the case if the last adjustment is a borrow and the
+                    // first adjustment was not a builtin deref.
+                    let adjustment = match typeck_results.expr_adjustments(receiver) {
+                        [
+                            Adjustment { kind: Adjust::Deref(None), target: _ },
+                            ..,
+                            Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), target: _ },
+                        ] => "",
+                        [
+                            ..,
+                            Adjustment {
+                                kind: Adjust::Borrow(AutoBorrow::Ref(_, mut_)),
+                                target: _,
+                            },
+                        ] => hir::Mutability::from(*mut_).ref_prefix_str(),
+                        _ => "",
+                    };
 
-                multi_suggestions.push(SourceKindMultiSuggestion::new_fully_qualified(
-                    receiver.span,
-                    def_path,
-                    adjustment,
-                    successor,
-                ));
+                    multi_suggestions.push(SourceKindMultiSuggestion::new_fully_qualified(
+                        receiver.span,
+                        def_path,
+                        adjustment,
+                        successor,
+                    ));
+                }
             }
             InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => {
-                let ty_info = ty_to_string(self, ty, None);
-                multi_suggestions.push(SourceKindMultiSuggestion::new_closure_return(
-                    ty_info,
-                    data,
-                    should_wrap_expr,
-                ));
+                let placeholder = Some(self.next_ty_var(TypeVariableOrigin {
+                    span: rustc_span::DUMMY_SP,
+                    kind: TypeVariableOriginKind::MiscVariable,
+                }));
+                if let Some(ty) = ty.make_suggestable(self.infcx.tcx, true, placeholder) {
+                    let ty_info = ty_to_string(self, ty, None);
+                    multi_suggestions.push(SourceKindMultiSuggestion::new_closure_return(
+                        ty_info,
+                        data,
+                        should_wrap_expr,
+                    ));
+                }
             }
         }
         match error_code {
@@ -1107,7 +1122,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
         self.tecx.tcx.hir()
     }
 
-    fn visit_local(&mut self, local: &'tcx Local<'tcx>) {
+    fn visit_local(&mut self, local: &'tcx LetStmt<'tcx>) {
         intravisit::walk_local(self, local);
 
         if let Some(ty) = self.opt_node_type(local.hir_id) {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index 503645191aa..fe70b631cdb 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -13,8 +13,8 @@ use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, Subdiagnosti
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{walk_ty, Visitor};
 use rustc_hir::{
-    self as hir, GenericBound, GenericParamKind, Item, ItemKind, Lifetime, LifetimeName, Node,
-    TyKind,
+    self as hir, GenericBound, GenericParam, GenericParamKind, Item, ItemKind, Lifetime,
+    LifetimeName, LifetimeParamKind, MissingLifetimeKind, Node, TyKind,
 };
 use rustc_middle::ty::{
     self, AssocItemContainer, StaticLifetimeVisitor, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
@@ -355,20 +355,8 @@ pub fn suggest_new_region_bound(
                     // introducing a new lifetime `'a` or making use of one from existing named lifetimes if any
                     if let Some(id) = scope_def_id
                         && let Some(generics) = tcx.hir().get_generics(id)
-                        && let mut spans_suggs = generics
-                            .params
-                            .iter()
-                            .filter(|p| p.is_elided_lifetime())
-                            .map(|p| {
-                                if p.span.hi() - p.span.lo() == rustc_span::BytePos(1) {
-                                    // Ampersand (elided without '_)
-                                    (p.span.shrink_to_hi(), format!("{name} "))
-                                } else {
-                                    // Underscore (elided with '_)
-                                    (p.span, name.to_string())
-                                }
-                            })
-                            .collect::<Vec<_>>()
+                        && let mut spans_suggs =
+                            make_elided_region_spans_suggs(name, generics.params.iter())
                         && spans_suggs.len() > 1
                     {
                         let use_lt = if existing_lt_name == None {
@@ -430,6 +418,57 @@ pub fn suggest_new_region_bound(
     }
 }
 
+fn make_elided_region_spans_suggs<'a>(
+    name: &str,
+    generic_params: impl Iterator<Item = &'a GenericParam<'a>>,
+) -> Vec<(Span, String)> {
+    let mut spans_suggs = Vec::new();
+    let mut bracket_span = None;
+    let mut consecutive_brackets = 0;
+
+    let mut process_consecutive_brackets =
+        |span: Option<Span>, spans_suggs: &mut Vec<(Span, String)>| {
+            if span
+                .is_some_and(|span| bracket_span.map_or(true, |bracket_span| span == bracket_span))
+            {
+                consecutive_brackets += 1;
+            } else if let Some(bracket_span) = bracket_span.take() {
+                let sugg = std::iter::once("<")
+                    .chain(std::iter::repeat(name).take(consecutive_brackets).intersperse(", "))
+                    .chain([">"])
+                    .collect();
+                spans_suggs.push((bracket_span.shrink_to_hi(), sugg));
+                consecutive_brackets = 0;
+            }
+            bracket_span = span;
+        };
+
+    for p in generic_params {
+        if let GenericParamKind::Lifetime { kind: LifetimeParamKind::Elided(kind) } = p.kind {
+            match kind {
+                MissingLifetimeKind::Underscore => {
+                    process_consecutive_brackets(None, &mut spans_suggs);
+                    spans_suggs.push((p.span, name.to_string()))
+                }
+                MissingLifetimeKind::Ampersand => {
+                    process_consecutive_brackets(None, &mut spans_suggs);
+                    spans_suggs.push((p.span.shrink_to_hi(), format!("{name} ")));
+                }
+                MissingLifetimeKind::Comma => {
+                    process_consecutive_brackets(None, &mut spans_suggs);
+                    spans_suggs.push((p.span.shrink_to_hi(), format!("{name}, ")));
+                }
+                MissingLifetimeKind::Brackets => {
+                    process_consecutive_brackets(Some(p.span), &mut spans_suggs);
+                }
+            }
+        }
+    }
+    process_consecutive_brackets(None, &mut spans_suggs);
+
+    spans_suggs
+}
+
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     pub fn get_impl_ident_and_self_ty_from_trait(
         tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
index 24eaff08220..008b75b4c9a 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
@@ -299,17 +299,19 @@ impl<T> Trait<T> for X {
                     }
                     (ty::Dynamic(t, _, ty::DynKind::Dyn), ty::Alias(ty::Opaque, alias))
                         if let Some(def_id) = t.principal_def_id()
-                            && tcx.explicit_item_bounds(alias.def_id).skip_binder().iter().any(
-                                |(pred, _span)| match pred.kind().skip_binder() {
+                            && tcx
+                                .explicit_item_super_predicates(alias.def_id)
+                                .skip_binder()
+                                .iter()
+                                .any(|(pred, _span)| match pred.kind().skip_binder() {
                                     ty::ClauseKind::Trait(trait_predicate)
                                         if trait_predicate.polarity
-                                            == ty::ImplPolarity::Positive =>
+                                            == ty::PredicatePolarity::Positive =>
                                     {
                                         trait_predicate.def_id() == def_id
                                     }
                                     _ => false,
-                                },
-                            ) =>
+                                }) =>
                     {
                         diag.help(format!(
                             "you can box the `{}` to coerce it to `Box<{}>`, but you'll have to \
@@ -412,13 +414,13 @@ impl<T> Trait<T> for X {
                             ty::Alias(..) => values.expected,
                             _ => values.found,
                         };
-                        let preds = tcx.explicit_item_bounds(opaque_ty.def_id);
+                        let preds = tcx.explicit_item_super_predicates(opaque_ty.def_id);
                         for (pred, _span) in preds.skip_binder() {
                             let ty::ClauseKind::Trait(trait_predicate) = pred.kind().skip_binder()
                             else {
                                 continue;
                             };
-                            if trait_predicate.polarity != ty::ImplPolarity::Positive {
+                            if trait_predicate.polarity != ty::PredicatePolarity::Positive {
                                 continue;
                             }
                             let def_id = trait_predicate.def_id();
diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
index 9081fbaa2dc..e220c4d02a2 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
@@ -2,7 +2,7 @@ use crate::infer::error_reporting::hir::Path;
 use core::ops::ControlFlow;
 use hir::def::CtorKind;
 use hir::intravisit::{walk_expr, walk_stmt, Visitor};
-use hir::{Local, QPath};
+use hir::{LetStmt, QPath};
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{Applicability, Diag};
 use rustc_hir as hir;
@@ -321,7 +321,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             && let Some(expr) = block.expr
             && let hir::ExprKind::Path(QPath::Resolved(_, Path { res, .. })) = expr.kind
             && let Res::Local(local) = res
-            && let Node::Local(Local { init: Some(init), .. }) = self.tcx.parent_hir_node(*local)
+            && let Node::LetStmt(LetStmt { init: Some(init), .. }) =
+                self.tcx.parent_hir_node(*local)
         {
             fn collect_blocks<'hir>(expr: &hir::Expr<'hir>, blocks: &mut Vec<&hir::Block<'hir>>) {
                 match expr.kind {
@@ -585,7 +586,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             }
 
             fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) -> Self::Result {
-                if let hir::StmtKind::Let(hir::Local {
+                if let hir::StmtKind::Let(LetStmt {
                     span,
                     pat: hir::Pat { .. },
                     ty: None,
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index c39d0425f7e..5ae7f8bf504 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -13,6 +13,7 @@ use rustc_data_structures::graph::implementation::{
     Direction, Graph, NodeIndex, INCOMING, OUTGOING,
 };
 use rustc_data_structures::intern::Interned;
+use rustc_data_structures::unord::UnordSet;
 use rustc_index::{IndexSlice, IndexVec};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -139,8 +140,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
         let mut var_data = self.construct_var_data();
 
         // Deduplicating constraints is shown to have a positive perf impact.
-        self.data.constraints.sort_by_key(|(constraint, _)| *constraint);
-        self.data.constraints.dedup_by_key(|(constraint, _)| *constraint);
+        let mut seen = UnordSet::default();
+        self.data.constraints.retain(|(constraint, _)| seen.insert(*constraint));
 
         if cfg!(debug_assertions) {
             self.dump_constraints();
@@ -888,12 +889,14 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
                     }
 
                     Constraint::RegSubVar(region, _) | Constraint::VarSubReg(_, region) => {
-                        let constraint_idx =
-                            this.constraints.binary_search_by(|(c, _)| c.cmp(&edge.data)).unwrap();
-                        state.result.push(RegionAndOrigin {
-                            region,
-                            origin: this.constraints[constraint_idx].1.clone(),
-                        });
+                        let origin = this
+                            .constraints
+                            .iter()
+                            .find(|(c, _)| *c == edge.data)
+                            .unwrap()
+                            .1
+                            .clone();
+                        state.result.push(RegionAndOrigin { region, origin });
                     }
 
                     Constraint::RegSubReg(..) => panic!(
diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
index a6f8115c27e..02b8ded285f 100644
--- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
@@ -94,9 +94,6 @@ impl<'tcx> InferCtxt<'tcx> {
         cause: &ObligationCause<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> InferResult<'tcx, ()> {
-        if a.references_error() || b.references_error() {
-            return Ok(InferOk { value: (), obligations: vec![] });
-        }
         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();
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index 3ef37bf3466..bd981c20567 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -300,7 +300,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
         alias_ty: ty::AliasTy<'tcx>,
     ) -> impl Iterator<Item = ty::Region<'tcx>> {
         let tcx = self.tcx;
-        let bounds = tcx.item_bounds(alias_ty.def_id);
+        let bounds = tcx.item_super_predicates(alias_ty.def_id);
         trace!("{:#?}", bounds.skip_binder());
         bounds
             .iter_instantiated(tcx, alias_ty.args)
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index 0f3f2bc5fa6..3d6b54721d0 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -104,7 +104,7 @@ pub struct RegionConstraintData<'tcx> {
 }
 
 /// Represents a constraint that influences the inference process.
-#[derive(Clone, Copy, PartialEq, Eq, Debug, PartialOrd, Ord)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
 pub enum Constraint<'tcx> {
     /// A region variable is a subregion of another.
     VarSubVar(RegionVid, RegionVid),
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index 807d5500a90..ee9ce842d00 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -24,6 +24,7 @@
 #![feature(extend_one)]
 #![feature(let_chains)]
 #![feature(if_let_guard)]
+#![feature(iter_intersperse)]
 #![feature(iterator_try_collect)]
 #![feature(try_blocks)]
 #![feature(yeet_expr)]
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index 4808a1defdd..616f5cc0456 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -209,7 +209,7 @@ impl<'tcx> FulfillmentError<'tcx> {
 }
 
 impl<'tcx> PolyTraitObligation<'tcx> {
-    pub fn polarity(&self) -> ty::ImplPolarity {
+    pub fn polarity(&self) -> ty::PredicatePolarity {
         self.predicate.skip_binder().polarity
     }
 
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index e9df0505cbb..6d43011d33c 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -270,7 +270,7 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
         match bound_clause.skip_binder() {
             ty::ClauseKind::Trait(data) => {
                 // Negative trait bounds do not imply any supertrait bounds
-                if data.polarity == ty::ImplPolarity::Negative {
+                if data.polarity != ty::PredicatePolarity::Positive {
                     return;
                 }
                 // Get predicates implied by the trait, or only super predicates if we only care about self predicates.
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 1a82e6c6910..8ba14d37982 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -341,51 +341,22 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
 
             let sysroot = filesearch::materialize_sysroot(config.opts.maybe_sysroot.clone());
 
-            let (codegen_backend, target_override) = match config.make_codegen_backend {
-                None => {
-                    // Build a target without override, so that it can override the backend if needed
-                    let target =
-                        config::build_target_config(&early_dcx, &config.opts, None, &sysroot);
-
-                    let backend = util::get_codegen_backend(
-                        &early_dcx,
-                        &sysroot,
-                        config.opts.unstable_opts.codegen_backend.as_deref(),
-                        &target,
-                    );
-
-                    // target_override is documented to be called before init(), so this is okay
-                    let target_override = backend.target_override(&config.opts);
-
-                    // Assert that we don't use target's override of the backend and
-                    // backend's override of the target at the same time
-                    if config.opts.unstable_opts.codegen_backend.is_none()
-                        && target.default_codegen_backend.is_some()
-                        && target_override.is_some()
-                    {
-                        rustc_middle::bug!(
-                            "Codegen backend requested target override even though the target requested the backend"
-                        );
-                    }
-
-                    (backend, target_override)
-                }
+            let target = config::build_target_config(&early_dcx, &config.opts, &sysroot);
+
+            let codegen_backend = match config.make_codegen_backend {
+                None => util::get_codegen_backend(
+                    &early_dcx,
+                    &sysroot,
+                    config.opts.unstable_opts.codegen_backend.as_deref(),
+                    &target,
+                ),
                 Some(make_codegen_backend) => {
-                    // N.B. `make_codegen_backend` takes precedence over `target.default_codegen_backend`,
-                    //      which is ignored in this case.
-                    let backend = make_codegen_backend(&config.opts);
-
-                    // target_override is documented to be called before init(), so this is okay
-                    let target_override = backend.target_override(&config.opts);
-
-                    (backend, target_override)
+                    // N.B. `make_codegen_backend` takes precedence over
+                    // `target.default_codegen_backend`, which is ignored in this case.
+                    make_codegen_backend(&config.opts)
                 }
             };
 
-            // Re-build target with the (potential) override
-            let target_cfg =
-                config::build_target_config(&early_dcx, &config.opts, target_override, &sysroot);
-
             let temps_dir = config.opts.unstable_opts.temps_dir.as_deref().map(PathBuf::from);
 
             let bundle = match rustc_errors::fluent_bundle(
@@ -418,7 +389,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
                 locale_resources,
                 config.lint_caps,
                 config.file_loader,
-                target_cfg,
+                target,
                 sysroot,
                 util::rustc_version_str().unwrap_or("unknown"),
                 config.ice_file,
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 4d8e749d1da..8a27e9a6453 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -41,8 +41,7 @@ fn mk_session(matches: getopts::Matches) -> (Session, Cfg) {
 
     let sysroot = filesearch::materialize_sysroot(sessopts.maybe_sysroot.clone());
 
-    let target_cfg =
-        rustc_session::config::build_target_config(&early_dcx, &sessopts, None, &sysroot);
+    let target = rustc_session::config::build_target_config(&early_dcx, &sessopts, &sysroot);
 
     let sess = build_session(
         early_dcx,
@@ -53,7 +52,7 @@ fn mk_session(matches: getopts::Matches) -> (Session, Cfg) {
         vec![],
         Default::default(),
         None,
-        target_cfg,
+        target,
         sysroot,
         "",
         None,
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 7d48f90db36..d09f8d7d7cf 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -48,12 +48,20 @@ pub fn add_configuration(cfg: &mut Cfg, sess: &mut Session, codegen_backend: &dy
     }
 }
 
-const STACK_SIZE: usize = 8 * 1024 * 1024;
-
-fn get_stack_size() -> Option<usize> {
-    // FIXME: Hacks on hacks. If the env is trying to override the stack size
-    // then *don't* set it explicitly.
-    env::var_os("RUST_MIN_STACK").is_none().then_some(STACK_SIZE)
+pub static STACK_SIZE: OnceLock<usize> = OnceLock::new();
+pub const DEFAULT_STACK_SIZE: usize = 8 * 1024 * 1024;
+
+fn init_stack_size() -> usize {
+    // Obey the environment setting or default
+    *STACK_SIZE.get_or_init(|| {
+        env::var_os("RUST_MIN_STACK")
+            .map(|os_str| os_str.to_string_lossy().into_owned())
+            // ignore if it is set to nothing
+            .filter(|s| s.trim() != "")
+            .map(|s| s.trim().parse::<usize>().unwrap())
+            // otherwise pick a consistent default
+            .unwrap_or(DEFAULT_STACK_SIZE)
+    })
 }
 
 pub(crate) fn run_in_thread_with_globals<F: FnOnce() -> R + Send, R: Send>(
@@ -66,10 +74,7 @@ pub(crate) fn run_in_thread_with_globals<F: FnOnce() -> R + Send, R: Send>(
     // the parallel compiler, in particular to ensure there is no accidental
     // sharing of data between the main thread and the compilation thread
     // (which might cause problems for the parallel compiler).
-    let mut builder = thread::Builder::new().name("rustc".to_string());
-    if let Some(size) = get_stack_size() {
-        builder = builder.stack_size(size);
-    }
+    let builder = thread::Builder::new().name("rustc".to_string()).stack_size(init_stack_size());
 
     // We build the session globals and run `f` on the spawned thread, because
     // `SessionGlobals` does not impl `Send` in the non-parallel compiler.
@@ -120,7 +125,7 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
         });
     }
 
-    let mut builder = rayon::ThreadPoolBuilder::new()
+    let builder = rayon::ThreadPoolBuilder::new()
         .thread_name(|_| "rustc".to_string())
         .acquire_thread_handler(jobserver::acquire_thread)
         .release_thread_handler(jobserver::release_thread)
@@ -144,10 +149,8 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
                     on_panic.disable();
                 })
                 .unwrap();
-        });
-    if let Some(size) = get_stack_size() {
-        builder = builder.stack_size(size);
-    }
+        })
+        .stack_size(init_stack_size());
 
     // We create the session globals on the main thread, then create the thread
     // pool. Upon creation, each worker thread created gets a copy of the
diff --git a/compiler/rustc_lexer/src/cursor.rs b/compiler/rustc_lexer/src/cursor.rs
index aba7f95487e..d173c3ac032 100644
--- a/compiler/rustc_lexer/src/cursor.rs
+++ b/compiler/rustc_lexer/src/cursor.rs
@@ -46,7 +46,7 @@ impl<'a> Cursor<'a> {
     /// If requested position doesn't exist, `EOF_CHAR` is returned.
     /// However, getting `EOF_CHAR` doesn't always mean actual end of file,
     /// it should be checked with `is_eof` method.
-    pub(crate) fn first(&self) -> char {
+    pub fn first(&self) -> char {
         // `.next()` optimizes better than `.nth(0)`
         self.chars.clone().next().unwrap_or(EOF_CHAR)
     }
@@ -59,6 +59,15 @@ impl<'a> Cursor<'a> {
         iter.next().unwrap_or(EOF_CHAR)
     }
 
+    /// Peeks the third symbol from the input stream without consuming it.
+    pub fn third(&self) -> char {
+        // `.next()` optimizes better than `.nth(1)`
+        let mut iter = self.chars.clone();
+        iter.next();
+        iter.next();
+        iter.next().unwrap_or(EOF_CHAR)
+    }
+
     /// Checks if there is nothing more to consume.
     pub(crate) fn is_eof(&self) -> bool {
         self.chars.as_str().is_empty()
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index aff1dc40954..70c7aff3f20 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -726,7 +726,7 @@ fn type_implements_negative_copy_modulo_regions<'tcx>(
     param_env: ty::ParamEnv<'tcx>,
 ) -> bool {
     let trait_ref = ty::TraitRef::new(tcx, tcx.require_lang_item(hir::LangItem::Copy, None), [ty]);
-    let pred = ty::TraitPredicate { trait_ref, polarity: ty::ImplPolarity::Negative };
+    let pred = ty::TraitPredicate { trait_ref, polarity: ty::PredicatePolarity::Negative };
     let obligation = traits::Obligation {
         cause: traits::ObligationCause::dummy(),
         param_env,
@@ -2477,7 +2477,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
                 Adt(..) if ty.is_box() => Some("`Box` must be non-null".into()),
                 FnPtr(..) => Some("function pointers must be non-null".into()),
                 Never => Some("the `!` type has no valid value".into()),
-                RawPtr(tm) if matches!(tm.ty.kind(), Dynamic(..)) =>
+                RawPtr(ty, _) if matches!(ty.kind(), Dynamic(..)) =>
                 // raw ptr to dyn Trait
                 {
                     Some("the vtable of a wide raw pointer must be non-null".into())
@@ -2493,7 +2493,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
                     Some("integers must be initialized".into())
                 }
                 Float(_) if init == InitKind::Uninit => Some("floats must be initialized".into()),
-                RawPtr(_) if init == InitKind::Uninit => {
+                RawPtr(_, _) if init == InitKind::Uninit => {
                     Some("raw pointers must be initialized".into())
                 }
                 // Recurse and checks for some compound types. (but not unions)
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 8c0e5b17fd8..64ef30039a8 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -937,7 +937,7 @@ impl<'tcx> LateContext<'tcx> {
             }
             && let Some(init) = match parent_node {
                 hir::Node::Expr(expr) => Some(expr),
-                hir::Node::Local(hir::Local { init, .. }) => *init,
+                hir::Node::LetStmt(hir::LetStmt { init, .. }) => *init,
                 _ => None,
             }
         {
@@ -982,7 +982,7 @@ impl<'tcx> LateContext<'tcx> {
             }
             && let Some(init) = match parent_node {
                 hir::Node::Expr(expr) => Some(expr),
-                hir::Node::Local(hir::Local { init, .. }) => *init,
+                hir::Node::LetStmt(hir::LetStmt { init, .. }) => *init,
                 hir::Node::Item(item) => match item.kind {
                     hir::ItemKind::Const(.., body_id) | hir::ItemKind::Static(.., body_id) => {
                         Some(self.tcx.hir().body(body_id).value)
diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs
index b995f38f23c..fae492f252e 100644
--- a/compiler/rustc_lint/src/foreign_modules.rs
+++ b/compiler/rustc_lint/src/foreign_modules.rs
@@ -322,10 +322,10 @@ fn structurally_same_type_impl<'tcx>(
                 (Slice(a_ty), Slice(b_ty)) => {
                     structurally_same_type_impl(seen_types, tcx, param_env, *a_ty, *b_ty, ckind)
                 }
-                (RawPtr(a_tymut), RawPtr(b_tymut)) => {
-                    a_tymut.mutbl == b_tymut.mutbl
+                (RawPtr(a_ty, a_mutbl), RawPtr(b_ty, b_mutbl)) => {
+                    a_mutbl == b_mutbl
                         && structurally_same_type_impl(
-                            seen_types, tcx, param_env, a_tymut.ty, b_tymut.ty, ckind,
+                            seen_types, tcx, param_env, *a_ty, *b_ty, ckind,
                         )
                 }
                 (Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => {
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index 506716e39a1..384bd353d75 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -238,7 +238,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
         }
     }
 
-    fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
+    fn visit_local(&mut self, l: &'tcx hir::LetStmt<'tcx>) {
         self.with_lint_attrs(l.hir_id, |cx| {
             lint_callback!(cx, check_local, l);
             hir_visit::walk_local(cx, l);
diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs
index de642f373b5..9d4d75a646a 100644
--- a/compiler/rustc_lint/src/let_underscore.rs
+++ b/compiler/rustc_lint/src/let_underscore.rs
@@ -105,7 +105,7 @@ const SYNC_GUARD_SYMBOLS: [Symbol; 3] = [
 
 impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
     #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
-    fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::Local<'_>) {
+    fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::LetStmt<'_>) {
         if matches!(local.source, rustc_hir::LocalSource::AsyncFn) {
             return;
         }
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 26fc3f20b2c..5bb2942ad4b 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -354,7 +354,7 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> {
         intravisit::walk_variant(self, v);
     }
 
-    fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
+    fn visit_local(&mut self, l: &'tcx hir::LetStmt<'tcx>) {
         self.add_id(l.hir_id);
         intravisit::walk_local(self, l);
     }
@@ -428,7 +428,7 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, QueryMapExpectationsWrapper<'
         intravisit::walk_variant(self, v);
     }
 
-    fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
+    fn visit_local(&mut self, l: &'tcx hir::LetStmt<'tcx>) {
         self.add_id(l.hir_id);
         intravisit::walk_local(self, l);
     }
diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs
index 508f3e1ec31..3e93cc0be6a 100644
--- a/compiler/rustc_lint/src/passes.rs
+++ b/compiler/rustc_lint/src/passes.rs
@@ -15,7 +15,7 @@ macro_rules! late_lint_methods {
             fn check_foreign_item(a: &'tcx rustc_hir::ForeignItem<'tcx>);
             fn check_item(a: &'tcx rustc_hir::Item<'tcx>);
             fn check_item_post(a: &'tcx rustc_hir::Item<'tcx>);
-            fn check_local(a: &'tcx rustc_hir::Local<'tcx>);
+            fn check_local(a: &'tcx rustc_hir::LetStmt<'tcx>);
             fn check_block(a: &'tcx rustc_hir::Block<'tcx>);
             fn check_block_post(a: &'tcx rustc_hir::Block<'tcx>);
             fn check_stmt(a: &'tcx rustc_hir::Stmt<'tcx>);
diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs
index f386db9d8db..9b938b34c00 100644
--- a/compiler/rustc_lint/src/reference_casting.rs
+++ b/compiler/rustc_lint/src/reference_casting.rs
@@ -1,7 +1,7 @@
 use rustc_ast::Mutability;
 use rustc_hir::{Expr, ExprKind, UnOp};
 use rustc_middle::ty::layout::LayoutOf as _;
-use rustc_middle::ty::{self, layout::TyAndLayout, TypeAndMut};
+use rustc_middle::ty::{self, layout::TyAndLayout};
 use rustc_span::sym;
 
 use crate::{lints::InvalidReferenceCastingDiag, LateContext, LateLintPass, LintContext};
@@ -153,7 +153,7 @@ fn is_cast_from_ref_to_mut_ptr<'tcx>(
     let end_ty = cx.typeck_results().node_type(orig_expr.hir_id);
 
     // Bail out early if the end type is **not** a mutable pointer.
-    if !matches!(end_ty.kind(), ty::RawPtr(TypeAndMut { ty: _, mutbl: Mutability::Mut })) {
+    if !matches!(end_ty.kind(), ty::RawPtr(_, Mutability::Mut)) {
         return None;
     }
 
@@ -183,7 +183,7 @@ fn is_cast_to_bigger_memory_layout<'tcx>(
 ) -> Option<(TyAndLayout<'tcx>, TyAndLayout<'tcx>, Expr<'tcx>)> {
     let end_ty = cx.typeck_results().node_type(orig_expr.hir_id);
 
-    let ty::RawPtr(TypeAndMut { ty: inner_end_ty, mutbl: _ }) = end_ty.kind() else {
+    let ty::RawPtr(inner_end_ty, _) = end_ty.kind() else {
         return None;
     };
 
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 0ad257d02bd..5331d2fb752 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -18,10 +18,10 @@ use rustc_errors::DiagMessage;
 use rustc_hir as hir;
 use rustc_hir::{is_range_literal, Expr, ExprKind, Node};
 use rustc_middle::ty::layout::{IntegerExt, LayoutOf, SizeSkeleton};
+use rustc_middle::ty::GenericArgsRef;
 use rustc_middle::ty::{
     self, AdtKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
 };
-use rustc_middle::ty::{GenericArgsRef, TypeAndMut};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map;
 use rustc_span::symbol::sym;
@@ -673,7 +673,7 @@ fn lint_wide_pointer<'tcx>(
             refs += 1;
         }
         match ty.kind() {
-            ty::RawPtr(TypeAndMut { mutbl: _, ty }) => (!ty.is_sized(cx.tcx, cx.param_env))
+            ty::RawPtr(ty, _) => (!ty.is_sized(cx.tcx, cx.param_env))
                 .then(|| (refs, matches!(ty.kind(), ty::Dynamic(_, _, ty::Dyn)))),
             _ => None,
         }
@@ -1046,10 +1046,10 @@ fn get_nullable_type<'tcx>(
         }
         ty::Int(ty) => Ty::new_int(tcx, ty),
         ty::Uint(ty) => Ty::new_uint(tcx, ty),
-        ty::RawPtr(ty_mut) => Ty::new_ptr(tcx, ty_mut),
+        ty::RawPtr(ty, mutbl) => Ty::new_ptr(tcx, ty, mutbl),
         // As these types are always non-null, the nullable equivalent of
         // `Option<T>` of these types are their raw pointer counterparts.
-        ty::Ref(_region, ty, mutbl) => Ty::new_ptr(tcx, ty::TypeAndMut { ty, mutbl }),
+        ty::Ref(_region, ty, mutbl) => Ty::new_ptr(tcx, ty, mutbl),
         // There is no nullable equivalent for Rust's function pointers,
         // you must use an `Option<fn(..) -> _>` to represent it.
         ty::FnPtr(..) => ty,
@@ -1374,7 +1374,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 help: Some(fluent::lint_improper_ctypes_tuple_help),
             },
 
-            ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _)
+            ty::RawPtr(ty, _) | ty::Ref(_, ty, _)
                 if {
                     matches!(self.mode, CItemKind::Definition)
                         && ty.is_sized(self.cx.tcx, self.cx.param_env)
@@ -1383,7 +1383,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 FfiSafe
             }
 
-            ty::RawPtr(ty::TypeAndMut { ty, .. })
+            ty::RawPtr(ty, _)
                 if match ty.kind() {
                     ty::Tuple(tuple) => tuple.is_empty(),
                     _ => false,
@@ -1392,9 +1392,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 FfiSafe
             }
 
-            ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => {
-                self.check_type_for_ffi(cache, ty)
-            }
+            ty::RawPtr(ty, _) | ty::Ref(_, ty, _) => self.check_type_for_ffi(cache, ty),
 
             ty::Array(inner_ty, _) => self.check_type_for_ffi(cache, inner_ty),
 
diff --git a/compiler/rustc_lint/src/unit_bindings.rs b/compiler/rustc_lint/src/unit_bindings.rs
index b74430d8fa0..6222adf58ae 100644
--- a/compiler/rustc_lint/src/unit_bindings.rs
+++ b/compiler/rustc_lint/src/unit_bindings.rs
@@ -46,7 +46,7 @@ declare_lint! {
 declare_lint_pass!(UnitBindings => [UNIT_BINDINGS]);
 
 impl<'tcx> LateLintPass<'tcx> for UnitBindings {
-    fn check_local(&mut self, cx: &crate::LateContext<'tcx>, local: &'tcx hir::Local<'tcx>) {
+    fn check_local(&mut self, cx: &crate::LateContext<'tcx>, local: &'tcx hir::LetStmt<'tcx>) {
         // Suppress warning if user:
         // - explicitly ascribes a type to the pattern
         // - explicitly wrote `let pat = ();`
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 3e10879e241..0b757f95a99 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -295,7 +295,9 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
                 ty::Alias(ty::Opaque | ty::Projection, ty::AliasTy { def_id: def, .. }) => {
                     elaborate(
                         cx.tcx,
-                        cx.tcx.explicit_item_bounds(def).instantiate_identity_iter_copied(),
+                        cx.tcx
+                            .explicit_item_super_predicates(def)
+                            .instantiate_identity_iter_copied(),
                     )
                     // We only care about self bounds for the impl-trait
                     .filter_only_self()
@@ -863,7 +865,7 @@ trait UnusedDelimLint {
                 (iter, UnusedDelimsCtx::ForIterExpr, true, None, Some(body.span.lo()), true)
             }
 
-            Match(ref head, _) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => {
+            Match(ref head, ..) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => {
                 let left = e.span.lo() + rustc_span::BytePos(5);
                 (head, UnusedDelimsCtx::MatchScrutineeExpr, true, Some(left), None, true)
             }
@@ -1131,7 +1133,7 @@ impl EarlyLintPass for UnusedParens {
                 }
                 return;
             }
-            ExprKind::Match(ref _expr, ref arm) => {
+            ExprKind::Match(ref _expr, ref arm, _) => {
                 for a in arm {
                     if let Some(body) = &a.body {
                         self.check_unused_delims_expr(
@@ -1181,7 +1183,7 @@ impl EarlyLintPass for UnusedParens {
                 self.check_unused_parens_pat(cx, &f.pat, false, false, keep_space);
             },
             // Avoid linting on `i @ (p0 | .. | pn)` and `box (p0 | .. | pn)`, #64106.
-            Ident(.., Some(p)) | Box(p) => self.check_unused_parens_pat(cx, p, true, false, keep_space),
+            Ident(.., Some(p)) | Box(p) | Deref(p) => self.check_unused_parens_pat(cx, p, true, false, keep_space),
             // Avoid linting on `&(mut x)` as `&mut x` has a different meaning, #55342.
             // Also avoid linting on `& mut? (p0 | .. | pn)`, #64106.
             Ref(p, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not, keep_space),
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 03783fa9798..596da58b091 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1063,6 +1063,20 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         ty::EarlyBinder::bind(&*output)
     }
 
+    fn get_explicit_item_super_predicates(
+        self,
+        index: DefIndex,
+        tcx: TyCtxt<'tcx>,
+    ) -> ty::EarlyBinder<&'tcx [(ty::Clause<'tcx>, Span)]> {
+        let lazy = self.root.tables.explicit_item_super_predicates.get(self, index);
+        let output = if lazy.is_default() {
+            &mut []
+        } else {
+            tcx.arena.alloc_from_iter(lazy.decode((self, tcx)))
+        };
+        ty::EarlyBinder::bind(&*output)
+    }
+
     fn get_variant(
         self,
         kind: DefKind,
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 1c59af51589..1aabd296641 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -206,6 +206,7 @@ impl IntoArgs for (CrateNum, SimplifiedType) {
 
 provide! { tcx, def_id, other, cdata,
     explicit_item_bounds => { cdata.get_explicit_item_bounds(def_id.index, tcx) }
+    explicit_item_super_predicates => { cdata.get_explicit_item_super_predicates(def_id.index, tcx) }
     explicit_predicates_of => { table }
     generics_of => { table }
     inferred_outlives_of => { table_defaulted_array }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 1bd2c88ebaa..42724f7dd2b 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1491,6 +1491,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             }
             if let DefKind::OpaqueTy = def_kind {
                 self.encode_explicit_item_bounds(def_id);
+                self.encode_explicit_item_super_predicates(def_id);
                 self.tables
                     .is_type_alias_impl_trait
                     .set(def_id.index, self.tcx.is_type_alias_impl_trait(def_id));
@@ -1599,6 +1600,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         record_defaulted_array!(self.tables.explicit_item_bounds[def_id] <- bounds);
     }
 
+    fn encode_explicit_item_super_predicates(&mut self, def_id: DefId) {
+        debug!("EncodeContext::encode_explicit_item_super_predicates({:?})", def_id);
+        let bounds = self.tcx.explicit_item_super_predicates(def_id).skip_binder();
+        record_defaulted_array!(self.tables.explicit_item_super_predicates[def_id] <- bounds);
+    }
+
     #[instrument(level = "debug", skip(self))]
     fn encode_info_for_assoc_item(&mut self, def_id: DefId) {
         let tcx = self.tcx;
@@ -1611,6 +1618,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             AssocItemContainer::TraitContainer => {
                 if let ty::AssocKind::Type = item.kind {
                     self.encode_explicit_item_bounds(def_id);
+                    self.encode_explicit_item_super_predicates(def_id);
                 }
             }
             AssocItemContainer::ImplContainer => {
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 8aa31ef564f..5b0be8ac230 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -387,6 +387,7 @@ define_tables! {
     // corresponding DefPathHash.
     def_path_hashes: Table<DefIndex, u64>,
     explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
+    explicit_item_super_predicates: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
     inferred_outlives_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
     inherent_impls: Table<DefIndex, LazyArray<DefIndex>>,
     associated_types_for_impl_traits_in_associated_fn: Table<DefIndex, LazyArray<DefId>>,
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index 96c58ef411b..9e8ee92b5d9 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -6,6 +6,7 @@ edition = "2021"
 [dependencies]
 # tidy-alphabetical-start
 bitflags = "2.4.1"
+derivative = "2.2.0"
 either = "1.5.0"
 field-offset = "0.3.5"
 gsgdt = "0.1.2"
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 5e74ce86007..53cb05198cd 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -166,12 +166,12 @@ impl<'hir> Map<'hir> {
 
     #[inline]
     pub fn items(self) -> impl Iterator<Item = ItemId> + 'hir {
-        self.tcx.hir_crate_items(()).items.iter().copied()
+        self.tcx.hir_crate_items(()).free_items.iter().copied()
     }
 
     #[inline]
     pub fn module_items(self, module: LocalModDefId) -> impl Iterator<Item = ItemId> + 'hir {
-        self.tcx.hir_module_items(module).items()
+        self.tcx.hir_module_items(module).free_items()
     }
 
     pub fn def_key(self, def_id: LocalDefId) -> DefKey {
@@ -418,7 +418,7 @@ impl<'hir> Map<'hir> {
         V: Visitor<'hir>,
     {
         let krate = self.tcx.hir_crate_items(());
-        walk_list!(visitor, visit_item, krate.items().map(|id| self.item(id)));
+        walk_list!(visitor, visit_item, krate.free_items().map(|id| self.item(id)));
         walk_list!(visitor, visit_trait_item, krate.trait_items().map(|id| self.trait_item(id)));
         walk_list!(visitor, visit_impl_item, krate.impl_items().map(|id| self.impl_item(id)));
         walk_list!(
@@ -436,7 +436,7 @@ impl<'hir> Map<'hir> {
         V: Visitor<'hir>,
     {
         let module = self.tcx.hir_module_items(module);
-        walk_list!(visitor, visit_item, module.items().map(|id| self.item(id)));
+        walk_list!(visitor, visit_item, module.free_items().map(|id| self.item(id)));
         walk_list!(visitor, visit_trait_item, module.trait_items().map(|id| self.trait_item(id)));
         walk_list!(visitor, visit_impl_item, module.impl_items().map(|id| self.impl_item(id)));
         walk_list!(
@@ -567,7 +567,7 @@ impl<'hir> Map<'hir> {
                 }
                 // Ignore `return`s on the first iteration
                 Node::Expr(Expr { kind: ExprKind::Loop(..) | ExprKind::Ret(..), .. })
-                | Node::Local(_) => {
+                | Node::LetStmt(_) => {
                     return None;
                 }
                 _ => {}
@@ -906,7 +906,7 @@ impl<'hir> Map<'hir> {
             Node::Lifetime(lifetime) => lifetime.ident.span,
             Node::GenericParam(param) => param.span,
             Node::Infer(i) => i.span,
-            Node::Local(local) => local.span,
+            Node::LetStmt(local) => local.span,
             Node::Crate(item) => item.spans.inner_span,
             Node::WhereBoundPredicate(pred) => pred.span,
             Node::ArrayLenInfer(inf) => inf.span,
@@ -1163,7 +1163,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
         Node::Arm(_) => node_str("arm"),
         Node::Block(_) => node_str("block"),
         Node::Infer(_) => node_str("infer"),
-        Node::Local(_) => node_str("local"),
+        Node::LetStmt(_) => node_str("local"),
         Node::Ctor(ctor) => format!(
             "{id} (ctor {})",
             ctor.ctor_def_id().map_or("<missing path>".into(), |def_id| path_str(def_id)),
@@ -1197,7 +1197,7 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod
     } = collector;
     return ModuleItems {
         submodules: submodules.into_boxed_slice(),
-        items: items.into_boxed_slice(),
+        free_items: items.into_boxed_slice(),
         trait_items: trait_items.into_boxed_slice(),
         impl_items: impl_items.into_boxed_slice(),
         foreign_items: foreign_items.into_boxed_slice(),
@@ -1226,7 +1226,7 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems {
 
     return ModuleItems {
         submodules: submodules.into_boxed_slice(),
-        items: items.into_boxed_slice(),
+        free_items: items.into_boxed_slice(),
         trait_items: trait_items.into_boxed_slice(),
         impl_items: impl_items.into_boxed_slice(),
         foreign_items: foreign_items.into_boxed_slice(),
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index f9fa8ac2f7a..28f7574f66f 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -22,7 +22,7 @@ use rustc_span::{ErrorGuaranteed, ExpnId};
 #[derive(Debug, HashStable, Encodable, Decodable)]
 pub struct ModuleItems {
     submodules: Box<[OwnerId]>,
-    items: Box<[ItemId]>,
+    free_items: Box<[ItemId]>,
     trait_items: Box<[TraitItemId]>,
     impl_items: Box<[ImplItemId]>,
     foreign_items: Box<[ForeignItemId]>,
@@ -30,14 +30,22 @@ pub struct ModuleItems {
 }
 
 impl ModuleItems {
-    pub fn items(&self) -> impl Iterator<Item = ItemId> + '_ {
-        self.items.iter().copied()
+    /// Returns all non-associated locally defined items in all modules.
+    ///
+    /// Note that this does *not* include associated items of `impl` blocks! It also does not
+    /// include foreign items. If you want to e.g. get all functions, use `definitions()` below.
+    ///
+    /// However, this does include the `impl` blocks themselves.
+    pub fn free_items(&self) -> impl Iterator<Item = ItemId> + '_ {
+        self.free_items.iter().copied()
     }
 
     pub fn trait_items(&self) -> impl Iterator<Item = TraitItemId> + '_ {
         self.trait_items.iter().copied()
     }
 
+    /// Returns all items that are associated with some `impl` block (both inherent and trait impl
+    /// blocks).
     pub fn impl_items(&self) -> impl Iterator<Item = ImplItemId> + '_ {
         self.impl_items.iter().copied()
     }
@@ -47,7 +55,7 @@ impl ModuleItems {
     }
 
     pub fn owners(&self) -> impl Iterator<Item = OwnerId> + '_ {
-        self.items
+        self.free_items
             .iter()
             .map(|id| id.owner_id)
             .chain(self.trait_items.iter().map(|id| id.owner_id))
@@ -63,7 +71,7 @@ impl ModuleItems {
         &self,
         f: impl Fn(ItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
     ) -> Result<(), ErrorGuaranteed> {
-        try_par_for_each_in(&self.items[..], |&id| f(id))
+        try_par_for_each_in(&self.free_items[..], |&id| f(id))
     }
 
     pub fn par_trait_items(
diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs
index 0ee97a6bed0..f70ef51107f 100644
--- a/compiler/rustc_middle/src/macros.rs
+++ b/compiler/rustc_middle/src/macros.rs
@@ -11,12 +11,18 @@
 /// [`span_bug`]: crate::span_bug
 #[macro_export]
 macro_rules! bug {
-    () => ( $crate::bug!("impossible case reached") );
-    ($msg:expr) => ({ $crate::util::bug::bug_fmt(::std::format_args!($msg)) });
-    ($msg:expr,) => ({ $crate::bug!($msg) });
-    ($fmt:expr, $($arg:tt)+) => ({
+    () => (
+        $crate::bug!("impossible case reached")
+    );
+    ($msg:expr) => (
+        $crate::util::bug::bug_fmt(::std::format_args!($msg))
+    );
+    ($msg:expr,) => (
+        $crate::bug!($msg)
+    );
+    ($fmt:expr, $($arg:tt)+) => (
         $crate::util::bug::bug_fmt(::std::format_args!($fmt, $($arg)+))
-    });
+    );
 }
 
 /// A macro for triggering an ICE with a span.
@@ -30,11 +36,15 @@ macro_rules! bug {
 /// [`DiagCtxt::span_delayed_bug`]: rustc_errors::DiagCtxt::span_delayed_bug
 #[macro_export]
 macro_rules! span_bug {
-    ($span:expr, $msg:expr) => ({ $crate::util::bug::span_bug_fmt($span, ::std::format_args!($msg)) });
-    ($span:expr, $msg:expr,) => ({ $crate::span_bug!($span, $msg) });
-    ($span:expr, $fmt:expr, $($arg:tt)+) => ({
+    ($span:expr, $msg:expr) => (
+        $crate::util::bug::span_bug_fmt($span, ::std::format_args!($msg))
+    );
+    ($span:expr, $msg:expr,) => (
+        $crate::span_bug!($span, $msg)
+    );
+    ($span:expr, $fmt:expr, $($arg:tt)+) => (
         $crate::util::bug::span_bug_fmt($span, ::std::format_args!($fmt, $($arg)+))
-    });
+    );
 }
 
 ///////////////////////////////////////////////////////////////////////////
diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs
index 214297b9869..02185cbeacf 100644
--- a/compiler/rustc_middle/src/mir/consts.rs
+++ b/compiler/rustc_middle/src/mir/consts.rs
@@ -456,7 +456,7 @@ impl<'tcx> Const<'tcx> {
 }
 
 /// An unevaluated (potentially generic) constant used in MIR.
-#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable)]
 #[derive(Hash, HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct UnevaluatedConst<'tcx> {
     pub def: DefId,
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index 645a417c322..588aa1f40d7 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -88,14 +88,13 @@ pub enum CoverageKind {
     /// Marks a span that might otherwise not be represented in MIR, so that
     /// coverage instrumentation can associate it with its enclosing block/BCB.
     ///
-    /// Only used by the `InstrumentCoverage` pass, and has no effect during
-    /// codegen.
+    /// Should be erased before codegen (at some point after `InstrumentCoverage`).
     SpanMarker,
 
     /// Marks its enclosing basic block with an ID that can be referred to by
     /// side data in [`BranchInfo`].
     ///
-    /// Has no effect during codegen.
+    /// Should be erased before codegen (at some point after `InstrumentCoverage`).
     BlockMarker { id: BlockMarkerId },
 
     /// Marks the point in MIR control flow represented by a coverage counter.
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index 4047891d769..00faa211853 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -37,9 +37,16 @@ pub trait AllocBytes:
     /// Create a zeroed `AllocBytes` of the specified size and alignment.
     /// Returns `None` if we ran out of memory on the host.
     fn zeroed(size: Size, _align: Align) -> Option<Self>;
+
+    /// Gives direct access to the raw underlying storage.
+    ///
+    /// Crucially this pointer is compatible with:
+    /// - other pointers retunred by this method, and
+    /// - references returned from `deref()`, as long as there was no write.
+    fn as_mut_ptr(&mut self) -> *mut u8;
 }
 
-// Default `bytes` for `Allocation` is a `Box<[u8]>`.
+/// Default `bytes` for `Allocation` is a `Box<u8>`.
 impl AllocBytes for Box<[u8]> {
     fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, _align: Align) -> Self {
         Box::<[u8]>::from(slice.into())
@@ -51,6 +58,11 @@ impl AllocBytes for Box<[u8]> {
         let bytes = unsafe { bytes.assume_init() };
         Some(bytes)
     }
+
+    fn as_mut_ptr(&mut self) -> *mut u8 {
+        // Carefully avoiding any intermediate references.
+        ptr::addr_of_mut!(**self).cast()
+    }
 }
 
 /// This type represents an Allocation in the Miri/CTFE core engine.
@@ -399,10 +411,6 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes>
 
 /// Byte accessors.
 impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> {
-    pub fn base_addr(&self) -> *const u8 {
-        self.bytes.as_ptr()
-    }
-
     /// This is the entirely abstraction-violating way to just grab the raw bytes without
     /// caring about provenance or initialization.
     ///
@@ -452,13 +460,14 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes>
         Ok(self.get_bytes_unchecked(range))
     }
 
-    /// Just calling this already marks everything as defined and removes provenance,
-    /// so be sure to actually put data there!
+    /// This is the entirely abstraction-violating way to just get mutable access to the raw bytes.
+    /// Just calling this already marks everything as defined and removes provenance, so be sure to
+    /// actually overwrite all the data there!
     ///
     /// It is the caller's responsibility to check bounds and alignment beforehand.
     /// Most likely, you want to use the `PlaceTy` and `OperandTy`-based methods
     /// on `InterpCx` instead.
-    pub fn get_bytes_mut(
+    pub fn get_bytes_unchecked_for_overwrite(
         &mut self,
         cx: &impl HasDataLayout,
         range: AllocRange,
@@ -469,8 +478,9 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes>
         Ok(&mut self.bytes[range.start.bytes_usize()..range.end().bytes_usize()])
     }
 
-    /// A raw pointer variant of `get_bytes_mut` that avoids invalidating existing aliases into this memory.
-    pub fn get_bytes_mut_ptr(
+    /// A raw pointer variant of `get_bytes_unchecked_for_overwrite` that avoids invalidating existing immutable aliases
+    /// into this memory.
+    pub fn get_bytes_unchecked_for_overwrite_ptr(
         &mut self,
         cx: &impl HasDataLayout,
         range: AllocRange,
@@ -479,10 +489,19 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes>
         self.provenance.clear(range, cx)?;
 
         assert!(range.end().bytes_usize() <= self.bytes.len()); // need to do our own bounds-check
+        // Cruciall, we go via `AllocBytes::as_mut_ptr`, not `AllocBytes::deref_mut`.
         let begin_ptr = self.bytes.as_mut_ptr().wrapping_add(range.start.bytes_usize());
         let len = range.end().bytes_usize() - range.start.bytes_usize();
         Ok(ptr::slice_from_raw_parts_mut(begin_ptr, len))
     }
+
+    /// This gives direct mutable access to the entire buffer, just exposing their internal state
+    /// without reseting anything. Directly exposes `AllocBytes::as_mut_ptr`. Only works if
+    /// `OFFSET_IS_ADDR` is true.
+    pub fn get_bytes_unchecked_raw_mut(&mut self) -> *mut u8 {
+        assert!(Prov::OFFSET_IS_ADDR);
+        self.bytes.as_mut_ptr()
+    }
 }
 
 /// Reading and writing.
@@ -589,7 +608,8 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes>
         };
 
         let endian = cx.data_layout().endian;
-        let dst = self.get_bytes_mut(cx, range)?;
+        // Yes we do overwrite all the bytes in `dst`.
+        let dst = self.get_bytes_unchecked_for_overwrite(cx, range)?;
         write_target_uint(endian, dst, bytes).unwrap();
 
         // See if we have to also store some provenance.
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 984d4687ef8..e4dce2bdc9e 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -20,6 +20,7 @@ use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
 use rustc_hir::{self, CoroutineDesugaring, CoroutineKind, ImplicitSelfKind};
 use rustc_hir::{self as hir, HirId};
 use rustc_session::Session;
+use rustc_span::source_map::Spanned;
 use rustc_target::abi::{FieldIdx, VariantIdx};
 
 use polonius_engine::Atom;
@@ -44,6 +45,7 @@ use std::ops::{Index, IndexMut};
 use std::{iter, mem};
 
 pub use self::query::*;
+use self::visit::TyContext;
 pub use basic_blocks::BasicBlocks;
 
 mod basic_blocks;
@@ -304,6 +306,21 @@ impl<'tcx> CoroutineInfo<'tcx> {
     }
 }
 
+/// Some item that needs to monomorphize successfully for a MIR body to be considered well-formed.
+#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, HashStable, TyEncodable, TyDecodable)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub enum MentionedItem<'tcx> {
+    /// A function that gets called. We don't necessarily know its precise type yet, since it can be
+    /// hidden behind a generic.
+    Fn(Ty<'tcx>),
+    /// A type that has its drop shim called.
+    Drop(Ty<'tcx>),
+    /// Unsizing casts might require vtables, so we have to record them.
+    UnsizeCast { source_ty: Ty<'tcx>, target_ty: Ty<'tcx> },
+    /// A closure that is coerced to a function pointer.
+    Closure(Ty<'tcx>),
+}
+
 /// The lowered representation of a single function.
 #[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)]
 pub struct Body<'tcx> {
@@ -367,8 +384,24 @@ pub struct Body<'tcx> {
 
     /// Constants that are required to evaluate successfully for this MIR to be well-formed.
     /// We hold in this field all the constants we are not able to evaluate yet.
+    ///
+    /// This is soundness-critical, we make a guarantee that all consts syntactically mentioned in a
+    /// function have successfully evaluated if the function ever gets executed at runtime.
     pub required_consts: Vec<ConstOperand<'tcx>>,
 
+    /// Further items that were mentioned in this function and hence *may* become monomorphized,
+    /// depending on optimizations. We use this to avoid optimization-dependent compile errors: the
+    /// collector recursively traverses all "mentioned" items and evaluates all their
+    /// `required_consts`.
+    ///
+    /// This is *not* soundness-critical and the contents of this list are *not* a stable guarantee.
+    /// All that's relevant is that this set is optimization-level-independent, and that it includes
+    /// everything that the collector would consider "used". (For example, we currently compute this
+    /// set after drop elaboration, so some drop calls that can never be reached are not considered
+    /// "mentioned".) See the documentation of `CollectionMode` in
+    /// `compiler/rustc_monomorphize/src/collector.rs` for more context.
+    pub mentioned_items: Vec<Spanned<MentionedItem<'tcx>>>,
+
     /// Does this body use generic parameters. This is used for the `ConstEvaluatable` check.
     ///
     /// Note that this does not actually mean that this body is not computable right now.
@@ -445,6 +478,7 @@ impl<'tcx> Body<'tcx> {
             var_debug_info,
             span,
             required_consts: Vec::new(),
+            mentioned_items: Vec::new(),
             is_polymorphic: false,
             injection_phase: None,
             tainted_by_errors,
@@ -474,6 +508,7 @@ impl<'tcx> Body<'tcx> {
             spread_arg: None,
             span: DUMMY_SP,
             required_consts: Vec::new(),
+            mentioned_items: Vec::new(),
             var_debug_info: Vec::new(),
             is_polymorphic: false,
             injection_phase: None,
@@ -568,6 +603,17 @@ impl<'tcx> Body<'tcx> {
         }
     }
 
+    pub fn span_for_ty_context(&self, ty_context: TyContext) -> Span {
+        match ty_context {
+            TyContext::UserTy(span) => span,
+            TyContext::ReturnTy(source_info)
+            | TyContext::LocalDecl { source_info, .. }
+            | TyContext::YieldTy(source_info)
+            | TyContext::ResumeTy(source_info) => source_info.span,
+            TyContext::Location(loc) => self.source_info(loc).span,
+        }
+    }
+
     /// Returns the return type; it always return first element from `local_decls` array.
     #[inline]
     pub fn return_ty(&self) -> Ty<'tcx> {
@@ -750,7 +796,7 @@ impl<'tcx> Body<'tcx> {
         }
 
         match rvalue {
-            Rvalue::NullaryOp(NullOp::UbCheck(_), _) => {
+            Rvalue::NullaryOp(NullOp::UbChecks, _) => {
                 Some((tcx.sess.opts.debug_assertions as u128, targets))
             }
             Rvalue::Use(Operand::Constant(constant)) => {
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 94751c44761..fbee4a9366f 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -944,7 +944,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
                     NullOp::SizeOf => write!(fmt, "SizeOf({t})"),
                     NullOp::AlignOf => write!(fmt, "AlignOf({t})"),
                     NullOp::OffsetOf(fields) => write!(fmt, "OffsetOf({t}, {fields:?})"),
-                    NullOp::UbCheck(kind) => write!(fmt, "UbCheck({kind:?})"),
+                    NullOp::UbChecks => write!(fmt, "UbChecks()"),
                 }
             }
             ThreadLocalRef(did) => ty::tls::with(|tcx| {
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index 8bd872c1b19..731e050ca9b 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -284,8 +284,15 @@ rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
 /// order of the category, thereby influencing diagnostic output.
 ///
 /// See also `rustc_const_eval::borrow_check::constraints`.
-#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
 #[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)]
+#[derive(derivative::Derivative)]
+#[derivative(
+    PartialOrd,
+    Ord,
+    PartialOrd = "feature_allow_slow_enum",
+    Ord = "feature_allow_slow_enum"
+)]
 pub enum ConstraintCategory<'tcx> {
     Return(ReturnConstraint),
     Yield,
@@ -295,6 +302,7 @@ pub enum ConstraintCategory<'tcx> {
     Cast {
         /// Whether this is an unsizing cast and if yes, this contains the target type.
         /// Region variables are erased to ReErased.
+        #[derivative(PartialOrd = "ignore", Ord = "ignore")]
         unsize_to: Option<Ty<'tcx>>,
     },
 
@@ -304,7 +312,7 @@ pub enum ConstraintCategory<'tcx> {
     ClosureBounds,
 
     /// Contains the function type if available.
-    CallArgument(Option<Ty<'tcx>>),
+    CallArgument(#[derivative(PartialOrd = "ignore", Ord = "ignore")] Option<Ty<'tcx>>),
     CopyBound,
     SizedBound,
     Assignment,
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 0ab797134c0..36b7a48b2a2 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -124,6 +124,7 @@ pub enum AnalysisPhase {
     /// * [`TerminatorKind::FalseEdge`]
     /// * [`StatementKind::FakeRead`]
     /// * [`StatementKind::AscribeUserType`]
+    /// * [`StatementKind::Coverage`] with [`CoverageKind::BlockMarker`] or [`CoverageKind::SpanMarker`]
     /// * [`Rvalue::Ref`] with `BorrowKind::Fake`
     ///
     /// Furthermore, `Deref` projections must be the first projection within any place (if they
@@ -1366,16 +1367,9 @@ pub enum NullOp<'tcx> {
     AlignOf,
     /// Returns the offset of a field
     OffsetOf(&'tcx List<(VariantIdx, FieldIdx)>),
-    /// Returns whether we want to check for library UB or language UB at monomorphization time.
-    /// Both kinds of UB evaluate to `true` in codegen, and only library UB evalutes to `true` in
-    /// const-eval/Miri, because the interpreter has its own better checks for language UB.
-    UbCheck(UbKind),
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
-pub enum UbKind {
-    LanguageUb,
-    LibraryUb,
+    /// Returns whether we want to check for UB.
+    /// This returns the value of `cfg!(debug_assertions)` at monomorphization time.
+    UbChecks,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index 0c29fe57d4f..56a0a623397 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -170,11 +170,11 @@ impl<'tcx> Rvalue<'tcx> {
             Rvalue::ThreadLocalRef(did) => tcx.thread_local_ptr_ty(did),
             Rvalue::Ref(reg, bk, ref place) => {
                 let place_ty = place.ty(local_decls, tcx).ty;
-                Ty::new_ref(tcx, reg, ty::TypeAndMut { ty: place_ty, mutbl: bk.to_mutbl_lossy() })
+                Ty::new_ref(tcx, reg, place_ty, bk.to_mutbl_lossy())
             }
             Rvalue::AddressOf(mutability, ref place) => {
                 let place_ty = place.ty(local_decls, tcx).ty;
-                Ty::new_ptr(tcx, ty::TypeAndMut { ty: place_ty, mutbl: mutability })
+                Ty::new_ptr(tcx, place_ty, mutability)
             }
             Rvalue::Len(..) => tcx.types.usize,
             Rvalue::Cast(.., ty) => ty,
@@ -194,7 +194,7 @@ impl<'tcx> Rvalue<'tcx> {
             Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
                 tcx.types.usize
             }
-            Rvalue::NullaryOp(NullOp::UbCheck(_), _) => tcx.types.bool,
+            Rvalue::NullaryOp(NullOp::UbChecks, _) => tcx.types.bool,
             Rvalue::Aggregate(ref ak, ref ops) => match **ak {
                 AggregateKind::Array(ty) => Ty::new_array(tcx, ty, ops.len() as u64),
                 AggregateKind::Tuple => {
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index 33ee3371605..d3da49c26a2 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -234,6 +234,7 @@ trivial! {
     Option<rustc_middle::middle::stability::DeprecationEntry>,
     Option<rustc_middle::ty::Destructor>,
     Option<rustc_middle::ty::ImplTraitInTraitData>,
+    Option<rustc_middle::ty::ScalarInt>,
     Option<rustc_span::def_id::CrateNum>,
     Option<rustc_span::def_id::DefId>,
     Option<rustc_span::def_id::LocalDefId>,
diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs
index 69d3974184d..3b1d1a04d6f 100644
--- a/compiler/rustc_middle/src/query/keys.rs
+++ b/compiler/rustc_middle/src/query/keys.rs
@@ -13,6 +13,7 @@ use rustc_query_system::query::DefIdCacheSelector;
 use rustc_query_system::query::{DefaultCacheSelector, SingleCacheSelector, VecCacheSelector};
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
+use rustc_target::abi;
 
 /// Placeholder for `CrateNum`'s "local" counterpart
 #[derive(Copy, Clone, Debug)]
@@ -502,6 +503,14 @@ impl<'tcx> Key for (DefId, Ty<'tcx>, GenericArgsRef<'tcx>, ty::ParamEnv<'tcx>) {
     }
 }
 
+impl<'tcx> Key for (Ty<'tcx>, abi::VariantIdx) {
+    type CacheSelector = DefaultCacheSelector<Self>;
+
+    fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
+        DUMMY_SP
+    }
+}
+
 impl<'tcx> Key for (ty::Predicate<'tcx>, traits::WellFormedLoc) {
     type CacheSelector = DefaultCacheSelector<Self>;
 
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 9f0d2a89e6d..3984b3b61c2 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -343,11 +343,14 @@ rustc_queries! {
         }
     }
 
-    /// Returns the list of bounds that can be used for
-    /// `SelectionCandidate::ProjectionCandidate(_)` and
-    /// `ProjectionTyCandidate::TraitDef`.
-    /// Specifically this is the bounds written on the trait's type
-    /// definition, or those after the `impl` keyword
+    /// Returns the list of bounds that are required to be satsified
+    /// by a implementation or definition. For associated types, these
+    /// must be satisfied for an implementation to be well-formed,
+    /// and for opaque types, these are required to be satisfied by
+    /// the hidden-type of the opaque.
+    ///
+    /// Syntactially, these are the bounds written on the trait's type
+    /// definition, or those after the `impl` keyword for an opaque:
     ///
     /// ```ignore (incomplete)
     /// type X: Bound + 'lt
@@ -363,7 +366,16 @@ rustc_queries! {
         desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
         separate_provide_extern
-        feedable
+    }
+
+    /// The set of item bounds (see [`TyCtxt::explicit_item_bounds`]) that
+    /// share the `Self` type of the item. These are a subset of the bounds
+    /// that may explicitly be used for things like closure signature
+    /// deduction.
+    query explicit_item_super_predicates(key: DefId) -> ty::EarlyBinder<&'tcx [(ty::Clause<'tcx>, Span)]> {
+        desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) }
+        cache_on_disk_if { key.is_local() }
+        separate_provide_extern
     }
 
     /// Elaborated version of the predicates from `explicit_item_bounds`.
@@ -390,6 +402,14 @@ rustc_queries! {
         desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) }
     }
 
+    query item_super_predicates(key: DefId) -> ty::EarlyBinder<&'tcx ty::List<ty::Clause<'tcx>>> {
+        desc { |tcx| "elaborating item assumptions for `{}`", tcx.def_path_str(key) }
+    }
+
+    query item_non_self_assumptions(key: DefId) -> ty::EarlyBinder<&'tcx ty::List<ty::Clause<'tcx>>> {
+        desc { |tcx| "elaborating item assumptions for `{}`", tcx.def_path_str(key) }
+    }
+
     /// Look up all native libraries this crate depends on.
     /// These are assembled from the following places:
     /// - `extern` blocks (depending on their `link` attributes)
@@ -1042,6 +1062,13 @@ rustc_queries! {
         }
     }
 
+    /// Computes the tag (if any) for a given type and variant.
+    query tag_for_variant(
+        key: (Ty<'tcx>, abi::VariantIdx)
+    ) -> Option<ty::ScalarInt> {
+        desc { "computing variant tag for enum" }
+    }
+
     /// Evaluates a constant and returns the computed allocation.
     ///
     /// **Do not use this** directly, use the `eval_to_const_value` or `eval_to_valtree` instead.
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 96a61883cc1..f684f83a261 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -647,6 +647,7 @@ impl<'tcx> Pat<'tcx> {
             AscribeUserType { subpattern, .. }
             | Binding { subpattern: Some(subpattern), .. }
             | Deref { subpattern }
+            | DerefPattern { subpattern }
             | InlineConstant { subpattern, .. } => subpattern.walk_(it),
             Leaf { subpatterns } | Variant { subpatterns, .. } => {
                 subpatterns.iter().for_each(|field| field.pattern.walk_(it))
@@ -762,6 +763,11 @@ pub enum PatKind<'tcx> {
         subpattern: Box<Pat<'tcx>>,
     },
 
+    /// Deref pattern, written `box P` for now.
+    DerefPattern {
+        subpattern: Box<Pat<'tcx>>,
+    },
+
     /// One of the following:
     /// * `&str` (represented as a valtree), which will be handled as a string pattern and thus
     ///   exhaustiveness checking will detect if you use the same string twice in different
@@ -1172,6 +1178,9 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
                 }
                 write!(f, "{subpattern}")
             }
+            PatKind::DerefPattern { ref subpattern } => {
+                write!(f, "deref!({subpattern})")
+            }
             PatKind::Constant { value } => write!(f, "{value}"),
             PatKind::InlineConstant { def: _, ref subpattern } => {
                 write!(f, "{} (from inline const)", subpattern)
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index 5952c296fb6..99ab006bcc0 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -229,6 +229,7 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
     match &pat.kind {
         AscribeUserType { subpattern, ascription: _ }
         | Deref { subpattern }
+        | DerefPattern { subpattern }
         | Binding {
             subpattern: Some(subpattern),
             mutability: _,
diff --git a/compiler/rustc_middle/src/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs
index e6558595519..50d629120ab 100644
--- a/compiler/rustc_middle/src/ty/cast.rs
+++ b/compiler/rustc_middle/src/ty/cast.rs
@@ -69,7 +69,7 @@ impl<'tcx> CastTy<'tcx> {
             ty::Uint(u) => Some(CastTy::Int(IntTy::U(u))),
             ty::Float(_) => Some(CastTy::Float),
             ty::Adt(d, _) if d.is_enum() && d.is_payloadfree() => Some(CastTy::Int(IntTy::CEnum)),
-            ty::RawPtr(mt) => Some(CastTy::Ptr(mt)),
+            ty::RawPtr(ty, mutbl) => Some(CastTy::Ptr(ty::TypeAndMut { ty, mutbl })),
             ty::FnPtr(..) => Some(CastTy::FnPtr),
             ty::Dynamic(_, _, ty::DynStar) => Some(CastTy::DynStar),
             _ => None,
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 5de2e2fb1e7..3393f444843 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -27,8 +27,8 @@ use crate::traits::solve::{
 use crate::ty::{
     self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Const, ConstData, GenericParamDefKind,
     ImplPolarity, List, ParamConst, ParamTy, PolyExistentialPredicate, PolyFnSig, Predicate,
-    PredicateKind, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid,
-    TypeVisitable, Visibility,
+    PredicateKind, PredicatePolarity, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty,
+    TyKind, TyVid, TypeVisitable, Visibility,
 };
 use crate::ty::{GenericArg, GenericArgs, GenericArgsRef};
 use rustc_ast::{self as ast, attr};
@@ -1526,7 +1526,7 @@ macro_rules! nop_slice_lift {
 nop_slice_lift! {ty::ValTree<'a> => ty::ValTree<'tcx>}
 
 TrivialLiftImpls! {
-    ImplPolarity, Promoted
+    ImplPolarity, PredicatePolarity, Promoted
 }
 
 macro_rules! sty_debug_print {
@@ -1828,12 +1828,12 @@ impl<'tcx> TyCtxt<'tcx> {
         let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = ty.kind() else { return false };
         let future_trait = self.require_lang_item(LangItem::Future, None);
 
-        self.explicit_item_bounds(def_id).skip_binder().iter().any(|&(predicate, _)| {
+        self.explicit_item_super_predicates(def_id).skip_binder().iter().any(|&(predicate, _)| {
             let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() else {
                 return false;
             };
             trait_predicate.trait_ref.def_id == future_trait
-                && trait_predicate.polarity == ImplPolarity::Positive
+                && trait_predicate.polarity == PredicatePolarity::Positive
         })
     }
 
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 05463b8554f..ee18647cdd8 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -91,7 +91,12 @@ pub trait IsSuggestable<'tcx>: Sized {
     /// inference variables to be suggestable.
     fn is_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> bool;
 
-    fn make_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> Option<Self>;
+    fn make_suggestable(
+        self,
+        tcx: TyCtxt<'tcx>,
+        infer_suggestable: bool,
+        placeholder: Option<Ty<'tcx>>,
+    ) -> Option<Self>;
 }
 
 impl<'tcx, T> IsSuggestable<'tcx> for T
@@ -103,8 +108,13 @@ where
         self.visit_with(&mut IsSuggestableVisitor { tcx, infer_suggestable }).is_continue()
     }
 
-    fn make_suggestable(self, tcx: TyCtxt<'tcx>, infer_suggestable: bool) -> Option<T> {
-        self.try_fold_with(&mut MakeSuggestableFolder { tcx, infer_suggestable }).ok()
+    fn make_suggestable(
+        self,
+        tcx: TyCtxt<'tcx>,
+        infer_suggestable: bool,
+        placeholder: Option<Ty<'tcx>>,
+    ) -> Option<T> {
+        self.try_fold_with(&mut MakeSuggestableFolder { tcx, infer_suggestable, placeholder }).ok()
     }
 }
 
@@ -559,6 +569,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IsSuggestableVisitor<'tcx> {
 pub struct MakeSuggestableFolder<'tcx> {
     tcx: TyCtxt<'tcx>,
     infer_suggestable: bool,
+    placeholder: Option<Ty<'tcx>>,
 }
 
 impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for MakeSuggestableFolder<'tcx> {
@@ -572,19 +583,24 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for MakeSuggestableFolder<'tcx> {
         let t = match *t.kind() {
             Infer(InferTy::TyVar(_)) if self.infer_suggestable => t,
 
-            FnDef(def_id, args) => {
+            FnDef(def_id, args) if self.placeholder.is_none() => {
                 Ty::new_fn_ptr(self.tcx, self.tcx.fn_sig(def_id).instantiate(self.tcx, args))
             }
 
-            // FIXME(compiler-errors): We could replace these with infer, I guess.
             Closure(..)
+            | FnDef(..)
             | Infer(..)
             | Coroutine(..)
             | CoroutineWitness(..)
             | Bound(_, _)
             | Placeholder(_)
             | Error(_) => {
-                return Err(());
+                if let Some(placeholder) = self.placeholder {
+                    // We replace these with infer (which is passed in from an infcx).
+                    placeholder
+                } else {
+                    return Err(());
+                }
             }
 
             Alias(Opaque, AliasTy { def_id, .. }) => {
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index e15f0378846..09586a95f1c 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -32,7 +32,7 @@ impl<T> ExpectedFound<T> {
 pub enum TypeError<'tcx> {
     Mismatch,
     ConstnessMismatch(ExpectedFound<ty::BoundConstness>),
-    PolarityMismatch(ExpectedFound<ty::ImplPolarity>),
+    PolarityMismatch(ExpectedFound<ty::PredicatePolarity>),
     UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
     AbiMismatch(ExpectedFound<abi::Abi>),
     Mutability,
@@ -286,7 +286,7 @@ impl<'tcx> Ty<'tcx> {
             ty::Foreign(_) => "extern type".into(),
             ty::Array(..) => "array".into(),
             ty::Slice(_) => "slice".into(),
-            ty::RawPtr(_) => "raw pointer".into(),
+            ty::RawPtr(_, _) => "raw pointer".into(),
             ty::Ref(.., mutbl) => match mutbl {
                 hir::Mutability::Mut => "mutable reference",
                 _ => "reference",
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index adc153c4dfd..5b257cdfd86 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -120,7 +120,7 @@ pub fn simplify_type<'tcx>(
         ty::Str => Some(SimplifiedType::Str),
         ty::Array(..) => Some(SimplifiedType::Array),
         ty::Slice(..) => Some(SimplifiedType::Slice),
-        ty::RawPtr(ptr) => Some(SimplifiedType::Ptr(ptr.mutbl)),
+        ty::RawPtr(_, mutbl) => Some(SimplifiedType::Ptr(mutbl)),
         ty::Dynamic(trait_info, ..) => match trait_info.principal_def_id() {
             Some(principal_def_id) if !tcx.trait_is_auto(principal_def_id) => {
                 Some(SimplifiedType::Trait(principal_def_id))
@@ -286,8 +286,10 @@ impl DeepRejectCtxt {
                 }
                 _ => false,
             },
-            ty::RawPtr(obl) => match k {
-                ty::RawPtr(imp) => obl.mutbl == imp.mutbl && self.types_may_unify(obl.ty, imp.ty),
+            ty::RawPtr(obl_ty, obl_mutbl) => match *k {
+                ty::RawPtr(imp_ty, imp_mutbl) => {
+                    obl_mutbl == imp_mutbl && self.types_may_unify(obl_ty, imp_ty)
+                }
                 _ => false,
             },
             ty::Dynamic(obl_preds, ..) => {
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 18cf5445e56..ca9c762611e 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -211,8 +211,8 @@ impl FlagComputation {
 
             &ty::Slice(tt) => self.add_ty(tt),
 
-            ty::RawPtr(m) => {
-                self.add_ty(m.ty);
+            &ty::RawPtr(ty, _) => {
+                self.add_ty(ty);
             }
 
             &ty::Ref(r, ty, _) => {
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 4748e961019..65574f5702b 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -10,6 +10,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_index::bit_set::FiniteBitSet;
 use rustc_macros::HashStable;
 use rustc_middle::ty::normalize_erasing_regions::NormalizationError;
+use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::Symbol;
 
 use std::assert_matches::assert_matches;
@@ -172,6 +173,11 @@ impl<'tcx> Instance<'tcx> {
         // If this a non-generic instance, it cannot be a shared monomorphization.
         self.args.non_erasable_generics(tcx, self.def_id()).next()?;
 
+        // compiler_builtins cannot use upstream monomorphizations.
+        if tcx.is_compiler_builtins(LOCAL_CRATE) {
+            return None;
+        }
+
         match self.def {
             InstanceDef::Item(def) => tcx
                 .upstream_monomorphizations_for(def)
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 11fd73c9094..66078663098 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -2,7 +2,7 @@ use crate::error::UnsupportedFnAbi;
 use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use crate::query::TyCtxtAt;
 use crate::ty::normalize_erasing_regions::NormalizationError;
-use crate::ty::{self, ConstKind, Ty, TyCtxt, TypeVisitableExt};
+use crate::ty::{self, Ty, TyCtxt, TypeVisitableExt};
 use rustc_error_messages::DiagMessage;
 use rustc_errors::{
     Diag, DiagArgValue, DiagCtxt, Diagnostic, EmissionGuarantee, IntoDiagArg, Level,
@@ -328,7 +328,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
         };
 
         match *ty.kind() {
-            ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
+            ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => {
                 let non_zero = !ty.is_unsafe_ptr();
                 let tail = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
                 match tail.kind() {
@@ -345,32 +345,26 @@ impl<'tcx> SizeSkeleton<'tcx> {
             ty::Array(inner, len)
                 if len.ty() == tcx.types.usize && tcx.features().transmute_generic_consts =>
             {
+                let len_eval = len.try_eval_target_usize(tcx, param_env);
+                if len_eval == Some(0) {
+                    return Ok(SizeSkeleton::Known(Size::from_bytes(0)));
+                }
+
                 match SizeSkeleton::compute(inner, tcx, param_env)? {
                     // This may succeed because the multiplication of two types may overflow
                     // but a single size of a nested array will not.
                     SizeSkeleton::Known(s) => {
-                        if let Some(c) = len.try_eval_target_usize(tcx, param_env) {
+                        if let Some(c) = len_eval {
                             let size = s
                                 .bytes()
                                 .checked_mul(c)
                                 .ok_or_else(|| &*tcx.arena.alloc(LayoutError::SizeOverflow(ty)))?;
                             return Ok(SizeSkeleton::Known(Size::from_bytes(size)));
                         }
-                        let len = tcx.expand_abstract_consts(len);
-                        let prev = ty::Const::from_target_usize(tcx, s.bytes());
-                        let Some(gen_size) = mul_sorted_consts(tcx, param_env, len, prev) else {
-                            return Err(tcx.arena.alloc(LayoutError::SizeOverflow(ty)));
-                        };
-                        Ok(SizeSkeleton::Generic(gen_size))
+                        Err(tcx.arena.alloc(LayoutError::Unknown(ty)))
                     }
                     SizeSkeleton::Pointer { .. } => Err(err),
-                    SizeSkeleton::Generic(g) => {
-                        let len = tcx.expand_abstract_consts(len);
-                        let Some(gen_size) = mul_sorted_consts(tcx, param_env, len, g) else {
-                            return Err(tcx.arena.alloc(LayoutError::SizeOverflow(ty)));
-                        };
-                        Ok(SizeSkeleton::Generic(gen_size))
-                    }
+                    SizeSkeleton::Generic(_) => Err(tcx.arena.alloc(LayoutError::Unknown(ty))),
                 }
             }
 
@@ -468,56 +462,6 @@ impl<'tcx> SizeSkeleton<'tcx> {
     }
 }
 
-/// When creating the layout for types with abstract consts in their size (i.e. [usize; 4 * N]),
-/// to ensure that they have a canonical order and can be compared directly we combine all
-/// constants, and sort the other terms. This allows comparison of expressions of sizes,
-/// allowing for things like transmuting between types that depend on generic consts.
-/// This returns `None` if multiplication of constants overflows.
-fn mul_sorted_consts<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    a: ty::Const<'tcx>,
-    b: ty::Const<'tcx>,
-) -> Option<ty::Const<'tcx>> {
-    use crate::mir::BinOp::Mul;
-
-    let mut work = vec![a, b];
-    let mut done = vec![];
-    while let Some(n) = work.pop() {
-        if let ConstKind::Expr(ty::Expr::Binop(Mul, l, r)) = n.kind() {
-            work.push(l);
-            work.push(r)
-        } else {
-            done.push(n);
-        }
-    }
-    let mut k = 1;
-    let mut overflow = false;
-    done.retain(|c| {
-        let Some(c) = c.try_eval_target_usize(tcx, param_env) else {
-            return true;
-        };
-        let Some(next) = c.checked_mul(k) else {
-            overflow = true;
-            return false;
-        };
-        k = next;
-        false
-    });
-    if overflow {
-        return None;
-    }
-    if k != 1 {
-        done.push(ty::Const::from_target_usize(tcx, k));
-    } else if k == 0 {
-        return Some(ty::Const::from_target_usize(tcx, 0));
-    }
-    done.sort_unstable();
-
-    // create a single tree from the buffer
-    done.into_iter().reduce(|acc, n| ty::Const::new_expr(tcx, ty::Expr::Binop(Mul, n, acc), n.ty()))
-}
-
 pub trait HasTyCtxt<'tcx>: HasDataLayout {
     fn tcx(&self) -> TyCtxt<'tcx>;
 }
@@ -803,7 +747,7 @@ where
                 }
 
                 // Potentially-fat pointers.
-                ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
+                ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => {
                     assert!(i < this.fields.count());
 
                     // Reuse the fat `*T` type as its own thin pointer data field.
@@ -981,8 +925,8 @@ where
         let param_env = cx.param_env();
 
         let pointee_info = match *this.ty.kind() {
-            ty::RawPtr(mt) if offset.bytes() == 0 => {
-                tcx.layout_of(param_env.and(mt.ty)).ok().map(|layout| PointeeInfo {
+            ty::RawPtr(p_ty, _) if offset.bytes() == 0 => {
+                tcx.layout_of(param_env.and(p_ty)).ok().map(|layout| PointeeInfo {
                     size: layout.size,
                     align: layout.align.abi,
                     safe: None,
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 6632d980bff..6ce53ccc8cd 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -280,23 +280,43 @@ pub enum ImplPolarity {
     Reservation,
 }
 
-impl ImplPolarity {
+impl fmt::Display for ImplPolarity {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::Positive => f.write_str("positive"),
+            Self::Negative => f.write_str("negative"),
+            Self::Reservation => f.write_str("reservation"),
+        }
+    }
+}
+
+/// Polarity for a trait predicate. May either be negative or positive.
+/// Distinguished from [`ImplPolarity`] since we never compute goals with
+/// "reservation" level.
+#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable, Debug)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub enum PredicatePolarity {
+    /// `Type: Trait`
+    Positive,
+    /// `Type: !Trait`
+    Negative,
+}
+
+impl PredicatePolarity {
     /// Flips polarity by turning `Positive` into `Negative` and `Negative` into `Positive`.
-    pub fn flip(&self) -> Option<ImplPolarity> {
+    pub fn flip(&self) -> PredicatePolarity {
         match self {
-            ImplPolarity::Positive => Some(ImplPolarity::Negative),
-            ImplPolarity::Negative => Some(ImplPolarity::Positive),
-            ImplPolarity::Reservation => None,
+            PredicatePolarity::Positive => PredicatePolarity::Negative,
+            PredicatePolarity::Negative => PredicatePolarity::Positive,
         }
     }
 }
 
-impl fmt::Display for ImplPolarity {
+impl fmt::Display for PredicatePolarity {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             Self::Positive => f.write_str("positive"),
             Self::Negative => f.write_str("negative"),
-            Self::Reservation => f.write_str("reservation"),
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs
index 62822505fa5..d3bc7dd22e7 100644
--- a/compiler/rustc_middle/src/ty/predicate.rs
+++ b/compiler/rustc_middle/src/ty/predicate.rs
@@ -11,7 +11,7 @@ use std::cmp::Ordering;
 use crate::ty::visit::TypeVisitableExt;
 use crate::ty::{
     self, AliasTy, Binder, DebruijnIndex, DebugWithInfcx, EarlyBinder, GenericArg, GenericArgs,
-    GenericArgsRef, ImplPolarity, Term, Ty, TyCtxt, TypeFlags, WithCachedTypeInfo,
+    GenericArgsRef, PredicatePolarity, Term, Ty, TyCtxt, TypeFlags, WithCachedTypeInfo,
 };
 
 pub type ClauseKind<'tcx> = IrClauseKind<TyCtxt<'tcx>>;
@@ -70,7 +70,7 @@ impl<'tcx> Predicate<'tcx> {
                     polarity,
                 })) => Some(PredicateKind::Clause(ClauseKind::Trait(TraitPredicate {
                     trait_ref,
-                    polarity: polarity.flip()?,
+                    polarity: polarity.flip(),
                 }))),
 
                 _ => None,
@@ -663,7 +663,7 @@ pub struct TraitPredicate<'tcx> {
     /// exist via a series of predicates.)
     ///
     /// If polarity is Reserved: that's a bug.
-    pub polarity: ImplPolarity,
+    pub polarity: PredicatePolarity,
 }
 
 pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>;
@@ -693,7 +693,7 @@ impl<'tcx> PolyTraitPredicate<'tcx> {
     }
 
     #[inline]
-    pub fn polarity(self) -> ImplPolarity {
+    pub fn polarity(self) -> PredicatePolarity {
         self.skip_binder().polarity
     }
 }
@@ -907,7 +907,7 @@ impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> {
 impl<'tcx> ToPredicate<'tcx, TraitPredicate<'tcx>> for TraitRef<'tcx> {
     #[inline(always)]
     fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> TraitPredicate<'tcx> {
-        TraitPredicate { trait_ref: self, polarity: ImplPolarity::Positive }
+        TraitPredicate { trait_ref: self, polarity: PredicatePolarity::Positive }
     }
 }
 
@@ -940,7 +940,7 @@ impl<'tcx> ToPredicate<'tcx, PolyTraitPredicate<'tcx>> for Binder<'tcx, TraitRef
     fn to_predicate(self, _: TyCtxt<'tcx>) -> PolyTraitPredicate<'tcx> {
         self.map_bound(|trait_ref| TraitPredicate {
             trait_ref,
-            polarity: ty::ImplPolarity::Positive,
+            polarity: ty::PredicatePolarity::Positive,
         })
     }
 }
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index 520fc1dd7aa..d9aa7f9e5c4 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -263,7 +263,7 @@ fn characteristic_def_id_of_type_cached<'a>(
             characteristic_def_id_of_type_cached(subty, visited)
         }
 
-        ty::RawPtr(mt) => characteristic_def_id_of_type_cached(mt.ty, visited),
+        ty::RawPtr(ty, _) => characteristic_def_id_of_type_cached(ty, visited),
 
         ty::Ref(_, ty, _) => characteristic_def_id_of_type_cached(ty, visited),
 
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 995b439d10a..3f0a3a1a7bf 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -667,15 +667,15 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
             ty::Int(t) => p!(write("{}", t.name_str())),
             ty::Uint(t) => p!(write("{}", t.name_str())),
             ty::Float(t) => p!(write("{}", t.name_str())),
-            ty::RawPtr(ref tm) => {
+            ty::RawPtr(ty, mutbl) => {
                 p!(write(
                     "*{} ",
-                    match tm.mutbl {
+                    match mutbl {
                         hir::Mutability::Mut => "mut",
                         hir::Mutability::Not => "const",
                     }
                 ));
-                p!(print(tm.ty))
+                p!(print(ty))
             }
             ty::Ref(r, ty, mutbl) => {
                 p!("&");
@@ -995,11 +995,11 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                     // Don't print `+ Sized`, but rather `+ ?Sized` if absent.
                     if Some(trait_ref.def_id()) == tcx.lang_items().sized_trait() {
                         match pred.polarity {
-                            ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => {
+                            ty::PredicatePolarity::Positive => {
                                 has_sized_bound = true;
                                 continue;
                             }
-                            ty::ImplPolarity::Negative => has_negative_sized_bound = true,
+                            ty::PredicatePolarity::Negative => has_negative_sized_bound = true,
                         }
                     }
 
@@ -1020,7 +1020,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
 
                     self.insert_trait_and_projection(
                         trait_ref,
-                        ty::ImplPolarity::Positive,
+                        ty::PredicatePolarity::Positive,
                         Some(proj_ty),
                         &mut traits,
                         &mut fn_traits,
@@ -1085,7 +1085,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                     _ => {
                         if entry.has_fn_once {
                             traits
-                                .entry((fn_once_trait_ref, ty::ImplPolarity::Positive))
+                                .entry((fn_once_trait_ref, ty::PredicatePolarity::Positive))
                                 .or_default()
                                 .extend(
                                     // Group the return ty with its def id, if we had one.
@@ -1095,10 +1095,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                                 );
                         }
                         if let Some(trait_ref) = entry.fn_mut_trait_ref {
-                            traits.entry((trait_ref, ty::ImplPolarity::Positive)).or_default();
+                            traits.entry((trait_ref, ty::PredicatePolarity::Positive)).or_default();
                         }
                         if let Some(trait_ref) = entry.fn_trait_ref {
-                            traits.entry((trait_ref, ty::ImplPolarity::Positive)).or_default();
+                            traits.entry((trait_ref, ty::PredicatePolarity::Positive)).or_default();
                         }
                     }
                 }
@@ -1114,7 +1114,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
             self.wrap_binder(&trait_ref, |trait_ref, cx| {
                 define_scoped_cx!(cx);
 
-                if polarity == ty::ImplPolarity::Negative {
+                if polarity == ty::PredicatePolarity::Negative {
                     p!("!");
                 }
                 p!(print(trait_ref.print_only_trait_name()));
@@ -1223,10 +1223,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
     fn insert_trait_and_projection(
         &mut self,
         trait_ref: ty::PolyTraitRef<'tcx>,
-        polarity: ty::ImplPolarity,
+        polarity: ty::PredicatePolarity,
         proj_ty: Option<(DefId, ty::Binder<'tcx, Term<'tcx>>)>,
         traits: &mut FxIndexMap<
-            (ty::PolyTraitRef<'tcx>, ty::ImplPolarity),
+            (ty::PolyTraitRef<'tcx>, ty::PredicatePolarity),
             FxIndexMap<DefId, ty::Binder<'tcx, Term<'tcx>>>,
         >,
         fn_traits: &mut FxIndexMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>,
@@ -1236,7 +1236,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
         // If our trait_ref is FnOnce or any of its children, project it onto the parent FnOnce
         // super-trait ref and record it there.
         // We skip negative Fn* bounds since they can't use parenthetical notation anyway.
-        if polarity == ty::ImplPolarity::Positive
+        if polarity == ty::PredicatePolarity::Positive
             && let Some(fn_once_trait) = self.tcx().lang_items().fn_once_trait()
         {
             // If we have a FnOnce, then insert it into
@@ -1752,7 +1752,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                 p!(write("{:?}", char::try_from(int).unwrap()))
             }
             // Pointer types
-            ty::Ref(..) | ty::RawPtr(_) | ty::FnPtr(_) => {
+            ty::Ref(..) | ty::RawPtr(_, _) | ty::FnPtr(_) => {
                 let data = int.assert_bits(self.tcx().data_layout.pointer_size);
                 self.typed_value(
                     |this| {
@@ -3139,7 +3139,7 @@ define_print_and_forward_display! {
 
     TraitPredPrintModifiersAndPath<'tcx> {
         p!(pretty_print_bound_constness(self.0.trait_ref));
-        if let ty::ImplPolarity::Negative = self.0.polarity {
+        if let ty::PredicatePolarity::Negative = self.0.polarity {
             p!("!")
         }
         p!(print(self.0.trait_ref.print_only_trait_path()));
@@ -3172,7 +3172,7 @@ define_print_and_forward_display! {
     ty::TraitPredicate<'tcx> {
         p!(print(self.trait_ref.self_ty()), ": ");
         p!(pretty_print_bound_constness(self.trait_ref));
-        if let ty::ImplPolarity::Negative = self.polarity {
+        if let ty::PredicatePolarity::Negative = self.polarity {
             p!("!");
         }
         p!(print(self.trait_ref.print_trait_sugared()))
diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs
index d21f0e6385c..c66b9864e46 100644
--- a/compiler/rustc_middle/src/ty/region.rs
+++ b/compiler/rustc_middle/src/ty/region.rs
@@ -251,6 +251,7 @@ impl<'tcx> Region<'tcx> {
             }
             ty::ReError(_) => {
                 flags = flags | TypeFlags::HAS_FREE_REGIONS;
+                flags = flags | TypeFlags::HAS_ERROR;
             }
         }
 
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 990e78aff8a..cf7caafcebb 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -94,28 +94,6 @@ pub trait Relate<'tcx>: TypeFoldable<TyCtxt<'tcx>> + PartialEq + Copy {
 ///////////////////////////////////////////////////////////////////////////
 // Relate impls
 
-pub fn relate_type_and_mut<'tcx, R: TypeRelation<'tcx>>(
-    relation: &mut R,
-    a: ty::TypeAndMut<'tcx>,
-    b: ty::TypeAndMut<'tcx>,
-    base_ty: Ty<'tcx>,
-) -> RelateResult<'tcx, ty::TypeAndMut<'tcx>> {
-    debug!("{}.mts({:?}, {:?})", relation.tag(), a, b);
-    if a.mutbl != b.mutbl {
-        Err(TypeError::Mutability)
-    } else {
-        let mutbl = a.mutbl;
-        let (variance, info) = match mutbl {
-            hir::Mutability::Not => (ty::Covariant, ty::VarianceDiagInfo::None),
-            hir::Mutability::Mut => {
-                (ty::Invariant, ty::VarianceDiagInfo::Invariant { ty: base_ty, param_index: 0 })
-            }
-        };
-        let ty = relation.relate_with_variance(variance, info, a.ty, b.ty)?;
-        Ok(ty::TypeAndMut { ty, mutbl })
-    }
-}
-
 #[inline]
 pub fn relate_args_invariantly<'tcx, R: TypeRelation<'tcx>>(
     relation: &mut R,
@@ -465,17 +443,39 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
             Ok(Ty::new_coroutine_closure(tcx, a_id, args))
         }
 
-        (&ty::RawPtr(a_mt), &ty::RawPtr(b_mt)) => {
-            let mt = relate_type_and_mut(relation, a_mt, b_mt, a)?;
-            Ok(Ty::new_ptr(tcx, mt))
+        (&ty::RawPtr(a_ty, a_mutbl), &ty::RawPtr(b_ty, b_mutbl)) => {
+            if a_mutbl != b_mutbl {
+                return Err(TypeError::Mutability);
+            }
+
+            let (variance, info) = match a_mutbl {
+                hir::Mutability::Not => (ty::Covariant, ty::VarianceDiagInfo::None),
+                hir::Mutability::Mut => {
+                    (ty::Invariant, ty::VarianceDiagInfo::Invariant { ty: a, param_index: 0 })
+                }
+            };
+
+            let ty = relation.relate_with_variance(variance, info, a_ty, b_ty)?;
+
+            Ok(Ty::new_ptr(tcx, ty, a_mutbl))
         }
 
         (&ty::Ref(a_r, a_ty, a_mutbl), &ty::Ref(b_r, b_ty, b_mutbl)) => {
+            if a_mutbl != b_mutbl {
+                return Err(TypeError::Mutability);
+            }
+
+            let (variance, info) = match a_mutbl {
+                hir::Mutability::Not => (ty::Covariant, ty::VarianceDiagInfo::None),
+                hir::Mutability::Mut => {
+                    (ty::Invariant, ty::VarianceDiagInfo::Invariant { ty: a, param_index: 0 })
+                }
+            };
+
             let r = relation.relate(a_r, b_r)?;
-            let a_mt = ty::TypeAndMut { ty: a_ty, mutbl: a_mutbl };
-            let b_mt = ty::TypeAndMut { ty: b_ty, mutbl: b_mutbl };
-            let mt = relate_type_and_mut(relation, a_mt, b_mt, a)?;
-            Ok(Ty::new_ref(tcx, r, mt))
+            let ty = relation.relate_with_variance(variance, info, a_ty, b_ty)?;
+
+            Ok(Ty::new_ref(tcx, r, ty, a_mutbl))
         }
 
         (&ty::Array(a_t, sz_a), &ty::Array(b_t, sz_b)) => {
@@ -769,12 +769,12 @@ impl<'tcx> Relate<'tcx> for GenericArg<'tcx> {
     }
 }
 
-impl<'tcx> Relate<'tcx> for ty::ImplPolarity {
+impl<'tcx> Relate<'tcx> for ty::PredicatePolarity {
     fn relate<R: TypeRelation<'tcx>>(
         _relation: &mut R,
-        a: ty::ImplPolarity,
-        b: ty::ImplPolarity,
-    ) -> RelateResult<'tcx, ty::ImplPolarity> {
+        a: ty::PredicatePolarity,
+        b: ty::PredicatePolarity,
+    ) -> RelateResult<'tcx, ty::PredicatePolarity> {
         if a != b { Err(TypeError::PolarityMismatch(expected_found(a, b))) } else { Ok(a) }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 4b015640f91..f14ca7ae4b7 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -560,7 +560,7 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for Ty<'tcx> {
         folder: &mut F,
     ) -> Result<Self, F::Error> {
         let kind = match *self.kind() {
-            ty::RawPtr(tm) => ty::RawPtr(tm.try_fold_with(folder)?),
+            ty::RawPtr(ty, mutbl) => ty::RawPtr(ty.try_fold_with(folder)?, mutbl),
             ty::Array(typ, sz) => ty::Array(typ.try_fold_with(folder)?, sz.try_fold_with(folder)?),
             ty::Slice(typ) => ty::Slice(typ.try_fold_with(folder)?),
             ty::Adt(tid, args) => ty::Adt(tid, args.try_fold_with(folder)?),
@@ -607,7 +607,7 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for Ty<'tcx> {
 impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for Ty<'tcx> {
     fn super_visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result {
         match self.kind() {
-            ty::RawPtr(ref tm) => tm.visit_with(visitor),
+            ty::RawPtr(ty, _mutbl) => ty.visit_with(visitor),
             ty::Array(typ, sz) => {
                 try_visit!(typ.visit_with(visitor));
                 sz.visit_with(visitor)
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 6e0a9eb86dd..c85ee140fa4 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1587,33 +1587,38 @@ impl<'tcx> Ty<'tcx> {
     }
 
     #[inline]
-    pub fn new_ref(tcx: TyCtxt<'tcx>, r: Region<'tcx>, tm: TypeAndMut<'tcx>) -> Ty<'tcx> {
-        Ty::new(tcx, Ref(r, tm.ty, tm.mutbl))
+    pub fn new_ref(
+        tcx: TyCtxt<'tcx>,
+        r: Region<'tcx>,
+        ty: Ty<'tcx>,
+        mutbl: ty::Mutability,
+    ) -> Ty<'tcx> {
+        Ty::new(tcx, Ref(r, ty, mutbl))
     }
 
     #[inline]
     pub fn new_mut_ref(tcx: TyCtxt<'tcx>, r: Region<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
-        Ty::new_ref(tcx, r, TypeAndMut { ty, mutbl: hir::Mutability::Mut })
+        Ty::new_ref(tcx, r, ty, hir::Mutability::Mut)
     }
 
     #[inline]
     pub fn new_imm_ref(tcx: TyCtxt<'tcx>, r: Region<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
-        Ty::new_ref(tcx, r, TypeAndMut { ty, mutbl: hir::Mutability::Not })
+        Ty::new_ref(tcx, r, ty, hir::Mutability::Not)
     }
 
     #[inline]
-    pub fn new_ptr(tcx: TyCtxt<'tcx>, tm: TypeAndMut<'tcx>) -> Ty<'tcx> {
-        Ty::new(tcx, RawPtr(tm))
+    pub fn new_ptr(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, mutbl: ty::Mutability) -> Ty<'tcx> {
+        Ty::new(tcx, ty::RawPtr(ty, mutbl))
     }
 
     #[inline]
     pub fn new_mut_ptr(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
-        Ty::new_ptr(tcx, TypeAndMut { ty, mutbl: hir::Mutability::Mut })
+        Ty::new_ptr(tcx, ty, hir::Mutability::Mut)
     }
 
     #[inline]
     pub fn new_imm_ptr(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
-        Ty::new_ptr(tcx, TypeAndMut { ty, mutbl: hir::Mutability::Not })
+        Ty::new_ptr(tcx, ty, hir::Mutability::Not)
     }
 
     #[inline]
@@ -1910,7 +1915,7 @@ impl<'tcx> Ty<'tcx> {
     pub fn is_array_slice(self) -> bool {
         match self.kind() {
             Slice(_) => true,
-            RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => matches!(ty.kind(), Slice(_)),
+            ty::RawPtr(ty, _) | Ref(_, ty, _) => matches!(ty.kind(), Slice(_)),
             _ => false,
         }
     }
@@ -1964,11 +1969,7 @@ impl<'tcx> Ty<'tcx> {
 
     #[inline]
     pub fn is_mutable_ptr(self) -> bool {
-        matches!(
-            self.kind(),
-            RawPtr(TypeAndMut { mutbl: hir::Mutability::Mut, .. })
-                | Ref(_, _, hir::Mutability::Mut)
-        )
+        matches!(self.kind(), RawPtr(_, hir::Mutability::Mut) | Ref(_, _, hir::Mutability::Mut))
     }
 
     /// Get the mutability of the reference or `None` when not a reference
@@ -1982,7 +1983,7 @@ impl<'tcx> Ty<'tcx> {
 
     #[inline]
     pub fn is_unsafe_ptr(self) -> bool {
-        matches!(self.kind(), RawPtr(_))
+        matches!(self.kind(), RawPtr(_, _))
     }
 
     /// Tests if this is any kind of primitive pointer type (reference, raw pointer, fn pointer).
@@ -2038,7 +2039,7 @@ impl<'tcx> Ty<'tcx> {
                 | Uint(_)
                 | FnDef(..)
                 | FnPtr(_)
-                | RawPtr(_)
+                | RawPtr(_, _)
                 | Infer(IntVar(_) | FloatVar(_))
         )
     }
@@ -2174,7 +2175,7 @@ impl<'tcx> Ty<'tcx> {
                 Some(TypeAndMut { ty: self.boxed_ty(), mutbl: hir::Mutability::Not })
             }
             Ref(_, ty, mutbl) => Some(TypeAndMut { ty: *ty, mutbl: *mutbl }),
-            RawPtr(mt) if explicit => Some(*mt),
+            RawPtr(ty, mutbl) if explicit => Some(TypeAndMut { ty: *ty, mutbl: *mutbl }),
             _ => None,
         }
     }
@@ -2293,7 +2294,7 @@ impl<'tcx> Ty<'tcx> {
             | ty::Str
             | ty::Array(..)
             | ty::Slice(_)
-            | ty::RawPtr(_)
+            | ty::RawPtr(_, _)
             | ty::Ref(..)
             | ty::FnDef(..)
             | ty::FnPtr(..)
@@ -2636,7 +2637,7 @@ impl<'tcx> Ty<'tcx> {
             | Str
             | Array(_, _)
             | Slice(_)
-            | RawPtr(_)
+            | RawPtr(_, _)
             | Ref(_, _, _)
             | FnDef(_, _)
             | FnPtr(_)
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index a6526b06851..f74bba134ab 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -682,6 +682,9 @@ impl<'tcx> TyCtxt<'tcx> {
 
     /// Return the set of types that should be taken into account when checking
     /// trait bounds on a coroutine's internal state.
+    // FIXME(compiler-errors): We should remove this when the old solver goes away;
+    // and all other usages of this function should go through `bound_coroutine_hidden_types`
+    // instead.
     pub fn coroutine_hidden_types(
         self,
         def_id: DefId,
@@ -694,6 +697,33 @@ impl<'tcx> TyCtxt<'tcx> {
             .map(|decl| ty::EarlyBinder::bind(decl.ty))
     }
 
+    /// Return the set of types that should be taken into account when checking
+    /// trait bounds on a coroutine's internal state. This properly replaces
+    /// `ReErased` with new existential bound lifetimes.
+    pub fn bound_coroutine_hidden_types(
+        self,
+        def_id: DefId,
+    ) -> impl Iterator<Item = ty::EarlyBinder<ty::Binder<'tcx, Ty<'tcx>>>> {
+        let coroutine_layout = self.mir_coroutine_witnesses(def_id);
+        coroutine_layout
+            .as_ref()
+            .map_or_else(|| [].iter(), |l| l.field_tys.iter())
+            .filter(|decl| !decl.ignore_for_traits)
+            .map(move |decl| {
+                let mut vars = vec![];
+                let ty = self.fold_regions(decl.ty, |re, debruijn| {
+                    assert_eq!(re, self.lifetimes.re_erased);
+                    let var = ty::BoundVar::from_usize(vars.len());
+                    vars.push(ty::BoundVariableKind::Region(ty::BrAnon));
+                    ty::Region::new_bound(self, debruijn, ty::BoundRegion { var, kind: ty::BrAnon })
+                });
+                ty::EarlyBinder::bind(ty::Binder::bind_with_vars(
+                    ty,
+                    self.mk_bound_variable_kinds(&vars),
+                ))
+            })
+    }
+
     /// Expands the given impl trait type, stopping if the type is recursive.
     #[instrument(skip(self), level = "debug", ret)]
     pub fn try_expand_impl_trait_type(
@@ -998,8 +1028,10 @@ impl<'tcx> OpaqueTypeExpander<'tcx> {
                 Some(expanded_ty) => *expanded_ty,
                 None => {
                     if matches!(self.inspect_coroutine_fields, InspectCoroutineFields::Yes) {
-                        for bty in self.tcx.coroutine_hidden_types(def_id) {
-                            let hidden_ty = bty.instantiate(self.tcx, args);
+                        for bty in self.tcx.bound_coroutine_hidden_types(def_id) {
+                            let hidden_ty = self.tcx.instantiate_bound_regions_with_erased(
+                                bty.instantiate(self.tcx, args),
+                            );
                             self.fold_ty(hidden_ty);
                         }
                     }
@@ -1205,7 +1237,7 @@ impl<'tcx> Ty<'tcx> {
             | ty::Str
             | ty::Never
             | ty::Ref(..)
-            | ty::RawPtr(_)
+            | ty::RawPtr(_, _)
             | ty::FnDef(..)
             | ty::Error(_)
             | ty::FnPtr(_) => true,
@@ -1245,7 +1277,7 @@ impl<'tcx> Ty<'tcx> {
             | ty::Str
             | ty::Never
             | ty::Ref(..)
-            | ty::RawPtr(_)
+            | ty::RawPtr(_, _)
             | ty::FnDef(..)
             | ty::Error(_)
             | ty::FnPtr(_) => true,
@@ -1369,7 +1401,7 @@ impl<'tcx> Ty<'tcx> {
             ty::Ref(..) | ty::Array(..) | ty::Slice(_) | ty::Tuple(..) => true,
 
             // Raw pointers use bitwise comparison.
-            ty::RawPtr(_) | ty::FnPtr(_) => true,
+            ty::RawPtr(_, _) | ty::FnPtr(_) => true,
 
             // Floating point numbers are not `Eq`.
             ty::Float(_) => false,
@@ -1462,7 +1494,7 @@ impl<'tcx> ExplicitSelf<'tcx> {
         match *self_arg_ty.kind() {
             _ if is_self_ty(self_arg_ty) => ByValue,
             ty::Ref(region, ty, mutbl) if is_self_ty(ty) => ByReference(region, mutbl),
-            ty::RawPtr(ty::TypeAndMut { ty, mutbl }) if is_self_ty(ty) => ByRawPointer(mutbl),
+            ty::RawPtr(ty, mutbl) if is_self_ty(ty) => ByRawPointer(mutbl),
             ty::Adt(def, _) if def.is_box() && is_self_ty(self_arg_ty.boxed_ty()) => ByBox,
             _ => Other,
         }
@@ -1487,7 +1519,7 @@ pub fn needs_drop_components<'tcx>(
         | ty::FnDef(..)
         | ty::FnPtr(_)
         | ty::Char
-        | ty::RawPtr(_)
+        | ty::RawPtr(_, _)
         | ty::Ref(..)
         | ty::Str => Ok(SmallVec::new()),
 
@@ -1542,7 +1574,7 @@ pub fn is_trivially_const_drop(ty: Ty<'_>) -> bool {
         | ty::Infer(ty::IntVar(_))
         | ty::Infer(ty::FloatVar(_))
         | ty::Str
-        | ty::RawPtr(_)
+        | ty::RawPtr(_, _)
         | ty::Ref(..)
         | ty::FnDef(..)
         | ty::FnPtr(_)
diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs
index 46c26241c3e..9e7bf980237 100644
--- a/compiler/rustc_middle/src/ty/walk.rs
+++ b/compiler/rustc_middle/src/ty/walk.rs
@@ -158,8 +158,8 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
             ty::Slice(ty) => {
                 stack.push(ty.into());
             }
-            ty::RawPtr(mt) => {
-                stack.push(mt.ty.into());
+            ty::RawPtr(ty, _) => {
+                stack.push(ty.into());
             }
             ty::Ref(lt, ty, _) => {
                 stack.push(ty.into());
diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs
index 288b787798b..109ffedec55 100644
--- a/compiler/rustc_mir_build/src/build/custom/mod.rs
+++ b/compiler/rustc_mir_build/src/build/custom/mod.rs
@@ -56,6 +56,7 @@ pub(super) fn build_custom_mir<'tcx>(
         var_debug_info: Vec::new(),
         span,
         required_consts: Vec::new(),
+        mentioned_items: Vec::new(),
         is_polymorphic: false,
         tainted_by_errors: None,
         injection_phase: None,
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index d2cbbf9be32..f4f452d474f 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -879,6 +879,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 self.visit_primary_bindings(subpattern, pattern_user_ty.deref(), f);
             }
 
+            PatKind::DerefPattern { ref subpattern } => {
+                self.visit_primary_bindings(subpattern, UserTypeProjections::none(), f);
+            }
+
             PatKind::AscribeUserType {
                 ref subpattern,
                 ascription: thir::Ascription { ref annotation, variance: _ },
diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs
index d0d49c13f13..1148cd19a01 100644
--- a/compiler/rustc_mir_build/src/build/matches/util.rs
+++ b/compiler/rustc_mir_build/src/build/matches/util.rs
@@ -256,6 +256,12 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
                 subpairs.push(MatchPair::new(place_builder, subpattern, cx));
                 default_irrefutable()
             }
+
+            PatKind::DerefPattern { .. } => {
+                // FIXME(deref_patterns)
+                // Treat it like a wildcard for now.
+                default_irrefutable()
+            }
         };
 
         MatchPair { place, test_case, subpairs, pattern }
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 1ce8da162bf..e04fe31a76f 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -250,6 +250,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 | PatKind::Variant { .. }
                 | PatKind::Leaf { .. }
                 | PatKind::Deref { .. }
+                | PatKind::DerefPattern { .. }
                 | PatKind::Range { .. }
                 | PatKind::Slice { .. }
                 | PatKind::Array { .. } => {
@@ -310,7 +311,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 }
                 visit::walk_pat(self, pat);
             }
-            PatKind::Deref { .. } => {
+            PatKind::Deref { .. } | PatKind::DerefPattern { .. } => {
                 let old_inside_adt = std::mem::replace(&mut self.inside_adt, false);
                 visit::walk_pat(self, pat);
                 self.inside_adt = old_inside_adt;
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 52d32a3b626..1e508ffc1e7 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -125,11 +125,7 @@ impl<'tcx> Cx<'tcx> {
 
                 expr = Expr {
                     temp_lifetime,
-                    ty: Ty::new_ref(
-                        self.tcx,
-                        deref.region,
-                        ty::TypeAndMut { ty: expr.ty, mutbl: deref.mutbl },
-                    ),
+                    ty: Ty::new_ref(self.tcx, deref.region, expr.ty, deref.mutbl),
                     span,
                     kind: ExprKind::Borrow {
                         borrow_kind: deref.mutbl.to_borrow_kind(),
@@ -1021,7 +1017,7 @@ impl<'tcx> Cx<'tcx> {
         let ty::Ref(region, _, mutbl) = *self.thir[args[0]].ty.kind() else {
             span_bug!(span, "overloaded_place: receiver is not a reference");
         };
-        let ref_ty = Ty::new_ref(self.tcx, region, ty::TypeAndMut { ty: place_ty, mutbl });
+        let ref_ty = Ty::new_ref(self.tcx, region, place_ty, mutbl);
 
         // construct the complete expression `foo()` for the overloaded call,
         // which will yield the &T type
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 cfa853417ca..434ed16d5c6 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -481,6 +481,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
             // when the iterator is an uninhabited type. unreachable_code will trigger instead.
             hir::MatchSource::ForLoopDesugar if arms.len() == 1 => {}
             hir::MatchSource::ForLoopDesugar
+            | hir::MatchSource::Postfix
             | hir::MatchSource::Normal
             | hir::MatchSource::FormatArgs => report_arm_reachability(&cx, &report),
             // Unreachable patterns in try and await expressions occur when one of
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 03eda9a9322..0a7e9653377 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -257,6 +257,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                 return self.lower_path(qpath, pat.hir_id, pat.span);
             }
 
+            hir::PatKind::Deref(subpattern) => {
+                PatKind::DerefPattern { subpattern: self.lower_pattern(subpattern) }
+            }
             hir::PatKind::Ref(subpattern, _) | hir::PatKind::Box(subpattern) => {
                 PatKind::Deref { subpattern: self.lower_pattern(subpattern) }
             }
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index d53704f89e7..16c4248a159 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -688,6 +688,12 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
                 self.print_pat(subpattern, depth_lvl + 2);
                 print_indented!(self, "}", depth_lvl + 1);
             }
+            PatKind::DerefPattern { subpattern } => {
+                print_indented!(self, "DerefPattern { ", depth_lvl + 1);
+                print_indented!(self, "subpattern:", depth_lvl + 2);
+                self.print_pat(subpattern, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl + 1);
+            }
             PatKind::Constant { value } => {
                 print_indented!(self, "Constant {", depth_lvl + 1);
                 print_indented!(self, format!("value: {:?}", value), depth_lvl + 2);
diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
index 1b2f2cd9477..256add3153c 100644
--- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
@@ -1,4 +1,3 @@
-use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
 use rustc_index::Idx;
 use rustc_middle::mir::patch::MirPatch;
@@ -629,11 +628,7 @@ where
         let drop_fn = tcx.associated_item_def_ids(drop_trait)[0];
         let ty = self.place_ty(self.place);
 
-        let ref_ty = Ty::new_ref(
-            tcx,
-            tcx.lifetimes.re_erased,
-            ty::TypeAndMut { ty, mutbl: hir::Mutability::Mut },
-        );
+        let ref_ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, ty);
         let ref_place = self.new_temp(ref_ty);
         let unit_temp = Place::from(self.new_temp(Ty::new_unit(tcx)));
 
@@ -700,7 +695,7 @@ where
         let move_ = |place: Place<'tcx>| Operand::Move(place);
         let tcx = self.tcx();
 
-        let ptr_ty = Ty::new_ptr(tcx, ty::TypeAndMut { ty: ety, mutbl: hir::Mutability::Mut });
+        let ptr_ty = Ty::new_mut_ptr(tcx, ety);
         let ptr = Place::from(self.new_temp(ptr_ty));
         let can_go = Place::from(self.new_temp(tcx.types.bool));
         let one = self.constant_usize(1);
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index 0f900e6a557..e73d945e0bb 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -194,7 +194,7 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> {
                     | ty::Str
                     | ty::Array(_, _)
                     | ty::Slice(_)
-                    | ty::RawPtr(_)
+                    | ty::RawPtr(_, _)
                     | ty::Ref(_, _, _)
                     | ty::FnDef(_, _)
                     | ty::FnPtr(_)
@@ -433,7 +433,7 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> {
             | Rvalue::Discriminant(..)
             | Rvalue::Len(..)
             | Rvalue::NullaryOp(
-                NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..) | NullOp::UbCheck(_),
+                NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..) | NullOp::UbChecks,
                 _,
             ) => {}
         }
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index 2b2af6ee7da..0e85f859ab2 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -843,7 +843,7 @@ impl Map {
             self.value_count += 1;
         }
 
-        if let ty::Ref(_, ref_ty, _) | ty::RawPtr(ty::TypeAndMut { ty: ref_ty, .. }) = ty.kind()
+        if let ty::Ref(_, ref_ty, _) | ty::RawPtr(ref_ty, _) = ty.kind()
             && let ty::Slice(..) = ref_ty.kind()
         {
             assert!(self.places[place].value_index.is_none(), "slices are not scalars");
diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs
index 9eec724ef21..b71c5894ff7 100644
--- a/compiler/rustc_mir_transform/src/check_alignment.rs
+++ b/compiler/rustc_mir_transform/src/check_alignment.rs
@@ -5,7 +5,7 @@ use rustc_middle::mir::{
     interpret::Scalar,
     visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor},
 };
-use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeAndMut};
+use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
 use rustc_session::Session;
 
 pub struct CheckAlignment;
@@ -157,7 +157,7 @@ fn insert_alignment_check<'tcx>(
     new_block: BasicBlock,
 ) {
     // Cast the pointer to a *const ()
-    let const_raw_ptr = Ty::new_ptr(tcx, TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Not });
+    let const_raw_ptr = Ty::new_imm_ptr(tcx, tcx.types.unit);
     let rvalue = Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(pointer), const_raw_ptr);
     let thin_ptr = local_decls.push(LocalDecl::with_source_info(const_raw_ptr, source_info)).into();
     block_data
diff --git a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
index 5b4bc4fa134..aaf2035fc21 100644
--- a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
+++ b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
@@ -5,15 +5,20 @@
 //!   - [`AscribeUserType`]
 //!   - [`FakeRead`]
 //!   - [`Assign`] statements with a [`Fake`] borrow
+//!   - [`Coverage`] statements of kind [`BlockMarker`] or [`SpanMarker`]
 //!
 //! [`AscribeUserType`]: rustc_middle::mir::StatementKind::AscribeUserType
 //! [`Assign`]: rustc_middle::mir::StatementKind::Assign
 //! [`FakeRead`]: rustc_middle::mir::StatementKind::FakeRead
 //! [`Nop`]: rustc_middle::mir::StatementKind::Nop
 //! [`Fake`]: rustc_middle::mir::BorrowKind::Fake
+//! [`Coverage`]: rustc_middle::mir::StatementKind::Coverage
+//! [`BlockMarker`]: rustc_middle::mir::coverage::CoverageKind::BlockMarker
+//! [`SpanMarker`]: rustc_middle::mir::coverage::CoverageKind::SpanMarker
 
 use crate::MirPass;
-use rustc_middle::mir::{Body, BorrowKind, Rvalue, StatementKind, TerminatorKind};
+use rustc_middle::mir::coverage::CoverageKind;
+use rustc_middle::mir::{Body, BorrowKind, Coverage, Rvalue, StatementKind, TerminatorKind};
 use rustc_middle::ty::TyCtxt;
 
 pub struct CleanupPostBorrowck;
@@ -25,6 +30,12 @@ impl<'tcx> MirPass<'tcx> for CleanupPostBorrowck {
                 match statement.kind {
                     StatementKind::AscribeUserType(..)
                     | StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Fake, _)))
+                    | StatementKind::Coverage(box Coverage {
+                        // These kinds of coverage statements are markers inserted during
+                        // MIR building, and are not needed after InstrumentCoverage.
+                        kind: CoverageKind::BlockMarker { .. } | CoverageKind::SpanMarker { .. },
+                        ..
+                    })
                     | StatementKind::FakeRead(..) => statement.make_nop(),
                     _ => (),
                 }
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index 0d18d4fd69e..f0a13f66555 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -570,11 +570,7 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> {
 fn make_coroutine_state_argument_indirect<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     let coroutine_ty = body.local_decls.raw[1].ty;
 
-    let ref_coroutine_ty = Ty::new_ref(
-        tcx,
-        tcx.lifetimes.re_erased,
-        ty::TypeAndMut { ty: coroutine_ty, mutbl: Mutability::Mut },
-    );
+    let ref_coroutine_ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, coroutine_ty);
 
     // Replace the by value coroutine argument
     body.local_decls.raw[1].ty = ref_coroutine_ty;
@@ -1265,10 +1261,8 @@ fn create_coroutine_drop_shim<'tcx>(
     make_coroutine_state_argument_indirect(tcx, &mut body);
 
     // Change the coroutine argument from &mut to *mut
-    body.local_decls[SELF_ARG] = LocalDecl::with_source_info(
-        Ty::new_ptr(tcx, ty::TypeAndMut { ty: coroutine_ty, mutbl: hir::Mutability::Mut }),
-        source_info,
-    );
+    body.local_decls[SELF_ARG] =
+        LocalDecl::with_source_info(Ty::new_mut_ptr(tcx, coroutine_ty), source_info);
 
     // Make sure we remove dead blocks to remove
     // unrelated code from the resume part of the function
diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
index 000b96ee801..e0bbd582d88 100644
--- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
+++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
@@ -64,12 +64,9 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
         let mut by_move_body = body.clone();
         MakeByMoveBody { tcx, by_ref_fields, by_move_coroutine_ty }.visit_body(&mut by_move_body);
         dump_mir(tcx, false, "coroutine_by_move", &0, &by_move_body, |_, _| Ok(()));
-        by_move_body.source = mir::MirSource {
-            instance: InstanceDef::CoroutineKindShim {
-                coroutine_def_id: coroutine_def_id.to_def_id(),
-            },
-            promoted: None,
-        };
+        by_move_body.source = mir::MirSource::from_instance(InstanceDef::CoroutineKindShim {
+            coroutine_def_id: coroutine_def_id.to_def_id(),
+        });
         body.coroutine.as_mut().unwrap().by_move_body = Some(by_move_body);
     }
 }
diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs
index 9a1d8bae6b4..69dc4f2ddea 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters.rs
@@ -1,13 +1,12 @@
+use std::fmt::{self, Debug};
+
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::graph::WithNumNodes;
-use rustc_index::bit_set::BitSet;
 use rustc_index::IndexVec;
-use rustc_middle::mir::coverage::*;
+use rustc_middle::mir::coverage::{CounterId, CovTerm, Expression, ExpressionId, Op};
 
-use super::graph::{BasicCoverageBlock, CoverageGraph, TraverseCoverageGraphWithLoops};
-
-use std::fmt::{self, Debug};
+use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, TraverseCoverageGraphWithLoops};
 
 /// The coverage counter or counter expression associated with a particular
 /// BCB node or BCB edge.
@@ -18,10 +17,6 @@ pub(super) enum BcbCounter {
 }
 
 impl BcbCounter {
-    fn is_expression(&self) -> bool {
-        matches!(self, Self::Expression { .. })
-    }
-
     pub(super) fn as_term(&self) -> CovTerm {
         match *self {
             BcbCounter::Counter { id, .. } => CovTerm::Counter(id),
@@ -60,10 +55,6 @@ pub(super) struct CoverageCounters {
     /// We currently don't iterate over this map, but if we do in the future,
     /// switch it back to `FxIndexMap` to avoid query stability hazards.
     bcb_edge_counters: FxHashMap<(BasicCoverageBlock, BasicCoverageBlock), BcbCounter>,
-    /// Tracks which BCBs have a counter associated with some incoming edge.
-    /// Only used by assertions, to verify that BCBs with incoming edge
-    /// counters do not have their own physical counters (expressions are allowed).
-    bcb_has_incoming_edge_counters: BitSet<BasicCoverageBlock>,
     /// Table of expression data, associating each expression ID with its
     /// corresponding operator (+ or -) and its LHS/RHS operands.
     expressions: IndexVec<ExpressionId, Expression>,
@@ -83,7 +74,6 @@ impl CoverageCounters {
             counter_increment_sites: IndexVec::new(),
             bcb_counters: IndexVec::from_elem_n(None, num_bcbs),
             bcb_edge_counters: FxHashMap::default(),
-            bcb_has_incoming_edge_counters: BitSet::new_empty(num_bcbs),
             expressions: IndexVec::new(),
         };
 
@@ -122,14 +112,6 @@ impl CoverageCounters {
     }
 
     fn set_bcb_counter(&mut self, bcb: BasicCoverageBlock, counter_kind: BcbCounter) -> BcbCounter {
-        assert!(
-            // If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also
-            // have an expression (to be injected into an existing `BasicBlock` represented by this
-            // `BasicCoverageBlock`).
-            counter_kind.is_expression() || !self.bcb_has_incoming_edge_counters.contains(bcb),
-            "attempt to add a `Counter` to a BCB target with existing incoming edge counters"
-        );
-
         if let Some(replaced) = self.bcb_counters[bcb].replace(counter_kind) {
             bug!(
                 "attempt to set a BasicCoverageBlock coverage counter more than once; \
@@ -146,19 +128,6 @@ impl CoverageCounters {
         to_bcb: BasicCoverageBlock,
         counter_kind: BcbCounter,
     ) -> BcbCounter {
-        // If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also
-        // have an expression (to be injected into an existing `BasicBlock` represented by this
-        // `BasicCoverageBlock`).
-        if let Some(node_counter) = self.bcb_counter(to_bcb)
-            && !node_counter.is_expression()
-        {
-            bug!(
-                "attempt to add an incoming edge counter from {from_bcb:?} \
-                when the target BCB already has {node_counter:?}"
-            );
-        }
-
-        self.bcb_has_incoming_edge_counters.insert(to_bcb);
         if let Some(replaced) = self.bcb_edge_counters.insert((from_bcb, to_bcb), counter_kind) {
             bug!(
                 "attempt to set an edge counter more than once; from_bcb: \
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index 3389305e7ee..3e9c1459f1c 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -2,52 +2,22 @@
 //!
 //! Currently, this pass only propagates scalar values.
 
-use rustc_const_eval::interpret::{
-    HasStaticRootDefId, ImmTy, Immediate, InterpCx, OpTy, PlaceTy, PointerArithmetic, Projectable,
-};
+use rustc_const_eval::const_eval::{throw_machine_stop_str, DummyMachine};
+use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, PlaceTy, Projectable};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::DefKind;
-use rustc_middle::mir::interpret::{AllocId, ConstAllocation, InterpResult, Scalar};
+use rustc_middle::mir::interpret::{InterpResult, Scalar};
 use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
 use rustc_middle::mir::*;
-use rustc_middle::query::TyCtxtAt;
-use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
+use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_mir_dataflow::value_analysis::{
     Map, PlaceIndex, State, TrackElem, ValueAnalysis, ValueAnalysisWrapper, ValueOrPlace,
 };
 use rustc_mir_dataflow::{lattice::FlatSet, Analysis, Results, ResultsVisitor};
-use rustc_span::def_id::DefId;
 use rustc_span::DUMMY_SP;
 use rustc_target::abi::{Abi, FieldIdx, Size, VariantIdx, FIRST_VARIANT};
 
-/// Macro for machine-specific `InterpError` without allocation.
-/// (These will never be shown to the user, but they help diagnose ICEs.)
-pub(crate) macro throw_machine_stop_str($($tt:tt)*) {{
-    // We make a new local type for it. The type itself does not carry any information,
-    // but its vtable (for the `MachineStopType` trait) does.
-    #[derive(Debug)]
-    struct Zst;
-    // Printing this type shows the desired string.
-    impl std::fmt::Display for Zst {
-        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-            write!(f, $($tt)*)
-        }
-    }
-
-    impl rustc_middle::mir::interpret::MachineStopType for Zst {
-        fn diagnostic_message(&self) -> rustc_errors::DiagMessage {
-            self.to_string().into()
-        }
-
-        fn add_args(
-            self: Box<Self>,
-            _: &mut dyn FnMut(rustc_errors::DiagArgName, rustc_errors::DiagArgValue),
-        ) {}
-    }
-    throw_machine_stop!(Zst)
-}}
-
 // These constants are somewhat random guesses and have not been optimized.
 // If `tcx.sess.mir_opt_level() >= 4`, we ignore the limits (this can become very expensive).
 const BLOCK_LIMIT: usize = 100;
@@ -888,165 +858,3 @@ impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> {
         }
     }
 }
-
-pub(crate) struct DummyMachine;
-
-impl HasStaticRootDefId for DummyMachine {
-    fn static_def_id(&self) -> Option<rustc_hir::def_id::LocalDefId> {
-        None
-    }
-}
-
-impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for DummyMachine {
-    rustc_const_eval::interpret::compile_time_machine!(<'mir, 'tcx>);
-    type MemoryKind = !;
-    const PANIC_ON_ALLOC_FAIL: bool = true;
-
-    #[inline(always)]
-    fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
-        false // no reason to enforce alignment
-    }
-
-    fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool {
-        false
-    }
-
-    fn before_access_global(
-        _tcx: TyCtxtAt<'tcx>,
-        _machine: &Self,
-        _alloc_id: AllocId,
-        alloc: ConstAllocation<'tcx>,
-        _static_def_id: Option<DefId>,
-        is_write: bool,
-    ) -> InterpResult<'tcx> {
-        if is_write {
-            throw_machine_stop_str!("can't write to global");
-        }
-
-        // If the static allocation is mutable, then we can't const prop it as its content
-        // might be different at runtime.
-        if alloc.inner().mutability.is_mut() {
-            throw_machine_stop_str!("can't access mutable globals in ConstProp");
-        }
-
-        Ok(())
-    }
-
-    fn find_mir_or_eval_fn(
-        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _instance: ty::Instance<'tcx>,
-        _abi: rustc_target::spec::abi::Abi,
-        _args: &[rustc_const_eval::interpret::FnArg<'tcx, Self::Provenance>],
-        _destination: &rustc_const_eval::interpret::MPlaceTy<'tcx, Self::Provenance>,
-        _target: Option<BasicBlock>,
-        _unwind: UnwindAction,
-    ) -> interpret::InterpResult<'tcx, Option<(&'mir Body<'tcx>, ty::Instance<'tcx>)>> {
-        unimplemented!()
-    }
-
-    fn panic_nounwind(
-        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _msg: &str,
-    ) -> interpret::InterpResult<'tcx> {
-        unimplemented!()
-    }
-
-    fn call_intrinsic(
-        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _instance: ty::Instance<'tcx>,
-        _args: &[rustc_const_eval::interpret::OpTy<'tcx, Self::Provenance>],
-        _destination: &rustc_const_eval::interpret::MPlaceTy<'tcx, Self::Provenance>,
-        _target: Option<BasicBlock>,
-        _unwind: UnwindAction,
-    ) -> interpret::InterpResult<'tcx> {
-        unimplemented!()
-    }
-
-    fn assert_panic(
-        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _msg: &rustc_middle::mir::AssertMessage<'tcx>,
-        _unwind: UnwindAction,
-    ) -> interpret::InterpResult<'tcx> {
-        unimplemented!()
-    }
-
-    fn binary_ptr_op(
-        ecx: &InterpCx<'mir, 'tcx, Self>,
-        bin_op: BinOp,
-        left: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>,
-        right: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>,
-    ) -> interpret::InterpResult<'tcx, (ImmTy<'tcx, Self::Provenance>, bool)> {
-        use rustc_middle::mir::BinOp::*;
-        Ok(match bin_op {
-            Eq | Ne | Lt | Le | Gt | Ge => {
-                // Types can differ, e.g. fn ptrs with different `for`.
-                assert_eq!(left.layout.abi, right.layout.abi);
-                let size = ecx.pointer_size();
-                // Just compare the bits. ScalarPairs are compared lexicographically.
-                // We thus always compare pairs and simply fill scalars up with 0.
-                // If the pointer has provenance, `to_bits` will return `Err` and we bail out.
-                let left = match **left {
-                    Immediate::Scalar(l) => (l.to_bits(size)?, 0),
-                    Immediate::ScalarPair(l1, l2) => (l1.to_bits(size)?, l2.to_bits(size)?),
-                    Immediate::Uninit => panic!("we should never see uninit data here"),
-                };
-                let right = match **right {
-                    Immediate::Scalar(r) => (r.to_bits(size)?, 0),
-                    Immediate::ScalarPair(r1, r2) => (r1.to_bits(size)?, r2.to_bits(size)?),
-                    Immediate::Uninit => panic!("we should never see uninit data here"),
-                };
-                let res = match bin_op {
-                    Eq => left == right,
-                    Ne => left != right,
-                    Lt => left < right,
-                    Le => left <= right,
-                    Gt => left > right,
-                    Ge => left >= right,
-                    _ => bug!(),
-                };
-                (ImmTy::from_bool(res, *ecx.tcx), false)
-            }
-
-            // Some more operations are possible with atomics.
-            // The return value always has the provenance of the *left* operand.
-            Add | Sub | BitOr | BitAnd | BitXor => {
-                throw_machine_stop_str!("pointer arithmetic is not handled")
-            }
-
-            _ => span_bug!(ecx.cur_span(), "Invalid operator on pointers: {:?}", bin_op),
-        })
-    }
-
-    fn expose_ptr(
-        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _ptr: interpret::Pointer<Self::Provenance>,
-    ) -> interpret::InterpResult<'tcx> {
-        unimplemented!()
-    }
-
-    fn init_frame_extra(
-        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _frame: rustc_const_eval::interpret::Frame<'mir, 'tcx, Self::Provenance>,
-    ) -> interpret::InterpResult<
-        'tcx,
-        rustc_const_eval::interpret::Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>,
-    > {
-        unimplemented!()
-    }
-
-    fn stack<'a>(
-        _ecx: &'a InterpCx<'mir, 'tcx, Self>,
-    ) -> &'a [rustc_const_eval::interpret::Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>]
-    {
-        // Return an empty stack instead of panicking, as `cur_span` uses it to evaluate constants.
-        &[]
-    }
-
-    fn stack_mut<'a>(
-        _ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
-    ) -> &'a mut Vec<
-        rustc_const_eval::interpret::Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>,
-    > {
-        unimplemented!()
-    }
-}
diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs
index e935dc7f5eb..30b1ca67800 100644
--- a/compiler/rustc_mir_transform/src/function_item_references.rs
+++ b/compiler/rustc_mir_transform/src/function_item_references.rs
@@ -121,7 +121,7 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> {
     fn is_fn_ref(ty: Ty<'tcx>) -> Option<(DefId, GenericArgsRef<'tcx>)> {
         let referent_ty = match ty.kind() {
             ty::Ref(_, referent_ty, _) => Some(referent_ty),
-            ty::RawPtr(ty_and_mut) => Some(&ty_and_mut.ty),
+            ty::RawPtr(referent_ty, _) => Some(referent_ty),
             _ => None,
         };
         referent_ty
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 87dff49e0be..59d6d89cf1f 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -82,6 +82,7 @@
 //! Second, when writing constants in MIR, we do not write `Const::Slice` or `Const`
 //! that contain `AllocId`s.
 
+use rustc_const_eval::const_eval::DummyMachine;
 use rustc_const_eval::interpret::{intern_const_alloc_for_constprop, MemoryKind};
 use rustc_const_eval::interpret::{ImmTy, InterpCx, OpTy, Projectable, Scalar};
 use rustc_data_structures::fx::FxIndexSet;
@@ -94,14 +95,13 @@ use rustc_middle::mir::interpret::GlobalAlloc;
 use rustc_middle::mir::visit::*;
 use rustc_middle::mir::*;
 use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeAndMut};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::def_id::DefId;
 use rustc_span::DUMMY_SP;
 use rustc_target::abi::{self, Abi, Size, VariantIdx, FIRST_VARIANT};
 use smallvec::SmallVec;
 use std::borrow::Cow;
 
-use crate::dataflow_const_prop::DummyMachine;
 use crate::ssa::{AssignedValue, SsaLocals};
 use either::Either;
 
@@ -131,7 +131,7 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         |local, value, location| {
             let value = match value {
                 // We do not know anything of this assigned value.
-                AssignedValue::Arg | AssignedValue::Terminator(_) => None,
+                AssignedValue::Arg | AssignedValue::Terminator => None,
                 // Try to get some insight.
                 AssignedValue::Rvalue(rvalue) => {
                     let value = state.simplify_rvalue(rvalue, location);
@@ -451,11 +451,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                     AddressKind::Ref(bk) => Ty::new_ref(
                         self.tcx,
                         self.tcx.lifetimes.re_erased,
-                        ty::TypeAndMut { ty: mplace.layout.ty, mutbl: bk.to_mutbl_lossy() },
+                        mplace.layout.ty,
+                        bk.to_mutbl_lossy(),
                     ),
-                    AddressKind::Address(mutbl) => {
-                        Ty::new_ptr(self.tcx, TypeAndMut { ty: mplace.layout.ty, mutbl })
-                    }
+                    AddressKind::Address(mutbl) => Ty::new_ptr(self.tcx, mplace.layout.ty, mutbl),
                 };
                 let layout = self.ecx.layout_of(ty).ok()?;
                 ImmTy::from_immediate(pointer, layout).into()
@@ -488,7 +487,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                     NullOp::OffsetOf(fields) => {
                         layout.offset_of_subfield(&self.ecx, fields.iter()).bytes()
                     }
-                    NullOp::UbCheck(_) => return None,
+                    NullOp::UbChecks => return None,
                 };
                 let usize_layout = self.ecx.layout_of(self.tcx.types.usize).unwrap();
                 let imm = ImmTy::try_from_uint(val, usize_layout)?;
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index f6a0945c222..78c0615b165 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -213,6 +213,7 @@ impl<'tcx> Inliner<'tcx> {
             MirPhase::Runtime(RuntimePhase::Optimized),
             self.param_env,
             &callee_body,
+            &caller_body,
         )
         .is_empty()
         {
@@ -565,7 +566,8 @@ impl<'tcx> Inliner<'tcx> {
         mut callee_body: Body<'tcx>,
     ) {
         let terminator = caller_body[callsite.block].terminator.take().unwrap();
-        let TerminatorKind::Call { args, destination, unwind, target, .. } = terminator.kind else {
+        let TerminatorKind::Call { func, args, destination, unwind, target, .. } = terminator.kind
+        else {
             bug!("unexpected terminator kind {:?}", terminator.kind);
         };
 
@@ -717,6 +719,24 @@ impl<'tcx> Inliner<'tcx> {
                 Const::Val(..) | Const::Unevaluated(..) => true,
             },
         ));
+        // Now that we incorporated the callee's `required_consts`, we can remove the callee from
+        // `mentioned_items` -- but we have to take their `mentioned_items` in return. This does
+        // some extra work here to save the monomorphization collector work later. It helps a lot,
+        // since monomorphization can avoid a lot of work when the "mentioned items" are similar to
+        // the actually used items. By doing this we can entirely avoid visiting the callee!
+        // We need to reconstruct the `required_item` for the callee so that we can find and
+        // remove it.
+        let callee_item = MentionedItem::Fn(func.ty(caller_body, self.tcx));
+        if let Some(idx) =
+            caller_body.mentioned_items.iter().position(|item| item.node == callee_item)
+        {
+            // We found the callee, so remove it and add its items instead.
+            caller_body.mentioned_items.remove(idx);
+            caller_body.mentioned_items.extend(callee_body.mentioned_items);
+        } else {
+            // If we can't find the callee, there's no point in adding its items.
+            // Probably it already got removed by being inlined elsewhere in the same function.
+        }
     }
 
     fn make_call_args(
diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs
index 116d6f48456..a458297210d 100644
--- a/compiler/rustc_mir_transform/src/jump_threading.rs
+++ b/compiler/rustc_mir_transform/src/jump_threading.rs
@@ -36,6 +36,7 @@
 //! cost by `MAX_COST`.
 
 use rustc_arena::DroplessArena;
+use rustc_const_eval::const_eval::DummyMachine;
 use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, Projectable};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_index::bit_set::BitSet;
@@ -50,7 +51,6 @@ use rustc_span::DUMMY_SP;
 use rustc_target::abi::{TagEncoding, Variants};
 
 use crate::cost_checker::CostChecker;
-use crate::dataflow_const_prop::DummyMachine;
 
 pub struct JumpThreading;
 
diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs
index f19b78a3a5c..a20958e74df 100644
--- a/compiler/rustc_mir_transform/src/known_panics_lint.rs
+++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs
@@ -6,6 +6,7 @@
 
 use std::fmt::Debug;
 
+use rustc_const_eval::const_eval::DummyMachine;
 use rustc_const_eval::interpret::{
     format_interp_error, ImmTy, InterpCx, InterpResult, Projectable, Scalar,
 };
@@ -20,7 +21,6 @@ use rustc_middle::ty::{self, ConstInt, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisi
 use rustc_span::Span;
 use rustc_target::abi::{Abi, FieldIdx, HasDataLayout, Size, TargetDataLayout, VariantIdx};
 
-use crate::dataflow_const_prop::DummyMachine;
 use crate::errors::{AssertLint, AssertLintKind};
 use crate::MirLint;
 
@@ -639,7 +639,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                     NullOp::OffsetOf(fields) => {
                         op_layout.offset_of_subfield(self, fields.iter()).bytes()
                     }
-                    NullOp::UbCheck(_) => return None,
+                    NullOp::UbChecks => return None,
                 };
                 ImmTy::from_scalar(Scalar::from_target_usize(val, self), layout).into()
             }
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 5d89015d61c..24bc263e5a7 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -88,6 +88,7 @@ mod lint;
 mod lower_intrinsics;
 mod lower_slice_len;
 mod match_branches;
+mod mentioned_items;
 mod multiple_return_terminators;
 mod normalize_array_len;
 mod nrvo;
@@ -565,6 +566,10 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         tcx,
         body,
         &[
+            // Before doing anything, remember which items are being mentioned so that the set of items
+            // visited does not depend on the optimization level.
+            &mentioned_items::MentionedItems,
+            // Add some UB checks before any UB gets optimized away.
             &check_alignment::CheckAlignment,
             // Before inlining: trim down MIR with passes to reduce inlining work.
 
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index 1bab240ef50..7d4c1b9c21a 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -20,30 +20,13 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
                     sym::unreachable => {
                         terminator.kind = TerminatorKind::Unreachable;
                     }
-                    sym::check_language_ub => {
+                    sym::ub_checks => {
                         let target = target.unwrap();
                         block.statements.push(Statement {
                             source_info: terminator.source_info,
                             kind: StatementKind::Assign(Box::new((
                                 *destination,
-                                Rvalue::NullaryOp(
-                                    NullOp::UbCheck(UbKind::LanguageUb),
-                                    tcx.types.bool,
-                                ),
-                            ))),
-                        });
-                        terminator.kind = TerminatorKind::Goto { target };
-                    }
-                    sym::check_library_ub => {
-                        let target = target.unwrap();
-                        block.statements.push(Statement {
-                            source_info: terminator.source_info,
-                            kind: StatementKind::Assign(Box::new((
-                                *destination,
-                                Rvalue::NullaryOp(
-                                    NullOp::UbCheck(UbKind::LibraryUb),
-                                    tcx.types.bool,
-                                ),
+                                Rvalue::NullaryOp(NullOp::UbChecks, tcx.types.bool),
                             ))),
                         });
                         terminator.kind = TerminatorKind::Goto { target };
diff --git a/compiler/rustc_mir_transform/src/mentioned_items.rs b/compiler/rustc_mir_transform/src/mentioned_items.rs
new file mode 100644
index 00000000000..57b6126dece
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/mentioned_items.rs
@@ -0,0 +1,117 @@
+use rustc_middle::mir::visit::Visitor;
+use rustc_middle::mir::{self, Location, MentionedItem, MirPass};
+use rustc_middle::ty::{self, adjustment::PointerCoercion, TyCtxt};
+use rustc_session::Session;
+use rustc_span::source_map::Spanned;
+
+pub struct MentionedItems;
+
+struct MentionedItemsVisitor<'a, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    body: &'a mir::Body<'tcx>,
+    mentioned_items: &'a mut Vec<Spanned<MentionedItem<'tcx>>>,
+}
+
+impl<'tcx> MirPass<'tcx> for MentionedItems {
+    fn is_enabled(&self, _sess: &Session) -> bool {
+        // If this pass is skipped the collector assume that nothing got mentioned! We could
+        // potentially skip it in opt-level 0 if we are sure that opt-level will never *remove* uses
+        // of anything, but that still seems fragile. Furthermore, even debug builds use level 1, so
+        // special-casing level 0 is just not worth it.
+        true
+    }
+
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) {
+        debug_assert!(body.mentioned_items.is_empty());
+        let mut mentioned_items = Vec::new();
+        MentionedItemsVisitor { tcx, body, mentioned_items: &mut mentioned_items }.visit_body(body);
+        body.mentioned_items = mentioned_items;
+    }
+}
+
+// This visitor is carefully in sync with the one in `rustc_monomorphize::collector`. We are
+// visiting the exact same places but then instead of monomorphizing and creating `MonoItems`, we
+// have to remain generic and just recording the relevant information in `mentioned_items`, where it
+// will then be monomorphized later during "mentioned items" collection.
+impl<'tcx> Visitor<'tcx> for MentionedItemsVisitor<'_, 'tcx> {
+    fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
+        self.super_terminator(terminator, location);
+        let span = || self.body.source_info(location).span;
+        match &terminator.kind {
+            mir::TerminatorKind::Call { func, .. } => {
+                let callee_ty = func.ty(self.body, self.tcx);
+                self.mentioned_items
+                    .push(Spanned { node: MentionedItem::Fn(callee_ty), span: span() });
+            }
+            mir::TerminatorKind::Drop { place, .. } => {
+                let ty = place.ty(self.body, self.tcx).ty;
+                self.mentioned_items.push(Spanned { node: MentionedItem::Drop(ty), span: span() });
+            }
+            mir::TerminatorKind::InlineAsm { ref operands, .. } => {
+                for op in operands {
+                    match *op {
+                        mir::InlineAsmOperand::SymFn { ref value } => {
+                            self.mentioned_items.push(Spanned {
+                                node: MentionedItem::Fn(value.const_.ty()),
+                                span: span(),
+                            });
+                        }
+                        _ => {}
+                    }
+                }
+            }
+            _ => {}
+        }
+    }
+
+    fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
+        self.super_rvalue(rvalue, location);
+        let span = || self.body.source_info(location).span;
+        match *rvalue {
+            // We need to detect unsizing casts that required vtables.
+            mir::Rvalue::Cast(
+                mir::CastKind::PointerCoercion(PointerCoercion::Unsize),
+                ref operand,
+                target_ty,
+            )
+            | mir::Rvalue::Cast(mir::CastKind::DynStar, ref operand, target_ty) => {
+                // This isn't monomorphized yet so we can't tell what the actual types are -- just
+                // add everything that may involve a vtable.
+                let source_ty = operand.ty(self.body, self.tcx);
+                let may_involve_vtable = match (
+                    source_ty.builtin_deref(true).map(|t| t.ty.kind()),
+                    target_ty.builtin_deref(true).map(|t| t.ty.kind()),
+                ) {
+                    (Some(ty::Array(..)), Some(ty::Str | ty::Slice(..))) => false, // &str/&[T] unsizing
+                    _ => true,
+                };
+                if may_involve_vtable {
+                    self.mentioned_items.push(Spanned {
+                        node: MentionedItem::UnsizeCast { source_ty, target_ty },
+                        span: span(),
+                    });
+                }
+            }
+            // Similarly, record closures that are turned into function pointers.
+            mir::Rvalue::Cast(
+                mir::CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)),
+                ref operand,
+                _,
+            ) => {
+                let source_ty = operand.ty(self.body, self.tcx);
+                self.mentioned_items
+                    .push(Spanned { node: MentionedItem::Closure(source_ty), span: span() });
+            }
+            // And finally, function pointer reification casts.
+            mir::Rvalue::Cast(
+                mir::CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer),
+                ref operand,
+                _,
+            ) => {
+                let fn_ty = operand.ty(self.body, self.tcx);
+                self.mentioned_items.push(Spanned { node: MentionedItem::Fn(fn_ty), span: span() });
+            }
+            _ => {}
+        }
+    }
+}
diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs
index 9fe8c34a8bf..2951897ebd6 100644
--- a/compiler/rustc_mir_transform/src/promote_consts.rs
+++ b/compiler/rustc_mir_transform/src/promote_consts.rs
@@ -446,7 +446,7 @@ impl<'tcx> Validator<'_, 'tcx> {
                 NullOp::SizeOf => {}
                 NullOp::AlignOf => {}
                 NullOp::OffsetOf(_) => {}
-                NullOp::UbCheck(_) => {}
+                NullOp::UbChecks => {}
             },
 
             Rvalue::ShallowInitBox(_, _) => return Err(Unpromotable),
@@ -464,7 +464,7 @@ impl<'tcx> Validator<'_, 'tcx> {
                 let op = *op;
                 let lhs_ty = lhs.ty(self.body, self.tcx);
 
-                if let ty::RawPtr(_) | ty::FnPtr(..) = lhs_ty.kind() {
+                if let ty::RawPtr(_, _) | ty::FnPtr(..) = lhs_ty.kind() {
                     // Raw and fn pointer operations are not allowed inside consts and thus not promotable.
                     assert!(matches!(
                         op,
@@ -820,11 +820,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
             let ty = local_decls[place.local].ty;
             let span = statement.source_info.span;
 
-            let ref_ty = Ty::new_ref(
-                tcx,
-                tcx.lifetimes.re_erased,
-                ty::TypeAndMut { ty, mutbl: borrow_kind.to_mutbl_lossy() },
-            );
+            let ref_ty =
+                Ty::new_ref(tcx, tcx.lifetimes.re_erased, ty, borrow_kind.to_mutbl_lossy());
 
             let mut projection = vec![PlaceElem::Deref];
             projection.extend(place.projection);
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index 28b502e8cab..94a95428ab0 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -17,7 +17,7 @@ use std::iter;
 
 use crate::{
     abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, deref_separator,
-    pass_manager as pm, remove_noop_landing_pads, simplify,
+    mentioned_items, pass_manager as pm, remove_noop_landing_pads, simplify,
 };
 use rustc_middle::mir::patch::MirPatch;
 use rustc_mir_dataflow::elaborate_drops::{self, DropElaborator, DropFlagMode, DropStyle};
@@ -112,6 +112,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
                     tcx,
                     &mut body,
                     &[
+                        &mentioned_items::MentionedItems,
                         &abort_unwinding_calls::AbortUnwindingCalls,
                         &add_call_guards::CriticalCallEdges,
                     ],
@@ -143,6 +144,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
         tcx,
         &mut result,
         &[
+            &mentioned_items::MentionedItems,
             &add_moves_for_packed_drops::AddMovesForPackedDrops,
             &deref_separator::Derefer,
             &remove_noop_landing_pads::RemoveNoopLandingPads,
@@ -537,14 +539,8 @@ impl<'tcx> CloneShimBuilder<'tcx> {
             const_: Const::zero_sized(func_ty),
         }));
 
-        let ref_loc = self.make_place(
-            Mutability::Not,
-            Ty::new_ref(
-                tcx,
-                tcx.lifetimes.re_erased,
-                ty::TypeAndMut { ty, mutbl: hir::Mutability::Not },
-            ),
-        );
+        let ref_loc =
+            self.make_place(Mutability::Not, Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty));
 
         // `let ref_loc: &ty = &src;`
         let statement = self.make_statement(StatementKind::Assign(Box::new((
@@ -769,11 +765,7 @@ fn build_call_shim<'tcx>(
             // let rcvr = &mut rcvr;
             let ref_rcvr = local_decls.push(
                 LocalDecl::new(
-                    Ty::new_ref(
-                        tcx,
-                        tcx.lifetimes.re_erased,
-                        ty::TypeAndMut { ty: sig.inputs()[0], mutbl: hir::Mutability::Mut },
-                    ),
+                    Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, sig.inputs()[0]),
                     span,
                 )
                 .immutable(),
diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs
index e4fdbd6ae69..fddc62e6652 100644
--- a/compiler/rustc_mir_transform/src/ssa.rs
+++ b/compiler/rustc_mir_transform/src/ssa.rs
@@ -29,7 +29,7 @@ pub struct SsaLocals {
 pub enum AssignedValue<'a, 'tcx> {
     Arg,
     Rvalue(&'a mut Rvalue<'tcx>),
-    Terminator(&'a mut TerminatorKind<'tcx>),
+    Terminator,
 }
 
 impl SsaLocals {
@@ -149,8 +149,7 @@ impl SsaLocals {
                 Set1::One(DefLocation::CallReturn { call, .. }) => {
                     let bb = &mut basic_blocks[call];
                     let loc = Location { block: call, statement_index: bb.statements.len() };
-                    let term = bb.terminator_mut();
-                    f(local, AssignedValue::Terminator(&mut term.kind), loc)
+                    f(local, AssignedValue::Terminator, loc)
                 }
                 _ => {}
             }
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index abe691ba0d8..a51b1c34a1a 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -28,6 +28,7 @@
 //! - VTables
 //! - Object Shims
 //!
+//! The main entry point is `collect_crate_mono_items`, at the bottom of this file.
 //!
 //! General Algorithm
 //! -----------------
@@ -137,21 +138,61 @@
 //! just linked to and no node is created; which is exactly what we want, since
 //! no machine code should be generated in the current crate for such an item.
 //!
-//! Eager and Lazy Collection Mode
-//! ------------------------------
-//! Mono item collection can be performed in one of two modes:
+//! Eager and Lazy Collection Strategy
+//! ----------------------------------
+//! Mono item collection can be performed with one of two strategies:
 //!
-//! - Lazy mode means that items will only be instantiated when actually
+//! - Lazy strategy means that items will only be instantiated when actually
 //!   used. The goal is to produce the least amount of machine code
 //!   possible.
 //!
-//! - Eager mode is meant to be used in conjunction with incremental compilation
+//! - Eager strategy is meant to be used in conjunction with incremental compilation
 //!   where a stable set of mono items is more important than a minimal
-//!   one. Thus, eager mode will instantiate drop-glue for every drop-able type
+//!   one. Thus, eager strategy will instantiate drop-glue for every drop-able type
 //!   in the crate, even if no drop call for that type exists (yet). It will
 //!   also instantiate default implementations of trait methods, something that
 //!   otherwise is only done on demand.
 //!
+//! Collection-time const evaluation and "mentioned" items
+//! ------------------------------------------------------
+//!
+//! One important role of collection is to evaluate all constants that are used by all the items
+//! which are being collected. Codegen can then rely on only encountering constants that evaluate
+//! successfully, and if a constant fails to evaluate, the collector has much better context to be
+//! able to show where this constant comes up.
+//!
+//! However, the exact set of "used" items (collected as described above), and therefore the exact
+//! set of used constants, can depend on optimizations. Optimizing away dead code may optimize away
+//! a function call that uses a failing constant, so an unoptimized build may fail where an
+//! optimized build succeeds. This is undesirable.
+//!
+//! To avoid this, the collector has the concept of "mentioned" items. Some time during the MIR
+//! pipeline, before any optimization-level-dependent optimizations, we compute a list of all items
+//! that syntactically appear in the code. These are considered "mentioned", and even if they are in
+//! dead code and get optimized away (which makes them no longer "used"), they are still
+//! "mentioned". For every used item, the collector ensures that all mentioned items, recursively,
+//! do not use a failing constant. This is reflected via the [`CollectionMode`], which determines
+//! whether we are visiting a used item or merely a mentioned item.
+//!
+//! The collector and "mentioned items" gathering (which lives in `rustc_mir_transform::mentioned_items`)
+//! need to stay in sync in the following sense:
+//!
+//! - For every item that the collector gather that could eventually lead to build failure (most
+//!   likely due to containing a constant that fails to evaluate), a corresponding mentioned item
+//!   must be added. This should use the exact same strategy as the ecollector to make sure they are
+//!   in sync. However, while the collector works on monomorphized types, mentioned items are
+//!   collected on generic MIR -- so any time the collector checks for a particular type (such as
+//!   `ty::FnDef`), we have to just onconditionally add this as a mentioned item.
+//! - In `visit_mentioned_item`, we then do with that mentioned item exactly what the collector
+//!   would have done during regular MIR visiting. Basically you can think of the collector having
+//!   two stages, a pre-monomorphization stage and a post-monomorphization stage (usually quite
+//!   literally separated by a call to `self.monomorphize`); the pre-monomorphizationn stage is
+//!   duplicated in mentioned items gathering and the post-monomorphization stage is duplicated in
+//!   `visit_mentioned_item`.
+//! - Finally, as a performance optimization, the collector should fill `used_mentioned_item` during
+//!   its MIR traversal with exactly what mentioned item gathering would have added in the same
+//!   situation. This detects mentioned items that have *not* been optimized away and hence don't
+//!   need a dedicated traversal.
 //!
 //! Open Issues
 //! -----------
@@ -165,15 +206,16 @@
 //! regardless of whether it is actually needed or not.
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::sync::{par_for_each_in, MTLock, MTLockRef};
+use rustc_data_structures::sync::{par_for_each_in, LRef, MTLock};
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
 use rustc_hir::lang_items::LangItem;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::interpret::{AllocId, ErrorHandled, GlobalAlloc, Scalar};
 use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
 use rustc_middle::mir::visit::Visitor as MirVisitor;
-use rustc_middle::mir::{self, Location};
+use rustc_middle::mir::{self, Location, MentionedItem};
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCoercion};
 use rustc_middle::ty::layout::ValidityRequirement;
@@ -183,7 +225,6 @@ use rustc_middle::ty::{
     TypeVisitableExt, VtblEntry,
 };
 use rustc_middle::ty::{GenericArgKind, GenericArgs};
-use rustc_middle::{middle::codegen_fn_attrs::CodegenFnAttrFlags, mir::visit::TyContext};
 use rustc_session::config::EntryFnType;
 use rustc_session::lint::builtin::LARGE_ASSIGNMENTS;
 use rustc_session::Limit;
@@ -199,7 +240,7 @@ use crate::errors::{
 };
 
 #[derive(PartialEq)]
-pub enum MonoItemCollectionMode {
+pub enum MonoItemCollectionStrategy {
     Eager,
     Lazy,
 }
@@ -214,6 +255,35 @@ pub struct UsageMap<'tcx> {
 
 type MonoItems<'tcx> = Vec<Spanned<MonoItem<'tcx>>>;
 
+/// The state that is shared across the concurrent threads that are doing collection.
+struct SharedState<'tcx> {
+    /// Items that have been or are currently being recursively collected.
+    visited: MTLock<FxHashSet<MonoItem<'tcx>>>,
+    /// Items that have been or are currently being recursively treated as "mentioned", i.e., their
+    /// consts are evaluated but nothing is added to the collection.
+    mentioned: MTLock<FxHashSet<MonoItem<'tcx>>>,
+    /// Which items are being used where, for better errors.
+    usage_map: MTLock<UsageMap<'tcx>>,
+}
+
+/// See module-level docs on some contect for "mentioned" items.
+#[derive(Copy, Clone, Debug, PartialEq)]
+enum CollectionMode {
+    /// Collect items that are used, i.e., actually needed for codegen.
+    ///
+    /// Which items are used can depend on optimization levels, as MIR optimizations can remove
+    /// uses.
+    UsedItems,
+    /// Collect items that are mentioned. The goal of this mode is that it is independent of
+    /// optimizations: the set of "mentioned" items is computed before optimizations are run.
+    ///
+    /// The exact contents of this set are *not* a stable guarantee. (For instance, it is currently
+    /// computed after drop-elaboration. If we ever do some optimizations even in debug builds, we
+    /// might decide to run them before computing mentioned items.) The key property of this set is
+    /// that it is optimization-independent.
+    MentionedItems,
+}
+
 impl<'tcx> UsageMap<'tcx> {
     fn new() -> UsageMap<'tcx> {
         UsageMap { used_map: FxHashMap::default(), user_map: FxHashMap::default() }
@@ -253,99 +323,40 @@ impl<'tcx> UsageMap<'tcx> {
     }
 }
 
-#[instrument(skip(tcx, mode), level = "debug")]
-pub fn collect_crate_mono_items(
-    tcx: TyCtxt<'_>,
-    mode: MonoItemCollectionMode,
-) -> (FxHashSet<MonoItem<'_>>, UsageMap<'_>) {
-    let _prof_timer = tcx.prof.generic_activity("monomorphization_collector");
-
-    let roots =
-        tcx.sess.time("monomorphization_collector_root_collections", || collect_roots(tcx, mode));
-
-    debug!("building mono item graph, beginning at roots");
-
-    let mut visited = MTLock::new(FxHashSet::default());
-    let mut usage_map = MTLock::new(UsageMap::new());
-    let recursion_limit = tcx.recursion_limit();
-
-    {
-        let visited: MTLockRef<'_, _> = &mut visited;
-        let usage_map: MTLockRef<'_, _> = &mut usage_map;
-
-        tcx.sess.time("monomorphization_collector_graph_walk", || {
-            par_for_each_in(roots, |root| {
-                let mut recursion_depths = DefIdMap::default();
-                collect_items_rec(
-                    tcx,
-                    dummy_spanned(root),
-                    visited,
-                    &mut recursion_depths,
-                    recursion_limit,
-                    usage_map,
-                );
-            });
-        });
-    }
-
-    (visited.into_inner(), usage_map.into_inner())
-}
-
-// Find all non-generic items by walking the HIR. These items serve as roots to
-// start monomorphizing from.
-#[instrument(skip(tcx, mode), level = "debug")]
-fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec<MonoItem<'_>> {
-    debug!("collecting roots");
-    let mut roots = Vec::new();
-
-    {
-        let entry_fn = tcx.entry_fn(());
-
-        debug!("collect_roots: entry_fn = {:?}", entry_fn);
-
-        let mut collector = RootCollector { tcx, mode, entry_fn, output: &mut roots };
-
-        let crate_items = tcx.hir_crate_items(());
-
-        for id in crate_items.items() {
-            collector.process_item(id);
-        }
-
-        for id in crate_items.impl_items() {
-            collector.process_impl_item(id);
-        }
-
-        collector.push_extra_entry_roots();
-    }
-
-    // We can only codegen items that are instantiable - items all of
-    // whose predicates hold. Luckily, items that aren't instantiable
-    // can't actually be used, so we can just skip codegenning them.
-    roots
-        .into_iter()
-        .filter_map(|Spanned { node: mono_item, .. }| {
-            mono_item.is_instantiable(tcx).then_some(mono_item)
-        })
-        .collect()
-}
-
 /// Collect all monomorphized items reachable from `starting_point`, and emit a note diagnostic if a
 /// post-monomorphization error is encountered during a collection step.
-#[instrument(skip(tcx, visited, recursion_depths, recursion_limit, usage_map), level = "debug")]
+///
+/// `mode` determined whether we are scanning for [used items][CollectionMode::UsedItems]
+/// or [mentioned items][CollectionMode::MentionedItems].
+#[instrument(skip(tcx, state, recursion_depths, recursion_limit), level = "debug")]
 fn collect_items_rec<'tcx>(
     tcx: TyCtxt<'tcx>,
     starting_item: Spanned<MonoItem<'tcx>>,
-    visited: MTLockRef<'_, FxHashSet<MonoItem<'tcx>>>,
+    state: LRef<'_, SharedState<'tcx>>,
     recursion_depths: &mut DefIdMap<usize>,
     recursion_limit: Limit,
-    usage_map: MTLockRef<'_, UsageMap<'tcx>>,
+    mode: CollectionMode,
 ) {
-    if !visited.lock_mut().insert(starting_item.node) {
-        // We've been here already, no need to search again.
-        return;
+    if mode == CollectionMode::UsedItems {
+        if !state.visited.lock_mut().insert(starting_item.node) {
+            // We've been here already, no need to search again.
+            return;
+        }
+    } else {
+        if state.visited.lock().contains(&starting_item.node) {
+            // We've already done a *full* visit on this one, no need to do the "mention" visit.
+            return;
+        }
+        if !state.mentioned.lock_mut().insert(starting_item.node) {
+            // We've been here already, no need to search again.
+            return;
+        }
+        // There's some risk that we first do a 'mention' visit and then a full visit. But there's no
+        // harm in that, the mention visit will trigger all the queries and the results are cached.
     }
 
-    let mut used_items = Vec::new();
+    let mut used_items = MonoItems::new();
+    let mut mentioned_items = MonoItems::new();
     let recursion_depth_reset;
 
     // Post-monomorphization errors MVP
@@ -373,37 +384,48 @@ fn collect_items_rec<'tcx>(
     // FIXME: don't rely on global state, instead bubble up errors. Note: this is very hard to do.
     let error_count = tcx.dcx().err_count();
 
+    // In `mentioned_items` we collect items that were mentioned in this MIR but possibly do not
+    // need to be monomorphized. This is done to ensure that optimizing away function calls does not
+    // hide const-eval errors that those calls would otherwise have triggered.
     match starting_item.node {
         MonoItem::Static(def_id) => {
-            let instance = Instance::mono(tcx, def_id);
+            recursion_depth_reset = None;
 
-            // Sanity check whether this ended up being collected accidentally
-            debug_assert!(should_codegen_locally(tcx, &instance));
+            // Statics always get evaluted (which is possible because they can't be generic), so for
+            // `MentionedItems` collection there's nothing to do here.
+            if mode == CollectionMode::UsedItems {
+                let instance = Instance::mono(tcx, def_id);
 
-            let DefKind::Static { nested, .. } = tcx.def_kind(def_id) else { bug!() };
-            // Nested statics have no type.
-            if !nested {
-                let ty = instance.ty(tcx, ty::ParamEnv::reveal_all());
-                visit_drop_use(tcx, ty, true, starting_item.span, &mut used_items);
-            }
+                // Sanity check whether this ended up being collected accidentally
+                debug_assert!(should_codegen_locally(tcx, &instance));
 
-            recursion_depth_reset = None;
+                let DefKind::Static { nested, .. } = tcx.def_kind(def_id) else { bug!() };
+                // Nested statics have no type.
+                if !nested {
+                    let ty = instance.ty(tcx, ty::ParamEnv::reveal_all());
+                    visit_drop_use(tcx, ty, true, starting_item.span, &mut used_items);
+                }
+
+                if let Ok(alloc) = tcx.eval_static_initializer(def_id) {
+                    for &prov in alloc.inner().provenance().ptrs().values() {
+                        collect_alloc(tcx, prov.alloc_id(), &mut used_items);
+                    }
+                }
 
-            if let Ok(alloc) = tcx.eval_static_initializer(def_id) {
-                for &prov in alloc.inner().provenance().ptrs().values() {
-                    collect_alloc(tcx, prov.alloc_id(), &mut used_items);
+                if tcx.needs_thread_local_shim(def_id) {
+                    used_items.push(respan(
+                        starting_item.span,
+                        MonoItem::Fn(Instance {
+                            def: InstanceDef::ThreadLocalShim(def_id),
+                            args: GenericArgs::empty(),
+                        }),
+                    ));
                 }
             }
 
-            if tcx.needs_thread_local_shim(def_id) {
-                used_items.push(respan(
-                    starting_item.span,
-                    MonoItem::Fn(Instance {
-                        def: InstanceDef::ThreadLocalShim(def_id),
-                        args: GenericArgs::empty(),
-                    }),
-                ));
-            }
+            // mentioned_items stays empty since there's no codegen for statics. statics don't get
+            // optimized, and if they did then the const-eval interpreter would have to worry about
+            // mentioned_items.
         }
         MonoItem::Fn(instance) => {
             // Sanity check whether this ended up being collected accidentally
@@ -420,10 +442,20 @@ fn collect_items_rec<'tcx>(
             check_type_length_limit(tcx, instance);
 
             rustc_data_structures::stack::ensure_sufficient_stack(|| {
-                collect_used_items(tcx, instance, &mut used_items);
+                collect_items_of_instance(
+                    tcx,
+                    instance,
+                    &mut used_items,
+                    &mut mentioned_items,
+                    mode,
+                )
             });
         }
         MonoItem::GlobalAsm(item_id) => {
+            assert!(
+                mode == CollectionMode::UsedItems,
+                "should never encounter global_asm when collecting mentioned items"
+            );
             recursion_depth_reset = None;
 
             let item = tcx.hir().item(item_id);
@@ -459,8 +491,10 @@ fn collect_items_rec<'tcx>(
             } else {
                 span_bug!(item.span, "Mismatch between hir::Item type and MonoItem type")
             }
+
+            // mention_items stays empty as nothing gets optimized here.
         }
-    }
+    };
 
     // Check for PMEs and emit a diagnostic if one happened. To try to show relevant edges of the
     // mono item graph.
@@ -474,10 +508,41 @@ fn collect_items_rec<'tcx>(
             formatted_item,
         });
     }
-    usage_map.lock_mut().record_used(starting_item.node, &used_items);
+    // Only updating `usage_map` for used items as otherwise we may be inserting the same item
+    // multiple times (if it is first 'mentioned' and then later actuall used), and the usage map
+    // logic does not like that.
+    // This is part of the output of collection and hence only relevant for "used" items.
+    // ("Mentioned" items are only considered internally during collection.)
+    if mode == CollectionMode::UsedItems {
+        state.usage_map.lock_mut().record_used(starting_item.node, &used_items);
+    }
 
-    for used_item in used_items {
-        collect_items_rec(tcx, used_item, visited, recursion_depths, recursion_limit, usage_map);
+    if mode == CollectionMode::MentionedItems {
+        assert!(used_items.is_empty(), "'mentioned' collection should never encounter used items");
+    } else {
+        for used_item in used_items {
+            collect_items_rec(
+                tcx,
+                used_item,
+                state,
+                recursion_depths,
+                recursion_limit,
+                CollectionMode::UsedItems,
+            );
+        }
+    }
+
+    // Walk over mentioned items *after* used items, so that if an item is both mentioned and used then
+    // the loop above has fully collected it, so this loop will skip it.
+    for mentioned_item in mentioned_items {
+        collect_items_rec(
+            tcx,
+            mentioned_item,
+            state,
+            recursion_depths,
+            recursion_limit,
+            CollectionMode::MentionedItems,
+        );
     }
 
     if let Some((def_id, depth)) = recursion_depth_reset {
@@ -596,7 +661,10 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
 struct MirUsedCollector<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     body: &'a mir::Body<'tcx>,
-    output: &'a mut MonoItems<'tcx>,
+    used_items: &'a mut MonoItems<'tcx>,
+    /// See the comment in `collect_items_of_instance` for the purpose of this set.
+    /// Note that this contains *not-monomorphized* items!
+    used_mentioned_items: &'a mut FxHashSet<MentionedItem<'tcx>>,
     instance: Instance<'tcx>,
     /// Spans for move size lints already emitted. Helps avoid duplicate lints.
     move_size_spans: Vec<Span>,
@@ -606,11 +674,11 @@ struct MirUsedCollector<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
-    pub fn monomorphize<T>(&self, value: T) -> T
+    fn monomorphize<T>(&self, value: T) -> T
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
     {
-        debug!("monomorphize: self.instance={:?}", self.instance);
+        trace!("monomorphize: self.instance={:?}", self.instance);
         self.instance.instantiate_mir_and_normalize_erasing_regions(
             self.tcx,
             ty::ParamEnv::reveal_all(),
@@ -735,6 +803,31 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
         );
         self.move_size_spans.push(span);
     }
+
+    /// Evaluates a *not yet monomorphized* constant.
+    fn eval_constant(
+        &mut self,
+        constant: &mir::ConstOperand<'tcx>,
+    ) -> Option<mir::ConstValue<'tcx>> {
+        let const_ = self.monomorphize(constant.const_);
+        let param_env = ty::ParamEnv::reveal_all();
+        // Evaluate the constant. This makes const eval failure a collection-time error (rather than
+        // a codegen-time error). rustc stops after collection if there was an error, so this
+        // ensures codegen never has to worry about failing consts.
+        // (codegen relies on this and ICEs will happen if this is violated.)
+        match const_.eval(self.tcx, param_env, constant.span) {
+            Ok(v) => Some(v),
+            Err(ErrorHandled::TooGeneric(..)) => span_bug!(
+                constant.span,
+                "collection encountered polymorphic constant: {:?}",
+                const_
+            ),
+            Err(err @ ErrorHandled::Reported(..)) => {
+                err.emit_note(self.tcx);
+                return None;
+            }
+        }
+    }
 }
 
 impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
@@ -753,8 +846,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
                 target_ty,
             )
             | mir::Rvalue::Cast(mir::CastKind::DynStar, ref operand, target_ty) => {
-                let target_ty = self.monomorphize(target_ty);
                 let source_ty = operand.ty(self.body, self.tcx);
+                // *Before* monomorphizing, record that we already handled this mention.
+                self.used_mentioned_items
+                    .insert(MentionedItem::UnsizeCast { source_ty, target_ty });
+                let target_ty = self.monomorphize(target_ty);
                 let source_ty = self.monomorphize(source_ty);
                 let (source_ty, target_ty) =
                     find_vtable_types_for_unsizing(self.tcx.at(span), source_ty, target_ty);
@@ -769,7 +865,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
                         target_ty,
                         source_ty,
                         span,
-                        self.output,
+                        self.used_items,
                     );
                 }
             }
@@ -779,8 +875,10 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
                 _,
             ) => {
                 let fn_ty = operand.ty(self.body, self.tcx);
+                // *Before* monomorphizing, record that we already handled this mention.
+                self.used_mentioned_items.insert(MentionedItem::Fn(fn_ty));
                 let fn_ty = self.monomorphize(fn_ty);
-                visit_fn_use(self.tcx, fn_ty, false, span, self.output);
+                visit_fn_use(self.tcx, fn_ty, false, span, self.used_items);
             }
             mir::Rvalue::Cast(
                 mir::CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)),
@@ -788,20 +886,17 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
                 _,
             ) => {
                 let source_ty = operand.ty(self.body, self.tcx);
+                // *Before* monomorphizing, record that we already handled this mention.
+                self.used_mentioned_items.insert(MentionedItem::Closure(source_ty));
                 let source_ty = self.monomorphize(source_ty);
-                match *source_ty.kind() {
-                    ty::Closure(def_id, args) => {
-                        let instance = Instance::resolve_closure(
-                            self.tcx,
-                            def_id,
-                            args,
-                            ty::ClosureKind::FnOnce,
-                        );
-                        if should_codegen_locally(self.tcx, &instance) {
-                            self.output.push(create_fn_mono_item(self.tcx, instance, span));
-                        }
+                if let ty::Closure(def_id, args) = *source_ty.kind() {
+                    let instance =
+                        Instance::resolve_closure(self.tcx, def_id, args, ty::ClosureKind::FnOnce);
+                    if should_codegen_locally(self.tcx, &instance) {
+                        self.used_items.push(create_fn_mono_item(self.tcx, instance, span));
                     }
-                    _ => bug!(),
+                } else {
+                    bug!()
                 }
             }
             mir::Rvalue::ThreadLocalRef(def_id) => {
@@ -809,7 +904,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
                 let instance = Instance::mono(self.tcx, def_id);
                 if should_codegen_locally(self.tcx, &instance) {
                     trace!("collecting thread-local static {:?}", def_id);
-                    self.output.push(respan(span, MonoItem::Static(def_id)));
+                    self.used_items.push(respan(span, MonoItem::Static(def_id)));
                 }
             }
             _ => { /* not interesting */ }
@@ -822,26 +917,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
     /// to ensure that the constant evaluates successfully and walk the result.
     #[instrument(skip(self), level = "debug")]
     fn visit_constant(&mut self, constant: &mir::ConstOperand<'tcx>, location: Location) {
-        let const_ = self.monomorphize(constant.const_);
-        let param_env = ty::ParamEnv::reveal_all();
-        // Evaluate the constant. This makes const eval failure a collection-time error (rather than
-        // a codegen-time error). rustc stops after collection if there was an error, so this
-        // ensures codegen never has to worry about failing consts.
-        // (codegen relies on this and ICEs will happen if this is violated.)
-        let val = match const_.eval(self.tcx, param_env, constant.span) {
-            Ok(v) => v,
-            Err(ErrorHandled::TooGeneric(..)) => span_bug!(
-                self.body.source_info(location).span,
-                "collection encountered polymorphic constant: {:?}",
-                const_
-            ),
-            Err(err @ ErrorHandled::Reported(..)) => {
-                err.emit_note(self.tcx);
-                return;
-            }
-        };
-        collect_const_value(self.tcx, val, self.output);
-        MirVisitor::visit_ty(self, const_.ty(), TyContext::Location(location));
+        // No `super_constant` as we don't care about `visit_ty`/`visit_ty_const`.
+        let Some(val) = self.eval_constant(constant) else { return };
+        collect_const_value(self.tcx, val, self.used_items);
     }
 
     fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
@@ -852,34 +930,41 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
         let push_mono_lang_item = |this: &mut Self, lang_item: LangItem| {
             let instance = Instance::mono(tcx, tcx.require_lang_item(lang_item, Some(source)));
             if should_codegen_locally(tcx, &instance) {
-                this.output.push(create_fn_mono_item(tcx, instance, source));
+                this.used_items.push(create_fn_mono_item(tcx, instance, source));
             }
         };
 
         match terminator.kind {
             mir::TerminatorKind::Call { ref func, ref args, ref fn_span, .. } => {
                 let callee_ty = func.ty(self.body, tcx);
+                // *Before* monomorphizing, record that we already handled this mention.
+                self.used_mentioned_items.insert(MentionedItem::Fn(callee_ty));
                 let callee_ty = self.monomorphize(callee_ty);
                 self.check_fn_args_move_size(callee_ty, args, *fn_span, location);
-                visit_fn_use(self.tcx, callee_ty, true, source, &mut self.output)
+                visit_fn_use(self.tcx, callee_ty, true, source, &mut self.used_items)
             }
             mir::TerminatorKind::Drop { ref place, .. } => {
                 let ty = place.ty(self.body, self.tcx).ty;
+                // *Before* monomorphizing, record that we already handled this mention.
+                self.used_mentioned_items.insert(MentionedItem::Drop(ty));
                 let ty = self.monomorphize(ty);
-                visit_drop_use(self.tcx, ty, true, source, self.output);
+                visit_drop_use(self.tcx, ty, true, source, self.used_items);
             }
             mir::TerminatorKind::InlineAsm { ref operands, .. } => {
                 for op in operands {
                     match *op {
                         mir::InlineAsmOperand::SymFn { ref value } => {
-                            let fn_ty = self.monomorphize(value.const_.ty());
-                            visit_fn_use(self.tcx, fn_ty, false, source, self.output);
+                            let fn_ty = value.const_.ty();
+                            // *Before* monomorphizing, record that we already handled this mention.
+                            self.used_mentioned_items.insert(MentionedItem::Fn(fn_ty));
+                            let fn_ty = self.monomorphize(fn_ty);
+                            visit_fn_use(self.tcx, fn_ty, false, source, self.used_items);
                         }
                         mir::InlineAsmOperand::SymStatic { def_id } => {
                             let instance = Instance::mono(self.tcx, def_id);
                             if should_codegen_locally(self.tcx, &instance) {
                                 trace!("collecting asm sym static {:?}", def_id);
-                                self.output.push(respan(source, MonoItem::Static(def_id)));
+                                self.used_items.push(respan(source, MonoItem::Static(def_id)));
                             }
                         }
                         _ => {}
@@ -936,6 +1021,8 @@ fn visit_drop_use<'tcx>(
     visit_instance_use(tcx, instance, is_direct_call, source, output);
 }
 
+/// For every call of this function in the visitor, make sure there is a matching call in the
+/// `mentioned_items` pass!
 fn visit_fn_use<'tcx>(
     tcx: TyCtxt<'tcx>,
     ty: Ty<'tcx>,
@@ -1020,7 +1107,7 @@ fn visit_instance_use<'tcx>(
 
 /// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we
 /// can just link to the upstream crate and therefore don't need a mono item.
-fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool {
+pub(crate) fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool {
     let Some(def_id) = instance.def.def_id_if_not_guaranteed_local_codegen() else {
         return true;
     };
@@ -1124,10 +1211,8 @@ fn find_vtable_types_for_unsizing<'tcx>(
     };
 
     match (&source_ty.kind(), &target_ty.kind()) {
-        (&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(ty::TypeAndMut { ty: b, .. }))
-        | (&ty::RawPtr(ty::TypeAndMut { ty: a, .. }), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => {
-            ptr_vtable(*a, *b)
-        }
+        (&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(b, _))
+        | (&ty::RawPtr(a, _), &ty::RawPtr(b, _)) => ptr_vtable(*a, *b),
         (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) if def_a.is_box() && def_b.is_box() => {
             ptr_vtable(source_ty.boxed_ty(), target_ty.boxed_ty())
         }
@@ -1197,34 +1282,225 @@ fn create_mono_items_for_vtable_methods<'tcx>(
 ) {
     assert!(!trait_ty.has_escaping_bound_vars() && !impl_ty.has_escaping_bound_vars());
 
-    if let ty::Dynamic(trait_ty, ..) = trait_ty.kind() {
-        if let Some(principal) = trait_ty.principal() {
-            let poly_trait_ref = principal.with_self_ty(tcx, impl_ty);
-            assert!(!poly_trait_ref.has_escaping_bound_vars());
-
-            // Walk all methods of the trait, including those of its supertraits
-            let entries = tcx.vtable_entries(poly_trait_ref);
-            let methods = entries
-                .iter()
-                .filter_map(|entry| match entry {
-                    VtblEntry::MetadataDropInPlace
-                    | VtblEntry::MetadataSize
-                    | VtblEntry::MetadataAlign
-                    | VtblEntry::Vacant => None,
-                    VtblEntry::TraitVPtr(_) => {
-                        // all super trait items already covered, so skip them.
-                        None
-                    }
-                    VtblEntry::Method(instance) => {
-                        Some(*instance).filter(|instance| should_codegen_locally(tcx, instance))
+    let ty::Dynamic(trait_ty, ..) = trait_ty.kind() else {
+        bug!("create_mono_items_for_vtable_methods: {trait_ty:?} not a trait type");
+    };
+    if let Some(principal) = trait_ty.principal() {
+        let poly_trait_ref = principal.with_self_ty(tcx, impl_ty);
+        assert!(!poly_trait_ref.has_escaping_bound_vars());
+
+        // Walk all methods of the trait, including those of its supertraits
+        let entries = tcx.vtable_entries(poly_trait_ref);
+        debug!(?entries);
+        let methods = entries
+            .iter()
+            .filter_map(|entry| match entry {
+                VtblEntry::MetadataDropInPlace
+                | VtblEntry::MetadataSize
+                | VtblEntry::MetadataAlign
+                | VtblEntry::Vacant => None,
+                VtblEntry::TraitVPtr(_) => {
+                    // all super trait items already covered, so skip them.
+                    None
+                }
+                VtblEntry::Method(instance) => {
+                    Some(*instance).filter(|instance| should_codegen_locally(tcx, instance))
+                }
+            })
+            .map(|item| create_fn_mono_item(tcx, item, source));
+        output.extend(methods);
+    }
+
+    // Also add the destructor.
+    visit_drop_use(tcx, impl_ty, false, source, output);
+}
+
+/// Scans the CTFE alloc in order to find function pointers and statics that must be monomorphized.
+fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoItems<'tcx>) {
+    match tcx.global_alloc(alloc_id) {
+        GlobalAlloc::Static(def_id) => {
+            assert!(!tcx.is_thread_local_static(def_id));
+            let instance = Instance::mono(tcx, def_id);
+            if should_codegen_locally(tcx, &instance) {
+                trace!("collecting static {:?}", def_id);
+                output.push(dummy_spanned(MonoItem::Static(def_id)));
+            }
+        }
+        GlobalAlloc::Memory(alloc) => {
+            trace!("collecting {:?} with {:#?}", alloc_id, alloc);
+            let ptrs = alloc.inner().provenance().ptrs();
+            // avoid `ensure_sufficient_stack` in the common case of "no pointers"
+            if !ptrs.is_empty() {
+                rustc_data_structures::stack::ensure_sufficient_stack(move || {
+                    for &prov in ptrs.values() {
+                        collect_alloc(tcx, prov.alloc_id(), output);
                     }
-                })
-                .map(|item| create_fn_mono_item(tcx, item, source));
-            output.extend(methods);
+                });
+            }
+        }
+        GlobalAlloc::Function(fn_instance) => {
+            if should_codegen_locally(tcx, &fn_instance) {
+                trace!("collecting {:?} with {:#?}", alloc_id, fn_instance);
+                output.push(create_fn_mono_item(tcx, fn_instance, DUMMY_SP));
+            }
+        }
+        GlobalAlloc::VTable(ty, trait_ref) => {
+            let alloc_id = tcx.vtable_allocation((ty, trait_ref));
+            collect_alloc(tcx, alloc_id, output)
+        }
+    }
+}
+
+fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) -> Option<DefId> {
+    for impl_def_id in tcx.inherent_impls(def_id).ok()? {
+        if let Some(new) = tcx.associated_items(impl_def_id).find_by_name_and_kind(
+            tcx,
+            fn_ident,
+            AssocKind::Fn,
+            def_id,
+        ) {
+            return Some(new.def_id);
+        }
+    }
+    return None;
+}
+
+fn build_skip_move_check_fns(tcx: TyCtxt<'_>) -> Vec<DefId> {
+    let fns = [
+        (tcx.lang_items().owned_box(), "new"),
+        (tcx.get_diagnostic_item(sym::Rc), "new"),
+        (tcx.get_diagnostic_item(sym::Arc), "new"),
+    ];
+    fns.into_iter()
+        .filter_map(|(def_id, fn_name)| {
+            def_id.and_then(|def_id| assoc_fn_of_type(tcx, def_id, Ident::from_str(fn_name)))
+        })
+        .collect::<Vec<_>>()
+}
+
+/// Scans the MIR in order to find function calls, closures, and drop-glue.
+///
+/// Anything that's found is added to `output`. Furthermore the "mentioned items" of the MIR are returned.
+#[instrument(skip(tcx, used_items, mentioned_items), level = "debug")]
+fn collect_items_of_instance<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    instance: Instance<'tcx>,
+    used_items: &mut MonoItems<'tcx>,
+    mentioned_items: &mut MonoItems<'tcx>,
+    mode: CollectionMode,
+) {
+    let body = tcx.instance_mir(instance.def);
+    // Naively, in "used" collection mode, all functions get added to *both* `used_items` and
+    // `mentioned_items`. Mentioned items processing will then notice that they have already been
+    // visited, but at that point each mentioned item has been monomorphized, added to the
+    // `mentioned_items` worklist, and checked in the global set of visited items. To remove that
+    // overhead, we have a special optimization that avoids adding items to `mentioned_items` when
+    // they are already added in `used_items`. We could just scan `used_items`, but that's a linear
+    // scan and not very efficient. Furthermore we can only do that *after* monomorphizing the
+    // mentioned item. So instead we collect all pre-monomorphized `MentionedItem` that were already
+    // added to `used_items` in a hash set, which can efficiently query in the
+    // `body.mentioned_items` loop below without even having to monomorphize the item.
+    let mut used_mentioned_items = FxHashSet::<MentionedItem<'tcx>>::default();
+    let mut collector = MirUsedCollector {
+        tcx,
+        body,
+        used_items,
+        used_mentioned_items: &mut used_mentioned_items,
+        instance,
+        move_size_spans: vec![],
+        visiting_call_terminator: false,
+        skip_move_check_fns: None,
+    };
+
+    if mode == CollectionMode::UsedItems {
+        // Visit everything. Here we rely on the visitor also visiting `required_consts`, so that we
+        // evaluate them and abort compilation if any of them errors.
+        collector.visit_body(body);
+    } else {
+        // We only need to evaluate all constants, but can ignore the rest of the MIR.
+        for const_op in &body.required_consts {
+            if let Some(val) = collector.eval_constant(const_op) {
+                collect_const_value(tcx, val, mentioned_items);
+            }
         }
+    }
 
-        // Also add the destructor.
-        visit_drop_use(tcx, impl_ty, false, source, output);
+    // Always gather mentioned items. We try to avoid processing items that we have already added to
+    // `used_items` above.
+    for item in &body.mentioned_items {
+        if !collector.used_mentioned_items.contains(&item.node) {
+            let item_mono = collector.monomorphize(item.node);
+            visit_mentioned_item(tcx, &item_mono, item.span, mentioned_items);
+        }
+    }
+}
+
+/// `item` must be already monomorphized.
+#[instrument(skip(tcx, span, output), level = "debug")]
+fn visit_mentioned_item<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    item: &MentionedItem<'tcx>,
+    span: Span,
+    output: &mut MonoItems<'tcx>,
+) {
+    match *item {
+        MentionedItem::Fn(ty) => {
+            if let ty::FnDef(def_id, args) = *ty.kind() {
+                let instance =
+                    Instance::expect_resolve(tcx, ty::ParamEnv::reveal_all(), def_id, args);
+                // `visit_instance_use` was written for "used" item collection but works just as well
+                // for "mentioned" item collection.
+                // We can set `is_direct_call`; that just means we'll skip a bunch of shims that anyway
+                // can't have their own failing constants.
+                visit_instance_use(tcx, instance, /*is_direct_call*/ true, span, output);
+            }
+        }
+        MentionedItem::Drop(ty) => {
+            visit_drop_use(tcx, ty, /*is_direct_call*/ true, span, output);
+        }
+        MentionedItem::UnsizeCast { source_ty, target_ty } => {
+            let (source_ty, target_ty) =
+                find_vtable_types_for_unsizing(tcx.at(span), source_ty, target_ty);
+            // This could also be a different Unsize instruction, like
+            // from a fixed sized array to a slice. But we are only
+            // interested in things that produce a vtable.
+            if (target_ty.is_trait() && !source_ty.is_trait())
+                || (target_ty.is_dyn_star() && !source_ty.is_dyn_star())
+            {
+                create_mono_items_for_vtable_methods(tcx, target_ty, source_ty, span, output);
+            }
+        }
+        MentionedItem::Closure(source_ty) => {
+            if let ty::Closure(def_id, args) = *source_ty.kind() {
+                let instance =
+                    Instance::resolve_closure(tcx, def_id, args, ty::ClosureKind::FnOnce);
+                if should_codegen_locally(tcx, &instance) {
+                    output.push(create_fn_mono_item(tcx, instance, span));
+                }
+            } else {
+                bug!()
+            }
+        }
+    }
+}
+
+#[instrument(skip(tcx, output), level = "debug")]
+fn collect_const_value<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    value: mir::ConstValue<'tcx>,
+    output: &mut MonoItems<'tcx>,
+) {
+    match value {
+        mir::ConstValue::Scalar(Scalar::Ptr(ptr, _size)) => {
+            collect_alloc(tcx, ptr.provenance.alloc_id(), output)
+        }
+        mir::ConstValue::Indirect { alloc_id, .. } => collect_alloc(tcx, alloc_id, output),
+        mir::ConstValue::Slice { data, meta: _ } => {
+            for &prov in data.inner().provenance().ptrs().values() {
+                collect_alloc(tcx, prov.alloc_id(), output);
+            }
+        }
+        _ => {}
     }
 }
 
@@ -1232,9 +1508,47 @@ fn create_mono_items_for_vtable_methods<'tcx>(
 // Root Collection
 //=-----------------------------------------------------------------------------
 
+// Find all non-generic items by walking the HIR. These items serve as roots to
+// start monomorphizing from.
+#[instrument(skip(tcx, mode), level = "debug")]
+fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionStrategy) -> Vec<MonoItem<'_>> {
+    debug!("collecting roots");
+    let mut roots = Vec::new();
+
+    {
+        let entry_fn = tcx.entry_fn(());
+
+        debug!("collect_roots: entry_fn = {:?}", entry_fn);
+
+        let mut collector = RootCollector { tcx, strategy: mode, entry_fn, output: &mut roots };
+
+        let crate_items = tcx.hir_crate_items(());
+
+        for id in crate_items.free_items() {
+            collector.process_item(id);
+        }
+
+        for id in crate_items.impl_items() {
+            collector.process_impl_item(id);
+        }
+
+        collector.push_extra_entry_roots();
+    }
+
+    // We can only codegen items that are instantiable - items all of
+    // whose predicates hold. Luckily, items that aren't instantiable
+    // can't actually be used, so we can just skip codegenning them.
+    roots
+        .into_iter()
+        .filter_map(|Spanned { node: mono_item, .. }| {
+            mono_item.is_instantiable(tcx).then_some(mono_item)
+        })
+        .collect()
+}
+
 struct RootCollector<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
-    mode: MonoItemCollectionMode,
+    strategy: MonoItemCollectionStrategy,
     output: &'a mut MonoItems<'tcx>,
     entry_fn: Option<(DefId, EntryFnType)>,
 }
@@ -1243,7 +1557,7 @@ impl<'v> RootCollector<'_, 'v> {
     fn process_item(&mut self, id: hir::ItemId) {
         match self.tcx.def_kind(id.owner_id) {
             DefKind::Enum | DefKind::Struct | DefKind::Union => {
-                if self.mode == MonoItemCollectionMode::Eager
+                if self.strategy == MonoItemCollectionStrategy::Eager
                     && self.tcx.generics_of(id.owner_id).count() == 0
                 {
                     debug!("RootCollector: ADT drop-glue for `{id:?}`",);
@@ -1274,7 +1588,7 @@ impl<'v> RootCollector<'_, 'v> {
                 }
             }
             DefKind::Impl { .. } => {
-                if self.mode == MonoItemCollectionMode::Eager {
+                if self.strategy == MonoItemCollectionStrategy::Eager {
                     create_mono_items_for_default_impls(self.tcx, id, self.output);
                 }
             }
@@ -1293,9 +1607,9 @@ impl<'v> RootCollector<'_, 'v> {
 
     fn is_root(&self, def_id: LocalDefId) -> bool {
         !self.tcx.generics_of(def_id).requires_monomorphization(self.tcx)
-            && match self.mode {
-                MonoItemCollectionMode::Eager => true,
-                MonoItemCollectionMode::Lazy => {
+            && match self.strategy {
+                MonoItemCollectionStrategy::Eager => true,
+                MonoItemCollectionStrategy::Lazy => {
                     self.entry_fn.and_then(|(id, _)| id.as_local()) == Some(def_id)
                         || self.tcx.is_reachable_non_generic(def_id)
                         || self
@@ -1428,108 +1742,47 @@ fn create_mono_items_for_default_impls<'tcx>(
     }
 }
 
-/// Scans the CTFE alloc in order to find function pointers and statics that must be monomorphized.
-fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoItems<'tcx>) {
-    match tcx.global_alloc(alloc_id) {
-        GlobalAlloc::Static(def_id) => {
-            assert!(!tcx.is_thread_local_static(def_id));
-            let instance = Instance::mono(tcx, def_id);
-            if should_codegen_locally(tcx, &instance) {
-                trace!("collecting static {:?}", def_id);
-                output.push(dummy_spanned(MonoItem::Static(def_id)));
-            }
-        }
-        GlobalAlloc::Memory(alloc) => {
-            trace!("collecting {:?} with {:#?}", alloc_id, alloc);
-            let ptrs = alloc.inner().provenance().ptrs();
-            // avoid `ensure_sufficient_stack` in the common case of "no pointers"
-            if !ptrs.is_empty() {
-                rustc_data_structures::stack::ensure_sufficient_stack(move || {
-                    for &prov in ptrs.values() {
-                        collect_alloc(tcx, prov.alloc_id(), output);
-                    }
-                });
-            }
-        }
-        GlobalAlloc::Function(fn_instance) => {
-            if should_codegen_locally(tcx, &fn_instance) {
-                trace!("collecting {:?} with {:#?}", alloc_id, fn_instance);
-                output.push(create_fn_mono_item(tcx, fn_instance, DUMMY_SP));
-            }
-        }
-        GlobalAlloc::VTable(ty, trait_ref) => {
-            let alloc_id = tcx.vtable_allocation((ty, trait_ref));
-            collect_alloc(tcx, alloc_id, output)
-        }
-    }
-}
+//=-----------------------------------------------------------------------------
+// Top-level entry point, tying it all together
+//=-----------------------------------------------------------------------------
 
-fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) -> Option<DefId> {
-    for impl_def_id in tcx.inherent_impls(def_id).ok()? {
-        if let Some(new) = tcx.associated_items(impl_def_id).find_by_name_and_kind(
-            tcx,
-            fn_ident,
-            AssocKind::Fn,
-            def_id,
-        ) {
-            return Some(new.def_id);
-        }
-    }
-    return None;
-}
+#[instrument(skip(tcx, strategy), level = "debug")]
+pub fn collect_crate_mono_items(
+    tcx: TyCtxt<'_>,
+    strategy: MonoItemCollectionStrategy,
+) -> (FxHashSet<MonoItem<'_>>, UsageMap<'_>) {
+    let _prof_timer = tcx.prof.generic_activity("monomorphization_collector");
 
-fn build_skip_move_check_fns(tcx: TyCtxt<'_>) -> Vec<DefId> {
-    let fns = [
-        (tcx.lang_items().owned_box(), "new"),
-        (tcx.get_diagnostic_item(sym::Rc), "new"),
-        (tcx.get_diagnostic_item(sym::Arc), "new"),
-    ];
-    fns.into_iter()
-        .filter_map(|(def_id, fn_name)| {
-            def_id.and_then(|def_id| assoc_fn_of_type(tcx, def_id, Ident::from_str(fn_name)))
-        })
-        .collect::<Vec<_>>()
-}
+    let roots = tcx
+        .sess
+        .time("monomorphization_collector_root_collections", || collect_roots(tcx, strategy));
 
-/// Scans the MIR in order to find function calls, closures, and drop-glue.
-#[instrument(skip(tcx, output), level = "debug")]
-fn collect_used_items<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    instance: Instance<'tcx>,
-    output: &mut MonoItems<'tcx>,
-) {
-    let body = tcx.instance_mir(instance.def);
+    debug!("building mono item graph, beginning at roots");
 
-    // Here we rely on the visitor also visiting `required_consts`, so that we evaluate them
-    // and abort compilation if any of them errors.
-    MirUsedCollector {
-        tcx,
-        body: body,
-        output,
-        instance,
-        move_size_spans: vec![],
-        visiting_call_terminator: false,
-        skip_move_check_fns: None,
-    }
-    .visit_body(body);
-}
+    let mut state = SharedState {
+        visited: MTLock::new(FxHashSet::default()),
+        mentioned: MTLock::new(FxHashSet::default()),
+        usage_map: MTLock::new(UsageMap::new()),
+    };
+    let recursion_limit = tcx.recursion_limit();
 
-#[instrument(skip(tcx, output), level = "debug")]
-fn collect_const_value<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    value: mir::ConstValue<'tcx>,
-    output: &mut MonoItems<'tcx>,
-) {
-    match value {
-        mir::ConstValue::Scalar(Scalar::Ptr(ptr, _size)) => {
-            collect_alloc(tcx, ptr.provenance.alloc_id(), output)
-        }
-        mir::ConstValue::Indirect { alloc_id, .. } => collect_alloc(tcx, alloc_id, output),
-        mir::ConstValue::Slice { data, meta: _ } => {
-            for &prov in data.inner().provenance().ptrs().values() {
-                collect_alloc(tcx, prov.alloc_id(), output);
-            }
-        }
-        _ => {}
+    {
+        let state: LRef<'_, _> = &mut state;
+
+        tcx.sess.time("monomorphization_collector_graph_walk", || {
+            par_for_each_in(roots, |root| {
+                let mut recursion_depths = DefIdMap::default();
+                collect_items_rec(
+                    tcx,
+                    dummy_spanned(root),
+                    state,
+                    &mut recursion_depths,
+                    recursion_limit,
+                    CollectionMode::UsedItems,
+                );
+            });
+        });
     }
+
+    (state.visited.into_inner(), state.usage_map.into_inner())
 }
diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs
index 7f36ae91f1a..4ec842e8f85 100644
--- a/compiler/rustc_monomorphize/src/lib.rs
+++ b/compiler/rustc_monomorphize/src/lib.rs
@@ -11,7 +11,10 @@ use rustc_hir::lang_items::LangItem;
 use rustc_middle::query::{Providers, TyCtxtAt};
 use rustc_middle::traits;
 use rustc_middle::ty::adjustment::CustomCoerceUnsized;
+use rustc_middle::ty::Instance;
+use rustc_middle::ty::TyCtxt;
 use rustc_middle::ty::{self, Ty};
+use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::ErrorGuaranteed;
 
 mod collector;
@@ -20,6 +23,8 @@ mod partitioning;
 mod polymorphize;
 mod util;
 
+use collector::should_codegen_locally;
+
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 
 fn custom_coerce_unsize_info<'tcx>(
@@ -45,6 +50,23 @@ fn custom_coerce_unsize_info<'tcx>(
     }
 }
 
+/// Returns whether a call from the current crate to the [`Instance`] would produce a call
+/// from `compiler_builtins` to a symbol the linker must resolve.
+///
+/// Such calls from `compiler_bultins` are effectively impossible for the linker to handle. Some
+/// linkers will optimize such that dead calls to unresolved symbols are not an error, but this is
+/// not guaranteed. So we used this function in codegen backends to ensure we do not generate any
+/// unlinkable calls.
+pub fn is_call_from_compiler_builtins_to_upstream_monomorphization<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    instance: Instance<'tcx>,
+) -> bool {
+    !instance.def_id().is_local()
+        && tcx.is_compiler_builtins(LOCAL_CRATE)
+        && tcx.codegen_fn_attrs(instance.def_id()).link_name.is_none()
+        && !should_codegen_locally(tcx, &instance)
+}
+
 pub fn provide(providers: &mut Providers) {
     partitioning::provide(providers);
     polymorphize::provide(providers);
diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs
index 15041b9cd41..5a92657cb40 100644
--- a/compiler/rustc_monomorphize/src/partitioning.rs
+++ b/compiler/rustc_monomorphize/src/partitioning.rs
@@ -117,7 +117,7 @@ use rustc_session::CodegenUnits;
 use rustc_span::symbol::Symbol;
 
 use crate::collector::UsageMap;
-use crate::collector::{self, MonoItemCollectionMode};
+use crate::collector::{self, MonoItemCollectionStrategy};
 use crate::errors::{CouldntDumpMonoStats, SymbolAlreadyDefined, UnknownCguCollectionMode};
 
 struct PartitioningCx<'a, 'tcx> {
@@ -1087,30 +1087,30 @@ where
 }
 
 fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> (&DefIdSet, &[CodegenUnit<'_>]) {
-    let collection_mode = match tcx.sess.opts.unstable_opts.print_mono_items {
+    let collection_strategy = match tcx.sess.opts.unstable_opts.print_mono_items {
         Some(ref s) => {
             let mode = s.to_lowercase();
             let mode = mode.trim();
             if mode == "eager" {
-                MonoItemCollectionMode::Eager
+                MonoItemCollectionStrategy::Eager
             } else {
                 if mode != "lazy" {
                     tcx.dcx().emit_warn(UnknownCguCollectionMode { mode });
                 }
 
-                MonoItemCollectionMode::Lazy
+                MonoItemCollectionStrategy::Lazy
             }
         }
         None => {
             if tcx.sess.link_dead_code() {
-                MonoItemCollectionMode::Eager
+                MonoItemCollectionStrategy::Eager
             } else {
-                MonoItemCollectionMode::Lazy
+                MonoItemCollectionStrategy::Lazy
             }
         }
     };
 
-    let (items, usage_map) = collector::collect_crate_mono_items(tcx, collection_mode);
+    let (items, usage_map) = collector::collect_crate_mono_items(tcx, collection_strategy);
 
     // If there was an error during collection (e.g. from one of the constants we evaluated),
     // then we stop here. This way codegen does not have to worry about failing constants.
diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
index 95b30066662..16d8453ea24 100644
--- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs
+++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
@@ -239,7 +239,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
             // FIXME: We should investigate the perf implications of not uniquifying
             // `ReErased`. We may be able to short-circuit registering region
             // obligations if we encounter a `ReErased` on one side, for example.
-            ty::ReStatic | ty::ReErased => match self.canonicalize_mode {
+            ty::ReStatic | ty::ReErased | ty::ReError(_) => match self.canonicalize_mode {
                 CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
                 CanonicalizeMode::Response { .. } => return r,
             },
@@ -277,7 +277,6 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
                     }
                 }
             }
-            ty::ReError(_) => return r,
         };
 
         let existing_bound_var = match self.canonicalize_mode {
@@ -351,7 +350,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
             | ty::Str
             | ty::Array(_, _)
             | ty::Slice(_)
-            | ty::RawPtr(_)
+            | ty::RawPtr(_, _)
             | ty::Ref(_, _, _)
             | ty::FnDef(_, _)
             | ty::FnPtr(_)
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index a100e2d47bb..aa735f3de1f 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -390,8 +390,6 @@ parse_invalid_dyn_keyword = invalid `dyn` keyword
 parse_invalid_expression_in_let_else = a `{$operator}` expression cannot be directly assigned in `let...else`
 parse_invalid_identifier_with_leading_number = identifiers cannot start with a number
 
-parse_invalid_interpolated_expression = invalid interpolated expression
-
 parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are invalid
     .label = invalid suffix `{$suffix}`
     .tuple_exception_line_1 = `{$suffix}` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases
@@ -570,7 +568,7 @@ parse_more_than_one_char = character literal may only contain one codepoint
     .remove_non = consider removing the non-printing characters
     .use_double_quotes = if you meant to write a {$is_byte ->
         [true] byte string
-        *[false] `str`
+        *[false] string
         } literal, use double quotes
 
 parse_multiple_skipped_lines = multiple lines skipped by escaped newline
@@ -835,6 +833,7 @@ parse_unknown_prefix = prefix `{$prefix}` is unknown
     .label = unknown prefix
     .note =  prefixed identifiers and literals are reserved since Rust 2021
     .suggestion_br = use `br` for a raw byte string
+    .suggestion_str = if you meant to write a string literal, use double quotes
     .suggestion_whitespace = consider inserting whitespace here
 
 parse_unknown_start_of_token = unknown start of token: {$escaped}
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 32b56bb7e87..20ebfc6691b 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -851,13 +851,6 @@ pub(crate) struct StructLiteralNotAllowedHereSugg {
 }
 
 #[derive(Diagnostic)]
-#[diag(parse_invalid_interpolated_expression)]
-pub(crate) struct InvalidInterpolatedExpression {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(parse_invalid_literal_suffix_on_tuple_index)]
 pub(crate) struct InvalidLiteralSuffixOnTupleIndex {
     #[primary_span]
@@ -1994,6 +1987,17 @@ pub enum UnknownPrefixSugg {
         style = "verbose"
     )]
     Whitespace(#[primary_span] Span),
+    #[multipart_suggestion(
+        parse_suggestion_str,
+        applicability = "maybe-incorrect",
+        style = "verbose"
+    )]
+    MeantStr {
+        #[suggestion_part(code = "\"")]
+        start: Span,
+        #[suggestion_part(code = "\"")]
+        end: Span,
+    },
 }
 
 #[derive(Diagnostic)]
@@ -2205,12 +2209,21 @@ pub enum MoreThanOneCharSugg {
         ch: String,
     },
     #[suggestion(parse_use_double_quotes, code = "{sugg}", applicability = "machine-applicable")]
-    Quotes {
+    QuotesFull {
         #[primary_span]
         span: Span,
         is_byte: bool,
         sugg: String,
     },
+    #[multipart_suggestion(parse_use_double_quotes, applicability = "machine-applicable")]
+    Quotes {
+        #[suggestion_part(code = "{prefix}\"")]
+        start: Span,
+        #[suggestion_part(code = "\"")]
+        end: Span,
+        is_byte: bool,
+        prefix: &'static str,
+    },
 }
 
 #[derive(Subdiagnostic)]
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index f57945a52df..63b2b47630b 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -63,6 +63,7 @@ pub(crate) fn parse_token_trees<'psess, 'src>(
         cursor,
         override_span,
         nbsp_is_whitespace: false,
+        last_lifetime: None,
     };
     let (stream, res, unmatched_delims) =
         tokentrees::TokenTreesReader::parse_all_token_trees(string_reader);
@@ -105,6 +106,10 @@ struct StringReader<'psess, 'src> {
     /// in this file, it's safe to treat further occurrences of the non-breaking
     /// space character as whitespace.
     nbsp_is_whitespace: bool,
+
+    /// Track the `Span` for the leading `'` of the last lifetime. Used for
+    /// diagnostics to detect possible typo where `"` was meant.
+    last_lifetime: Option<Span>,
 }
 
 impl<'psess, 'src> StringReader<'psess, 'src> {
@@ -130,6 +135,18 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
 
             debug!("next_token: {:?}({:?})", token.kind, self.str_from(start));
 
+            if let rustc_lexer::TokenKind::Semi
+            | rustc_lexer::TokenKind::LineComment { .. }
+            | rustc_lexer::TokenKind::BlockComment { .. }
+            | rustc_lexer::TokenKind::CloseParen
+            | rustc_lexer::TokenKind::CloseBrace
+            | rustc_lexer::TokenKind::CloseBracket = token.kind
+            {
+                // Heuristic: we assume that it is unlikely we're dealing with an unterminated
+                // string surrounded by single quotes.
+                self.last_lifetime = None;
+            }
+
             // Now "cook" the token, converting the simple `rustc_lexer::TokenKind` enum into a
             // rich `rustc_ast::TokenKind`. This turns strings into interned symbols and runs
             // additional validation.
@@ -247,6 +264,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
                     // expansion purposes. See #12512 for the gory details of why
                     // this is necessary.
                     let lifetime_name = self.str_from(start);
+                    self.last_lifetime = Some(self.mk_sp(start, start + BytePos(1)));
                     if starts_with_number {
                         let span = self.mk_sp(start, self.pos);
                         self.dcx().struct_err("lifetimes cannot start with a number")
@@ -395,10 +413,21 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
         match kind {
             rustc_lexer::LiteralKind::Char { terminated } => {
                 if !terminated {
-                    self.dcx()
+                    let mut err = self
+                        .dcx()
                         .struct_span_fatal(self.mk_sp(start, end), "unterminated character literal")
-                        .with_code(E0762)
-                        .emit()
+                        .with_code(E0762);
+                    if let Some(lt_sp) = self.last_lifetime {
+                        err.multipart_suggestion(
+                            "if you meant to write a string literal, use double quotes",
+                            vec![
+                                (lt_sp, "\"".to_string()),
+                                (self.mk_sp(start, start + BytePos(1)), "\"".to_string()),
+                            ],
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                    err.emit()
                 }
                 self.cook_unicode(token::Char, Mode::Char, start, end, 1, 1) // ' '
             }
@@ -669,15 +698,33 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
         let expn_data = prefix_span.ctxt().outer_expn_data();
 
         if expn_data.edition >= Edition::Edition2021 {
+            let mut silence = false;
             // In Rust 2021, this is a hard error.
             let sugg = if prefix == "rb" {
                 Some(errors::UnknownPrefixSugg::UseBr(prefix_span))
             } else if expn_data.is_root() {
-                Some(errors::UnknownPrefixSugg::Whitespace(prefix_span.shrink_to_hi()))
+                if self.cursor.first() == '\''
+                    && let Some(start) = self.last_lifetime
+                    && self.cursor.third() != '\''
+                {
+                    // An "unclosed `char`" error will be emitted already, silence redundant error.
+                    silence = true;
+                    Some(errors::UnknownPrefixSugg::MeantStr {
+                        start,
+                        end: self.mk_sp(self.pos, self.pos + BytePos(1)),
+                    })
+                } else {
+                    Some(errors::UnknownPrefixSugg::Whitespace(prefix_span.shrink_to_hi()))
+                }
             } else {
                 None
             };
-            self.dcx().emit_err(errors::UnknownPrefix { span: prefix_span, prefix, sugg });
+            let err = errors::UnknownPrefix { span: prefix_span, prefix, sugg };
+            if silence {
+                self.dcx().create_err(err).delay_as_bug();
+            } else {
+                self.dcx().emit_err(err);
+            }
         } else {
             // Before Rust 2021, only emit a lint for migration.
             self.psess.buffer_lint_with_diagnostic(
diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
index 3ebad6a9fd7..fa242a32a18 100644
--- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
+++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
@@ -95,11 +95,21 @@ pub(crate) fn emit_unescape_error(
                     }
                     escaped.push(c);
                 }
-                let sugg = format!("{prefix}\"{escaped}\"");
-                MoreThanOneCharSugg::Quotes {
-                    span: full_lit_span,
-                    is_byte: mode == Mode::Byte,
-                    sugg,
+                if escaped.len() != lit.len() || full_lit_span.is_empty() {
+                    let sugg = format!("{prefix}\"{escaped}\"");
+                    MoreThanOneCharSugg::QuotesFull {
+                        span: full_lit_span,
+                        is_byte: mode == Mode::Byte,
+                        sugg,
+                    }
+                } else {
+                    MoreThanOneCharSugg::Quotes {
+                        start: full_lit_span
+                            .with_hi(full_lit_span.lo() + BytePos((prefix.len() + 1) as u32)),
+                        end: full_lit_span.with_lo(full_lit_span.hi() - BytePos(1)),
+                        is_byte: mode == Mode::Byte,
+                        prefix,
+                    }
                 }
             });
             dcx.emit_err(UnescapeError::MoreThanOneChar {
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index d08c50b5b06..ab5f51eedc3 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -3,11 +3,12 @@ use crate::errors::{
     SuffixedLiteralInAttribute,
 };
 use crate::fluent_generated as fluent;
+use crate::maybe_whole;
 
 use super::{AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, PathStyle};
 use rustc_ast as ast;
 use rustc_ast::attr;
-use rustc_ast::token::{self, Delimiter, Nonterminal};
+use rustc_ast::token::{self, Delimiter};
 use rustc_errors::{codes::*, Diag, PResult};
 use rustc_span::{sym, BytePos, Span};
 use thin_vec::ThinVec;
@@ -251,25 +252,15 @@ impl<'a> Parser<'a> {
     ///     PATH `=` UNSUFFIXED_LIT
     /// The delimiters or `=` are still put into the resulting token stream.
     pub fn parse_attr_item(&mut self, capture_tokens: bool) -> PResult<'a, ast::AttrItem> {
-        let item = match &self.token.kind {
-            token::Interpolated(nt) => match &nt.0 {
-                Nonterminal::NtMeta(item) => Some(item.clone().into_inner()),
-                _ => None,
-            },
-            _ => None,
+        maybe_whole!(self, NtMeta, |attr| attr.into_inner());
+
+        let do_parse = |this: &mut Self| {
+            let path = this.parse_path(PathStyle::Mod)?;
+            let args = this.parse_attr_args()?;
+            Ok(ast::AttrItem { path, args, tokens: None })
         };
-        Ok(if let Some(item) = item {
-            self.bump();
-            item
-        } else {
-            let do_parse = |this: &mut Self| {
-                let path = this.parse_path(PathStyle::Mod)?;
-                let args = this.parse_attr_args()?;
-                Ok(ast::AttrItem { path, args, tokens: None })
-            };
-            // Attr items don't have attributes
-            if capture_tokens { self.collect_tokens_no_attrs(do_parse) } else { do_parse(self) }?
-        })
+        // Attr items don't have attributes
+        if capture_tokens { self.collect_tokens_no_attrs(do_parse) } else { do_parse(self) }
     }
 
     /// Parses attributes that appear after the opening of an item. These should
@@ -371,22 +362,18 @@ impl<'a> Parser<'a> {
     /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ;
     /// ```
     pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
-        let nt_meta = match &self.token.kind {
-            token::Interpolated(nt) => match &nt.0 {
-                token::NtMeta(e) => Some(e.clone()),
-                _ => None,
-            },
-            _ => None,
-        };
-
-        if let Some(item) = nt_meta {
-            match item.meta(item.path.span) {
+        // We can't use `maybe_whole` here because it would bump in the `None`
+        // case, which we don't want.
+        if let token::Interpolated(nt) = &self.token.kind
+            && let token::NtMeta(attr_item) = &nt.0
+        {
+            match attr_item.meta(attr_item.path.span) {
                 Some(meta) => {
                     self.bump();
                     return Ok(meta);
                 }
                 None => self.unexpected()?,
-            };
+            }
         }
 
         let lo = self.token.span;
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 136145dd182..fe17eba0d7b 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -11,7 +11,7 @@ use crate::errors;
 use crate::maybe_recover_from_interpolated_ty_qpath;
 use ast::mut_visit::{noop_visit_expr, MutVisitor};
 use ast::token::IdentIsRaw;
-use ast::{CoroutineKind, ForLoopKind, GenBlockKind, Pat, Path, PathSegment};
+use ast::{CoroutineKind, ForLoopKind, GenBlockKind, MatchKind, Pat, Path, PathSegment};
 use core::mem;
 use core::ops::ControlFlow;
 use rustc_ast::ptr::P;
@@ -1379,6 +1379,13 @@ impl<'a> Parser<'a> {
             return Ok(self.mk_await_expr(self_arg, lo));
         }
 
+        // Post-fix match
+        if self.eat_keyword(kw::Match) {
+            let match_span = self.prev_token.span;
+            self.psess.gated_spans.gate(sym::postfix_match, match_span);
+            return self.parse_match_block(lo, match_span, self_arg, MatchKind::Postfix);
+        }
+
         let fn_span_lo = self.token.span;
         let mut seg = self.parse_path_segment(PathStyle::Expr, None)?;
         self.check_trailing_angle_brackets(&seg, &[&token::OpenDelim(Delimiter::Parenthesis)]);
@@ -1939,11 +1946,11 @@ impl<'a> Parser<'a> {
     /// Parse `builtin # ident(args,*)`.
     fn parse_expr_builtin(&mut self) -> PResult<'a, P<Expr>> {
         self.parse_builtin(|this, lo, ident| {
-            if ident.name == sym::offset_of {
-                return Ok(Some(this.parse_expr_offset_of(lo)?));
-            }
-
-            Ok(None)
+            Ok(match ident.name {
+                sym::offset_of => Some(this.parse_expr_offset_of(lo)?),
+                sym::type_ascribe => Some(this.parse_expr_type_ascribe(lo)?),
+                _ => None,
+            })
         })
     }
 
@@ -1978,6 +1985,7 @@ impl<'a> Parser<'a> {
         ret
     }
 
+    /// Built-in macro for `offset_of!` expressions.
     pub(crate) fn parse_expr_offset_of(&mut self, lo: Span) -> PResult<'a, P<Expr>> {
         let container = self.parse_ty()?;
         self.expect(&TokenKind::Comma)?;
@@ -2007,6 +2015,15 @@ impl<'a> Parser<'a> {
         Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields)))
     }
 
+    /// Built-in macro for type ascription expressions.
+    pub(crate) fn parse_expr_type_ascribe(&mut self, lo: Span) -> PResult<'a, P<Expr>> {
+        let expr = self.parse_expr()?;
+        self.expect(&token::Comma)?;
+        let ty = self.parse_ty()?;
+        let span = lo.to(self.token.span);
+        Ok(self.mk_expr(span, ExprKind::Type(expr, ty)))
+    }
+
     /// Returns a string literal if the next token is a string literal.
     /// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind,
     /// and returns `None` if the next token is not literal at all.
@@ -2043,16 +2060,6 @@ impl<'a> Parser<'a> {
         &mut self,
         mk_lit_char: impl FnOnce(Symbol, Span) -> L,
     ) -> PResult<'a, L> {
-        if let token::Interpolated(nt) = &self.token.kind
-            && let token::NtExpr(e) | token::NtLiteral(e) = &nt.0
-            && matches!(e.kind, ExprKind::Err(_))
-        {
-            let mut err = self
-                .dcx()
-                .create_err(errors::InvalidInterpolatedExpression { span: self.token.span });
-            err.downgrade_to_delayed_bug();
-            return Err(err);
-        }
         let token = self.token.clone();
         let err = |self_: &Self| {
             let msg = format!("unexpected token: {}", super::token_descr(&token));
@@ -2894,8 +2901,20 @@ impl<'a> Parser<'a> {
     /// Parses a `match ... { ... }` expression (`match` token already eaten).
     fn parse_expr_match(&mut self) -> PResult<'a, P<Expr>> {
         let match_span = self.prev_token.span;
-        let lo = self.prev_token.span;
         let scrutinee = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
+
+        self.parse_match_block(match_span, match_span, scrutinee, MatchKind::Prefix)
+    }
+
+    /// Parses the block of a `match expr { ... }` or a `expr.match { ... }`
+    /// expression. This is after the match token and scrutinee are eaten
+    fn parse_match_block(
+        &mut self,
+        lo: Span,
+        match_span: Span,
+        scrutinee: P<Expr>,
+        match_kind: MatchKind,
+    ) -> PResult<'a, P<Expr>> {
         if let Err(mut e) = self.expect(&token::OpenDelim(Delimiter::Brace)) {
             if self.token == token::Semi {
                 e.span_suggestion_short(
@@ -2938,7 +2957,7 @@ impl<'a> Parser<'a> {
                     });
                     return Ok(self.mk_expr_with_attrs(
                         span,
-                        ExprKind::Match(scrutinee, arms),
+                        ExprKind::Match(scrutinee, arms, match_kind),
                         attrs,
                     ));
                 }
@@ -2946,7 +2965,7 @@ impl<'a> Parser<'a> {
         }
         let hi = self.token.span;
         self.bump();
-        Ok(self.mk_expr_with_attrs(lo.to(hi), ExprKind::Match(scrutinee, arms), attrs))
+        Ok(self.mk_expr_with_attrs(lo.to(hi), ExprKind::Match(scrutinee, arms, match_kind), attrs))
     }
 
     /// Attempt to recover from match arm body with statements and no surrounding braces.
@@ -3955,7 +3974,7 @@ impl MutVisitor for CondChecker<'_> {
             | ExprKind::While(_, _, _)
             | ExprKind::ForLoop { .. }
             | ExprKind::Loop(_, _, _)
-            | ExprKind::Match(_, _)
+            | ExprKind::Match(_, _, _)
             | ExprKind::Closure(_)
             | ExprKind::Block(_, _)
             | ExprKind::Gen(_, _, _)
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 18d210eacfa..d54eb8dc4c9 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -6,6 +6,7 @@ use super::{
 };
 use crate::errors::{self, MacroExpandsToAdtField};
 use crate::fluent_generated as fluent;
+use crate::maybe_whole;
 use ast::token::IdentIsRaw;
 use rustc_ast::ast::*;
 use rustc_ast::ptr::P;
@@ -115,17 +116,10 @@ impl<'a> Parser<'a> {
         fn_parse_mode: FnParseMode,
         force_collect: ForceCollect,
     ) -> PResult<'a, Option<Item>> {
-        // Don't use `maybe_whole` so that we have precise control
-        // over when we bump the parser
-        if let token::Interpolated(nt) = &self.token.kind
-            && let token::NtItem(item) = &nt.0
-        {
-            let mut item = item.clone();
-            self.bump();
-
+        maybe_whole!(self, NtItem, |item| {
             attrs.prepend_to_nt_inner(&mut item.attrs);
-            return Ok(Some(item.into_inner()));
-        };
+            Some(item.into_inner())
+        });
 
         let item =
             self.collect_tokens_trailing_token(attrs, force_collect, |this: &mut Self, attrs| {
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 125e77d8ee7..de83528b52c 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -20,7 +20,7 @@ pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma};
 pub use path::PathStyle;
 
 use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Delimiter, Nonterminal, Token, TokenKind};
+use rustc_ast::token::{self, Delimiter, Token, TokenKind};
 use rustc_ast::tokenstream::{AttributesData, DelimSpacing, DelimSpan, Spacing};
 use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor};
 use rustc_ast::util::case::Case;
@@ -93,12 +93,13 @@ pub enum TrailingToken {
 #[macro_export]
 macro_rules! maybe_whole {
     ($p:expr, $constructor:ident, |$x:ident| $e:expr) => {
-        if let token::Interpolated(nt) = &$p.token.kind {
-            if let token::$constructor(x) = &nt.0 {
-                let $x = x.clone();
-                $p.bump();
-                return Ok($e);
-            }
+        if let token::Interpolated(nt) = &$p.token.kind
+            && let token::$constructor(x) = &nt.0
+        {
+            #[allow(unused_mut)]
+            let mut $x = x.clone();
+            $p.bump();
+            return Ok($e);
         }
     };
 }
@@ -449,6 +450,7 @@ impl<'a> Parser<'a> {
         parser
     }
 
+    #[inline]
     pub fn recovery(mut self, recovery: Recovery) -> Self {
         self.recovery = recovery;
         self
@@ -461,6 +463,7 @@ impl<'a> Parser<'a> {
     ///
     /// Technically, this only needs to restrict eager recovery by doing lookahead at more tokens.
     /// But making the distinction is very subtle, and simply forbidding all recovery is a lot simpler to uphold.
+    #[inline]
     fn may_recover(&self) -> bool {
         matches!(self.recovery, Recovery::Allowed)
     }
@@ -548,6 +551,7 @@ impl<'a> Parser<'a> {
     ///
     /// This method will automatically add `tok` to `expected_tokens` if `tok` is not
     /// encountered.
+    #[inline]
     fn check(&mut self, tok: &TokenKind) -> bool {
         let is_present = self.token == *tok;
         if !is_present {
@@ -556,6 +560,7 @@ impl<'a> Parser<'a> {
         is_present
     }
 
+    #[inline]
     fn check_noexpect(&self, tok: &TokenKind) -> bool {
         self.token == *tok
     }
@@ -564,6 +569,7 @@ impl<'a> Parser<'a> {
     ///
     /// the main purpose of this function is to reduce the cluttering of the suggestions list
     /// which using the normal eat method could introduce in some cases.
+    #[inline]
     pub fn eat_noexpect(&mut self, tok: &TokenKind) -> bool {
         let is_present = self.check_noexpect(tok);
         if is_present {
@@ -573,6 +579,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Consumes a token 'tok' if it exists. Returns whether the given token was present.
+    #[inline]
     pub fn eat(&mut self, tok: &TokenKind) -> bool {
         let is_present = self.check(tok);
         if is_present {
@@ -583,11 +590,13 @@ impl<'a> Parser<'a> {
 
     /// If the next token is the given keyword, returns `true` without eating it.
     /// An expectation is also added for diagnostics purposes.
+    #[inline]
     fn check_keyword(&mut self, kw: Symbol) -> bool {
         self.expected_tokens.push(TokenType::Keyword(kw));
         self.token.is_keyword(kw)
     }
 
+    #[inline]
     fn check_keyword_case(&mut self, kw: Symbol, case: Case) -> bool {
         if self.check_keyword(kw) {
             return true;
@@ -606,6 +615,7 @@ impl<'a> Parser<'a> {
     /// If the next token is the given keyword, eats it and returns `true`.
     /// Otherwise, returns `false`. An expectation is also added for diagnostics purposes.
     // Public for rustfmt usage.
+    #[inline]
     pub fn eat_keyword(&mut self, kw: Symbol) -> bool {
         if self.check_keyword(kw) {
             self.bump();
@@ -618,6 +628,7 @@ impl<'a> Parser<'a> {
     /// Eats a keyword, optionally ignoring the case.
     /// If the case differs (and is ignored) an error is issued.
     /// This is useful for recovery.
+    #[inline]
     fn eat_keyword_case(&mut self, kw: Symbol, case: Case) -> bool {
         if self.eat_keyword(kw) {
             return true;
@@ -635,6 +646,7 @@ impl<'a> Parser<'a> {
         false
     }
 
+    #[inline]
     fn eat_keyword_noexpect(&mut self, kw: Symbol) -> bool {
         if self.token.is_keyword(kw) {
             self.bump();
@@ -656,6 +668,7 @@ impl<'a> Parser<'a> {
         self.token.is_keyword(kw) && self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident())
     }
 
+    #[inline]
     fn check_or_expected(&mut self, ok: bool, typ: TokenType) -> bool {
         if ok {
             true
@@ -703,6 +716,7 @@ impl<'a> Parser<'a> {
 
     /// Checks to see if the next token is either `+` or `+=`.
     /// Otherwise returns `false`.
+    #[inline]
     fn check_plus(&mut self) -> bool {
         self.check_or_expected(
             self.token.is_like_plus(),
@@ -1394,7 +1408,7 @@ impl<'a> Parser<'a> {
     /// so emit a proper diagnostic.
     // Public for rustfmt usage.
     pub fn parse_visibility(&mut self, fbt: FollowedByType) -> PResult<'a, Visibility> {
-        maybe_whole!(self, NtVis, |x| x.into_inner());
+        maybe_whole!(self, NtVis, |vis| vis.into_inner());
 
         if !self.eat_keyword(kw::Pub) {
             // We need a span for our `Spanned<VisibilityKind>`, but there's inherently no
@@ -1571,8 +1585,21 @@ pub enum FlatToken {
     Empty,
 }
 
-#[derive(Debug)]
-pub enum ParseNtResult {
-    Nt(Nonterminal),
+// Metavar captures of various kinds.
+#[derive(Clone, Debug)]
+pub enum ParseNtResult<NtType> {
     Tt(TokenTree),
+    Nt(NtType),
+}
+
+impl<T> ParseNtResult<T> {
+    pub fn map_nt<F, U>(self, mut f: F) -> ParseNtResult<U>
+    where
+        F: FnMut(T) -> U,
+    {
+        match self {
+            ParseNtResult::Tt(tt) => ParseNtResult::Tt(tt),
+            ParseNtResult::Nt(nt) => ParseNtResult::Nt(f(nt)),
+        }
+    }
 }
diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs
index f1572a18a8b..36a00df7b44 100644
--- a/compiler/rustc_parse/src/parser/nonterminal.rs
+++ b/compiler/rustc_parse/src/parser/nonterminal.rs
@@ -1,5 +1,5 @@
 use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Delimiter, Nonterminal::*, NonterminalKind, Token};
+use rustc_ast::token::{self, Delimiter, Nonterminal, Nonterminal::*, NonterminalKind, Token};
 use rustc_ast::HasTokens;
 use rustc_ast_pretty::pprust;
 use rustc_errors::PResult;
@@ -66,15 +66,14 @@ impl<'a> Parser<'a> {
                 token::Interpolated(nt) => may_be_ident(&nt.0),
                 _ => false,
             },
-            NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr => {
-                match &token.kind {
+            NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr => match &token.kind {
                 token::Ident(..) |                          // box, ref, mut, and other identifiers (can stricten)
                 token::OpenDelim(Delimiter::Parenthesis) |  // tuple pattern
                 token::OpenDelim(Delimiter::Bracket) |      // slice pattern
                 token::BinOp(token::And) |                  // reference
                 token::BinOp(token::Minus) |                // negative literal
                 token::AndAnd |                             // double reference
-                token::Literal(_) |                        // literal
+                token::Literal(_) |                         // literal
                 token::DotDot |                             // range pattern (future compat)
                 token::DotDotDot |                          // range pattern (future compat)
                 token::ModSep |                             // path
@@ -84,8 +83,7 @@ impl<'a> Parser<'a> {
                 token::BinOp(token::Or) => matches!(kind, NonterminalKind::PatWithOr),
                 token::Interpolated(nt) => may_be_ident(&nt.0),
                 _ => false,
-            }
-            }
+            },
             NonterminalKind::Lifetime => match &token.kind {
                 token::Lifetime(_) => true,
                 token::Interpolated(nt) => {
@@ -102,7 +100,10 @@ impl<'a> Parser<'a> {
     /// Parse a non-terminal (e.g. MBE `:pat` or `:ident`). Inlined because there is only one call
     /// site.
     #[inline]
-    pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, ParseNtResult> {
+    pub fn parse_nonterminal(
+        &mut self,
+        kind: NonterminalKind,
+    ) -> PResult<'a, ParseNtResult<Nonterminal>> {
         // A `macro_rules!` invocation may pass a captured item/expr to a proc-macro,
         // which requires having captured tokens available. Since we cannot determine
         // in advance whether or not a proc-macro will be (transitively) invoked,
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 88ae1b5420f..fbc28859535 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -435,7 +435,7 @@ impl<'a> Parser<'a> {
         syntax_loc: Option<PatternLocation>,
     ) -> PResult<'a, P<Pat>> {
         maybe_recover_from_interpolated_ty_qpath!(self, true);
-        maybe_whole!(self, NtPat, |x| x);
+        maybe_whole!(self, NtPat, |pat| pat);
 
         let mut lo = self.token.span;
 
@@ -498,11 +498,14 @@ impl<'a> Parser<'a> {
             } else {
                 PatKind::Lit(const_expr)
             }
+        } else if self.is_builtin() {
+            self.parse_pat_builtin()?
+        }
         // Don't eagerly error on semantically invalid tokens when matching
         // declarative macros, as the input to those doesn't have to be
         // semantically valid. For attribute/derive proc macros this is not the
         // case, so doing the recovery for them is fine.
-        } else if self.can_be_ident_pat()
+        else if self.can_be_ident_pat()
             || (self.is_lit_bad_ident().is_some() && self.may_recover())
         {
             // Parse `ident @ pat`
@@ -1119,6 +1122,21 @@ impl<'a> Parser<'a> {
         .contains(&self.token.kind)
     }
 
+    fn parse_pat_builtin(&mut self) -> PResult<'a, PatKind> {
+        self.parse_builtin(|self_, _lo, ident| {
+            Ok(match ident.name {
+                // builtin#deref(PAT)
+                sym::deref => Some(ast::PatKind::Deref(self_.parse_pat_allow_top_alt(
+                    None,
+                    RecoverComma::Yes,
+                    RecoverColon::Yes,
+                    CommaRecoveryMode::LikelyTuple,
+                )?)),
+                _ => None,
+            })
+        })
+    }
+
     /// Parses `box pat`
     fn parse_pat_box(&mut self) -> PResult<'a, PatKind> {
         let box_span = self.prev_token.span;
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index fc907760531..6601011665b 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -40,8 +40,8 @@ impl<'a> Parser<'a> {
         }))
     }
 
-    /// If `force_collect` is [`ForceCollect::Yes`], forces collection of tokens regardless of whether
-    /// or not we have attributes
+    /// If `force_collect` is [`ForceCollect::Yes`], forces collection of tokens regardless of
+    /// whether or not we have attributes.
     // Public for `cfg_eval` macro expansion.
     pub fn parse_stmt_without_recovery(
         &mut self,
@@ -51,18 +51,12 @@ impl<'a> Parser<'a> {
         let attrs = self.parse_outer_attributes()?;
         let lo = self.token.span;
 
-        // Don't use `maybe_whole` so that we have precise control
-        // over when we bump the parser
-        if let token::Interpolated(nt) = &self.token.kind
-            && let token::NtStmt(stmt) = &nt.0
-        {
-            let mut stmt = stmt.clone();
-            self.bump();
+        maybe_whole!(self, NtStmt, |stmt| {
             stmt.visit_attrs(|stmt_attrs| {
                 attrs.prepend_to_nt_inner(stmt_attrs);
             });
-            return Ok(Some(stmt.into_inner()));
-        }
+            Some(stmt.into_inner())
+        });
 
         if self.token.is_keyword(kw::Mut) && self.is_keyword_ahead(1, &[kw::Let]) {
             self.bump();
@@ -539,7 +533,7 @@ impl<'a> Parser<'a> {
         blk_mode: BlockCheckMode,
         can_be_struct_literal: bool,
     ) -> PResult<'a, (AttrVec, P<Block>)> {
-        maybe_whole!(self, NtBlock, |x| (AttrVec::new(), x));
+        maybe_whole!(self, NtBlock, |block| (AttrVec::new(), block));
 
         let maybe_ident = self.prev_token.clone();
         self.maybe_recover_unexpected_block_label();
@@ -643,7 +637,7 @@ impl<'a> Parser<'a> {
         recover: AttemptLocalParseRecovery,
     ) -> PResult<'a, Option<Stmt>> {
         // Skip looking for a trailing semicolon when we have an interpolated statement.
-        maybe_whole!(self, NtStmt, |x| Some(x.into_inner()));
+        maybe_whole!(self, NtStmt, |stmt| Some(stmt.into_inner()));
 
         let Some(mut stmt) = self.parse_stmt_without_recovery(true, ForceCollect::No)? else {
             return Ok(None);
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 2385c18c089..1cea32cb90f 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -250,7 +250,7 @@ impl<'a> Parser<'a> {
     ) -> PResult<'a, P<Ty>> {
         let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes;
         maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
-        maybe_whole!(self, NtTy, |x| x);
+        maybe_whole!(self, NtTy, |ty| ty);
 
         let lo = self.token.span;
         let mut impl_dyn_multi = false;
diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs
index 8080216a252..4a1a2049083 100644
--- a/compiler/rustc_passes/src/check_const.rs
+++ b/compiler/rustc_passes/src/check_const.rs
@@ -48,7 +48,7 @@ impl NonConstExpr {
             Self::Match(TryDesugar(_)) => &[sym::const_try],
 
             // All other expressions are allowed.
-            Self::Loop(Loop | While) | Self::Match(Normal | FormatArgs) => &[],
+            Self::Loop(Loop | While) | Self::Match(Normal | Postfix | FormatArgs) => &[],
         };
 
         Some(gates)
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 350f7e166bf..80f2078fff2 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -525,15 +525,16 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
         let tcx = self.tcx;
         let unconditionally_treat_fields_as_live = self.repr_unconditionally_treats_fields_as_live;
         let has_repr_simd = self.repr_has_repr_simd;
+        let effective_visibilities = &tcx.effective_visibilities(());
         let live_fields = def.fields().iter().filter_map(|f| {
             let def_id = f.def_id;
             if unconditionally_treat_fields_as_live || (f.is_positional() && has_repr_simd) {
                 return Some(def_id);
             }
-            if !tcx.visibility(f.hir_id.owner.def_id).is_public() {
+            if !effective_visibilities.is_reachable(f.hir_id.owner.def_id) {
                 return None;
             }
-            if tcx.visibility(def_id).is_public() { Some(def_id) } else { None }
+            if effective_visibilities.is_reachable(def_id) { Some(def_id) } else { None }
         });
         self.live_symbols.extend(live_fields);
 
@@ -831,7 +832,7 @@ fn create_and_seed_worklist(
         .collect::<Vec<_>>();
 
     let crate_items = tcx.hir_crate_items(());
-    for id in crate_items.items() {
+    for id in crate_items.free_items() {
         check_item(tcx, &mut worklist, &mut struct_constructors, &mut unsolved_impl_item, id);
     }
 
@@ -1084,7 +1085,7 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
 
     let module_items = tcx.hir_module_items(module);
 
-    for item in module_items.items() {
+    for item in module_items.free_items() {
         let def_kind = tcx.def_kind(item.owner_id);
 
         let mut dead_codes = Vec::new();
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index d742ffc69e4..e6e52648d6f 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -264,7 +264,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
         hir_visit::walk_foreign_item(self, i)
     }
 
-    fn visit_local(&mut self, l: &'v hir::Local<'v>) {
+    fn visit_local(&mut self, l: &'v hir::LetStmt<'v>) {
         self.record("Local", Id::Node(l.hir_id), l);
         hir_visit::walk_local(self, l)
     }
@@ -300,6 +300,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
                 Path,
                 Tuple,
                 Box,
+                Deref,
                 Ref,
                 Lit,
                 Range,
@@ -566,6 +567,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
                 Path,
                 Tuple,
                 Box,
+                Deref,
                 Ref,
                 Lit,
                 Range,
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index f0c3f7a385d..125084f4750 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -342,7 +342,7 @@ impl<'tcx> IrMaps<'tcx> {
 }
 
 impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
-    fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
+    fn visit_local(&mut self, local: &'tcx hir::LetStmt<'tcx>) {
         self.add_from_pat(local.pat);
         if local.els.is_some() {
             self.add_live_node_for_node(local.hir_id, ExprNode(local.span, local.hir_id));
@@ -1350,7 +1350,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 // Checking for error conditions
 
 impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> {
-    fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
+    fn visit_local(&mut self, local: &'tcx hir::LetStmt<'tcx>) {
         self.check_unused_vars_in_pat(local.pat, None, None, |spans, hir_id, ln, var| {
             if local.init.is_some() {
                 self.warn_about_dead_assign(spans, hir_id, ln, var);
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index b7135de08ba..c2e604b02b3 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -437,7 +437,7 @@ fn reachable_set(tcx: TyCtxt<'_>, (): ()) -> LocalDefIdSet {
         // trait is a lang item.
         let crate_items = tcx.hir_crate_items(());
 
-        for id in crate_items.items() {
+        for id in crate_items.free_items() {
             check_item(tcx, id, &mut reachable_context.worklist, effective_visibilities);
         }
 
diff --git a/compiler/rustc_pattern_analysis/Cargo.toml b/compiler/rustc_pattern_analysis/Cargo.toml
index b9bdcb41929..6357d18b9da 100644
--- a/compiler/rustc_pattern_analysis/Cargo.toml
+++ b/compiler/rustc_pattern_analysis/Cargo.toml
@@ -22,6 +22,10 @@ smallvec = { version = "1.8.1", features = ["union"] }
 tracing = "0.1"
 # tidy-alphabetical-end
 
+[dev-dependencies]
+tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "ansi"] }
+tracing-tree = "0.2.0"
+
 [features]
 default = ["rustc"]
 rustc = [
diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs
index 5b58d7f43b2..95c5556410d 100644
--- a/compiler/rustc_pattern_analysis/src/constructor.rs
+++ b/compiler/rustc_pattern_analysis/src/constructor.rs
@@ -819,6 +819,81 @@ impl<Cx: PatCx> Constructor<Cx> {
             }
         })
     }
+
+    pub(crate) fn fmt_fields(
+        &self,
+        f: &mut fmt::Formatter<'_>,
+        ty: &Cx::Ty,
+        mut fields: impl Iterator<Item = impl fmt::Debug>,
+    ) -> fmt::Result {
+        let mut first = true;
+        let mut start_or_continue = |s| {
+            if first {
+                first = false;
+                ""
+            } else {
+                s
+            }
+        };
+        let mut start_or_comma = || start_or_continue(", ");
+
+        match self {
+            Struct | Variant(_) | UnionField => {
+                Cx::write_variant_name(f, self, ty)?;
+                // Without `cx`, we can't know which field corresponds to which, so we can't
+                // get the names of the fields. Instead we just display everything as a tuple
+                // struct, which should be good enough.
+                write!(f, "(")?;
+                for p in fields {
+                    write!(f, "{}{:?}", start_or_comma(), p)?;
+                }
+                write!(f, ")")?;
+            }
+            // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should
+            // be careful to detect strings here. However a string literal pattern will never
+            // be reported as a non-exhaustiveness witness, so we can ignore this issue.
+            Ref => {
+                write!(f, "&{:?}", &fields.next().unwrap())?;
+            }
+            Slice(slice) => {
+                write!(f, "[")?;
+                match slice.kind {
+                    SliceKind::FixedLen(_) => {
+                        for p in fields {
+                            write!(f, "{}{:?}", start_or_comma(), p)?;
+                        }
+                    }
+                    SliceKind::VarLen(prefix_len, _) => {
+                        for p in fields.by_ref().take(prefix_len) {
+                            write!(f, "{}{:?}", start_or_comma(), p)?;
+                        }
+                        write!(f, "{}..", start_or_comma())?;
+                        for p in fields {
+                            write!(f, "{}{:?}", start_or_comma(), p)?;
+                        }
+                    }
+                }
+                write!(f, "]")?;
+            }
+            Bool(b) => write!(f, "{b}")?,
+            // Best-effort, will render signed ranges incorrectly
+            IntRange(range) => write!(f, "{range:?}")?,
+            F32Range(lo, hi, end) => write!(f, "{lo}{end}{hi}")?,
+            F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}")?,
+            Str(value) => write!(f, "{value:?}")?,
+            Opaque(..) => write!(f, "<constant pattern>")?,
+            Or => {
+                for pat in fields {
+                    write!(f, "{}{:?}", start_or_continue(" | "), pat)?;
+                }
+            }
+            Never => write!(f, "!")?,
+            Wildcard | Missing | NonExhaustive | Hidden | PrivateUninhabited => {
+                write!(f, "_ : {:?}", ty)?
+            }
+        }
+        Ok(())
+    }
 }
 
 #[derive(Debug, Clone, Copy)]
diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs
index 5c57c990323..1a1da5c55f6 100644
--- a/compiler/rustc_pattern_analysis/src/lib.rs
+++ b/compiler/rustc_pattern_analysis/src/lib.rs
@@ -49,6 +49,12 @@ pub mod index {
         }
     }
 
+    impl<V> FromIterator<V> for IdxContainer<usize, V> {
+        fn from_iter<T: IntoIterator<Item = V>>(iter: T) -> Self {
+            Self(iter.into_iter().enumerate().collect())
+        }
+    }
+
     #[derive(Debug)]
     pub struct IdxSet<T>(pub rustc_hash::FxHashSet<T>);
     impl<T: Idx> IdxSet<T> {
@@ -120,7 +126,8 @@ pub trait PatCx: Sized + fmt::Debug {
     /// `DeconstructedPat`. Only invoqued when `pat.ctor()` is `Struct | Variant(_) | UnionField`.
     fn write_variant_name(
         f: &mut fmt::Formatter<'_>,
-        pat: &crate::pat::DeconstructedPat<Self>,
+        ctor: &crate::constructor::Constructor<Self>,
+        ty: &Self::Ty,
     ) -> fmt::Result;
 
     /// Raise a bug.
diff --git a/compiler/rustc_pattern_analysis/src/pat.rs b/compiler/rustc_pattern_analysis/src/pat.rs
index e7eed673c94..5f388ee9f89 100644
--- a/compiler/rustc_pattern_analysis/src/pat.rs
+++ b/compiler/rustc_pattern_analysis/src/pat.rs
@@ -138,81 +138,11 @@ impl<Cx: PatCx> DeconstructedPat<Cx> {
 /// This is best effort and not good enough for a `Display` impl.
 impl<Cx: PatCx> fmt::Debug for DeconstructedPat<Cx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let pat = self;
-        let mut first = true;
-        let mut start_or_continue = |s| {
-            if first {
-                first = false;
-                ""
-            } else {
-                s
-            }
-        };
-        let mut start_or_comma = || start_or_continue(", ");
-
         let mut fields: Vec<_> = (0..self.arity).map(|_| PatOrWild::Wild).collect();
         for ipat in self.iter_fields() {
             fields[ipat.idx] = PatOrWild::Pat(&ipat.pat);
         }
-
-        match pat.ctor() {
-            Struct | Variant(_) | UnionField => {
-                Cx::write_variant_name(f, pat)?;
-                // Without `cx`, we can't know which field corresponds to which, so we can't
-                // get the names of the fields. Instead we just display everything as a tuple
-                // struct, which should be good enough.
-                write!(f, "(")?;
-                for p in fields {
-                    write!(f, "{}", start_or_comma())?;
-                    write!(f, "{p:?}")?;
-                }
-                write!(f, ")")
-            }
-            // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should
-            // be careful to detect strings here. However a string literal pattern will never
-            // be reported as a non-exhaustiveness witness, so we can ignore this issue.
-            Ref => {
-                write!(f, "&{:?}", &fields[0])
-            }
-            Slice(slice) => {
-                write!(f, "[")?;
-                match slice.kind {
-                    SliceKind::FixedLen(_) => {
-                        for p in fields {
-                            write!(f, "{}{:?}", start_or_comma(), p)?;
-                        }
-                    }
-                    SliceKind::VarLen(prefix_len, _) => {
-                        for p in &fields[..prefix_len] {
-                            write!(f, "{}{:?}", start_or_comma(), p)?;
-                        }
-                        write!(f, "{}", start_or_comma())?;
-                        write!(f, "..")?;
-                        for p in &fields[prefix_len..] {
-                            write!(f, "{}{:?}", start_or_comma(), p)?;
-                        }
-                    }
-                }
-                write!(f, "]")
-            }
-            Bool(b) => write!(f, "{b}"),
-            // Best-effort, will render signed ranges incorrectly
-            IntRange(range) => write!(f, "{range:?}"),
-            F32Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
-            F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
-            Str(value) => write!(f, "{value:?}"),
-            Opaque(..) => write!(f, "<constant pattern>"),
-            Or => {
-                for pat in fields {
-                    write!(f, "{}{:?}", start_or_continue(" | "), pat)?;
-                }
-                Ok(())
-            }
-            Never => write!(f, "!"),
-            Wildcard | Missing | NonExhaustive | Hidden | PrivateUninhabited => {
-                write!(f, "_ : {:?}", pat.ty())
-            }
-        }
+        self.ctor().fmt_fields(f, self.ty(), fields.into_iter())
     }
 }
 
@@ -295,7 +225,6 @@ impl<'p, Cx: PatCx> fmt::Debug for PatOrWild<'p, Cx> {
 
 /// Same idea as `DeconstructedPat`, except this is a fictitious pattern built up for diagnostics
 /// purposes. As such they don't use interning and can be cloned.
-#[derive(Debug)]
 pub struct WitnessPat<Cx: PatCx> {
     ctor: Constructor<Cx>,
     pub(crate) fields: Vec<WitnessPat<Cx>>,
@@ -353,3 +282,10 @@ impl<Cx: PatCx> WitnessPat<Cx> {
         self.fields.iter()
     }
 }
+
+/// This is best effort and not good enough for a `Display` impl.
+impl<Cx: PatCx> fmt::Debug for WitnessPat<Cx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.ctor().fmt_fields(f, self.ty(), self.fields.iter())
+    }
+}
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index eedc00a5613..b0f506c3651 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -398,7 +398,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
             ty::Float(_)
             | ty::Str
             | ty::Foreign(_)
-            | ty::RawPtr(_)
+            | ty::RawPtr(_, _)
             | ty::FnDef(_, _)
             | ty::FnPtr(_)
             | ty::Dynamic(_, _, _)
@@ -462,6 +462,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                     _ => bug!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, ty),
                 };
             }
+            PatKind::DerefPattern { .. } => {
+                // FIXME(deref_patterns): At least detect that `box _` is irrefutable.
+                fields = vec![];
+                arity = 0;
+                ctor = Opaque(OpaqueId::new());
+            }
             PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => {
                 match ty.kind() {
                     ty::Tuple(fs) => {
@@ -874,13 +880,14 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> {
 
     fn write_variant_name(
         f: &mut fmt::Formatter<'_>,
-        pat: &crate::pat::DeconstructedPat<Self>,
+        ctor: &crate::constructor::Constructor<Self>,
+        ty: &Self::Ty,
     ) -> fmt::Result {
-        if let ty::Adt(adt, _) = pat.ty().kind() {
+        if let ty::Adt(adt, _) = ty.kind() {
             if adt.is_box() {
                 write!(f, "Box")?
             } else {
-                let variant = adt.variant(Self::variant_index_for_adt(pat.ctor(), *adt));
+                let variant = adt.variant(Self::variant_index_for_adt(ctor, *adt));
                 write!(f, "{}", variant.name)?;
             }
         }
diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs
index 3760db8b688..cdc03eaeb37 100644
--- a/compiler/rustc_pattern_analysis/src/usefulness.rs
+++ b/compiler/rustc_pattern_analysis/src/usefulness.rs
@@ -1042,7 +1042,7 @@ struct MatrixRow<'p, Cx: PatCx> {
     is_under_guard: bool,
     /// When we specialize, we remember which row of the original matrix produced a given row of the
     /// specialized matrix. When we unspecialize, we use this to propagate usefulness back up the
-    /// callstack.
+    /// callstack. On creation, this stores the index of the original match arm.
     parent_row: usize,
     /// False when the matrix is just built. This is set to `true` by
     /// [`compute_exhaustiveness_and_usefulness`] if the arm is found to be useful.
@@ -1163,10 +1163,10 @@ impl<'p, Cx: PatCx> Matrix<'p, Cx> {
             place_info: smallvec![place_info],
             wildcard_row_is_relevant: true,
         };
-        for (row_id, arm) in arms.iter().enumerate() {
+        for (arm_id, arm) in arms.iter().enumerate() {
             let v = MatrixRow {
                 pats: PatStack::from_pattern(arm.pat),
-                parent_row: row_id, // dummy, we don't read it
+                parent_row: arm_id,
                 is_under_guard: arm.has_guard,
                 useful: false,
                 intersects: BitSet::new_empty(0), // Initialized in `Matrix::expand_and_push`.
@@ -1738,6 +1738,9 @@ pub struct UsefulnessReport<'p, Cx: PatCx> {
     /// If the match is exhaustive, this is empty. If not, this contains witnesses for the lack of
     /// exhaustiveness.
     pub non_exhaustiveness_witnesses: Vec<WitnessPat<Cx>>,
+    /// For each arm, a set of indices of arms above it that have non-empty intersection, i.e. there
+    /// is a value matched by both arms. This may miss real intersections.
+    pub arm_intersections: Vec<BitSet<usize>>,
 }
 
 /// Computes whether a match is exhaustive and which of its arms are useful.
@@ -1769,5 +1772,19 @@ pub fn compute_match_usefulness<'p, Cx: PatCx>(
         })
         .collect();
 
-    Ok(UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses })
+    let mut arm_intersections: Vec<_> =
+        arms.iter().enumerate().map(|(i, _)| BitSet::new_empty(i)).collect();
+    for row in matrix.rows() {
+        let arm_id = row.parent_row;
+        for intersection in row.intersects.iter() {
+            // Convert the matrix row ids into arm ids (they can differ because we expand or-patterns).
+            let arm_intersection = matrix.rows[intersection].parent_row;
+            // Note: self-intersection can happen with or-patterns.
+            if arm_intersection != arm_id {
+                arm_intersections[arm_id].insert(arm_intersection);
+            }
+        }
+    }
+
+    Ok(UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses, arm_intersections })
 }
diff --git a/compiler/rustc_pattern_analysis/tests/common/mod.rs b/compiler/rustc_pattern_analysis/tests/common/mod.rs
new file mode 100644
index 00000000000..e72fddb9e9a
--- /dev/null
+++ b/compiler/rustc_pattern_analysis/tests/common/mod.rs
@@ -0,0 +1,315 @@
+use rustc_pattern_analysis::{
+    constructor::{
+        Constructor, ConstructorSet, IntRange, MaybeInfiniteInt, RangeEnd, VariantVisibility,
+    },
+    usefulness::{PlaceValidity, UsefulnessReport},
+    Captures, MatchArm, PatCx, PrivateUninhabitedField,
+};
+
+/// Sets up `tracing` for easier debugging. Tries to look like the `rustc` setup.
+pub fn init_tracing() {
+    use tracing_subscriber::layer::SubscriberExt;
+    use tracing_subscriber::util::SubscriberInitExt;
+    use tracing_subscriber::Layer;
+    let _ = tracing_tree::HierarchicalLayer::default()
+        .with_writer(std::io::stderr)
+        .with_indent_lines(true)
+        .with_ansi(true)
+        .with_targets(true)
+        .with_indent_amount(2)
+        .with_subscriber(
+            tracing_subscriber::Registry::default()
+                .with(tracing_subscriber::EnvFilter::from_default_env()),
+        )
+        .try_init();
+}
+
+/// A simple set of types.
+#[allow(dead_code)]
+#[derive(Debug, Copy, Clone)]
+pub enum Ty {
+    /// Booleans
+    Bool,
+    /// 8-bit unsigned integers
+    U8,
+    /// Tuples.
+    Tuple(&'static [Ty]),
+    /// A struct with `arity` fields of type `ty`.
+    BigStruct { arity: usize, ty: &'static Ty },
+    /// A enum with `arity` variants of type `ty`.
+    BigEnum { arity: usize, ty: &'static Ty },
+}
+
+/// The important logic.
+impl Ty {
+    pub fn sub_tys(&self, ctor: &Constructor<Cx>) -> Vec<Self> {
+        use Constructor::*;
+        match (ctor, *self) {
+            (Struct, Ty::Tuple(tys)) => tys.iter().copied().collect(),
+            (Struct, Ty::BigStruct { arity, ty }) => (0..arity).map(|_| *ty).collect(),
+            (Variant(_), Ty::BigEnum { ty, .. }) => vec![*ty],
+            (Bool(..) | IntRange(..) | NonExhaustive | Missing | Wildcard, _) => vec![],
+            _ => panic!("Unexpected ctor {ctor:?} for type {self:?}"),
+        }
+    }
+
+    pub fn ctor_set(&self) -> ConstructorSet<Cx> {
+        match *self {
+            Ty::Bool => ConstructorSet::Bool,
+            Ty::U8 => ConstructorSet::Integers {
+                range_1: IntRange::from_range(
+                    MaybeInfiniteInt::new_finite_uint(0),
+                    MaybeInfiniteInt::new_finite_uint(255),
+                    RangeEnd::Included,
+                ),
+                range_2: None,
+            },
+            Ty::Tuple(..) | Ty::BigStruct { .. } => ConstructorSet::Struct { empty: false },
+            Ty::BigEnum { arity, .. } => ConstructorSet::Variants {
+                variants: (0..arity).map(|_| VariantVisibility::Visible).collect(),
+                non_exhaustive: false,
+            },
+        }
+    }
+
+    pub fn write_variant_name(
+        &self,
+        f: &mut std::fmt::Formatter<'_>,
+        ctor: &Constructor<Cx>,
+    ) -> std::fmt::Result {
+        match (*self, ctor) {
+            (Ty::Tuple(..), _) => Ok(()),
+            (Ty::BigStruct { .. }, _) => write!(f, "BigStruct"),
+            (Ty::BigEnum { .. }, Constructor::Variant(i)) => write!(f, "BigEnum::Variant{i}"),
+            _ => write!(f, "{:?}::{:?}", self, ctor),
+        }
+    }
+}
+
+/// Compute usefulness in our simple context (and set up tracing for easier debugging).
+pub fn compute_match_usefulness<'p>(
+    arms: &[MatchArm<'p, Cx>],
+    ty: Ty,
+    scrut_validity: PlaceValidity,
+    complexity_limit: Option<usize>,
+) -> Result<UsefulnessReport<'p, Cx>, ()> {
+    init_tracing();
+    rustc_pattern_analysis::usefulness::compute_match_usefulness(
+        &Cx,
+        arms,
+        ty,
+        scrut_validity,
+        complexity_limit,
+    )
+}
+
+#[derive(Debug)]
+pub struct Cx;
+
+/// The context for pattern analysis. Forwards anything interesting to `Ty` methods.
+impl PatCx for Cx {
+    type Ty = Ty;
+    type Error = ();
+    type VariantIdx = usize;
+    type StrLit = ();
+    type ArmData = ();
+    type PatData = ();
+
+    fn is_exhaustive_patterns_feature_on(&self) -> bool {
+        false
+    }
+
+    fn is_min_exhaustive_patterns_feature_on(&self) -> bool {
+        false
+    }
+
+    fn ctor_arity(&self, ctor: &Constructor<Self>, ty: &Self::Ty) -> usize {
+        ty.sub_tys(ctor).len()
+    }
+
+    fn ctor_sub_tys<'a>(
+        &'a self,
+        ctor: &'a Constructor<Self>,
+        ty: &'a Self::Ty,
+    ) -> impl Iterator<Item = (Self::Ty, PrivateUninhabitedField)> + ExactSizeIterator + Captures<'a>
+    {
+        ty.sub_tys(ctor).into_iter().map(|ty| (ty, PrivateUninhabitedField(false)))
+    }
+
+    fn ctors_for_ty(&self, ty: &Self::Ty) -> Result<ConstructorSet<Self>, Self::Error> {
+        Ok(ty.ctor_set())
+    }
+
+    fn write_variant_name(
+        f: &mut std::fmt::Formatter<'_>,
+        ctor: &Constructor<Self>,
+        ty: &Self::Ty,
+    ) -> std::fmt::Result {
+        ty.write_variant_name(f, ctor)
+    }
+
+    fn bug(&self, fmt: std::fmt::Arguments<'_>) -> Self::Error {
+        panic!("{}", fmt)
+    }
+
+    /// Abort when reaching the complexity limit. This is what we'll check in tests.
+    fn complexity_exceeded(&self) -> Result<(), Self::Error> {
+        Err(())
+    }
+}
+
+/// Construct a single pattern; see `pats!()`.
+#[allow(unused_macros)]
+macro_rules! pat {
+    ($($rest:tt)*) => {{
+        let mut vec = pats!($($rest)*);
+        vec.pop().unwrap()
+    }};
+}
+
+/// A macro to construct patterns. Called like `pats!(type_expr; pattern, pattern, ..)` and returns
+/// a `Vec<DeconstructedPat>`. A pattern can be nested and looks like `Constructor(pat, pat)` or
+/// `Constructor { .i: pat, .j: pat }`, where `Constructor` is `Struct`, `Variant.i` (with index
+/// `i`), as well as booleans and integer ranges.
+///
+/// The general structure of the macro is a tt-muncher with several stages identified with
+/// `@something(args)`. The args are a key-value list (the keys ensure we don't mix the arguments
+/// around) which is passed down and modified as needed. We then parse token-trees from
+/// left-to-right. Non-trivial recursion happens when we parse the arguments to a pattern: we
+/// recurse to parse the tokens inside `{..}`/`(..)`, and then we continue parsing anything that
+/// follows.
+macro_rules! pats {
+    // Entrypoint
+    // Parse `type; ..`
+    ($ty:expr; $($rest:tt)*) => {{
+        #[allow(unused_imports)]
+        use rustc_pattern_analysis::{
+            constructor::{Constructor, IntRange, MaybeInfiniteInt, RangeEnd},
+            pat::DeconstructedPat,
+        };
+        let ty = $ty;
+        // The heart of the macro is designed to push `IndexedPat`s into a `Vec`, so we work around
+        // that.
+        let sub_tys = ::std::iter::repeat(&ty);
+        let mut vec = Vec::new();
+        pats!(@ctor(vec:vec, sub_tys:sub_tys, idx:0) $($rest)*);
+        vec.into_iter().map(|ipat| ipat.pat).collect::<Vec<_>>()
+    }};
+
+    // Parse `constructor ..`
+
+    (@ctor($($args:tt)*) true $($rest:tt)*) => {{
+        let ctor = Constructor::Bool(true);
+        pats!(@pat($($args)*, ctor:ctor) $($rest)*)
+    }};
+    (@ctor($($args:tt)*) false $($rest:tt)*) => {{
+        let ctor = Constructor::Bool(false);
+        pats!(@pat($($args)*, ctor:ctor) $($rest)*)
+    }};
+    (@ctor($($args:tt)*) Struct $($rest:tt)*) => {{
+        let ctor = Constructor::Struct;
+        pats!(@pat($($args)*, ctor:ctor) $($rest)*)
+    }};
+    (@ctor($($args:tt)*) ( $($fields:tt)* ) $($rest:tt)*) => {{
+        let ctor = Constructor::Struct; // tuples
+        pats!(@pat($($args)*, ctor:ctor) ( $($fields)* ) $($rest)*)
+    }};
+    (@ctor($($args:tt)*) Variant.$variant:ident $($rest:tt)*) => {{
+        let ctor = Constructor::Variant($variant);
+        pats!(@pat($($args)*, ctor:ctor) $($rest)*)
+    }};
+    (@ctor($($args:tt)*) Variant.$variant:literal $($rest:tt)*) => {{
+        let ctor = Constructor::Variant($variant);
+        pats!(@pat($($args)*, ctor:ctor) $($rest)*)
+    }};
+    (@ctor($($args:tt)*) _ $($rest:tt)*) => {{
+        let ctor = Constructor::Wildcard;
+        pats!(@pat($($args)*, ctor:ctor) $($rest)*)
+    }};
+
+    // Integers and int ranges
+    (@ctor($($args:tt)*) $($start:literal)?..$end:literal $($rest:tt)*) => {{
+        let ctor = Constructor::IntRange(IntRange::from_range(
+            pats!(@rangeboundary- $($start)?),
+            pats!(@rangeboundary+ $end),
+            RangeEnd::Excluded,
+        ));
+        pats!(@pat($($args)*, ctor:ctor) $($rest)*)
+    }};
+    (@ctor($($args:tt)*) $($start:literal)?.. $($rest:tt)*) => {{
+        let ctor = Constructor::IntRange(IntRange::from_range(
+            pats!(@rangeboundary- $($start)?),
+            pats!(@rangeboundary+),
+            RangeEnd::Excluded,
+        ));
+        pats!(@pat($($args)*, ctor:ctor) $($rest)*)
+    }};
+    (@ctor($($args:tt)*) $($start:literal)?..=$end:literal $($rest:tt)*) => {{
+        let ctor = Constructor::IntRange(IntRange::from_range(
+            pats!(@rangeboundary- $($start)?),
+            pats!(@rangeboundary+ $end),
+            RangeEnd::Included,
+        ));
+        pats!(@pat($($args)*, ctor:ctor) $($rest)*)
+    }};
+    (@ctor($($args:tt)*) $int:literal $($rest:tt)*) => {{
+        let ctor = Constructor::IntRange(IntRange::from_range(
+            pats!(@rangeboundary- $int),
+            pats!(@rangeboundary+ $int),
+            RangeEnd::Included,
+        ));
+        pats!(@pat($($args)*, ctor:ctor) $($rest)*)
+    }};
+    // Utility to manage range boundaries.
+    (@rangeboundary $sign:tt $int:literal) => { MaybeInfiniteInt::new_finite_uint($int) };
+    (@rangeboundary -) => { MaybeInfiniteInt::NegInfinity };
+    (@rangeboundary +) => { MaybeInfiniteInt::PosInfinity };
+
+    // Parse subfields: `(..)` or `{..}`
+
+    // Constructor with no fields, e.g. `bool` or `Variant.1`.
+    (@pat($($args:tt)*) $(,)?) => {
+        pats!(@pat($($args)*) {})
+    };
+    (@pat($($args:tt)*) , $($rest:tt)*) => {
+        pats!(@pat($($args)*) {}, $($rest)*)
+    };
+    // `(..)` and `{..}` are treated the same.
+    (@pat($($args:tt)*) ( $($subpat:tt)* ) $($rest:tt)*) => {{
+        pats!(@pat($($args)*) { $($subpat)* } $($rest)*)
+    }};
+    (@pat(vec:$vec:expr, sub_tys:$sub_tys:expr, idx:$idx:expr, ctor:$ctor:expr) { $($fields:tt)* } $($rest:tt)*) => {{
+        let sub_tys = $sub_tys;
+        let index = $idx;
+        // Silly dance to work with both a vec and `iter::repeat()`.
+        let ty = *(&sub_tys).clone().into_iter().nth(index).unwrap();
+        let ctor = $ctor;
+        let ctor_sub_tys = &ty.sub_tys(&ctor);
+        #[allow(unused_mut)]
+        let mut fields = Vec::new();
+        // Parse subpatterns (note the leading comma).
+        pats!(@fields(idx:0, vec:fields, sub_tys:ctor_sub_tys) ,$($fields)*);
+        let arity = ctor_sub_tys.len();
+        let pat = DeconstructedPat::new(ctor, fields, arity, ty, ()).at_index(index);
+        $vec.push(pat);
+
+        // Continue parsing further patterns.
+        pats!(@fields(idx:index+1, vec:$vec, sub_tys:sub_tys) $($rest)*);
+    }};
+
+    // Parse fields one by one.
+
+    // No fields left.
+    (@fields($($args:tt)*) $(,)?) => {};
+    // `.i: pat` sets the current index to `i`.
+    (@fields(idx:$_idx:expr, $($args:tt)*) , .$idx:literal : $($rest:tt)*) => {{
+        pats!(@ctor($($args)*, idx:$idx) $($rest)*);
+    }};
+    (@fields(idx:$_idx:expr, $($args:tt)*) , .$idx:ident : $($rest:tt)*) => {{
+        pats!(@ctor($($args)*, idx:$idx) $($rest)*);
+    }};
+    // Field without an explicit index; we use the current index which gets incremented above.
+    (@fields(idx:$idx:expr, $($args:tt)*) , $($rest:tt)*) => {{
+        pats!(@ctor($($args)*, idx:$idx) $($rest)*);
+    }};
+}
diff --git a/compiler/rustc_pattern_analysis/tests/complexity.rs b/compiler/rustc_pattern_analysis/tests/complexity.rs
new file mode 100644
index 00000000000..93f455c6257
--- /dev/null
+++ b/compiler/rustc_pattern_analysis/tests/complexity.rs
@@ -0,0 +1,109 @@
+//! Test the pattern complexity limit.
+use common::*;
+use rustc_pattern_analysis::{pat::DeconstructedPat, usefulness::PlaceValidity, MatchArm};
+
+#[macro_use]
+mod common;
+
+/// Analyze a match made of these patterns. Ignore the report; we only care whether we exceeded the
+/// limit or not.
+fn check(patterns: &[DeconstructedPat<Cx>], complexity_limit: usize) -> Result<(), ()> {
+    let ty = *patterns[0].ty();
+    let arms: Vec<_> =
+        patterns.iter().map(|pat| MatchArm { pat, has_guard: false, arm_data: () }).collect();
+    compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, Some(complexity_limit))
+        .map(|_report| ())
+}
+
+/// Asserts that analyzing this match takes exactly `complexity` steps.
+#[track_caller]
+fn assert_complexity(patterns: Vec<DeconstructedPat<Cx>>, complexity: usize) {
+    assert!(check(&patterns, complexity).is_ok());
+    assert!(check(&patterns, complexity - 1).is_err());
+}
+
+/// Construct a match like:
+/// ```ignore(illustrative)
+/// match ... {
+///     BigStruct { field01: true, .. } => {}
+///     BigStruct { field02: true, .. } => {}
+///     BigStruct { field03: true, .. } => {}
+///     BigStruct { field04: true, .. } => {}
+///     ...
+///     _ => {}
+/// }
+/// ```
+fn diagonal_match(arity: usize) -> Vec<DeconstructedPat<Cx>> {
+    let struct_ty = Ty::BigStruct { arity, ty: &Ty::Bool };
+    let mut patterns = vec![];
+    for i in 0..arity {
+        patterns.push(pat!(struct_ty; Struct { .i: true }));
+    }
+    patterns.push(pat!(struct_ty; _));
+    patterns
+}
+
+/// Construct a match like:
+/// ```ignore(illustrative)
+/// match ... {
+///     BigStruct { field01: true, .. } => {}
+///     BigStruct { field02: true, .. } => {}
+///     BigStruct { field03: true, .. } => {}
+///     BigStruct { field04: true, .. } => {}
+///     ...
+///     BigStruct { field01: false, .. } => {}
+///     BigStruct { field02: false, .. } => {}
+///     BigStruct { field03: false, .. } => {}
+///     BigStruct { field04: false, .. } => {}
+///     ...
+///     _ => {}
+/// }
+/// ```
+fn diagonal_exponential_match(arity: usize) -> Vec<DeconstructedPat<Cx>> {
+    let struct_ty = Ty::BigStruct { arity, ty: &Ty::Bool };
+    let mut patterns = vec![];
+    for i in 0..arity {
+        patterns.push(pat!(struct_ty; Struct { .i: true }));
+    }
+    for i in 0..arity {
+        patterns.push(pat!(struct_ty; Struct { .i: false }));
+    }
+    patterns.push(pat!(struct_ty; _));
+    patterns
+}
+
+#[test]
+fn test_diagonal_struct_match() {
+    // These cases are nicely linear: we check `arity` patterns with exactly one `true`, matching
+    // in 2 branches each, and a final pattern with all `false`, matching only the `_` branch.
+    assert_complexity(diagonal_match(20), 41);
+    assert_complexity(diagonal_match(30), 61);
+    // This case goes exponential.
+    assert!(check(&diagonal_exponential_match(10), 10000).is_err());
+}
+
+/// Construct a match like:
+/// ```ignore(illustrative)
+/// match ... {
+///     BigEnum::Variant1(_) => {}
+///     BigEnum::Variant2(_) => {}
+///     BigEnum::Variant3(_) => {}
+///     ...
+///     _ => {}
+/// }
+/// ```
+fn big_enum(arity: usize) -> Vec<DeconstructedPat<Cx>> {
+    let enum_ty = Ty::BigEnum { arity, ty: &Ty::Bool };
+    let mut patterns = vec![];
+    for i in 0..arity {
+        patterns.push(pat!(enum_ty; Variant.i));
+    }
+    patterns.push(pat!(enum_ty; _));
+    patterns
+}
+
+#[test]
+fn test_big_enum() {
+    // We try 2 branches per variant.
+    assert_complexity(big_enum(20), 40);
+}
diff --git a/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs b/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs
new file mode 100644
index 00000000000..4c6c72fa8ec
--- /dev/null
+++ b/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs
@@ -0,0 +1,77 @@
+//! Test exhaustiveness checking.
+use common::*;
+use rustc_pattern_analysis::{
+    pat::{DeconstructedPat, WitnessPat},
+    usefulness::PlaceValidity,
+    MatchArm,
+};
+
+#[macro_use]
+mod common;
+
+/// Analyze a match made of these patterns.
+fn check(patterns: Vec<DeconstructedPat<Cx>>) -> Vec<WitnessPat<Cx>> {
+    let ty = *patterns[0].ty();
+    let arms: Vec<_> =
+        patterns.iter().map(|pat| MatchArm { pat, has_guard: false, arm_data: () }).collect();
+    let report =
+        compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, None).unwrap();
+    report.non_exhaustiveness_witnesses
+}
+
+#[track_caller]
+fn assert_exhaustive(patterns: Vec<DeconstructedPat<Cx>>) {
+    let witnesses = check(patterns);
+    if !witnesses.is_empty() {
+        panic!("non-exaustive match: missing {witnesses:?}");
+    }
+}
+
+#[track_caller]
+fn assert_non_exhaustive(patterns: Vec<DeconstructedPat<Cx>>) {
+    let witnesses = check(patterns);
+    assert!(!witnesses.is_empty())
+}
+
+#[test]
+fn test_int_ranges() {
+    let ty = Ty::U8;
+    assert_exhaustive(pats!(ty;
+        0..=255,
+    ));
+    assert_exhaustive(pats!(ty;
+        0..,
+    ));
+    assert_non_exhaustive(pats!(ty;
+        0..255,
+    ));
+    assert_exhaustive(pats!(ty;
+        0..255,
+        255,
+    ));
+    assert_exhaustive(pats!(ty;
+        ..10,
+        10..
+    ));
+}
+
+#[test]
+fn test_nested() {
+    let ty = Ty::BigStruct { arity: 2, ty: &Ty::BigEnum { arity: 2, ty: &Ty::Bool } };
+    assert_non_exhaustive(pats!(ty;
+        Struct(Variant.0, _),
+    ));
+    assert_exhaustive(pats!(ty;
+        Struct(Variant.0, _),
+        Struct(Variant.1, _),
+    ));
+    assert_non_exhaustive(pats!(ty;
+        Struct(Variant.0, _),
+        Struct(_, Variant.0),
+    ));
+    assert_exhaustive(pats!(ty;
+        Struct(Variant.0, _),
+        Struct(_, Variant.0),
+        Struct(Variant.1, Variant.1),
+    ));
+}
diff --git a/compiler/rustc_pattern_analysis/tests/intersection.rs b/compiler/rustc_pattern_analysis/tests/intersection.rs
new file mode 100644
index 00000000000..4d8a21506d7
--- /dev/null
+++ b/compiler/rustc_pattern_analysis/tests/intersection.rs
@@ -0,0 +1,69 @@
+//! Test the computation of arm intersections.
+use common::*;
+use rustc_pattern_analysis::{pat::DeconstructedPat, usefulness::PlaceValidity, MatchArm};
+
+#[macro_use]
+mod common;
+
+/// Analyze a match made of these patterns and returns the computed arm intersections.
+fn check(patterns: Vec<DeconstructedPat<Cx>>) -> Vec<Vec<usize>> {
+    let ty = *patterns[0].ty();
+    let arms: Vec<_> =
+        patterns.iter().map(|pat| MatchArm { pat, has_guard: false, arm_data: () }).collect();
+    let report =
+        compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, None).unwrap();
+    report.arm_intersections.into_iter().map(|bitset| bitset.iter().collect()).collect()
+}
+
+#[track_caller]
+fn assert_intersects(patterns: Vec<DeconstructedPat<Cx>>, intersects: &[&[usize]]) {
+    let computed_intersects = check(patterns);
+    assert_eq!(computed_intersects, intersects);
+}
+
+#[test]
+fn test_int_ranges() {
+    let ty = Ty::U8;
+    assert_intersects(
+        pats!(ty;
+            0..=100,
+            100..,
+        ),
+        &[&[], &[0]],
+    );
+    assert_intersects(
+        pats!(ty;
+            0..=101,
+            100..,
+        ),
+        &[&[], &[0]],
+    );
+    assert_intersects(
+        pats!(ty;
+            0..100,
+            100..,
+        ),
+        &[&[], &[]],
+    );
+}
+
+#[test]
+fn test_nested() {
+    let ty = Ty::Tuple(&[Ty::Bool; 2]);
+    assert_intersects(
+        pats!(ty;
+            (true, true),
+            (true, _),
+            (_, true),
+        ),
+        &[&[], &[0], &[0, 1]],
+    );
+    // Here we shortcut because `(true, true)` is irrelevant, so we fail to detect the intersection.
+    assert_intersects(
+        pats!(ty;
+            (true, _),
+            (_, true),
+        ),
+        &[&[], &[]],
+    );
+}
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 073982ca5c3..41d63407418 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -1209,7 +1209,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
         intravisit::walk_pat(self, pattern);
     }
 
-    fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
+    fn visit_local(&mut self, local: &'tcx hir::LetStmt<'tcx>) {
         if let Some(init) = local.init {
             if self.check_expr_pat_type(init.hir_id, init.span) {
                 // Do not report duplicate errors for `let x = y`.
@@ -1696,7 +1696,7 @@ fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
         }
     }
 
-    for id in module.items() {
+    for id in module.free_items() {
         if let ItemKind::Impl(i) = tcx.hir().item(id).kind {
             if let Some(item) = i.of_trait {
                 let trait_ref = tcx.impl_trait_ref(id.owner_id.def_id).unwrap();
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index c661be3587e..b2b339d2521 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -22,7 +22,7 @@ use rustc_errors::{
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS};
 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
-use rustc_hir::{PrimTy, TraitCandidate};
+use rustc_hir::{MissingLifetimeKind, PrimTy, TraitCandidate};
 use rustc_middle::middle::resolve_bound_vars::Set1;
 use rustc_middle::{bug, span_bug};
 use rustc_session::config::{CrateType, ResolveDocLinks};
@@ -44,9 +44,7 @@ type Res = def::Res<NodeId>;
 
 type IdentMap<T> = FxHashMap<Ident, T>;
 
-use diagnostics::{
-    ElisionFnParameter, LifetimeElisionCandidate, MissingLifetime, MissingLifetimeKind,
-};
+use diagnostics::{ElisionFnParameter, LifetimeElisionCandidate, MissingLifetime};
 
 #[derive(Copy, Clone, Debug)]
 struct BindingInfo {
@@ -1637,22 +1635,16 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
     fn resolve_anonymous_lifetime(&mut self, lifetime: &Lifetime, elided: bool) {
         debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
 
-        let missing_lifetime = MissingLifetime {
-            id: lifetime.id,
-            span: lifetime.ident.span,
-            kind: if elided {
-                MissingLifetimeKind::Ampersand
-            } else {
-                MissingLifetimeKind::Underscore
-            },
-            count: 1,
-        };
+        let kind =
+            if elided { MissingLifetimeKind::Ampersand } else { MissingLifetimeKind::Underscore };
+        let missing_lifetime =
+            MissingLifetime { id: lifetime.id, span: lifetime.ident.span, kind, count: 1 };
         let elision_candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
         for (i, rib) in self.lifetime_ribs.iter().enumerate().rev() {
             debug!(?rib.kind);
             match rib.kind {
                 LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
-                    let res = self.create_fresh_lifetime(lifetime.ident, binder);
+                    let res = self.create_fresh_lifetime(lifetime.ident, binder, kind);
                     self.record_lifetime_res(lifetime.id, res, elision_candidate);
                     return;
                 }
@@ -1744,13 +1736,18 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
     }
 
     #[instrument(level = "debug", skip(self))]
-    fn create_fresh_lifetime(&mut self, ident: Ident, binder: NodeId) -> LifetimeRes {
+    fn create_fresh_lifetime(
+        &mut self,
+        ident: Ident,
+        binder: NodeId,
+        kind: MissingLifetimeKind,
+    ) -> LifetimeRes {
         debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
         debug!(?ident.span);
 
         // Leave the responsibility to create the `LocalDefId` to lowering.
         let param = self.r.next_node_id();
-        let res = LifetimeRes::Fresh { param, binder };
+        let res = LifetimeRes::Fresh { param, binder, kind };
         self.record_lifetime_param(param, res);
 
         // Record the created lifetime parameter so lowering can pick it up and add it to HIR.
@@ -1844,14 +1841,15 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             };
             let ident = Ident::new(kw::UnderscoreLifetime, elided_lifetime_span);
 
+            let kind = if segment.has_generic_args {
+                MissingLifetimeKind::Comma
+            } else {
+                MissingLifetimeKind::Brackets
+            };
             let missing_lifetime = MissingLifetime {
                 id: node_ids.start,
                 span: elided_lifetime_span,
-                kind: if segment.has_generic_args {
-                    MissingLifetimeKind::Comma
-                } else {
-                    MissingLifetimeKind::Brackets
-                },
+                kind,
                 count: expected_lifetimes,
             };
             let mut should_lint = true;
@@ -1897,7 +1895,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
                         // Group all suggestions into the first record.
                         let mut candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
                         for id in node_ids {
-                            let res = self.create_fresh_lifetime(ident, binder);
+                            let res = self.create_fresh_lifetime(ident, binder, kind);
                             self.record_lifetime_res(
                                 id,
                                 res,
@@ -4672,7 +4670,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             return;
         }
 
-        if path.iter().any(|seg| seg.ident.span.from_expansion()) {
+        if finalize.path_span.from_expansion()
+            || path.iter().any(|seg| seg.ident.span.from_expansion())
+        {
             return;
         }
 
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 47f8cc56139..bb4294fbcfb 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -24,7 +24,7 @@ use rustc_errors::{
 use rustc_hir as hir;
 use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
 use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
-use rustc_hir::PrimTy;
+use rustc_hir::{MissingLifetimeKind, PrimTy};
 use rustc_session::lint;
 use rustc_session::Session;
 use rustc_span::edit_distance::find_best_match_for_name;
@@ -109,18 +109,6 @@ pub(super) struct MissingLifetime {
     pub count: usize,
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
-pub(super) enum MissingLifetimeKind {
-    /// An explicit `'_`.
-    Underscore,
-    /// An elided lifetime `&' ty`.
-    Ampersand,
-    /// An elided lifetime in brackets with written brackets.
-    Comma,
-    /// An elided lifetime with elided brackets.
-    Brackets,
-}
-
 /// Description of the lifetimes appearing in a function parameter.
 /// This is used to provide a literal explanation to the elision failure.
 #[derive(Clone, Debug)]
@@ -1604,18 +1592,23 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
 
         match (res, source) {
             (
-                Res::Def(DefKind::Macro(MacroKind::Bang), _),
+                Res::Def(DefKind::Macro(MacroKind::Bang), def_id),
                 PathSource::Expr(Some(Expr {
                     kind: ExprKind::Index(..) | ExprKind::Call(..), ..
                 }))
                 | PathSource::Struct,
             ) => {
+                // Don't suggest macro if it's unstable.
+                let suggestable = def_id.is_local()
+                    || self.r.tcx.lookup_stability(def_id).map_or(true, |s| s.is_stable());
+
                 err.span_label(span, fallback_label.to_string());
 
                 // Don't suggest `!` for a macro invocation if there are generic args
                 if path
                     .last()
                     .is_some_and(|segment| !segment.has_generic_args && !segment.has_lifetime_args)
+                    && suggestable
                 {
                     err.span_suggestion_verbose(
                         span.shrink_to_hi(),
diff --git a/compiler/rustc_session/src/code_stats.rs b/compiler/rustc_session/src/code_stats.rs
index 2553df33cc7..93839fa1186 100644
--- a/compiler/rustc_session/src/code_stats.rs
+++ b/compiler/rustc_session/src/code_stats.rs
@@ -44,6 +44,10 @@ pub struct FieldInfo {
     pub offset: u64,
     pub size: u64,
     pub align: u64,
+    /// Name of the type of this field.
+    /// Present only if the creator thought that this would be important for identifying the field,
+    /// typically because the field name is uninformative.
+    pub type_name: Option<Symbol>,
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
@@ -192,7 +196,7 @@ impl CodeStats {
                 fields.sort_by_key(|f| (f.offset, f.size));
 
                 for field in fields {
-                    let FieldInfo { kind, ref name, offset, size, align } = field;
+                    let FieldInfo { kind, ref name, offset, size, align, type_name } = field;
 
                     if offset > min_offset {
                         let pad = offset - min_offset;
@@ -201,21 +205,27 @@ impl CodeStats {
 
                     if offset < min_offset {
                         // If this happens it's probably a union.
-                        println!(
+                        print!(
                             "print-type-size {indent}{kind} `.{name}`: {size} bytes, \
                                   offset: {offset} bytes, \
                                   alignment: {align} bytes"
                         );
                     } else if info.packed || offset == min_offset {
-                        println!("print-type-size {indent}{kind} `.{name}`: {size} bytes");
+                        print!("print-type-size {indent}{kind} `.{name}`: {size} bytes");
                     } else {
                         // Include field alignment in output only if it caused padding injection
-                        println!(
+                        print!(
                             "print-type-size {indent}{kind} `.{name}`: {size} bytes, \
                                   alignment: {align} bytes"
                         );
                     }
 
+                    if let Some(type_name) = type_name {
+                        println!(", type: {type_name}");
+                    } else {
+                        println!();
+                    }
+
                     min_offset = offset + size;
                 }
             }
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index e6eb1a3e83c..a88ae268e27 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -22,7 +22,7 @@ use rustc_span::{FileName, FileNameDisplayPreference, RealFileName, SourceFileHa
 use rustc_target::abi::Align;
 use rustc_target::spec::LinkSelfContainedComponents;
 use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, SplitDebuginfo};
-use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS};
+use rustc_target::spec::{Target, TargetTriple, TARGETS};
 use std::collections::btree_map::{
     Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
 };
@@ -1549,34 +1549,25 @@ pub fn build_configuration(sess: &Session, mut user_cfg: Cfg) -> Cfg {
     user_cfg
 }
 
-pub fn build_target_config(
-    early_dcx: &EarlyDiagCtxt,
-    opts: &Options,
-    target_override: Option<Target>,
-    sysroot: &Path,
-) -> Target {
-    let target_result = target_override.map_or_else(
-        || Target::search(&opts.target_triple, sysroot),
-        |t| Ok((t, TargetWarnings::empty())),
-    );
-    let (target, target_warnings) = target_result.unwrap_or_else(|e| {
-        early_dcx.early_fatal(format!(
+pub fn build_target_config(early_dcx: &EarlyDiagCtxt, opts: &Options, sysroot: &Path) -> Target {
+    match Target::search(&opts.target_triple, sysroot) {
+        Ok((target, warnings)) => {
+            for warning in warnings.warning_messages() {
+                early_dcx.early_warn(warning)
+            }
+            if !matches!(target.pointer_width, 16 | 32 | 64) {
+                early_dcx.early_fatal(format!(
+                    "target specification was invalid: unrecognized target-pointer-width {}",
+                    target.pointer_width
+                ))
+            }
+            target
+        }
+        Err(e) => early_dcx.early_fatal(format!(
             "Error loading target specification: {e}. \
-                 Run `rustc --print target-list` for a list of built-in targets"
-        ))
-    });
-    for warning in target_warnings.warning_messages() {
-        early_dcx.early_warn(warning)
-    }
-
-    if !matches!(target.pointer_width, 16 | 32 | 64) {
-        early_dcx.early_fatal(format!(
-            "target specification was invalid: unrecognized target-pointer-width {}",
-            target.pointer_width
-        ))
+                     Run `rustc --print target-list` for a list of built-in targets"
+        )),
     }
-
-    target
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 9c94fd7027f..e6d82d6fab3 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1008,7 +1008,7 @@ pub fn build_session(
     fluent_resources: Vec<&'static str>,
     driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
     file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
-    target_cfg: Target,
+    target: Target,
     sysroot: PathBuf,
     cfg_version: &'static str,
     ice_file: Option<PathBuf>,
@@ -1036,7 +1036,7 @@ pub fn build_session(
 
     let loader = file_loader.unwrap_or_else(|| Box::new(RealFileLoader));
     let hash_kind = sopts.unstable_opts.src_hash_algorithm.unwrap_or_else(|| {
-        if target_cfg.is_like_msvc {
+        if target.is_like_msvc {
             SourceFileHashAlgorithm::Sha256
         } else {
             SourceFileHashAlgorithm::Md5
@@ -1117,11 +1117,10 @@ pub fn build_session(
         _ => CtfeBacktrace::Disabled,
     });
 
-    let asm_arch =
-        if target_cfg.allow_asm { InlineAsmArch::from_str(&target_cfg.arch).ok() } else { None };
+    let asm_arch = if target.allow_asm { InlineAsmArch::from_str(&target.arch).ok() } else { None };
 
     let sess = Session {
-        target: target_cfg,
+        target,
         host,
         opts: sopts,
         host_tlib_path,
diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs
index 2cc9bc31873..e8cc41cc886 100644
--- a/compiler/rustc_smir/src/rustc_internal/internal.rs
+++ b/compiler/rustc_smir/src/rustc_internal/internal.rs
@@ -10,7 +10,7 @@ use rustc_span::Symbol;
 use stable_mir::abi::Layout;
 use stable_mir::mir::alloc::AllocId;
 use stable_mir::mir::mono::{Instance, MonoItem, StaticDef};
-use stable_mir::mir::{Mutability, Safety};
+use stable_mir::mir::{Mutability, Place, ProjectionElem, Safety};
 use stable_mir::ty::{
     Abi, AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const,
     DynKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FloatTy, FnSig,
@@ -95,10 +95,9 @@ impl RustcInternal for RigidTy {
             }
             RigidTy::Str => rustc_ty::TyKind::Str,
             RigidTy::Slice(ty) => rustc_ty::TyKind::Slice(ty.internal(tables, tcx)),
-            RigidTy::RawPtr(ty, mutability) => rustc_ty::TyKind::RawPtr(rustc_ty::TypeAndMut {
-                ty: ty.internal(tables, tcx),
-                mutbl: mutability.internal(tables, tcx),
-            }),
+            RigidTy::RawPtr(ty, mutability) => {
+                rustc_ty::TyKind::RawPtr(ty.internal(tables, tcx), mutability.internal(tables, tcx))
+            }
             RigidTy::Ref(region, ty, mutability) => rustc_ty::TyKind::Ref(
                 region.internal(tables, tcx),
                 ty.internal(tables, tcx),
@@ -492,6 +491,50 @@ impl RustcInternal for Layout {
     }
 }
 
+impl RustcInternal for Place {
+    type T<'tcx> = rustc_middle::mir::Place<'tcx>;
+
+    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+        rustc_middle::mir::Place {
+            local: rustc_middle::mir::Local::from_usize(self.local),
+            projection: tcx.mk_place_elems(&self.projection.internal(tables, tcx)),
+        }
+    }
+}
+
+impl RustcInternal for ProjectionElem {
+    type T<'tcx> = rustc_middle::mir::PlaceElem<'tcx>;
+
+    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+        match self {
+            ProjectionElem::Deref => rustc_middle::mir::PlaceElem::Deref,
+            ProjectionElem::Field(idx, ty) => {
+                rustc_middle::mir::PlaceElem::Field((*idx).into(), ty.internal(tables, tcx))
+            }
+            ProjectionElem::Index(idx) => rustc_middle::mir::PlaceElem::Index((*idx).into()),
+            ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
+                rustc_middle::mir::PlaceElem::ConstantIndex {
+                    offset: *offset,
+                    min_length: *min_length,
+                    from_end: *from_end,
+                }
+            }
+            ProjectionElem::Subslice { from, to, from_end } => {
+                rustc_middle::mir::PlaceElem::Subslice { from: *from, to: *to, from_end: *from_end }
+            }
+            ProjectionElem::Downcast(idx) => {
+                rustc_middle::mir::PlaceElem::Downcast(None, idx.internal(tables, tcx))
+            }
+            ProjectionElem::OpaqueCast(ty) => {
+                rustc_middle::mir::PlaceElem::OpaqueCast(ty.internal(tables, tcx))
+            }
+            ProjectionElem::Subtype(ty) => {
+                rustc_middle::mir::PlaceElem::Subtype(ty.internal(tables, tcx))
+            }
+        }
+    }
+}
+
 impl<T> RustcInternal for &T
 where
     T: RustcInternal,
diff --git a/compiler/rustc_smir/src/rustc_internal/pretty.rs b/compiler/rustc_smir/src/rustc_internal/pretty.rs
index 3ef2d28ea47..c0dce08b0d3 100644
--- a/compiler/rustc_smir/src/rustc_internal/pretty.rs
+++ b/compiler/rustc_smir/src/rustc_internal/pretty.rs
@@ -14,7 +14,7 @@ pub fn write_smir_pretty<'tcx, W: io::Write>(tcx: TyCtxt<'tcx>, w: &mut W) -> io
     )?;
     let _ = run(tcx, || {
         let items = stable_mir::all_local_items();
-        let _ = items.iter().map(|item| -> io::Result<()> { item.dump(w) }).collect::<Vec<_>>();
+        let _ = items.iter().map(|item| -> io::Result<()> { item.emit_mir(w) }).collect::<Vec<_>>();
     });
     Ok(())
 }
diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs
index d427e5fb88d..d39a3788d4c 100644
--- a/compiler/rustc_smir/src/rustc_smir/context.rs
+++ b/compiler/rustc_smir/src/rustc_smir/context.rs
@@ -19,7 +19,7 @@ use stable_mir::abi::{FnAbi, Layout, LayoutShape};
 use stable_mir::compiler_interface::Context;
 use stable_mir::mir::alloc::GlobalAlloc;
 use stable_mir::mir::mono::{InstanceDef, StaticDef};
-use stable_mir::mir::Body;
+use stable_mir::mir::{Body, Place};
 use stable_mir::target::{MachineInfo, MachineSize};
 use stable_mir::ty::{
     AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef,
@@ -423,7 +423,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         def_ty.instantiate(tables.tcx, args).stable(&mut *tables)
     }
 
-    fn const_literal(&self, cnst: &stable_mir::ty::Const) -> String {
+    fn const_pretty(&self, cnst: &stable_mir::ty::Const) -> String {
         let mut tables = self.0.borrow_mut();
         let tcx = tables.tcx;
         cnst.internal(&mut *tables, tcx).to_string()
@@ -434,6 +434,11 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         tables.tcx.def_span(tables[def_id]).stable(&mut *tables)
     }
 
+    fn ty_pretty(&self, ty: stable_mir::ty::Ty) -> String {
+        let tables = self.0.borrow_mut();
+        tables.types[ty].to_string()
+    }
+
     fn ty_kind(&self, ty: stable_mir::ty::Ty) -> TyKind {
         let mut tables = self.0.borrow_mut();
         tables.types[ty].kind().stable(&mut *tables)
@@ -654,6 +659,12 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         let tcx = tables.tcx;
         id.internal(&mut *tables, tcx).0.stable(&mut *tables)
     }
+
+    fn place_pretty(&self, place: &Place) -> String {
+        let mut tables = self.0.borrow_mut();
+        let tcx = tables.tcx;
+        format!("{:?}", place.internal(&mut *tables, tcx))
+    }
 }
 
 pub struct TablesWrapper<'tcx>(pub RefCell<Tables<'tcx>>);
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
index c0876adf905..b6a722da602 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
@@ -251,19 +251,13 @@ impl<'tcx> Stable<'tcx> for mir::NullOp<'tcx> {
     type T = stable_mir::mir::NullOp;
     fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
         use rustc_middle::mir::NullOp::*;
-        use rustc_middle::mir::UbKind;
         match self {
             SizeOf => stable_mir::mir::NullOp::SizeOf,
             AlignOf => stable_mir::mir::NullOp::AlignOf,
             OffsetOf(indices) => stable_mir::mir::NullOp::OffsetOf(
                 indices.iter().map(|idx| idx.stable(tables)).collect(),
             ),
-            UbCheck(UbKind::LanguageUb) => {
-                stable_mir::mir::NullOp::UbCheck(stable_mir::mir::UbKind::LanguageUb)
-            }
-            UbCheck(UbKind::LibraryUb) => {
-                stable_mir::mir::NullOp::UbCheck(stable_mir::mir::UbKind::LibraryUb)
-            }
+            UbChecks => stable_mir::mir::NullOp::UbChecks,
         }
     }
 }
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
index 84c6cbf178b..2ad8f350f10 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
@@ -331,7 +331,7 @@ impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> {
                 TyKind::RigidTy(RigidTy::Array(ty.stable(tables), constant.stable(tables)))
             }
             ty::Slice(ty) => TyKind::RigidTy(RigidTy::Slice(ty.stable(tables))),
-            ty::RawPtr(ty::TypeAndMut { ty, mutbl }) => {
+            ty::RawPtr(ty, mutbl) => {
                 TyKind::RigidTy(RigidTy::RawPtr(ty.stable(tables), mutbl.stable(tables)))
             }
             ty::Ref(region, ty, mutbl) => TyKind::RigidTy(RigidTy::Ref(
@@ -719,6 +719,18 @@ impl<'tcx> Stable<'tcx> for ty::ImplPolarity {
     }
 }
 
+impl<'tcx> Stable<'tcx> for ty::PredicatePolarity {
+    type T = stable_mir::ty::PredicatePolarity;
+
+    fn stable(&self, _: &mut Tables<'_>) -> Self::T {
+        use rustc_middle::ty::PredicatePolarity::*;
+        match self {
+            Positive => stable_mir::ty::PredicatePolarity::Positive,
+            Negative => stable_mir::ty::PredicatePolarity::Negative,
+        }
+    }
+}
+
 impl<'tcx> Stable<'tcx> for ty::Region<'tcx> {
     type T = stable_mir::ty::Region;
 
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index 527938daae4..37fea6c122c 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -1062,7 +1062,7 @@ pub enum ExpnKind {
     Macro(MacroKind, Symbol),
     /// Transform done by the compiler on the AST.
     AstPass(AstPass),
-    /// Desugaring done by the compiler during HIR lowering.
+    /// Desugaring done by the compiler during AST lowering.
     Desugaring(DesugaringKind),
 }
 
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 8b911a41a11..73fcd2a76df 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -207,6 +207,7 @@ symbols! {
         FromResidual,
         FsOpenOptions,
         FsPermissions,
+        FusedIterator,
         Future,
         FutureOutput,
         GlobalAlloc,
@@ -517,8 +518,6 @@ symbols! {
         cfi,
         cfi_encoding,
         char,
-        check_language_ub,
-        check_library_ub,
         client,
         clippy,
         clobber_abi,
@@ -674,6 +673,7 @@ symbols! {
         deref_method,
         deref_mut,
         deref_mut_method,
+        deref_patterns,
         deref_target,
         derive,
         derive_const,
@@ -689,6 +689,7 @@ symbols! {
         dispatch_from_dyn,
         div,
         div_assign,
+        diverging_block_default,
         do_not_recommend,
         doc,
         doc_alias,
@@ -814,9 +815,7 @@ symbols! {
         fadd_algebraic,
         fadd_fast,
         fake_variadic,
-        fallback_to_never,
-        fallback_to_niko,
-        fallback_to_unit,
+        fallback,
         fdiv_algebraic,
         fdiv_fast,
         feature,
@@ -885,6 +884,7 @@ symbols! {
         fsub_algebraic,
         fsub_fast,
         fundamental,
+        fused_iterator,
         future,
         future_trait,
         gdb_script_file,
@@ -1227,6 +1227,7 @@ symbols! {
         new_v1,
         new_v1_formatted,
         next,
+        niko,
         nll,
         no,
         no_builtins,
@@ -1235,7 +1236,6 @@ symbols! {
         no_crate_inject,
         no_debug,
         no_default_passes,
-        no_fallback,
         no_implicit_prelude,
         no_inline,
         no_link,
@@ -1333,6 +1333,7 @@ symbols! {
         poll,
         poll_next,
         post_dash_lto: "post-lto",
+        postfix_match,
         powerpc_target_feature,
         powf128,
         powf16,
@@ -1553,7 +1554,7 @@ symbols! {
         rustc_mir,
         rustc_must_implement_one_of,
         rustc_never_returns_null_ptr,
-        rustc_never_type_mode,
+        rustc_never_type_options,
         rustc_no_mir_inline,
         rustc_nonnull_optimization_guaranteed,
         rustc_nounwind,
@@ -1833,6 +1834,7 @@ symbols! {
         type_macros,
         type_name,
         type_privacy_lints,
+        typed_swap,
         u128,
         u128_legacy_const_max,
         u128_legacy_const_min,
@@ -1863,6 +1865,7 @@ symbols! {
         u8_legacy_fn_max_value,
         u8_legacy_fn_min_value,
         u8_legacy_mod,
+        ub_checks,
         unaligned_volatile_load,
         unaligned_volatile_store,
         unboxed_closures,
diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs
index 6766080a54f..f0fb87fe83c 100644
--- a/compiler/rustc_symbol_mangling/src/test.rs
+++ b/compiler/rustc_symbol_mangling/src/test.rs
@@ -25,7 +25,7 @@ pub fn report_symbol_names(tcx: TyCtxt<'_>) {
         let mut symbol_names = SymbolNamesTest { tcx };
         let crate_items = tcx.hir_crate_items(());
 
-        for id in crate_items.items() {
+        for id in crate_items.free_items() {
             symbol_names.process_attrs(id.owner_id.def_id);
         }
 
diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
index 51e2c96120c..07a382d161d 100644
--- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
@@ -18,7 +18,7 @@ use rustc_middle::ty::{
 use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgsRef};
 use rustc_span::def_id::DefId;
 use rustc_span::sym;
-use rustc_target::abi::call::{Conv, FnAbi};
+use rustc_target::abi::call::{Conv, FnAbi, PassMode};
 use rustc_target::abi::Integer;
 use rustc_target::spec::abi::Abi;
 use std::fmt::Write as _;
@@ -525,8 +525,8 @@ fn encode_ty<'tcx>(
                 "{}",
                 &len.try_to_scalar()
                     .unwrap()
-                    .to_u64()
-                    .unwrap_or_else(|_| panic!("failed to convert length to u64"))
+                    .to_target_usize(&tcx.data_layout)
+                    .expect("Array lens are defined in usize")
             );
             s.push_str(&encode_ty(tcx, *ty0, dict, options));
             compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
@@ -683,13 +683,14 @@ fn encode_ty<'tcx>(
             typeid.push_str(&s);
         }
 
-        ty::RawPtr(tm) => {
+        ty::RawPtr(ptr_ty, _mutbl) => {
+            // FIXME: This can definitely not be so spaghettified.
             // P[K]<element-type>
             let mut s = String::new();
-            s.push_str(&encode_ty(tcx, tm.ty, dict, options));
+            s.push_str(&encode_ty(tcx, *ptr_ty, dict, options));
             if !ty.is_mutable_ptr() {
                 s = format!("{}{}", "K", &s);
-                compress(dict, DictKey::Ty(tm.ty, TyQ::Const), &mut s);
+                compress(dict, DictKey::Ty(*ptr_ty, TyQ::Const), &mut s);
             };
             s = format!("{}{}", "P", &s);
             compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
@@ -930,7 +931,7 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
             }
         }
 
-        ty::RawPtr(tm) => {
+        ty::RawPtr(ptr_ty, _) => {
             if options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
                 if ty.is_mutable_ptr() {
                     ty = Ty::new_mut_ptr(tcx, Ty::new_unit(tcx));
@@ -939,9 +940,9 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
                 }
             } else {
                 if ty.is_mutable_ptr() {
-                    ty = Ty::new_mut_ptr(tcx, transform_ty(tcx, tm.ty, options));
+                    ty = Ty::new_mut_ptr(tcx, transform_ty(tcx, *ptr_ty, options));
                 } else {
-                    ty = Ty::new_imm_ptr(tcx, transform_ty(tcx, tm.ty, options));
+                    ty = Ty::new_imm_ptr(tcx, transform_ty(tcx, *ptr_ty, options));
                 }
             }
         }
@@ -1040,19 +1041,27 @@ pub fn typeid_for_fnabi<'tcx>(
     typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
 
     // Encode the parameter types
+
+    // We erase ZSTs as we go if the argument is skipped. This is an implementation detail of how
+    // MIR is currently treated by rustc, and subject to change in the future. Specifically, MIR
+    // interpretation today will allow skipped arguments to simply not be passed at a call-site.
     if !fn_abi.c_variadic {
-        if !fn_abi.args.is_empty() {
-            for arg in fn_abi.args.iter() {
-                let ty = transform_ty(tcx, arg.layout.ty, transform_ty_options);
-                typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
-            }
-        } else {
+        let mut pushed_arg = false;
+        for arg in fn_abi.args.iter().filter(|arg| arg.mode != PassMode::Ignore) {
+            pushed_arg = true;
+            let ty = transform_ty(tcx, arg.layout.ty, transform_ty_options);
+            typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
+        }
+        if !pushed_arg {
             // Empty parameter lists, whether declared as () or conventionally as (void), are
             // encoded with a void parameter specifier "v".
             typeid.push('v');
         }
     } else {
         for n in 0..fn_abi.fixed_count as usize {
+            if fn_abi.args[n].mode == PassMode::Ignore {
+                continue;
+            }
             let ty = transform_ty(tcx, fn_abi.args[n].layout.ty, transform_ty_options);
             typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
         }
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 6bc375512ac..4369f020d27 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -361,12 +361,12 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
                 ty.print(self)?;
             }
 
-            ty::RawPtr(mt) => {
-                self.push(match mt.mutbl {
+            ty::RawPtr(ty, mutbl) => {
+                self.push(match mutbl {
                     hir::Mutability::Not => "P",
                     hir::Mutability::Mut => "O",
                 });
-                mt.ty.print(self)?;
+                ty.print(self)?;
             }
 
             ty::Array(ty, len) => {
diff --git a/compiler/rustc_target/src/asm/aarch64.rs b/compiler/rustc_target/src/asm/aarch64.rs
index 97132311a5c..70528c1222c 100644
--- a/compiler/rustc_target/src/asm/aarch64.rs
+++ b/compiler/rustc_target/src/asm/aarch64.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use crate::spec::{RelocModel, Target};
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_macros::HashStable_Generic;
@@ -27,32 +27,28 @@ impl AArch64InlineAsmRegClass {
         None
     }
 
-    pub fn suggest_modifier(
-        self,
-        _arch: InlineAsmArch,
-        ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    pub fn suggest_modifier(self, _arch: InlineAsmArch, ty: InlineAsmType) -> Option<ModifierInfo> {
         match self {
             Self::reg => match ty.size().bits() {
                 64 => None,
-                _ => Some(('w', "w0")),
+                _ => Some(('w', "w0", 32).into()),
             },
             Self::vreg | Self::vreg_low16 => match ty.size().bits() {
-                8 => Some(('b', "b0")),
-                16 => Some(('h', "h0")),
-                32 => Some(('s', "s0")),
-                64 => Some(('d', "d0")),
-                128 => Some(('q', "q0")),
+                8 => Some(('b', "b0", 8).into()),
+                16 => Some(('h', "h0", 16).into()),
+                32 => Some(('s', "s0", 32).into()),
+                64 => Some(('d', "d0", 64).into()),
+                128 => Some(('q', "q0", 128).into()),
                 _ => None,
             },
             Self::preg => None,
         }
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         match self {
-            Self::reg => Some(('x', "x0")),
-            Self::vreg | Self::vreg_low16 => Some(('v', "v0")),
+            Self::reg => Some(('x', "x0", 64).into()),
+            Self::vreg | Self::vreg_low16 => Some(('v', "v0", 128).into()),
             Self::preg => None,
         }
     }
diff --git a/compiler/rustc_target/src/asm/arm.rs b/compiler/rustc_target/src/asm/arm.rs
index 514e30ae020..f56dbac708b 100644
--- a/compiler/rustc_target/src/asm/arm.rs
+++ b/compiler/rustc_target/src/asm/arm.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use crate::spec::{RelocModel, Target};
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_macros::HashStable_Generic;
@@ -35,11 +35,11 @@ impl ArmInlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/avr.rs b/compiler/rustc_target/src/asm/avr.rs
index 9a96a61f5b2..eab38a4a4f4 100644
--- a/compiler/rustc_target/src/asm/avr.rs
+++ b/compiler/rustc_target/src/asm/avr.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 use std::fmt;
@@ -29,11 +29,11 @@ impl AvrInlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/bpf.rs b/compiler/rustc_target/src/asm/bpf.rs
index 3b03766a089..9bc94274675 100644
--- a/compiler/rustc_target/src/asm/bpf.rs
+++ b/compiler/rustc_target/src/asm/bpf.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 use std::fmt;
@@ -23,11 +23,11 @@ impl BpfInlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/csky.rs b/compiler/rustc_target/src/asm/csky.rs
index db3d8106040..64607ee4b81 100644
--- a/compiler/rustc_target/src/asm/csky.rs
+++ b/compiler/rustc_target/src/asm/csky.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 use std::fmt;
@@ -23,11 +23,11 @@ impl CSKYInlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/hexagon.rs b/compiler/rustc_target/src/asm/hexagon.rs
index d20270ac9e9..19da7b80848 100644
--- a/compiler/rustc_target/src/asm/hexagon.rs
+++ b/compiler/rustc_target/src/asm/hexagon.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 use std::fmt;
@@ -22,11 +22,11 @@ impl HexagonInlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/loongarch.rs b/compiler/rustc_target/src/asm/loongarch.rs
index 9d1a4f3eeea..15d0f54ce3b 100644
--- a/compiler/rustc_target/src/asm/loongarch.rs
+++ b/compiler/rustc_target/src/asm/loongarch.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 use std::fmt;
@@ -23,11 +23,11 @@ impl LoongArchInlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/m68k.rs b/compiler/rustc_target/src/asm/m68k.rs
index 8c857550cf2..ac94dcc03dc 100644
--- a/compiler/rustc_target/src/asm/m68k.rs
+++ b/compiler/rustc_target/src/asm/m68k.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 use std::fmt;
@@ -24,11 +24,11 @@ impl M68kInlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/mips.rs b/compiler/rustc_target/src/asm/mips.rs
index 4e7c2eb1bf8..0ac1a43ae18 100644
--- a/compiler/rustc_target/src/asm/mips.rs
+++ b/compiler/rustc_target/src/asm/mips.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 use std::fmt;
@@ -23,11 +23,11 @@ impl MipsInlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index a11884bea26..2e04dca98c5 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -6,6 +6,18 @@ use rustc_span::Symbol;
 use std::fmt;
 use std::str::FromStr;
 
+pub struct ModifierInfo {
+    pub modifier: char,
+    pub result: &'static str,
+    pub size: u64,
+}
+
+impl From<(char, &'static str, u64)> for ModifierInfo {
+    fn from((modifier, result, size): (char, &'static str, u64)) -> Self {
+        Self { modifier, result, size }
+    }
+}
+
 macro_rules! def_reg_class {
     ($arch:ident $arch_regclass:ident {
         $(
@@ -512,11 +524,7 @@ impl InlineAsmRegClass {
     /// Such suggestions are useful if a type smaller than the full register
     /// size is used and a modifier can be used to point to the subregister of
     /// the correct size.
-    pub fn suggest_modifier(
-        self,
-        arch: InlineAsmArch,
-        ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    pub fn suggest_modifier(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<ModifierInfo> {
         match self {
             Self::X86(r) => r.suggest_modifier(arch, ty),
             Self::Arm(r) => r.suggest_modifier(arch, ty),
@@ -545,7 +553,7 @@ impl InlineAsmRegClass {
     /// This is only needed when the register class can suggest a modifier, so
     /// that the user can be shown how to get the default behavior without a
     /// warning.
-    pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, arch: InlineAsmArch) -> Option<ModifierInfo> {
         match self {
             Self::X86(r) => r.default_modifier(arch),
             Self::Arm(r) => r.default_modifier(arch),
diff --git a/compiler/rustc_target/src/asm/msp430.rs b/compiler/rustc_target/src/asm/msp430.rs
index a27d6390a72..439f3ba0b57 100644
--- a/compiler/rustc_target/src/asm/msp430.rs
+++ b/compiler/rustc_target/src/asm/msp430.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 use std::fmt;
@@ -22,11 +22,11 @@ impl Msp430InlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/nvptx.rs b/compiler/rustc_target/src/asm/nvptx.rs
index 8e1e91e7c5f..57aa50fceb8 100644
--- a/compiler/rustc_target/src/asm/nvptx.rs
+++ b/compiler/rustc_target/src/asm/nvptx.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 
@@ -23,11 +23,11 @@ impl NvptxInlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/powerpc.rs b/compiler/rustc_target/src/asm/powerpc.rs
index d3ccb30350a..4e8cbe34de9 100644
--- a/compiler/rustc_target/src/asm/powerpc.rs
+++ b/compiler/rustc_target/src/asm/powerpc.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 use std::fmt;
@@ -26,11 +26,11 @@ impl PowerPCInlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/riscv.rs b/compiler/rustc_target/src/asm/riscv.rs
index dea6d50fe2b..2505d36f5b8 100644
--- a/compiler/rustc_target/src/asm/riscv.rs
+++ b/compiler/rustc_target/src/asm/riscv.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use crate::spec::{RelocModel, Target};
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_macros::HashStable_Generic;
@@ -26,11 +26,11 @@ impl RiscVInlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/s390x.rs b/compiler/rustc_target/src/asm/s390x.rs
index b8afeb824d8..6bc668454b1 100644
--- a/compiler/rustc_target/src/asm/s390x.rs
+++ b/compiler/rustc_target/src/asm/s390x.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 use std::fmt;
@@ -24,11 +24,11 @@ impl S390xInlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/spirv.rs b/compiler/rustc_target/src/asm/spirv.rs
index 31073da10b2..d13a6131f9a 100644
--- a/compiler/rustc_target/src/asm/spirv.rs
+++ b/compiler/rustc_target/src/asm/spirv.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 
@@ -21,11 +21,11 @@ impl SpirVInlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/wasm.rs b/compiler/rustc_target/src/asm/wasm.rs
index f095b7c6e11..eb0b23ef43d 100644
--- a/compiler/rustc_target/src/asm/wasm.rs
+++ b/compiler/rustc_target/src/asm/wasm.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use rustc_macros::HashStable_Generic;
 use rustc_span::Symbol;
 
@@ -21,11 +21,11 @@ impl WasmInlineAsmRegClass {
         self,
         _arch: InlineAsmArch,
         _ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    ) -> Option<ModifierInfo> {
         None
     }
 
-    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> {
         None
     }
 
diff --git a/compiler/rustc_target/src/asm/x86.rs b/compiler/rustc_target/src/asm/x86.rs
index 3902dac7ff6..3b5da8806cc 100644
--- a/compiler/rustc_target/src/asm/x86.rs
+++ b/compiler/rustc_target/src/asm/x86.rs
@@ -1,4 +1,4 @@
-use super::{InlineAsmArch, InlineAsmType};
+use super::{InlineAsmArch, InlineAsmType, ModifierInfo};
 use crate::spec::{RelocModel, Target};
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_macros::HashStable_Generic;
@@ -53,32 +53,28 @@ impl X86InlineAsmRegClass {
         }
     }
 
-    pub fn suggest_modifier(
-        self,
-        arch: InlineAsmArch,
-        ty: InlineAsmType,
-    ) -> Option<(char, &'static str)> {
+    pub fn suggest_modifier(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<ModifierInfo> {
         match self {
             Self::reg => match ty.size().bits() {
-                16 => Some(('x', "ax")),
-                32 if arch == InlineAsmArch::X86_64 => Some(('e', "eax")),
+                16 => Some(('x', "ax", 16).into()),
+                32 if arch == InlineAsmArch::X86_64 => Some(('e', "eax", 32).into()),
                 _ => None,
             },
             Self::reg_abcd => match ty.size().bits() {
-                16 => Some(('x', "ax")),
-                32 if arch == InlineAsmArch::X86_64 => Some(('e', "eax")),
+                16 => Some(('x', "ax", 16).into()),
+                32 if arch == InlineAsmArch::X86_64 => Some(('e', "eax", 32).into()),
                 _ => None,
             },
             Self::reg_byte => None,
             Self::xmm_reg => None,
             Self::ymm_reg => match ty.size().bits() {
                 256 => None,
-                _ => Some(('x', "xmm0")),
+                _ => Some(('x', "xmm0", 128).into()),
             },
             Self::zmm_reg => match ty.size().bits() {
                 512 => None,
-                256 => Some(('y', "ymm0")),
-                _ => Some(('x', "xmm0")),
+                256 => Some(('y', "ymm0", 256).into()),
+                _ => Some(('x', "xmm0", 128).into()),
             },
             Self::kreg | Self::kreg0 => None,
             Self::mmx_reg | Self::x87_reg => None,
@@ -86,19 +82,19 @@ impl X86InlineAsmRegClass {
         }
     }
 
-    pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str)> {
+    pub fn default_modifier(self, arch: InlineAsmArch) -> Option<ModifierInfo> {
         match self {
             Self::reg | Self::reg_abcd => {
                 if arch == InlineAsmArch::X86_64 {
-                    Some(('r', "rax"))
+                    Some(('r', "rax", 64).into())
                 } else {
-                    Some(('e', "eax"))
+                    Some(('e', "eax", 32).into())
                 }
             }
             Self::reg_byte => None,
-            Self::xmm_reg => Some(('x', "xmm0")),
-            Self::ymm_reg => Some(('y', "ymm0")),
-            Self::zmm_reg => Some(('z', "zmm0")),
+            Self::xmm_reg => Some(('x', "xmm0", 128).into()),
+            Self::ymm_reg => Some(('y', "ymm0", 256).into()),
+            Self::zmm_reg => Some(('z', "zmm0", 512).into()),
             Self::kreg | Self::kreg0 => None,
             Self::mmx_reg | Self::x87_reg => None,
             Self::tmm_reg => None,
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 941d767b850..966da2c5eda 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1621,6 +1621,7 @@ supported_targets! {
     ("riscv32i-unknown-none-elf", riscv32i_unknown_none_elf),
     ("riscv32im-risc0-zkvm-elf", riscv32im_risc0_zkvm_elf),
     ("riscv32im-unknown-none-elf", riscv32im_unknown_none_elf),
+    ("riscv32ima-unknown-none-elf", riscv32ima_unknown_none_elf),
     ("riscv32imc-unknown-none-elf", riscv32imc_unknown_none_elf),
     ("riscv32imc-esp-espidf", riscv32imc_esp_espidf),
     ("riscv32imac-esp-espidf", riscv32imac_esp_espidf),
@@ -2091,6 +2092,9 @@ pub struct TargetOptions {
     /// compiling `rustc` will be used instead (or llvm if it is not set).
     ///
     /// N.B. when *using* the compiler, backend can always be overridden with `-Zcodegen-backend`.
+    ///
+    /// This was added by WaffleLapkin in #116793. The motivation is a rustc fork that requires a
+    /// custom codegen backend for a particular target.
     pub default_codegen_backend: Option<StaticCow<str>>,
 
     /// Whether to generate trap instructions in places where optimization would
diff --git a/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs
new file mode 100644
index 00000000000..9acf6a3b5a0
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/riscv32ima_unknown_none_elf.rs
@@ -0,0 +1,29 @@
+use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+
+pub fn target() -> Target {
+    Target {
+        data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
+        llvm_target: "riscv32".into(),
+        metadata: crate::spec::TargetMetadata {
+            description: None,
+            tier: None,
+            host_tools: None,
+            std: None,
+        },
+        pointer_width: 32,
+        arch: "riscv32".into(),
+
+        options: TargetOptions {
+            linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
+            linker: Some("rust-lld".into()),
+            cpu: "generic-rv32".into(),
+            max_atomic_width: Some(32),
+            features: "+m,+a".into(),
+            panic_strategy: PanicStrategy::Abort,
+            relocation_model: RelocModel::Static,
+            emit_debug_gdb_scripts: false,
+            eh_frame_header: false,
+            ..Default::default()
+        },
+    }
+}
diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl
index 0dcba0e05f7..f96bd985237 100644
--- a/compiler/rustc_trait_selection/messages.ftl
+++ b/compiler/rustc_trait_selection/messages.ftl
@@ -19,6 +19,9 @@ trait_selection_closure_kind_mismatch = expected a closure that implements the `
 
 trait_selection_closure_kind_requirement = the requirement to implement `{$trait_prefix}{$expected}` derives from here
 
+trait_selection_disallowed_positional_argument = positional format arguments are not allowed here
+    .help = only named format arguments with the name of one of the generic types are allowed in this context
+
 trait_selection_dump_vtable_entries = vtable entries for `{$trait_ref}`: {$entries}
 
 trait_selection_empty_on_clause_in_rustc_on_unimplemented = empty `on`-clause in `#[rustc_on_unimplemented]`
@@ -30,6 +33,9 @@ trait_selection_ignored_diagnostic_option = `{$option_name}` is ignored due to p
 
 trait_selection_inherent_projection_normalization_overflow = overflow evaluating associated type `{$ty}`
 
+trait_selection_invalid_format_specifier = invalid format specifier
+    .help = no format specifier are supported in this position
+
 trait_selection_invalid_on_clause_in_rustc_on_unimplemented = invalid `on`-clause in `#[rustc_on_unimplemented]`
     .label = invalid on-clause here
 
@@ -60,3 +66,6 @@ trait_selection_unable_to_construct_constant_value = unable to construct a const
 
 trait_selection_unknown_format_parameter_for_on_unimplemented_attr = there is no parameter `{$argument_name}` on trait `{$trait_name}`
     .help = expect either a generic argument name or {"`{Self}`"} as format argument
+
+trait_selection_wrapped_parser_error = {$description}
+    .label = {$label}
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index 9f33dce2a6d..5e580df01cb 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -215,6 +215,13 @@ pub(super) trait GoalKind<'tcx>:
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
 
+    /// A coroutine (that comes from a `gen` desugaring) is known to implement
+    /// `FusedIterator`
+    fn consider_builtin_fused_iterator_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx>;
+
     fn consider_builtin_async_iterator_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
@@ -350,7 +357,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             | ty::Str
             | ty::Array(_, _)
             | ty::Slice(_)
-            | ty::RawPtr(_)
+            | ty::RawPtr(_, _)
             | ty::Ref(_, _, _)
             | ty::FnDef(_, _)
             | ty::FnPtr(_)
@@ -497,6 +504,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             G::consider_builtin_future_candidate(self, goal)
         } else if lang_items.iterator_trait() == Some(trait_def_id) {
             G::consider_builtin_iterator_candidate(self, goal)
+        } else if lang_items.fused_iterator_trait() == Some(trait_def_id) {
+            G::consider_builtin_fused_iterator_candidate(self, goal)
         } else if lang_items.async_iterator_trait() == Some(trait_def_id) {
             G::consider_builtin_async_iterator_candidate(self, goal)
         } else if lang_items.coroutine_trait() == Some(trait_def_id) {
@@ -581,7 +590,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             | ty::Str
             | ty::Array(_, _)
             | ty::Slice(_)
-            | ty::RawPtr(_)
+            | ty::RawPtr(_, _)
             | ty::Ref(_, _, _)
             | ty::FnDef(_, _)
             | ty::FnPtr(_)
@@ -669,7 +678,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             | ty::Str
             | ty::Array(_, _)
             | ty::Slice(_)
-            | ty::RawPtr(_)
+            | ty::RawPtr(_, _)
             | ty::Ref(_, _, _)
             | ty::FnDef(_, _)
             | ty::FnPtr(_)
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
index faf8c55c475..00cd4b48797 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
@@ -6,7 +6,7 @@ use rustc_hir::{def_id::DefId, Movability, Mutability};
 use rustc_infer::traits::query::NoSolution;
 use rustc_middle::traits::solve::Goal;
 use rustc_middle::ty::{
-    self, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
+    self, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
 };
 use rustc_span::sym;
 
@@ -46,7 +46,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
             bug!("unexpected type `{ty}`")
         }
 
-        ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => {
+        ty::RawPtr(element_ty, _) | ty::Ref(_, element_ty, _) => {
             Ok(vec![ty::Binder::dummy(element_ty)])
         }
 
@@ -73,8 +73,8 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
 
         ty::CoroutineWitness(def_id, args) => Ok(ecx
             .tcx()
-            .coroutine_hidden_types(def_id)
-            .map(|bty| replace_erased_lifetimes_with_bound_vars(tcx, bty.instantiate(tcx, args)))
+            .bound_coroutine_hidden_types(def_id)
+            .map(|bty| bty.instantiate(tcx, args))
             .collect()),
 
         // For `PhantomData<T>`, we pass `T`.
@@ -93,27 +93,6 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
     }
 }
 
-pub(in crate::solve) fn replace_erased_lifetimes_with_bound_vars<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    ty: Ty<'tcx>,
-) -> ty::Binder<'tcx, Ty<'tcx>> {
-    debug_assert!(!ty.has_bound_regions());
-    let mut counter = 0;
-    let ty = tcx.fold_regions(ty, |r, current_depth| match r.kind() {
-        ty::ReErased => {
-            let br = ty::BoundRegion { var: ty::BoundVar::from_u32(counter), kind: ty::BrAnon };
-            counter += 1;
-            ty::Region::new_bound(tcx, current_depth, br)
-        }
-        // All free regions should be erased here.
-        r => bug!("unexpected region: {r:?}"),
-    });
-    let bound_vars = tcx.mk_bound_variable_kinds_from_iter(
-        (0..counter).map(|_| ty::BoundVariableKind::Region(ty::BrAnon)),
-    );
-    ty::Binder::bind_with_vars(ty, bound_vars)
-}
-
 #[instrument(level = "debug", skip(ecx), ret)]
 pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
     ecx: &EvalCtxt<'_, 'tcx>,
@@ -241,13 +220,8 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
         // impl Copy/Clone for CoroutineWitness where T: Copy/Clone forall T in coroutine_hidden_types
         ty::CoroutineWitness(def_id, args) => Ok(ecx
             .tcx()
-            .coroutine_hidden_types(def_id)
-            .map(|bty| {
-                replace_erased_lifetimes_with_bound_vars(
-                    ecx.tcx(),
-                    bty.instantiate(ecx.tcx(), args),
-                )
-            })
+            .bound_coroutine_hidden_types(def_id)
+            .map(|bty| bty.instantiate(ecx.tcx(), args))
             .collect()),
     }
 }
@@ -366,7 +340,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
         | ty::Str
         | ty::Array(_, _)
         | ty::Slice(_)
-        | ty::RawPtr(_)
+        | ty::RawPtr(_, _)
         | ty::Ref(_, _, _)
         | ty::Dynamic(_, _, _)
         | ty::Coroutine(_, _)
@@ -553,7 +527,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
         | ty::Str
         | ty::Array(_, _)
         | ty::Slice(_)
-        | ty::RawPtr(_)
+        | ty::RawPtr(_, _)
         | ty::Ref(_, _, _)
         | ty::Dynamic(_, _, _)
         | ty::Coroutine(_, _)
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs
index d60490bce44..439f9eec831 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs
@@ -1,5 +1,5 @@
 //! Computes a normalizes-to (projection) goal for inherent associated types,
-//! `#![feature(inherent_associated_type)]`. Since astconv already determines
+//! `#![feature(inherent_associated_type)]`. Since HIR ty lowering already determines
 //! which impl the IAT is being projected from, we just:
 //! 1. instantiate generic parameters,
 //! 2. equate the self type, and
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
index 85bb6338daf..66688893235 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
@@ -647,6 +647,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
         )
     }
 
+    fn consider_builtin_fused_iterator_candidate(
+        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        bug!("`FusedIterator` does not have an associated type: {:?}", goal);
+    }
+
     fn consider_builtin_async_iterator_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index c252ad76dfe..eb3ad0aa782 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -55,17 +55,23 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         // An upper bound of the certainty of this goal, used to lower the certainty
         // of reservation impl to ambiguous during coherence.
         let impl_polarity = impl_trait_header.polarity;
-        let maximal_certainty = match impl_polarity {
-            ty::ImplPolarity::Positive | ty::ImplPolarity::Negative => {
-                match impl_polarity == goal.predicate.polarity {
-                    true => Certainty::Yes,
-                    false => return Err(NoSolution),
-                }
-            }
-            ty::ImplPolarity::Reservation => match ecx.solver_mode() {
-                SolverMode::Normal => return Err(NoSolution),
+        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),
             },
+
+            // Impl matches polarity
+            (ty::ImplPolarity::Positive, ty::PredicatePolarity::Positive)
+            | (ty::ImplPolarity::Negative, ty::PredicatePolarity::Negative) => Certainty::Yes,
+
+            // Impl doesn't match polarity
+            (ty::ImplPolarity::Positive, ty::PredicatePolarity::Negative)
+            | (ty::ImplPolarity::Negative, ty::PredicatePolarity::Positive) => {
+                return Err(NoSolution);
+            }
         };
 
         ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| {
@@ -123,7 +129,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
-        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+        if goal.predicate.polarity != ty::PredicatePolarity::Positive {
             return Err(NoSolution);
         }
 
@@ -168,7 +174,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
-        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+        if goal.predicate.polarity != ty::PredicatePolarity::Positive {
             return Err(NoSolution);
         }
 
@@ -191,7 +197,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
-        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+        if goal.predicate.polarity != ty::PredicatePolarity::Positive {
             return Err(NoSolution);
         }
 
@@ -205,7 +211,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
-        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+        if goal.predicate.polarity != ty::PredicatePolarity::Positive {
             return Err(NoSolution);
         }
 
@@ -219,7 +225,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
-        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+        if goal.predicate.polarity != ty::PredicatePolarity::Positive {
             return Err(NoSolution);
         }
 
@@ -251,7 +257,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         let self_ty = goal.predicate.self_ty();
         match goal.predicate.polarity {
             // impl FnPtr for FnPtr {}
-            ty::ImplPolarity::Positive => {
+            ty::PredicatePolarity::Positive => {
                 if self_ty.is_fn_ptr() {
                     ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
                 } else {
@@ -259,7 +265,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
                 }
             }
             //  impl !FnPtr for T where T != FnPtr && T is rigid {}
-            ty::ImplPolarity::Negative => {
+            ty::PredicatePolarity::Negative => {
                 // If a type is rigid and not a fn ptr, then we know for certain
                 // that it does *not* implement `FnPtr`.
                 if !self_ty.is_fn_ptr() && self_ty.is_known_rigid() {
@@ -268,10 +274,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
                     Err(NoSolution)
                 }
             }
-            // FIXME: Goal polarity should be split from impl polarity
-            ty::ImplPolarity::Reservation => {
-                bug!("we never expect a `Reservation` polarity in a trait goal")
-            }
         }
     }
 
@@ -280,7 +282,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         goal: Goal<'tcx, Self>,
         goal_kind: ty::ClosureKind,
     ) -> QueryResult<'tcx> {
-        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+        if goal.predicate.polarity != ty::PredicatePolarity::Positive {
             return Err(NoSolution);
         }
 
@@ -316,7 +318,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         goal: Goal<'tcx, Self>,
         goal_kind: ty::ClosureKind,
     ) -> QueryResult<'tcx> {
-        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+        if goal.predicate.polarity != ty::PredicatePolarity::Positive {
             return Err(NoSolution);
         }
 
@@ -386,7 +388,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
-        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+        if goal.predicate.polarity != ty::PredicatePolarity::Positive {
             return Err(NoSolution);
         }
 
@@ -401,7 +403,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
-        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+        if goal.predicate.polarity != ty::PredicatePolarity::Positive {
             return Err(NoSolution);
         }
 
@@ -412,7 +414,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
-        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+        if goal.predicate.polarity != ty::PredicatePolarity::Positive {
             return Err(NoSolution);
         }
 
@@ -436,7 +438,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
-        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+        if goal.predicate.polarity != ty::PredicatePolarity::Positive {
             return Err(NoSolution);
         }
 
@@ -456,11 +458,33 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
     }
 
+    fn consider_builtin_fused_iterator_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        if goal.predicate.polarity != ty::PredicatePolarity::Positive {
+            return Err(NoSolution);
+        }
+
+        let ty::Coroutine(def_id, _) = *goal.predicate.self_ty().kind() else {
+            return Err(NoSolution);
+        };
+
+        // Coroutines are not iterators unless they come from `gen` desugaring
+        let tcx = ecx.tcx();
+        if !tcx.coroutine_is_gen(def_id) {
+            return Err(NoSolution);
+        }
+
+        // Gen coroutines unconditionally implement `FusedIterator`
+        ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+    }
+
     fn consider_builtin_async_iterator_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
-        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+        if goal.predicate.polarity != ty::PredicatePolarity::Positive {
             return Err(NoSolution);
         }
 
@@ -484,7 +508,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
-        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+        if goal.predicate.polarity != ty::PredicatePolarity::Positive {
             return Err(NoSolution);
         }
 
@@ -515,7 +539,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
-        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+        if goal.predicate.polarity != ty::PredicatePolarity::Positive {
             return Err(NoSolution);
         }
 
@@ -527,7 +551,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
-        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+        if goal.predicate.polarity != ty::PredicatePolarity::Positive {
             return Err(NoSolution);
         }
 
@@ -542,7 +566,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
-        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+        if goal.predicate.polarity != ty::PredicatePolarity::Positive {
             return Err(NoSolution);
         }
 
@@ -579,7 +603,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)> {
-        if goal.predicate.polarity != ty::ImplPolarity::Positive {
+        if goal.predicate.polarity != ty::PredicatePolarity::Positive {
             return vec![];
         }
 
@@ -1028,7 +1052,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             | ty::Str
             | ty::Array(_, _)
             | ty::Slice(_)
-            | ty::RawPtr(_)
+            | ty::RawPtr(_, _)
             | ty::Ref(_, _, _)
             | ty::FnDef(_, _)
             | ty::FnPtr(_)
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 0796ffcbc45..c909a0b49e2 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -8,7 +8,7 @@ use crate::infer::region_constraints::{Constraint, RegionConstraintData};
 use crate::traits::project::ProjectAndUnifyResult;
 use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_middle::mir::interpret::ErrorHandled;
-use rustc_middle::ty::{ImplPolarity, Region, RegionVid};
+use rustc_middle::ty::{Region, RegionVid};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
 
@@ -96,9 +96,9 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                 ty::TraitPredicate {
                     trait_ref,
                     polarity: if polarity {
-                        ImplPolarity::Positive
+                        ty::PredicatePolarity::Positive
                     } else {
-                        ImplPolarity::Negative
+                        ty::PredicatePolarity::Negative
                     },
                 },
             ));
@@ -258,7 +258,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
             trait_ref: ty::TraitRef::new(infcx.tcx, trait_did, [ty]),
 
             // Auto traits are positive
-            polarity: ty::ImplPolarity::Positive,
+            polarity: ty::PredicatePolarity::Positive,
         }));
 
         let computed_preds = param_env.caller_bounds().iter().map(|c| c.as_predicate());
@@ -295,7 +295,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                     }) = impl_source
                     {
                         // Blame 'tidy' for the weird bracket placement.
-                        if infcx.tcx.impl_polarity(*impl_def_id) == ty::ImplPolarity::Negative {
+                        if infcx.tcx.impl_polarity(*impl_def_id) != ty::ImplPolarity::Positive {
                             debug!(
                                 "evaluate_nested_obligations: found explicit negative impl\
                                         {:?}, bailing out",
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs
index cbe2ec0f0eb..6c6c8ca1d9f 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs
@@ -206,7 +206,7 @@ impl<'tcx> InferCtxt<'tcx> {
         &self,
         param_env: ty::ParamEnv<'tcx>,
         ty: ty::Binder<'tcx, Ty<'tcx>>,
-        polarity: ty::ImplPolarity,
+        polarity: ty::PredicatePolarity,
     ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()> {
         self.commit_if_ok(|_| {
             for trait_def_id in [
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index 745ddfc08af..5fccc769785 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -367,6 +367,23 @@ pub struct UnknownFormatParameterForOnUnimplementedAttr {
     trait_name: Symbol,
 }
 
+#[derive(LintDiagnostic)]
+#[diag(trait_selection_disallowed_positional_argument)]
+#[help]
+pub struct DisallowedPositionalArgument;
+
+#[derive(LintDiagnostic)]
+#[diag(trait_selection_invalid_format_specifier)]
+#[help]
+pub struct InvalidFormatSpecifier;
+
+#[derive(LintDiagnostic)]
+#[diag(trait_selection_wrapped_parser_error)]
+pub struct WrappedParserError {
+    description: String,
+    label: String,
+}
+
 impl<'tcx> OnUnimplementedDirective {
     fn parse(
         tcx: TyCtxt<'tcx>,
@@ -758,64 +775,108 @@ impl<'tcx> OnUnimplementedFormatString {
         let trait_name = tcx.item_name(trait_def_id);
         let generics = tcx.generics_of(item_def_id);
         let s = self.symbol.as_str();
-        let parser = Parser::new(s, None, None, false, ParseMode::Format);
+        let mut parser = Parser::new(s, None, None, false, ParseMode::Format);
         let mut result = Ok(());
-        for token in parser {
+        for token in &mut parser {
             match token {
                 Piece::String(_) => (), // Normal string, no need to check it
-                Piece::NextArgument(a) => match a.position {
-                    Position::ArgumentNamed(s) => {
-                        match Symbol::intern(s) {
-                            // `{ThisTraitsName}` is allowed
-                            s if s == trait_name && !self.is_diagnostic_namespace_variant => (),
-                            s if ALLOWED_FORMAT_SYMBOLS.contains(&s)
-                                && !self.is_diagnostic_namespace_variant =>
-                            {
-                                ()
-                            }
-                            // So is `{A}` if A is a type parameter
-                            s if generics.params.iter().any(|param| param.name == s) => (),
-                            s => {
-                                if self.is_diagnostic_namespace_variant {
-                                    tcx.emit_node_span_lint(
-                                        UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
-                                        tcx.local_def_id_to_hir_id(item_def_id.expect_local()),
-                                        self.span,
-                                        UnknownFormatParameterForOnUnimplementedAttr {
-                                            argument_name: s,
-                                            trait_name,
-                                        },
-                                    );
-                                } else {
-                                    result = Err(struct_span_code_err!(
-                                        tcx.dcx(),
-                                        self.span,
-                                        E0230,
-                                        "there is no parameter `{}` on {}",
-                                        s,
-                                        if trait_def_id == item_def_id {
-                                            format!("trait `{trait_name}`")
-                                        } else {
-                                            "impl".to_string()
-                                        }
-                                    )
-                                    .emit());
+                Piece::NextArgument(a) => {
+                    let format_spec = a.format;
+                    if self.is_diagnostic_namespace_variant
+                        && (format_spec.ty_span.is_some()
+                            || format_spec.width_span.is_some()
+                            || format_spec.precision_span.is_some()
+                            || format_spec.fill_span.is_some())
+                    {
+                        tcx.emit_node_span_lint(
+                            UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                            tcx.local_def_id_to_hir_id(item_def_id.expect_local()),
+                            self.span,
+                            InvalidFormatSpecifier,
+                        );
+                    }
+                    match a.position {
+                        Position::ArgumentNamed(s) => {
+                            match Symbol::intern(s) {
+                                // `{ThisTraitsName}` is allowed
+                                s if s == trait_name && !self.is_diagnostic_namespace_variant => (),
+                                s if ALLOWED_FORMAT_SYMBOLS.contains(&s)
+                                    && !self.is_diagnostic_namespace_variant =>
+                                {
+                                    ()
+                                }
+                                // So is `{A}` if A is a type parameter
+                                s if generics.params.iter().any(|param| param.name == s) => (),
+                                s => {
+                                    if self.is_diagnostic_namespace_variant {
+                                        tcx.emit_node_span_lint(
+                                            UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                                            tcx.local_def_id_to_hir_id(item_def_id.expect_local()),
+                                            self.span,
+                                            UnknownFormatParameterForOnUnimplementedAttr {
+                                                argument_name: s,
+                                                trait_name,
+                                            },
+                                        );
+                                    } else {
+                                        result = Err(struct_span_code_err!(
+                                            tcx.dcx(),
+                                            self.span,
+                                            E0230,
+                                            "there is no parameter `{}` on {}",
+                                            s,
+                                            if trait_def_id == item_def_id {
+                                                format!("trait `{trait_name}`")
+                                            } else {
+                                                "impl".to_string()
+                                            }
+                                        )
+                                        .emit());
+                                    }
                                 }
                             }
                         }
+                        // `{:1}` and `{}` are not to be used
+                        Position::ArgumentIs(..) | Position::ArgumentImplicitlyIs(_) => {
+                            if self.is_diagnostic_namespace_variant {
+                                tcx.emit_node_span_lint(
+                                    UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                                    tcx.local_def_id_to_hir_id(item_def_id.expect_local()),
+                                    self.span,
+                                    DisallowedPositionalArgument,
+                                );
+                            } else {
+                                let reported = struct_span_code_err!(
+                                    tcx.dcx(),
+                                    self.span,
+                                    E0231,
+                                    "only named generic parameters are allowed"
+                                )
+                                .emit();
+                                result = Err(reported);
+                            }
+                        }
                     }
-                    // `{:1}` and `{}` are not to be used
-                    Position::ArgumentIs(..) | Position::ArgumentImplicitlyIs(_) => {
-                        let reported = struct_span_code_err!(
-                            tcx.dcx(),
-                            self.span,
-                            E0231,
-                            "only named generic parameters are allowed"
-                        )
-                        .emit();
-                        result = Err(reported);
-                    }
-                },
+                }
+            }
+        }
+        // we cannot return errors from processing the format string as hard error here
+        // as the diagnostic namespace gurantees that malformed input cannot cause an error
+        //
+        // if we encounter any error while processing we nevertheless want to show it as warning
+        // so that users are aware that something is not correct
+        for e in parser.errors {
+            if self.is_diagnostic_namespace_variant {
+                tcx.emit_node_span_lint(
+                    UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                    tcx.local_def_id_to_hir_id(item_def_id.expect_local()),
+                    self.span,
+                    WrappedParserError { description: e.description, label: e.label },
+                );
+            } else {
+                let reported =
+                    struct_span_code_err!(tcx.dcx(), self.span, E0231, "{}", e.description,).emit();
+                result = Err(reported);
             }
         }
 
@@ -853,9 +914,9 @@ impl<'tcx> OnUnimplementedFormatString {
         let empty_string = String::new();
 
         let s = self.symbol.as_str();
-        let parser = Parser::new(s, None, None, false, ParseMode::Format);
+        let mut parser = Parser::new(s, None, None, false, ParseMode::Format);
         let item_context = (options.get(&sym::ItemContext)).unwrap_or(&empty_string);
-        parser
+        let constructed_message = (&mut parser)
             .map(|p| match p {
                 Piece::String(s) => s.to_owned(),
                 Piece::NextArgument(a) => match a.position {
@@ -895,9 +956,29 @@ impl<'tcx> OnUnimplementedFormatString {
                             }
                         }
                     }
+                    Position::ArgumentImplicitlyIs(_) if self.is_diagnostic_namespace_variant => {
+                        String::from("{}")
+                    }
+                    Position::ArgumentIs(idx) if self.is_diagnostic_namespace_variant => {
+                        format!("{{{idx}}}")
+                    }
                     _ => bug!("broken on_unimplemented {:?} - bad format arg", self.symbol),
                 },
             })
-            .collect()
+            .collect();
+        // we cannot return errors from processing the format string as hard error here
+        // as the diagnostic namespace gurantees that malformed input cannot cause an error
+        //
+        // if we encounter any error while processing the format string
+        // we don't want to show the potentially half assembled formated string,
+        // therefore we fall back to just showing the input string in this case
+        //
+        // The actual parser errors are emitted earlier
+        // as lint warnings in OnUnimplementedFormatString::verify
+        if self.is_diagnostic_namespace_variant && !parser.errors.is_empty() {
+            String::from(s)
+        } else {
+            constructed_message
+        }
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index d19c2bd1f60..28f4f81e7d8 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -31,8 +31,8 @@ use rustc_middle::traits::IsConstable;
 use rustc_middle::ty::error::TypeError::{self, Sorts};
 use rustc_middle::ty::{
     self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, GenericArgs,
-    InferTy, IsSuggestable, ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder,
-    TypeSuperFoldable, TypeVisitableExt, TypeckResults,
+    InferTy, IsSuggestable, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
+    TypeVisitableExt, TypeckResults,
 };
 use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -245,7 +245,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         associated_ty: Option<(&'static str, Ty<'tcx>)>,
         mut body_id: LocalDefId,
     ) {
-        if trait_pred.skip_binder().polarity == ty::ImplPolarity::Negative {
+        if trait_pred.skip_binder().polarity != ty::PredicatePolarity::Positive {
             return;
         }
 
@@ -482,7 +482,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     if let Some(steps) =
                         autoderef.into_iter().enumerate().find_map(|(steps, (ty, obligations))| {
                             // Re-add the `&`
-                            let ty = Ty::new_ref(self.tcx, region, TypeAndMut { ty, mutbl });
+                            let ty = Ty::new_ref(self.tcx, region, ty, mutbl);
 
                             // Remapping bound vars here
                             let real_trait_pred_and_ty = real_trait_pred
@@ -768,7 +768,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             }
             // Different to previous arm because one is `&hir::Local` and the other
             // is `P<hir::Local>`.
-            hir::Node::Local(local) => get_name(err, &local.pat.kind),
+            hir::Node::LetStmt(local) => get_name(err, &local.pat.kind),
             _ => None,
         }
     }
@@ -930,7 +930,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         let hir::Node::Pat(pat) = self.tcx.hir_node(hir_id) else {
             return;
         };
-        let hir::Node::Local(hir::Local { ty: None, init: Some(init), .. }) =
+        let hir::Node::LetStmt(hir::LetStmt { ty: None, init: Some(init), .. }) =
             self.tcx.parent_hir_node(pat.hir_id)
         else {
             return;
@@ -1098,8 +1098,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         ))
                     }
                     ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
-                        self.tcx.item_bounds(def_id).instantiate(self.tcx, args).iter().find_map(
-                            |pred| {
+                        self.tcx
+                            .item_super_predicates(def_id)
+                            .instantiate(self.tcx, args)
+                            .iter()
+                            .find_map(|pred| {
                                 if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()
                         && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
                         // args tuple will always be args[1]
@@ -1113,8 +1116,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                                 } else {
                                     None
                                 }
-                            },
-                        )
+                            })
                     }
                     ty::Dynamic(data, _, ty::Dyn) => {
                         data.iter().find_map(|pred| {
@@ -1560,7 +1562,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
                 && let Res::Local(hir_id) = path.res
                 && let hir::Node::Pat(binding) = self.tcx.hir_node(hir_id)
-                && let hir::Node::Local(local) = self.tcx.parent_hir_node(binding.hir_id)
+                && let hir::Node::LetStmt(local) = self.tcx.parent_hir_node(binding.hir_id)
                 && let None = local.ty
                 && let Some(binding_expr) = local.init
             {
@@ -2964,7 +2966,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     err.downgrade_to_delayed_bug();
                 }
                 match tcx.parent_hir_node(hir_id) {
-                    Node::Local(hir::Local { ty: Some(ty), .. }) => {
+                    Node::LetStmt(hir::LetStmt { ty: Some(ty), .. }) => {
                         err.span_suggestion_verbose(
                             ty.span.shrink_to_lo(),
                             "consider borrowing here",
@@ -2973,7 +2975,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         );
                         err.note("all local variables must have a statically known size");
                     }
-                    Node::Local(hir::Local {
+                    Node::LetStmt(hir::LetStmt {
                         init: Some(hir::Expr { kind: hir::ExprKind::Index(..), span, .. }),
                         ..
                     }) => {
@@ -3865,7 +3867,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
                 && let hir::Path { res: Res::Local(hir_id), .. } = path
                 && let hir::Node::Pat(binding) = self.tcx.hir_node(*hir_id)
-                && let hir::Node::Local(local) = self.tcx.parent_hir_node(binding.hir_id)
+                && let hir::Node::LetStmt(local) = self.tcx.parent_hir_node(binding.hir_id)
                 && let Some(binding_expr) = local.init
             {
                 // If the expression we're calling on is a binding, we want to point at the
@@ -4055,7 +4057,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                                 span,
                                 [*ty],
                             ),
-                            polarity: ty::ImplPolarity::Positive,
+                            polarity: ty::PredicatePolarity::Positive,
                         });
                         let Some(generics) = node.generics() else {
                             continue;
@@ -4126,7 +4128,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             {
                 let parent = self.tcx.parent_hir_node(binding.hir_id);
                 // We've reached the root of the method call chain...
-                if let hir::Node::Local(local) = parent
+                if let hir::Node::LetStmt(local) = parent
                     && let Some(binding_expr) = local.init
                 {
                     // ...and it is a binding. Get the binding creation and continue the chain.
@@ -4350,7 +4352,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         // Go through all the candidate impls to see if any of them is for
         // slices of `element_ty` with `mutability`.
         let mut is_slice = |candidate: Ty<'tcx>| match *candidate.kind() {
-            ty::RawPtr(ty::TypeAndMut { ty: t, mutbl: m }) | ty::Ref(_, t, m) => {
+            ty::RawPtr(t, m) | ty::Ref(_, t, m) => {
                 if matches!(*t.kind(), ty::Slice(e) if e == element_ty)
                     && m == mutability.unwrap_or(m)
                 {
@@ -4800,7 +4802,7 @@ pub(super) fn get_explanation_based_on_obligation<'tcx>(
             Some(desc) => format!(" {desc}"),
             None => String::new(),
         };
-        if let ty::ImplPolarity::Positive = trait_predicate.polarity() {
+        if let ty::PredicatePolarity::Positive = trait_predicate.polarity() {
             format!(
                 "{pre_message}the trait `{}` is not implemented for{desc} `{}`{post}",
                 trait_predicate.print_modifiers_and_trait_path(),
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
index 4bc3ff92a67..9444cf8248e 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
@@ -1272,7 +1272,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             {
                 let parent = self.tcx.parent_hir_node(binding.hir_id);
                 // We've reached the root of the method call chain...
-                if let hir::Node::Local(local) = parent
+                if let hir::Node::LetStmt(local) = parent
                     && let Some(binding_expr) = local.init
                 {
                     // ...and it is a binding. Get the binding creation and continue the chain.
@@ -1357,7 +1357,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     "using function pointers as const generic parameters is forbidden",
                 )
             }
-            ty::RawPtr(_) => {
+            ty::RawPtr(_, _) => {
                 struct_span_code_err!(
                     self.dcx(),
                     span,
@@ -1809,9 +1809,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         let strip_references = |mut t: Ty<'tcx>| -> Ty<'tcx> {
             loop {
                 match t.kind() {
-                    ty::Ref(_, inner, _) | ty::RawPtr(ty::TypeAndMut { ty: inner, .. }) => {
-                        t = *inner
-                    }
+                    ty::Ref(_, inner, _) | ty::RawPtr(inner, _) => t = *inner,
                     _ => break t,
                 }
             }
@@ -1907,7 +1905,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             .all_impls(trait_pred.def_id())
             .filter_map(|def_id| {
                 let imp = self.tcx.impl_trait_header(def_id).unwrap();
-                if imp.polarity == ty::ImplPolarity::Negative
+                if imp.polarity != ty::ImplPolarity::Positive
                     || !self.tcx.is_user_visible_dep(def_id.krate)
                 {
                     return None;
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index cc8b8f72cf3..c875d3da47e 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -46,7 +46,7 @@ pub use self::coherence::{IsFirstInputType, OrphanCheckErr, OverlapResult};
 pub use self::engine::{ObligationCtxt, TraitEngineExt};
 pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation};
 pub use self::normalize::NormalizeExt;
-pub use self::object_safety::astconv_object_safety_violations;
+pub use self::object_safety::hir_ty_lowering_object_safety_violations;
 pub use self::object_safety::is_vtable_safe_method;
 pub use self::object_safety::object_safety_violations_for_assoc_item;
 pub use self::object_safety::ObjectSafetyViolation;
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 1816b98a636..5e1343b50ce 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -32,11 +32,13 @@ use std::ops::ControlFlow;
 
 pub use crate::traits::{MethodViolationCode, ObjectSafetyViolation};
 
-/// Returns the object safety violations that affect
-/// astconv -- currently, `Self` in supertraits. This is needed
+/// Returns the object safety violations that affect HIR ty lowering.
+///
+/// Currently that is `Self` in supertraits. This is needed
 /// because `object_safety_violations` can't be used during
 /// type collection.
-pub fn astconv_object_safety_violations(
+#[instrument(level = "debug", skip(tcx))]
+pub fn hir_ty_lowering_object_safety_violations(
     tcx: TyCtxt<'_>,
     trait_def_id: DefId,
 ) -> Vec<ObjectSafetyViolation> {
@@ -46,9 +48,7 @@ pub fn astconv_object_safety_violations(
         .filter(|spans| !spans.is_empty())
         .map(ObjectSafetyViolation::SupertraitSelf)
         .collect();
-
-    debug!("astconv_object_safety_violations(trait_def_id={:?}) = {:?}", trait_def_id, violations);
-
+    debug!(?violations);
     violations
 }
 
@@ -584,7 +584,7 @@ fn virtual_call_violations_for_method<'tcx>(
         // implement auto traits if the underlying type does as well.
         if let ty::ClauseKind::Trait(ty::TraitPredicate {
             trait_ref: pred_trait_ref,
-            polarity: ty::ImplPolarity::Positive,
+            polarity: ty::PredicatePolarity::Positive,
         }) = pred.kind().skip_binder()
             && pred_trait_ref.self_ty() == tcx.types.self_param
             && tcx.trait_is_auto(pred_trait_ref.def_id)
diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
index 6c8834f11f1..aaa38d14d6e 100644
--- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
@@ -36,7 +36,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
         | ty::FnPtr(_)
         | ty::Char
         | ty::CoroutineWitness(..)
-        | ty::RawPtr(_)
+        | ty::RawPtr(_, _)
         | ty::Ref(..)
         | ty::Str
         | ty::Foreign(..)
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 49091e53be7..c6ea596b819 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -56,7 +56,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let mut candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
 
         // Negative trait predicates have different rules than positive trait predicates.
-        if obligation.polarity() == ty::ImplPolarity::Negative {
+        if obligation.polarity() == ty::PredicatePolarity::Negative {
             self.assemble_candidates_for_trait_alias(obligation, &mut candidates);
             self.assemble_candidates_from_impls(obligation, &mut candidates);
             self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?;
@@ -118,6 +118,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     self.assemble_future_candidates(obligation, &mut candidates);
                 } else if lang_items.iterator_trait() == Some(def_id) {
                     self.assemble_iterator_candidates(obligation, &mut candidates);
+                } else if lang_items.fused_iterator_trait() == Some(def_id) {
+                    self.assemble_fused_iterator_candidates(obligation, &mut candidates);
                 } else if lang_items.async_iterator_trait() == Some(def_id) {
                     self.assemble_async_iterator_candidates(obligation, &mut candidates);
                 } else if lang_items.async_fn_kind_helper() == Some(def_id) {
@@ -302,14 +304,31 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         candidates: &mut SelectionCandidateSet<'tcx>,
     ) {
         let self_ty = obligation.self_ty().skip_binder();
-        if let ty::Coroutine(did, ..) = self_ty.kind() {
-            // gen constructs get lowered to a special kind of coroutine that
-            // should directly `impl Iterator`.
-            if self.tcx().coroutine_is_gen(*did) {
-                debug!(?self_ty, ?obligation, "assemble_iterator_candidates",);
+        // gen constructs get lowered to a special kind of coroutine that
+        // should directly `impl Iterator`.
+        if let ty::Coroutine(did, ..) = self_ty.kind()
+            && self.tcx().coroutine_is_gen(*did)
+        {
+            debug!(?self_ty, ?obligation, "assemble_iterator_candidates",);
 
-                candidates.vec.push(IteratorCandidate);
-            }
+            candidates.vec.push(IteratorCandidate);
+        }
+    }
+
+    fn assemble_fused_iterator_candidates(
+        &mut self,
+        obligation: &PolyTraitObligation<'tcx>,
+        candidates: &mut SelectionCandidateSet<'tcx>,
+    ) {
+        let self_ty = obligation.self_ty().skip_binder();
+        // gen constructs get lowered to a special kind of coroutine that
+        // should directly `impl FusedIterator`.
+        if let ty::Coroutine(did, ..) = self_ty.kind()
+            && self.tcx().coroutine_is_gen(*did)
+        {
+            debug!(?self_ty, ?obligation, "assemble_fused_iterator_candidates",);
+
+            candidates.vec.push(BuiltinCandidate { has_nested: false });
         }
     }
 
@@ -652,7 +671,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 | ty::Str
                 | ty::Array(_, _)
                 | ty::Slice(_)
-                | ty::RawPtr(_)
+                | ty::RawPtr(_, _)
                 | ty::Ref(_, _, _)
                 | ty::Closure(..)
                 | ty::CoroutineClosure(..)
@@ -786,7 +805,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 | ty::Array(_, _)
                 | ty::Slice(_)
                 | ty::Adt(..)
-                | ty::RawPtr(_)
+                | ty::RawPtr(_, _)
                 | ty::Ref(..)
                 | ty::FnDef(..)
                 | ty::FnPtr(_)
@@ -1167,7 +1186,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             | ty::Infer(ty::IntVar(_))
             | ty::Infer(ty::FloatVar(_))
             | ty::Str
-            | ty::RawPtr(_)
+            | ty::RawPtr(_, _)
             | ty::Ref(..)
             | ty::FnDef(..)
             | ty::FnPtr(_)
@@ -1248,7 +1267,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             | ty::Str
             | ty::Array(_, _)
             | ty::Slice(_)
-            | ty::RawPtr(_)
+            | ty::RawPtr(_, _)
             | ty::Ref(_, _, _)
             | ty::FnDef(_, _)
             | ty::FnPtr(_)
@@ -1311,7 +1330,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             | ty::Str
             | ty::Array(..)
             | ty::Slice(_)
-            | ty::RawPtr(_)
+            | ty::RawPtr(_, _)
             | ty::Ref(..)
             | ty::FnDef(..)
             | ty::Placeholder(..)
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 51fc223a5d1..6f512a1173f 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -14,7 +14,7 @@ use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
 use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData};
 use rustc_middle::ty::{
     self, GenericArgs, GenericArgsRef, GenericParamDefKind, ToPolyTraitRef, ToPredicate,
-    TraitPredicate, Ty, TyCtxt, TypeVisitableExt,
+    TraitPredicate, Ty, TyCtxt,
 };
 use rustc_span::def_id::DefId;
 
@@ -267,6 +267,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 self.copy_clone_conditions(obligation)
             } else if Some(trait_def) == lang_items.clone_trait() {
                 self.copy_clone_conditions(obligation)
+            } else if Some(trait_def) == lang_items.fused_iterator_trait() {
+                self.fused_iterator_conditions(obligation)
             } else {
                 bug!("unexpected builtin trait {:?}", trait_def)
             };
@@ -1262,7 +1264,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
                 // Extract `TailField<T>` and `TailField<U>` from `Struct<T>` and `Struct<U>`,
                 // normalizing in the process, since `type_of` returns something directly from
-                // astconv (which means it's un-normalized).
+                // HIR ty lowering (which means it's un-normalized).
                 let source_tail = normalize_with_depth_to(
                     self,
                     obligation.param_env,
@@ -1411,7 +1413,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 | ty::Infer(ty::IntVar(_))
                 | ty::Infer(ty::FloatVar(_))
                 | ty::Str
-                | ty::RawPtr(_)
+                | ty::RawPtr(_, _)
                 | ty::Ref(..)
                 | ty::FnDef(..)
                 | ty::FnPtr(_)
@@ -1438,10 +1440,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 }
                 ty::CoroutineWitness(def_id, args) => {
                     let tcx = self.tcx();
-                    stack.extend(tcx.coroutine_hidden_types(def_id).map(|bty| {
-                        let ty = bty.instantiate(tcx, args);
-                        debug_assert!(!ty.has_bound_regions());
-                        ty
+                    stack.extend(tcx.bound_coroutine_hidden_types(def_id).map(|bty| {
+                        self.infcx.enter_forall_and_leak_universe(bty.instantiate(tcx, args))
                     }))
                 }
 
@@ -1460,7 +1460,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                 cause.span,
                                 [nested_ty.into(), host_effect_param],
                             ),
-                            polarity: ty::ImplPolarity::Positive,
+                            polarity: ty::PredicatePolarity::Positive,
                         }),
                         &mut nested,
                     );
@@ -1485,7 +1485,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                             cause.span,
                             [nested_ty.into(), host_effect_param],
                         ),
-                        polarity: ty::ImplPolarity::Positive,
+                        polarity: ty::PredicatePolarity::Positive,
                     });
 
                     nested.push(Obligation::with_depth(
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 6460613d7d5..1894fbba302 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -1418,10 +1418,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         for candidate in candidates {
             if let ImplCandidate(def_id) = candidate {
-                if ty::ImplPolarity::Reservation == tcx.impl_polarity(def_id)
-                    || obligation.polarity() == tcx.impl_polarity(def_id)
-                {
-                    result.push(candidate);
+                match (tcx.impl_polarity(def_id), obligation.polarity()) {
+                    (ty::ImplPolarity::Reservation, _)
+                    | (ty::ImplPolarity::Positive, ty::PredicatePolarity::Positive)
+                    | (ty::ImplPolarity::Negative, ty::PredicatePolarity::Negative) => {
+                        result.push(candidate);
+                    }
+                    _ => {}
                 }
             } else {
                 result.push(candidate);
@@ -1617,21 +1620,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 _ => return ControlFlow::Continue(()),
             };
 
-            for bound in
-                self.tcx().item_bounds(alias_ty.def_id).instantiate(self.tcx(), alias_ty.args)
-            {
-                // HACK: On subsequent recursions, we only care about bounds that don't
-                // share the same type as `self_ty`. This is because for truly rigid
-                // projections, we will never be able to equate, e.g. `<T as Tr>::A`
-                // with `<<T as Tr>::A as Tr>::A`.
-                if in_parent_alias_type {
-                    match bound.kind().skip_binder() {
-                        ty::ClauseKind::Trait(tr) if tr.self_ty() == self_ty => continue,
-                        ty::ClauseKind::Projection(p) if p.self_ty() == self_ty => continue,
-                        _ => {}
-                    }
-                }
+            // HACK: On subsequent recursions, we only care about bounds that don't
+            // share the same type as `self_ty`. This is because for truly rigid
+            // projections, we will never be able to equate, e.g. `<T as Tr>::A`
+            // with `<<T as Tr>::A as Tr>::A`.
+            let relevant_bounds = if in_parent_alias_type {
+                self.tcx().item_non_self_assumptions(alias_ty.def_id)
+            } else {
+                self.tcx().item_super_predicates(alias_ty.def_id)
+            };
 
+            for bound in relevant_bounds.instantiate(self.tcx(), alias_ty.args) {
                 for_each(self, bound, idx)?;
                 idx += 1;
             }
@@ -2263,6 +2262,20 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
         }
     }
 
+    fn fused_iterator_conditions(
+        &mut self,
+        obligation: &PolyTraitObligation<'tcx>,
+    ) -> BuiltinImplConditions<'tcx> {
+        let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
+        if let ty::Coroutine(did, ..) = *self_ty.kind()
+            && self.tcx().coroutine_is_gen(did)
+        {
+            BuiltinImplConditions::Where(ty::Binder::dummy(Vec::new()))
+        } else {
+            BuiltinImplConditions::None
+        }
+    }
+
     /// For default impls, we need to break apart a type into its
     /// "constituent types" -- meaning, the types that it contains.
     ///
@@ -2304,9 +2317,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 bug!("asked to assemble constituent types of unexpected type: {:?}", t);
             }
 
-            ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => {
-                t.rebind(vec![element_ty])
-            }
+            ty::RawPtr(element_ty, _) | ty::Ref(_, element_ty, _) => t.rebind(vec![element_ty]),
 
             ty::Array(element_ty, _) | ty::Slice(element_ty) => t.rebind(vec![element_ty]),
 
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
index 95db9e2092f..1aa65b87f0b 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -396,7 +396,7 @@ pub(crate) fn assoc_def(
         // associated type. Normally this situation
         // could only arise through a compiler bug --
         // if the user wrote a bad item name, it
-        // should have failed in astconv.
+        // should have failed during HIR ty lowering.
         bug!(
             "No associated type `{}` for {}",
             tcx.item_name(assoc_def_id),
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 64f02bfd321..7941a8fe95c 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -363,7 +363,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
 
         // Negative trait predicates don't require supertraits to hold, just
         // that their args are WF.
-        if trait_pred.polarity == ty::ImplPolarity::Negative {
+        if trait_pred.polarity == ty::PredicatePolarity::Negative {
             self.compute_negative_trait_pred(trait_ref);
             return;
         }
@@ -687,7 +687,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
                 }
             }
 
-            ty::RawPtr(_) => {
+            ty::RawPtr(_, _) => {
                 // Simple cases that are WF if their type args are WF.
             }
 
diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs
index 9a43d67d435..f6bc224c7e7 100644
--- a/compiler/rustc_transmute/src/layout/tree.rs
+++ b/compiler/rustc_transmute/src/layout/tree.rs
@@ -174,10 +174,10 @@ pub(crate) mod rustc {
     use crate::layout::rustc::{Def, Ref};
 
     use rustc_middle::ty::layout::LayoutError;
-    use rustc_middle::ty::util::Discr;
     use rustc_middle::ty::AdtDef;
     use rustc_middle::ty::GenericArgsRef;
     use rustc_middle::ty::ParamEnv;
+    use rustc_middle::ty::ScalarInt;
     use rustc_middle::ty::VariantDef;
     use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
     use rustc_span::ErrorGuaranteed;
@@ -331,14 +331,15 @@ pub(crate) mod rustc {
                             trace!(?adt_def, "treeifying enum");
                             let mut tree = Tree::uninhabited();
 
-                            for (idx, discr) in adt_def.discriminants(tcx) {
+                            for (idx, variant) in adt_def.variants().iter_enumerated() {
+                                let tag = tcx.tag_for_variant((ty, idx));
                                 tree = tree.or(Self::from_repr_c_variant(
                                     ty,
                                     *adt_def,
                                     args_ref,
                                     &layout_summary,
-                                    Some(discr),
-                                    adt_def.variant(idx),
+                                    tag,
+                                    variant,
                                     tcx,
                                 )?);
                             }
@@ -393,7 +394,7 @@ pub(crate) mod rustc {
             adt_def: AdtDef<'tcx>,
             args_ref: GenericArgsRef<'tcx>,
             layout_summary: &LayoutSummary,
-            discr: Option<Discr<'tcx>>,
+            tag: Option<ScalarInt>,
             variant_def: &'tcx VariantDef,
             tcx: TyCtxt<'tcx>,
         ) -> Result<Self, Err> {
@@ -403,9 +404,6 @@ pub(crate) mod rustc {
             let min_align = repr.align.unwrap_or(Align::ONE);
             let max_align = repr.pack.unwrap_or(Align::MAX);
 
-            let clamp =
-                |align: Align| align.clamp(min_align, max_align).bytes().try_into().unwrap();
-
             let variant_span = trace_span!(
                 "treeifying variant",
                 min_align = ?min_align,
@@ -419,17 +417,12 @@ pub(crate) mod rustc {
             )
             .unwrap();
 
-            // The layout of the variant is prefixed by the discriminant, if any.
-            if let Some(discr) = discr {
-                trace!(?discr, "treeifying discriminant");
-                let discr_layout = alloc::Layout::from_size_align(
-                    layout_summary.discriminant_size,
-                    clamp(layout_summary.discriminant_align),
-                )
-                .unwrap();
-                trace!(?discr_layout, "computed discriminant layout");
-                variant_layout = variant_layout.extend(discr_layout).unwrap().0;
-                tree = tree.then(Self::from_discr(discr, tcx, layout_summary.discriminant_size));
+            // The layout of the variant is prefixed by the tag, if any.
+            if let Some(tag) = tag {
+                let tag_layout =
+                    alloc::Layout::from_size_align(tag.size().bytes_usize(), 1).unwrap();
+                tree = tree.then(Self::from_tag(tag, tcx));
+                variant_layout = variant_layout.extend(tag_layout).unwrap().0;
             }
 
             // Next come fields.
@@ -469,18 +462,19 @@ pub(crate) mod rustc {
             Ok(tree)
         }
 
-        pub fn from_discr(discr: Discr<'tcx>, tcx: TyCtxt<'tcx>, size: usize) -> Self {
+        pub fn from_tag(tag: ScalarInt, tcx: TyCtxt<'tcx>) -> Self {
             use rustc_target::abi::Endian;
-
+            let size = tag.size();
+            let bits = tag.to_bits(size).unwrap();
             let bytes: [u8; 16];
             let bytes = match tcx.data_layout.endian {
                 Endian::Little => {
-                    bytes = discr.val.to_le_bytes();
-                    &bytes[..size]
+                    bytes = bits.to_le_bytes();
+                    &bytes[..size.bytes_usize()]
                 }
                 Endian::Big => {
-                    bytes = discr.val.to_be_bytes();
-                    &bytes[bytes.len() - size..]
+                    bytes = bits.to_be_bytes();
+                    &bytes[bytes.len() - size.bytes_usize()..]
                 }
             };
             Self::Seq(bytes.iter().map(|&b| Self::from_bits(b)).collect())
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index baf4de768c5..af1dfb6f7e9 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -623,7 +623,7 @@ fn fn_abi_new_uncached<'tcx>(
         let is_return = arg_idx.is_none();
         let is_drop_target = is_drop_in_place && arg_idx == Some(0);
         let drop_target_pointee = is_drop_target.then(|| match ty.kind() {
-            ty::RawPtr(ty::TypeAndMut { ty, .. }) => *ty,
+            ty::RawPtr(ty, _) => *ty,
             _ => bug!("argument to drop_in_place is not a raw ptr: {:?}", ty),
         });
 
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index e32179d56d1..9c3d39307b2 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -10,6 +10,7 @@ use rustc_middle::ty::layout::{
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, AdtDef, EarlyBinder, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt};
 use rustc_session::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
+use rustc_span::sym;
 use rustc_span::symbol::Symbol;
 use rustc_target::abi::*;
 
@@ -156,7 +157,7 @@ fn layout_of_uncached<'tcx>(
         ty::Never => tcx.mk_layout(cx.layout_of_never_type()),
 
         // Potentially-wide pointers.
-        ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
+        ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => {
             let mut data_ptr = scalar_unit(Pointer(AddressSpace::DATA));
             if !ty.is_unsafe_ptr() {
                 data_ptr.valid_range_mut().start = 1;
@@ -1007,6 +1008,7 @@ fn variant_info_for_adt<'tcx>(
                     offset: offset.bytes(),
                     size: field_layout.size.bytes(),
                     align: field_layout.align.abi.bytes(),
+                    type_name: None,
                 }
             })
             .collect();
@@ -1090,6 +1092,7 @@ fn variant_info_for_coroutine<'tcx>(
                 offset: offset.bytes(),
                 size: field_layout.size.bytes(),
                 align: field_layout.align.abi.bytes(),
+                type_name: None,
             }
         })
         .collect();
@@ -1104,19 +1107,24 @@ fn variant_info_for_coroutine<'tcx>(
                 .iter()
                 .enumerate()
                 .map(|(field_idx, local)| {
+                    let field_name = coroutine.field_names[*local];
                     let field_layout = variant_layout.field(cx, field_idx);
                     let offset = variant_layout.fields.offset(field_idx);
                     // The struct is as large as the last field's end
                     variant_size = variant_size.max(offset + field_layout.size);
                     FieldInfo {
                         kind: FieldKind::CoroutineLocal,
-                        name: coroutine.field_names[*local].unwrap_or(Symbol::intern(&format!(
+                        name: field_name.unwrap_or(Symbol::intern(&format!(
                             ".coroutine_field{}",
                             local.as_usize()
                         ))),
                         offset: offset.bytes(),
                         size: field_layout.size.bytes(),
                         align: field_layout.align.abi.bytes(),
+                        // Include the type name if there is no field name, or if the name is the
+                        // __awaitee placeholder symbol which means a child future being `.await`ed.
+                        type_name: (field_name.is_none() || field_name == Some(sym::__awaitee))
+                            .then(|| Symbol::intern(&field_layout.ty.to_string())),
                     }
                 })
                 .chain(upvar_fields.iter().copied())
diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs
index b38ef2ad84d..cd199222d90 100644
--- a/compiler/rustc_type_ir/src/flags.rs
+++ b/compiler/rustc_type_ir/src/flags.rs
@@ -85,7 +85,7 @@ bitflags! {
                                           | TypeFlags::HAS_TY_INHERENT.bits()
                                           | TypeFlags::HAS_CT_PROJECTION.bits();
 
-        /// Is an error type/const reachable?
+        /// Is an error type/lifetime/const reachable?
         const HAS_ERROR                   = 1 << 15;
 
         /// Does this have any region that "appears free" in the type?
diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs
index de8f56618d0..5ed73cd94f4 100644
--- a/compiler/rustc_type_ir/src/ty_kind.rs
+++ b/compiler/rustc_type_ir/src/ty_kind.rs
@@ -60,7 +60,7 @@ impl AliasKind {
 /// Defines the kinds of types used by the type system.
 ///
 /// Types written by the user start out as `hir::TyKind` and get
-/// converted to this representation using `AstConv::ast_ty_to_ty`.
+/// converted to this representation using `<dyn HirTyLowerer>::lower_ty`.
 #[cfg_attr(feature = "nightly", rustc_diagnostic_item = "IrTyKind")]
 #[derive(derivative::Derivative)]
 #[derivative(
@@ -112,7 +112,7 @@ pub enum TyKind<I: Interner> {
     Slice(I::Ty),
 
     /// A raw pointer. Written as `*mut T` or `*const T`
-    RawPtr(TypeAndMut<I>),
+    RawPtr(I::Ty, Mutability),
 
     /// A reference; a pointer with an associated lifetime. Written as
     /// `&'a mut T` or `&'a T`.
@@ -270,7 +270,7 @@ const fn tykind_discriminant<I: Interner>(value: &TyKind<I>) -> usize {
         Str => 7,
         Array(_, _) => 8,
         Slice(_) => 9,
-        RawPtr(_) => 10,
+        RawPtr(_, _) => 10,
         Ref(_, _, _) => 11,
         FnDef(_, _) => 12,
         FnPtr(_) => 13,
@@ -308,7 +308,7 @@ impl<I: Interner> PartialEq for TyKind<I> {
             (Foreign(a_d), Foreign(b_d)) => a_d == b_d,
             (Array(a_t, a_c), Array(b_t, b_c)) => a_t == b_t && a_c == b_c,
             (Slice(a_t), Slice(b_t)) => a_t == b_t,
-            (RawPtr(a_t), RawPtr(b_t)) => a_t == b_t,
+            (RawPtr(a_t, a_m), RawPtr(b_t, b_m)) => a_t == b_t && a_m == b_m,
             (Ref(a_r, a_t, a_m), Ref(b_r, b_t, b_m)) => a_r == b_r && a_t == b_t && a_m == b_m,
             (FnDef(a_d, a_s), FnDef(b_d, b_s)) => a_d == b_d && a_s == b_s,
             (FnPtr(a_s), FnPtr(b_s)) => a_s == b_s,
@@ -371,7 +371,7 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
             Str => write!(f, "str"),
             Array(t, c) => write!(f, "[{:?}; {:?}]", &this.wrap(t), &this.wrap(c)),
             Slice(t) => write!(f, "[{:?}]", &this.wrap(t)),
-            RawPtr(TypeAndMut { ty, mutbl }) => {
+            RawPtr(ty, mutbl) => {
                 match mutbl {
                     Mutability::Mut => write!(f, "*mut "),
                     Mutability::Not => write!(f, "*const "),
diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs
index f53dbcfbd96..8ed34fab54d 100644
--- a/compiler/stable_mir/src/compiler_interface.rs
+++ b/compiler/stable_mir/src/compiler_interface.rs
@@ -8,7 +8,7 @@ use std::cell::Cell;
 use crate::abi::{FnAbi, Layout, LayoutShape};
 use crate::mir::alloc::{AllocId, GlobalAlloc};
 use crate::mir::mono::{Instance, InstanceDef, StaticDef};
-use crate::mir::Body;
+use crate::mir::{Body, Place};
 use crate::target::MachineInfo;
 use crate::ty::{
     AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef,
@@ -126,12 +126,15 @@ pub trait Context {
     fn def_ty_with_args(&self, item: DefId, args: &GenericArgs) -> Ty;
 
     /// Returns literal value of a const as a string.
-    fn const_literal(&self, cnst: &Const) -> String;
+    fn const_pretty(&self, cnst: &Const) -> String;
 
     /// `Span` of an item
     fn span_of_an_item(&self, def_id: DefId) -> Span;
 
     /// Obtain the representation of a type.
+    fn ty_pretty(&self, ty: Ty) -> String;
+
+    /// Obtain the representation of a type.
     fn ty_kind(&self, ty: Ty) -> TyKind;
 
     // Get the discriminant Ty for this Ty if there's one.
@@ -205,6 +208,9 @@ pub trait Context {
 
     /// Get the layout shape.
     fn layout_shape(&self, id: Layout) -> LayoutShape;
+
+    /// Get a debug string representation of a place.
+    fn place_pretty(&self, place: &Place) -> String;
 }
 
 // A thread local variable that stores a pointer to the tables mapping between TyCtxt
diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs
index d849c834ae0..d1a2948ea77 100644
--- a/compiler/stable_mir/src/lib.rs
+++ b/compiler/stable_mir/src/lib.rs
@@ -27,7 +27,6 @@ use crate::compiler_interface::with;
 pub use crate::crate_def::CrateDef;
 pub use crate::crate_def::DefId;
 pub use crate::error::*;
-use crate::mir::pretty::function_name;
 use crate::mir::Body;
 use crate::mir::Mutability;
 use crate::ty::{ForeignModuleDef, ImplDef, IndexedVal, Span, TraitDef, Ty};
@@ -148,9 +147,8 @@ impl CrateItem {
         with(|cx| cx.is_foreign_item(self.0))
     }
 
-    pub fn dump<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
-        writeln!(w, "{}", function_name(*self))?;
-        self.body().dump(w)
+    pub fn emit_mir<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
+        self.body().dump(w, &self.name())
     }
 }
 
diff --git a/compiler/stable_mir/src/mir/alloc.rs b/compiler/stable_mir/src/mir/alloc.rs
index 66457933438..408e0bafa58 100644
--- a/compiler/stable_mir/src/mir/alloc.rs
+++ b/compiler/stable_mir/src/mir/alloc.rs
@@ -55,7 +55,7 @@ impl IndexedVal for AllocId {
 /// Utility function used to read an allocation data into a unassigned integer.
 pub(crate) fn read_target_uint(mut bytes: &[u8]) -> Result<u128, Error> {
     let mut buf = [0u8; std::mem::size_of::<u128>()];
-    match MachineInfo::target_endianess() {
+    match MachineInfo::target_endianness() {
         Endian::Little => {
             bytes.read_exact(&mut buf[..bytes.len()])?;
             Ok(u128::from_le_bytes(buf))
@@ -70,7 +70,7 @@ pub(crate) fn read_target_uint(mut bytes: &[u8]) -> Result<u128, Error> {
 /// Utility function used to read an allocation data into an assigned integer.
 pub(crate) fn read_target_int(mut bytes: &[u8]) -> Result<i128, Error> {
     let mut buf = [0u8; std::mem::size_of::<i128>()];
-    match MachineInfo::target_endianess() {
+    match MachineInfo::target_endianness() {
         Endian::Little => {
             bytes.read_exact(&mut buf[..bytes.len()])?;
             Ok(i128::from_le_bytes(buf))
diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs
index ae8e71bb950..7c536a3e914 100644
--- a/compiler/stable_mir/src/mir/body.rs
+++ b/compiler/stable_mir/src/mir/body.rs
@@ -1,10 +1,11 @@
-use crate::mir::pretty::{function_body, pretty_statement, pretty_terminator};
+use crate::mir::pretty::function_body;
 use crate::ty::{
     AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability, Region, RigidTy, Ty, TyKind,
     VariantIdx,
 };
 use crate::{Error, Opaque, Span, Symbol};
 use std::io;
+
 /// The SMIR representation of a single function.
 #[derive(Clone, Debug)]
 pub struct Body {
@@ -90,28 +91,9 @@ impl Body {
         self.locals.iter().enumerate()
     }
 
-    pub fn dump<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
-        writeln!(w, "{}", function_body(self))?;
-        self.blocks
-            .iter()
-            .enumerate()
-            .map(|(index, block)| -> io::Result<()> {
-                writeln!(w, "    bb{}: {{", index)?;
-                let _ = block
-                    .statements
-                    .iter()
-                    .map(|statement| -> io::Result<()> {
-                        writeln!(w, "{}", pretty_statement(&statement.kind))?;
-                        Ok(())
-                    })
-                    .collect::<Vec<_>>();
-                pretty_terminator(&block.terminator.kind, w)?;
-                writeln!(w, "").unwrap();
-                writeln!(w, "    }}").unwrap();
-                Ok(())
-            })
-            .collect::<Result<Vec<_>, _>>()?;
-        Ok(())
+    /// Emit the body using the provided name for the signature.
+    pub fn dump<W: io::Write>(&self, w: &mut W, fn_name: &str) -> io::Result<()> {
+        function_body(w, self, fn_name)
     }
 
     pub fn spread_arg(&self) -> Option<Local> {
@@ -639,7 +621,7 @@ impl Rvalue {
             Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
                 Ok(Ty::usize_ty())
             }
-            Rvalue::NullaryOp(NullOp::UbCheck(_), _) => Ok(Ty::bool_ty()),
+            Rvalue::NullaryOp(NullOp::UbChecks, _) => Ok(Ty::bool_ty()),
             Rvalue::Aggregate(ak, ops) => match *ak {
                 AggregateKind::Array(ty) => Ty::try_new_array(ty, ops.len() as u64),
                 AggregateKind::Tuple => Ok(Ty::new_tuple(
@@ -674,7 +656,7 @@ pub enum Operand {
     Constant(Constant),
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Eq, PartialEq)]
 pub struct Place {
     pub local: Local,
     /// projection out of a place (access a field, deref a pointer, etc)
@@ -1007,13 +989,7 @@ pub enum NullOp {
     /// Returns the offset of a field.
     OffsetOf(Vec<(VariantIdx, FieldIdx)>),
     /// cfg!(debug_assertions), but at codegen time
-    UbCheck(UbKind),
-}
-
-#[derive(Clone, Debug, Eq, PartialEq)]
-pub enum UbKind {
-    LanguageUb,
-    LibraryUb,
+    UbChecks,
 }
 
 impl Operand {
diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs
index 38e5776c48c..aafa89c03e0 100644
--- a/compiler/stable_mir/src/mir/mono.rs
+++ b/compiler/stable_mir/src/mir/mono.rs
@@ -4,6 +4,7 @@ use crate::mir::Body;
 use crate::ty::{Allocation, ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty};
 use crate::{with, CrateItem, DefId, Error, ItemKind, Opaque, Symbol};
 use std::fmt::{Debug, Formatter};
+use std::io;
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
 pub enum MonoItem {
@@ -157,6 +158,11 @@ impl Instance {
     pub fn try_const_eval(&self, const_ty: Ty) -> Result<Allocation, Error> {
         with(|cx| cx.eval_instance(self.def, const_ty))
     }
+
+    /// Emit the body of this instance if it has one.
+    pub fn emit_mir<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
+        if let Some(body) = self.body() { body.dump(w, &self.name()) } else { Ok(()) }
+    }
 }
 
 impl Debug for Instance {
diff --git a/compiler/stable_mir/src/mir/pretty.rs b/compiler/stable_mir/src/mir/pretty.rs
index 8b7b488d312..4ac4833add7 100644
--- a/compiler/stable_mir/src/mir/pretty.rs
+++ b/compiler/stable_mir/src/mir/pretty.rs
@@ -1,185 +1,193 @@
-use crate::crate_def::CrateDef;
-use crate::mir::{Operand, Rvalue, StatementKind, UnwindAction};
-use crate::ty::{DynKind, FloatTy, IntTy, RigidTy, TyKind, UintTy};
-use crate::{with, Body, CrateItem, Mutability};
+use crate::mir::{Operand, Place, Rvalue, StatementKind, UnwindAction, VarDebugInfoContents};
+use crate::ty::{Const, IndexedVal, Ty};
+use crate::{with, Body, Mutability};
+use fmt::{Display, Formatter};
+use std::fmt::Debug;
 use std::io::Write;
-use std::{io, iter};
+use std::{fmt, io, iter};
 
 use super::{AssertMessage, BinOp, TerminatorKind};
 
-pub fn function_name(item: CrateItem) -> String {
-    let mut pretty_name = String::new();
-    let body = item.body();
-    pretty_name.push_str("fn ");
-    pretty_name.push_str(item.name().as_str());
-    if body.arg_locals().is_empty() {
-        pretty_name.push_str("()");
-    } else {
-        pretty_name.push_str("(");
-    }
-    body.arg_locals().iter().enumerate().for_each(|(index, local)| {
-        pretty_name.push_str(format!("_{}: ", index).as_str());
-        pretty_name.push_str(&pretty_ty(local.ty.kind()));
-    });
-    if !body.arg_locals().is_empty() {
-        pretty_name.push_str(")");
+use super::BorrowKind;
+
+impl Display for Ty {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        with(|ctx| write!(f, "{}", ctx.ty_pretty(*self)))
     }
-    let return_local = body.ret_local();
-    pretty_name.push_str(" -> ");
-    pretty_name.push_str(&pretty_ty(return_local.ty.kind()));
-    pretty_name.push_str(" {");
-    pretty_name
 }
 
-pub fn function_body(body: &Body) -> String {
-    let mut pretty_body = String::new();
-    body.inner_locals().iter().enumerate().for_each(|(index, local)| {
-        pretty_body.push_str("    ");
-        pretty_body.push_str(format!("let {}", ret_mutability(&local.mutability)).as_str());
-        pretty_body.push_str(format!("_{}: ", index).as_str());
-        pretty_body.push_str(format!("{}", pretty_ty(local.ty.kind())).as_str());
-        pretty_body.push_str(";\n");
-    });
-    pretty_body.push_str("}");
-    pretty_body
+impl Debug for Place {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        with(|ctx| write!(f, "{}", ctx.place_pretty(self)))
+    }
 }
 
-pub fn ret_mutability(mutability: &Mutability) -> String {
-    match mutability {
-        Mutability::Not => "".to_string(),
-        Mutability::Mut => "mut ".to_string(),
-    }
+pub(crate) fn function_body<W: Write>(writer: &mut W, body: &Body, name: &str) -> io::Result<()> {
+    write!(writer, "fn {}(", name)?;
+    body.arg_locals()
+        .iter()
+        .enumerate()
+        .try_for_each(|(index, local)| write!(writer, "_{}: {}", index + 1, local.ty))?;
+    write!(writer, ")")?;
+
+    let return_local = body.ret_local();
+    writeln!(writer, " -> {} {{", return_local.ty)?;
+
+    body.locals().iter().enumerate().try_for_each(|(index, local)| -> io::Result<()> {
+        if index == 0 || index > body.arg_count {
+            writeln!(writer, "    let {}_{}: {};", pretty_mut(local.mutability), index, local.ty)
+        } else {
+            Ok(())
+        }
+    })?;
+
+    body.var_debug_info.iter().try_for_each(|info| {
+        let content = match &info.value {
+            VarDebugInfoContents::Place(place) => {
+                format!("{place:?}")
+            }
+            VarDebugInfoContents::Const(constant) => pretty_const(&constant.const_),
+        };
+        writeln!(writer, "    debug {} => {};", info.name, content)
+    })?;
+
+    body.blocks
+        .iter()
+        .enumerate()
+        .map(|(index, block)| -> io::Result<()> {
+            writeln!(writer, "    bb{}: {{", index)?;
+            let _ = block
+                .statements
+                .iter()
+                .map(|statement| -> io::Result<()> {
+                    pretty_statement(writer, &statement.kind)?;
+                    Ok(())
+                })
+                .collect::<Vec<_>>();
+            pretty_terminator(writer, &block.terminator.kind)?;
+            writeln!(writer, "    }}").unwrap();
+            Ok(())
+        })
+        .collect::<Result<Vec<_>, _>>()?;
+    writeln!(writer, "}}")?;
+    Ok(())
 }
 
-pub fn pretty_statement(statement: &StatementKind) -> String {
-    let mut pretty = String::new();
+fn pretty_statement<W: Write>(writer: &mut W, statement: &StatementKind) -> io::Result<()> {
     match statement {
         StatementKind::Assign(place, rval) => {
-            pretty.push_str(format!("        _{} = ", place.local).as_str());
-            pretty.push_str(format!("{}", &pretty_rvalue(rval)).as_str());
+            write!(writer, "        {:?} = ", place)?;
+            pretty_rvalue(writer, rval)?;
+            writeln!(writer, ";")
         }
         // FIXME: Add rest of the statements
-        StatementKind::FakeRead(_, _) => {
-            return String::from("StatementKind::FakeRead:Unimplemented");
+        StatementKind::FakeRead(cause, place) => {
+            writeln!(writer, "FakeRead({cause:?}, {place:?});")
         }
-        StatementKind::SetDiscriminant { .. } => {
-            return String::from("StatementKind::SetDiscriminant:Unimplemented");
+        StatementKind::SetDiscriminant { place, variant_index } => {
+            writeln!(writer, "discriminant({place:?} = {};", variant_index.to_index())
         }
-        StatementKind::Deinit(_) => return String::from("StatementKind::Deinit:Unimplemented"),
-        StatementKind::StorageLive(_) => {
-            return String::from("StatementKind::StorageLive:Unimplemented");
+        StatementKind::Deinit(place) => writeln!(writer, "Deinit({place:?};"),
+        StatementKind::StorageLive(local) => {
+            writeln!(writer, "StorageLive(_{local});")
         }
-        StatementKind::StorageDead(_) => {
-            return String::from("StatementKind::StorageDead:Unimplemented");
+        StatementKind::StorageDead(local) => {
+            writeln!(writer, "StorageDead(_{local});")
         }
-        StatementKind::Retag(_, _) => return String::from("StatementKind::Retag:Unimplemented"),
-        StatementKind::PlaceMention(_) => {
-            return String::from("StatementKind::PlaceMention:Unimplemented");
-        }
-        StatementKind::AscribeUserType { .. } => {
-            return String::from("StatementKind::AscribeUserType:Unimplemented");
-        }
-        StatementKind::Coverage(_) => return String::from("StatementKind::Coverage:Unimplemented"),
-        StatementKind::Intrinsic(_) => {
-            return String::from("StatementKind::Intrinsic:Unimplemented");
+        StatementKind::Retag(kind, place) => writeln!(writer, "Retag({kind:?}, {place:?});"),
+        StatementKind::PlaceMention(place) => {
+            writeln!(writer, "PlaceMention({place:?};")
         }
         StatementKind::ConstEvalCounter => {
-            return String::from("StatementKind::ConstEvalCounter:Unimplemented");
+            writeln!(writer, "ConstEvalCounter;")
+        }
+        StatementKind::Nop => writeln!(writer, "nop;"),
+        StatementKind::AscribeUserType { .. }
+        | StatementKind::Coverage(_)
+        | StatementKind::Intrinsic(_) => {
+            // FIX-ME: Make them pretty.
+            writeln!(writer, "{statement:?};")
         }
-        StatementKind::Nop => return String::from("StatementKind::Nop:Unimplemented"),
     }
-    pretty
 }
 
-pub fn pretty_terminator<W: io::Write>(terminator: &TerminatorKind, w: &mut W) -> io::Result<()> {
-    write!(w, "{}", pretty_terminator_head(terminator))?;
+fn pretty_terminator<W: Write>(writer: &mut W, terminator: &TerminatorKind) -> io::Result<()> {
+    pretty_terminator_head(writer, terminator)?;
     let successors = terminator.successors();
     let successor_count = successors.len();
     let labels = pretty_successor_labels(terminator);
 
     let show_unwind = !matches!(terminator.unwind(), None | Some(UnwindAction::Cleanup(_)));
-    let fmt_unwind = |fmt: &mut dyn Write| -> io::Result<()> {
-        write!(fmt, "unwind ")?;
+    let fmt_unwind = |w: &mut W| -> io::Result<()> {
+        write!(w, "unwind ")?;
         match terminator.unwind() {
             None | Some(UnwindAction::Cleanup(_)) => unreachable!(),
-            Some(UnwindAction::Continue) => write!(fmt, "continue"),
-            Some(UnwindAction::Unreachable) => write!(fmt, "unreachable"),
-            Some(UnwindAction::Terminate) => write!(fmt, "terminate"),
+            Some(UnwindAction::Continue) => write!(w, "continue"),
+            Some(UnwindAction::Unreachable) => write!(w, "unreachable"),
+            Some(UnwindAction::Terminate) => write!(w, "terminate"),
         }
     };
 
     match (successor_count, show_unwind) {
-        (0, false) => Ok(()),
+        (0, false) => {}
         (0, true) => {
-            write!(w, " -> ")?;
-            fmt_unwind(w)?;
-            Ok(())
-        }
-        (1, false) => {
-            write!(w, " -> {:?}", successors[0])?;
-            Ok(())
+            write!(writer, " -> ")?;
+            fmt_unwind(writer)?;
         }
+        (1, false) => write!(writer, " -> bb{:?}", successors[0])?,
         _ => {
-            write!(w, " -> [")?;
+            write!(writer, " -> [")?;
             for (i, target) in successors.iter().enumerate() {
                 if i > 0 {
-                    write!(w, ", ")?;
+                    write!(writer, ", ")?;
                 }
-                write!(w, "{}: bb{:?}", labels[i], target)?;
+                write!(writer, "{}: bb{:?}", labels[i], target)?;
             }
             if show_unwind {
-                write!(w, ", ")?;
-                fmt_unwind(w)?;
+                write!(writer, ", ")?;
+                fmt_unwind(writer)?;
             }
-            write!(w, "]")
+            write!(writer, "]")?;
         }
-    }?;
+    };
 
-    Ok(())
+    writeln!(writer, ";")
 }
 
-pub fn pretty_terminator_head(terminator: &TerminatorKind) -> String {
+fn pretty_terminator_head<W: Write>(writer: &mut W, terminator: &TerminatorKind) -> io::Result<()> {
     use self::TerminatorKind::*;
-    let mut pretty = String::new();
+    const INDENT: &'static str = "        ";
     match terminator {
-        Goto { .. } => format!("        goto"),
+        Goto { .. } => write!(writer, "{INDENT}goto"),
         SwitchInt { discr, .. } => {
-            format!("        switchInt(_{})", pretty_operand(discr))
+            write!(writer, "{INDENT}switchInt({})", pretty_operand(discr))
         }
-        Resume => format!("        resume"),
-        Abort => format!("        abort"),
-        Return => format!("        return"),
-        Unreachable => format!("        unreachable"),
-        Drop { place, .. } => format!("        drop(_{:?})", place.local),
+        Resume => write!(writer, "{INDENT}resume"),
+        Abort => write!(writer, "{INDENT}abort"),
+        Return => write!(writer, "{INDENT}return"),
+        Unreachable => write!(writer, "{INDENT}unreachable"),
+        Drop { place, .. } => write!(writer, "{INDENT}drop({:?})", place),
         Call { func, args, destination, .. } => {
-            pretty.push_str("        ");
-            pretty.push_str(format!("_{} = ", destination.local).as_str());
-            pretty.push_str(&pretty_operand(func));
-            pretty.push_str("(");
-            args.iter().enumerate().for_each(|(i, arg)| {
-                if i > 0 {
-                    pretty.push_str(", ");
-                }
-                pretty.push_str(&pretty_operand(arg));
-            });
-            pretty.push_str(")");
-            pretty
+            write!(writer, "{INDENT}{:?} = {}(", destination, pretty_operand(func))?;
+            let mut args_iter = args.iter();
+            args_iter.next().map_or(Ok(()), |arg| write!(writer, "{}", pretty_operand(arg)))?;
+            args_iter.try_for_each(|arg| write!(writer, ", {}", pretty_operand(arg)))?;
+            write!(writer, ")")
         }
         Assert { cond, expected, msg, target: _, unwind: _ } => {
-            pretty.push_str("        assert(");
+            write!(writer, "{INDENT}assert(")?;
             if !expected {
-                pretty.push_str("!");
+                write!(writer, "!")?;
             }
-            pretty.push_str(format!("{} bool),", &pretty_operand(cond)).as_str());
-            pretty.push_str(&pretty_assert_message(msg));
-            pretty.push_str(")");
-            pretty
+            write!(writer, "{}, ", &pretty_operand(cond))?;
+            pretty_assert_message(writer, msg)?;
+            write!(writer, ")")
         }
-        InlineAsm { .. } => todo!(),
+        InlineAsm { .. } => write!(writer, "{INDENT}InlineAsm"),
     }
 }
 
-pub fn pretty_successor_labels(terminator: &TerminatorKind) -> Vec<String> {
+fn pretty_successor_labels(terminator: &TerminatorKind) -> Vec<String> {
     use self::TerminatorKind::*;
     match terminator {
         Resume | Abort | Return | Unreachable => vec![],
@@ -201,283 +209,174 @@ pub fn pretty_successor_labels(terminator: &TerminatorKind) -> Vec<String> {
             vec!["success".into(), "unwind".into()]
         }
         Assert { unwind: _, .. } => vec!["success".into()],
-        InlineAsm { .. } => todo!(),
+        InlineAsm { destination: Some(_), .. } => vec!["goto".into(), "unwind".into()],
+        InlineAsm { destination: None, .. } => vec!["unwind".into()],
     }
 }
 
-pub fn pretty_assert_message(msg: &AssertMessage) -> String {
-    let mut pretty = String::new();
+fn pretty_assert_message<W: Write>(writer: &mut W, msg: &AssertMessage) -> io::Result<()> {
     match msg {
         AssertMessage::BoundsCheck { len, index } => {
             let pretty_len = pretty_operand(len);
             let pretty_index = pretty_operand(index);
-            pretty.push_str(format!("\"index out of bounds: the length is {{}} but the index is {{}}\", {pretty_len}, {pretty_index}").as_str());
-            pretty
+            write!(
+                writer,
+                "\"index out of bounds: the length is {{}} but the index is {{}}\", {pretty_len}, {pretty_index}"
+            )
         }
         AssertMessage::Overflow(BinOp::Add, l, r) => {
             let pretty_l = pretty_operand(l);
             let pretty_r = pretty_operand(r);
-            pretty.push_str(format!("\"attempt to compute `{{}} + {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str());
-            pretty
+            write!(
+                writer,
+                "\"attempt to compute `{{}} + {{}}`, which would overflow\", {pretty_l}, {pretty_r}"
+            )
         }
         AssertMessage::Overflow(BinOp::Sub, l, r) => {
             let pretty_l = pretty_operand(l);
             let pretty_r = pretty_operand(r);
-            pretty.push_str(format!("\"attempt to compute `{{}} - {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str());
-            pretty
+            write!(
+                writer,
+                "\"attempt to compute `{{}} - {{}}`, which would overflow\", {pretty_l}, {pretty_r}"
+            )
         }
         AssertMessage::Overflow(BinOp::Mul, l, r) => {
             let pretty_l = pretty_operand(l);
             let pretty_r = pretty_operand(r);
-            pretty.push_str(format!("\"attempt to compute `{{}} * {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str());
-            pretty
+            write!(
+                writer,
+                "\"attempt to compute `{{}} * {{}}`, which would overflow\", {pretty_l}, {pretty_r}"
+            )
         }
         AssertMessage::Overflow(BinOp::Div, l, r) => {
             let pretty_l = pretty_operand(l);
             let pretty_r = pretty_operand(r);
-            pretty.push_str(format!("\"attempt to compute `{{}} / {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str());
-            pretty
+            write!(
+                writer,
+                "\"attempt to compute `{{}} / {{}}`, which would overflow\", {pretty_l}, {pretty_r}"
+            )
         }
         AssertMessage::Overflow(BinOp::Rem, l, r) => {
             let pretty_l = pretty_operand(l);
             let pretty_r = pretty_operand(r);
-            pretty.push_str(format!("\"attempt to compute `{{}} % {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str());
-            pretty
+            write!(
+                writer,
+                "\"attempt to compute `{{}} % {{}}`, which would overflow\", {pretty_l}, {pretty_r}"
+            )
         }
         AssertMessage::Overflow(BinOp::Shr, _, r) => {
             let pretty_r = pretty_operand(r);
-            pretty.push_str(
-                format!("\"attempt to shift right by `{{}}`, which would overflow\", {pretty_r}")
-                    .as_str(),
-            );
-            pretty
+            write!(writer, "\"attempt to shift right by `{{}}`, which would overflow\", {pretty_r}")
         }
         AssertMessage::Overflow(BinOp::Shl, _, r) => {
             let pretty_r = pretty_operand(r);
-            pretty.push_str(
-                format!("\"attempt to shift left by `{{}}`, which would overflow\", {pretty_r}")
-                    .as_str(),
-            );
-            pretty
+            write!(writer, "\"attempt to shift left by `{{}}`, which would overflow\", {pretty_r}")
         }
         AssertMessage::Overflow(op, _, _) => unreachable!("`{:?}` cannot overflow", op),
         AssertMessage::OverflowNeg(op) => {
             let pretty_op = pretty_operand(op);
-            pretty.push_str(
-                format!("\"attempt to negate `{{}}`, which would overflow\", {pretty_op}").as_str(),
-            );
-            pretty
+            write!(writer, "\"attempt to negate `{{}}`, which would overflow\", {pretty_op}")
         }
         AssertMessage::DivisionByZero(op) => {
             let pretty_op = pretty_operand(op);
-            pretty.push_str(format!("\"attempt to divide `{{}}` by zero\", {pretty_op}").as_str());
-            pretty
+            write!(writer, "\"attempt to divide `{{}}` by zero\", {pretty_op}")
         }
         AssertMessage::RemainderByZero(op) => {
             let pretty_op = pretty_operand(op);
-            pretty.push_str(
-                format!("\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {pretty_op}").as_str(),
-            );
-            pretty
+            write!(
+                writer,
+                "\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {pretty_op}"
+            )
         }
         AssertMessage::MisalignedPointerDereference { required, found } => {
             let pretty_required = pretty_operand(required);
             let pretty_found = pretty_operand(found);
-            pretty.push_str(format!("\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\",{pretty_required}, {pretty_found}").as_str());
-            pretty
+            write!(
+                writer,
+                "\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\",{pretty_required}, {pretty_found}"
+            )
         }
         AssertMessage::ResumedAfterReturn(_) | AssertMessage::ResumedAfterPanic(_) => {
-            msg.description().unwrap().to_string()
+            write!(writer, "{}", msg.description().unwrap())
         }
     }
 }
 
-pub fn pretty_operand(operand: &Operand) -> String {
-    let mut pretty = String::new();
+fn pretty_operand(operand: &Operand) -> String {
     match operand {
         Operand::Copy(copy) => {
-            pretty.push_str("");
-            pretty.push_str(format!("{}", copy.local).as_str());
+            format!("{:?}", copy)
         }
         Operand::Move(mv) => {
-            pretty.push_str("move ");
-            pretty.push_str(format!("_{}", mv.local).as_str());
-        }
-        Operand::Constant(cnst) => {
-            pretty.push_str("const ");
-            pretty.push_str(with(|cx| cx.const_literal(&cnst.literal)).as_str());
+            format!("move {:?}", mv)
         }
+        Operand::Constant(cnst) => pretty_const(&cnst.literal),
     }
-    pretty
 }
 
-pub fn pretty_rvalue(rval: &Rvalue) -> String {
-    let mut pretty = String::new();
+fn pretty_const(literal: &Const) -> String {
+    with(|cx| cx.const_pretty(&literal))
+}
+
+fn pretty_rvalue<W: Write>(writer: &mut W, rval: &Rvalue) -> io::Result<()> {
     match rval {
-        Rvalue::AddressOf(muta, addr) => {
-            pretty.push_str("&raw ");
-            pretty.push_str(&ret_mutability(muta));
-            pretty.push_str(format!("(*_{})", addr.local).as_str());
-        }
-        Rvalue::Aggregate(aggregatekind, operands) => {
-            pretty.push_str(format!("{:#?}", aggregatekind).as_str());
-            pretty.push_str("(");
-            operands.iter().enumerate().for_each(|(i, op)| {
-                pretty.push_str(&pretty_operand(op));
-                if i != operands.len() - 1 {
-                    pretty.push_str(", ");
-                }
-            });
-            pretty.push_str(")");
+        Rvalue::AddressOf(mutability, place) => {
+            write!(writer, "&raw {}(*{:?})", &pretty_mut(*mutability), place)
         }
-        Rvalue::BinaryOp(bin, op, op2) => {
-            pretty.push_str(&pretty_operand(op));
-            pretty.push_str(" ");
-            pretty.push_str(format!("{:#?}", bin).as_str());
-            pretty.push_str(" ");
-            pretty.push_str(&pretty_operand(op2));
+        Rvalue::Aggregate(aggregate_kind, operands) => {
+            // FIXME: Add pretty_aggregate function that returns a pretty string
+            write!(writer, "{aggregate_kind:?} (")?;
+            let mut op_iter = operands.iter();
+            op_iter.next().map_or(Ok(()), |op| write!(writer, "{}", pretty_operand(op)))?;
+            op_iter.try_for_each(|op| write!(writer, ", {}", pretty_operand(op)))?;
+            write!(writer, ")")
+        }
+        Rvalue::BinaryOp(bin, op1, op2) => {
+            write!(writer, "{:?}({}, {})", bin, &pretty_operand(op1), pretty_operand(op2))
         }
         Rvalue::Cast(_, op, ty) => {
-            pretty.push_str(&pretty_operand(op));
-            pretty.push_str(" as ");
-            pretty.push_str(&pretty_ty(ty.kind()));
+            write!(writer, "{} as {}", pretty_operand(op), ty)
         }
         Rvalue::CheckedBinaryOp(bin, op1, op2) => {
-            pretty.push_str(&pretty_operand(op1));
-            pretty.push_str(" ");
-            pretty.push_str(format!("{:#?}", bin).as_str());
-            pretty.push_str(" ");
-            pretty.push_str(&pretty_operand(op2));
+            write!(writer, "Checked{:?}({}, {})", bin, &pretty_operand(op1), pretty_operand(op2))
         }
         Rvalue::CopyForDeref(deref) => {
-            pretty.push_str("CopyForDeref");
-            pretty.push_str(format!("{}", deref.local).as_str());
+            write!(writer, "CopyForDeref({:?})", deref)
         }
         Rvalue::Discriminant(place) => {
-            pretty.push_str("discriminant");
-            pretty.push_str(format!("{}", place.local).as_str());
+            write!(writer, "discriminant({:?})", place)
         }
         Rvalue::Len(len) => {
-            pretty.push_str("len");
-            pretty.push_str(format!("{}", len.local).as_str());
+            write!(writer, "len({:?})", len)
         }
         Rvalue::Ref(_, borrowkind, place) => {
-            pretty.push_str("ref");
-            pretty.push_str(format!("{:#?}", borrowkind).as_str());
-            pretty.push_str(format!("{}", place.local).as_str());
+            let kind = match borrowkind {
+                BorrowKind::Shared => "&",
+                BorrowKind::Fake => "&fake ",
+                BorrowKind::Mut { .. } => "&mut ",
+            };
+            write!(writer, "{kind}{:?}", place)
         }
         Rvalue::Repeat(op, cnst) => {
-            pretty.push_str(&pretty_operand(op));
-            pretty.push_str(" ");
-            pretty.push_str(&pretty_ty(cnst.ty().kind()));
+            write!(writer, "{} \" \" {}", &pretty_operand(op), cnst.ty())
         }
-        Rvalue::ShallowInitBox(_, _) => (),
+        Rvalue::ShallowInitBox(_, _) => Ok(()),
         Rvalue::ThreadLocalRef(item) => {
-            pretty.push_str("thread_local_ref");
-            pretty.push_str(format!("{:#?}", item).as_str());
+            write!(writer, "thread_local_ref{:?}", item)
         }
         Rvalue::NullaryOp(nul, ty) => {
-            pretty.push_str(format!("{:#?}", nul).as_str());
-            pretty.push_str(&pretty_ty(ty.kind()));
-            pretty.push_str(" ");
+            write!(writer, "{:?} {} \" \"", nul, ty)
         }
         Rvalue::UnaryOp(un, op) => {
-            pretty.push_str(&pretty_operand(op));
-            pretty.push_str(" ");
-            pretty.push_str(format!("{:#?}", un).as_str());
+            write!(writer, "{} \" \" {:?}", pretty_operand(op), un)
         }
-        Rvalue::Use(op) => pretty.push_str(&pretty_operand(op)),
+        Rvalue::Use(op) => write!(writer, "{}", pretty_operand(op)),
     }
-    pretty
 }
 
-pub fn pretty_ty(ty: TyKind) -> String {
-    let mut pretty = String::new();
-    match ty {
-        TyKind::RigidTy(rigid_ty) => match rigid_ty {
-            RigidTy::Bool => "bool".to_string(),
-            RigidTy::Char => "char".to_string(),
-            RigidTy::Int(i) => match i {
-                IntTy::Isize => "isize".to_string(),
-                IntTy::I8 => "i8".to_string(),
-                IntTy::I16 => "i16".to_string(),
-                IntTy::I32 => "i32".to_string(),
-                IntTy::I64 => "i64".to_string(),
-                IntTy::I128 => "i128".to_string(),
-            },
-            RigidTy::Uint(u) => match u {
-                UintTy::Usize => "usize".to_string(),
-                UintTy::U8 => "u8".to_string(),
-                UintTy::U16 => "u16".to_string(),
-                UintTy::U32 => "u32".to_string(),
-                UintTy::U64 => "u64".to_string(),
-                UintTy::U128 => "u128".to_string(),
-            },
-            RigidTy::Float(f) => match f {
-                FloatTy::F32 => "f32".to_string(),
-                FloatTy::F64 => "f64".to_string(),
-            },
-            RigidTy::Adt(def, _) => {
-                format!("{:#?}", with(|cx| cx.def_ty(def.0)))
-            }
-            RigidTy::Str => "str".to_string(),
-            RigidTy::Array(ty, len) => {
-                format!("[{}; {}]", pretty_ty(ty.kind()), with(|cx| cx.const_literal(&len)))
-            }
-            RigidTy::Slice(ty) => {
-                format!("[{}]", pretty_ty(ty.kind()))
-            }
-            RigidTy::RawPtr(ty, mutability) => {
-                pretty.push_str("*");
-                match mutability {
-                    Mutability::Not => pretty.push_str("const "),
-                    Mutability::Mut => pretty.push_str("mut "),
-                }
-                pretty.push_str(&pretty_ty(ty.kind()));
-                pretty
-            }
-            RigidTy::Ref(_, ty, mutability) => match mutability {
-                Mutability::Not => format!("&{}", pretty_ty(ty.kind())),
-                Mutability::Mut => format!("&mut {}", pretty_ty(ty.kind())),
-            },
-            RigidTy::FnDef(_, _) => format!("{:#?}", rigid_ty),
-            RigidTy::FnPtr(_) => format!("{:#?}", rigid_ty),
-            RigidTy::Closure(_, _) => format!("{:#?}", rigid_ty),
-            RigidTy::Coroutine(_, _, _) => format!("{:#?}", rigid_ty),
-            RigidTy::Dynamic(data, region, repr) => {
-                // FIXME: Fix binder printing, it looks ugly now
-                pretty.push_str("(");
-                match repr {
-                    DynKind::Dyn => pretty.push_str("dyn "),
-                    DynKind::DynStar => pretty.push_str("dyn* "),
-                }
-                pretty.push_str(format!("{:#?}", data).as_str());
-                pretty.push_str(format!(" +  {:#?} )", region).as_str());
-                pretty
-            }
-            RigidTy::Never => "!".to_string(),
-            RigidTy::Tuple(tuple) => {
-                if tuple.is_empty() {
-                    "()".to_string()
-                } else {
-                    let mut tuple_str = String::new();
-                    tuple_str.push_str("(");
-                    tuple.iter().enumerate().for_each(|(i, ty)| {
-                        tuple_str.push_str(&pretty_ty(ty.kind()));
-                        if i != tuple.len() - 1 {
-                            tuple_str.push_str(", ");
-                        }
-                    });
-                    tuple_str.push_str(")");
-                    tuple_str
-                }
-            }
-            _ => format!("{:#?}", rigid_ty),
-        },
-        TyKind::Alias(_, _) => format!("{:#?}", ty),
-        TyKind::Param(param_ty) => {
-            format!("{:#?}", param_ty.name)
-        }
-        TyKind::Bound(_, _) => format!("{:#?}", ty),
+fn pretty_mut(mutability: Mutability) -> &'static str {
+    match mutability {
+        Mutability::Not => " ",
+        Mutability::Mut => "mut ",
     }
 }
diff --git a/compiler/stable_mir/src/target.rs b/compiler/stable_mir/src/target.rs
index 3a9011a2ffe..e00a418c540 100644
--- a/compiler/stable_mir/src/target.rs
+++ b/compiler/stable_mir/src/target.rs
@@ -14,7 +14,7 @@ impl MachineInfo {
         with(|cx| cx.target_info())
     }
 
-    pub fn target_endianess() -> Endian {
+    pub fn target_endianness() -> Endian {
         with(|cx| cx.target_info().endian)
     }
 
diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs
index a3376752028..21db222095f 100644
--- a/compiler/stable_mir/src/ty.rs
+++ b/compiler/stable_mir/src/ty.rs
@@ -1332,7 +1332,7 @@ pub enum AliasRelationDirection {
 #[derive(Clone, Debug, Eq, PartialEq)]
 pub struct TraitPredicate {
     pub trait_ref: TraitRef,
-    pub polarity: ImplPolarity,
+    pub polarity: PredicatePolarity,
 }
 
 #[derive(Clone, Debug, Eq, PartialEq)]
@@ -1354,6 +1354,12 @@ pub enum ImplPolarity {
     Reservation,
 }
 
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub enum PredicatePolarity {
+    Positive,
+    Negative,
+}
+
 pub trait IndexedVal {
     fn to_val(index: usize) -> Self;
 
diff --git a/config.example.toml b/config.example.toml
index f94553dd63f..b8cdc2ec848 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -915,6 +915,6 @@
 # Available options: fast, balanced, best
 #compression-profile = "fast"
 
-# Copy the linker, DLLs, and various libraries from MinGW into the rustc toolchain.
+# Copy the linker, DLLs, and various libraries from MinGW into the Rust toolchain.
 # Only applies when the host or target is pc-windows-gnu.
 #include-mingw-linker = true
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index e99c6220e20..3875f61efaf 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -72,7 +72,7 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT;
 /// `BTreeMap` that observed the logic error and not result in undefined behavior. This could
 /// include panics, incorrect results, aborts, memory leaks, and non-termination.
 ///
-/// Iterators obtained from functions such as [`BTreeMap::iter`], [`BTreeMap::values`], or
+/// Iterators obtained from functions such as [`BTreeMap::iter`], [`BTreeMap::into_iter`], [`BTreeMap::values`], or
 /// [`BTreeMap::keys`] produce their items in order by key, and take worst-case logarithmic and
 /// amortized constant time per item returned.
 ///
@@ -415,7 +415,7 @@ impl<'a, K: 'a, V: 'a> Default for IterMut<'a, K, V> {
     }
 }
 
-/// An owning iterator over the entries of a `BTreeMap`.
+/// An owning iterator over the entries of a `BTreeMap`, sorted by key.
 ///
 /// This `struct` is created by the [`into_iter`] method on [`BTreeMap`]
 /// (provided by the [`IntoIterator`] trait). See its documentation for more.
@@ -1637,6 +1637,7 @@ impl<K, V, A: Allocator + Clone> IntoIterator for BTreeMap<K, V, A> {
     type Item = (K, V);
     type IntoIter = IntoIter<K, V, A>;
 
+    /// Gets an owning iterator over the entries of the map, sorted by key.
     fn into_iter(self) -> IntoIter<K, V, A> {
         let mut me = ManuallyDrop::new(self);
         if let Some(root) = me.root.take() {
diff --git a/library/alloc/src/collections/btree/navigate.rs b/library/alloc/src/collections/btree/navigate.rs
index a85a3162451..5e6a26f65c4 100644
--- a/library/alloc/src/collections/btree/navigate.rs
+++ b/library/alloc/src/collections/btree/navigate.rs
@@ -655,7 +655,7 @@ impl<BorrowType: marker::BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Lea
 pub enum Position<BorrowType, K, V> {
     Leaf(NodeRef<BorrowType, K, V, marker::Leaf>),
     Internal(NodeRef<BorrowType, K, V, marker::Internal>),
-    InternalKV(Handle<NodeRef<BorrowType, K, V, marker::Internal>, marker::KV>),
+    InternalKV,
 }
 
 impl<'a, K: 'a, V: 'a> NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal> {
@@ -677,7 +677,7 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal>
                             visit(Position::Leaf(leaf));
                             match edge.next_kv() {
                                 Ok(kv) => {
-                                    visit(Position::InternalKV(kv));
+                                    visit(Position::InternalKV);
                                     kv.right_edge()
                                 }
                                 Err(_) => return,
@@ -699,7 +699,7 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal>
         self.visit_nodes_in_order(|pos| match pos {
             Position::Leaf(node) => result += node.len(),
             Position::Internal(node) => result += node.len(),
-            Position::InternalKV(_) => (),
+            Position::InternalKV => (),
         });
         result
     }
diff --git a/library/alloc/src/collections/btree/node/tests.rs b/library/alloc/src/collections/btree/node/tests.rs
index 64bce0ff8c0..d230749d712 100644
--- a/library/alloc/src/collections/btree/node/tests.rs
+++ b/library/alloc/src/collections/btree/node/tests.rs
@@ -32,11 +32,7 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal>
                 result += &format!("\n{}{:?}", indent, leaf.keys());
             }
             navigate::Position::Internal(_) => {}
-            navigate::Position::InternalKV(kv) => {
-                let depth = self.height() - kv.into_node().height();
-                let indent = "  ".repeat(depth);
-                result += &format!("\n{}{:?}", indent, kv.into_kv().0);
-            }
+            navigate::Position::InternalKV => {}
         });
         result
     }
diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs
index ed91ae1a66e..7508ae468ae 100644
--- a/library/alloc/src/collections/btree/set.rs
+++ b/library/alloc/src/collections/btree/set.rs
@@ -27,7 +27,7 @@ use crate::alloc::{Allocator, Global};
 /// `BTreeSet` that observed the logic error and not result in undefined behavior. This could
 /// include panics, incorrect results, aborts, memory leaks, and non-termination.
 ///
-/// Iterators returned by [`BTreeSet::iter`] produce their items in order, and take worst-case
+/// Iterators returned by [`BTreeSet::iter`] and [`BTreeSet::into_iter`] produce their items in order, and take worst-case
 /// logarithmic and amortized constant time per item returned.
 ///
 /// [`Cell`]: core::cell::Cell
@@ -140,7 +140,7 @@ impl<T: fmt::Debug> fmt::Debug for Iter<'_, T> {
     }
 }
 
-/// An owning iterator over the items of a `BTreeSet`.
+/// An owning iterator over the items of a `BTreeSet` in ascending order.
 ///
 /// This `struct` is created by the [`into_iter`] method on [`BTreeSet`]
 /// (provided by the [`IntoIterator`] trait). See its documentation for more.
@@ -1237,7 +1237,7 @@ impl<T, A: Allocator + Clone> IntoIterator for BTreeSet<T, A> {
     type Item = T;
     type IntoIter = IntoIter<T, A>;
 
-    /// Gets an iterator for moving out the `BTreeSet`'s contents.
+    /// Gets an iterator for moving out the `BTreeSet`'s contents in ascending order.
     ///
     /// # Examples
     ///
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 80f0f2acc99..7e3e2fb38b1 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -233,7 +233,7 @@ macro_rules! acquire {
 ///     let val = Arc::clone(&val);
 ///
 ///     thread::spawn(move || {
-///         let v = val.fetch_add(1, Ordering::SeqCst);
+///         let v = val.fetch_add(1, Ordering::Relaxed);
 ///         println!("{v:?}");
 ///     });
 /// }
diff --git a/library/alloc/src/vec/in_place_collect.rs b/library/alloc/src/vec/in_place_collect.rs
index 07eb91c9005..4907a45e881 100644
--- a/library/alloc/src/vec/in_place_collect.rs
+++ b/library/alloc/src/vec/in_place_collect.rs
@@ -229,96 +229,106 @@ where
     I: Iterator<Item = T> + InPlaceCollect,
     <I as SourceIter>::Source: AsVecIntoIter,
 {
-    default fn from_iter(mut iterator: I) -> Self {
-        // See "Layout constraints" section in the module documentation. We rely on const
-        // optimization here since these conditions currently cannot be expressed as trait bounds
-        if const { !in_place_collectible::<T, I::Src>(I::MERGE_BY, I::EXPAND_BY) } {
-            // fallback to more generic implementations
-            return SpecFromIterNested::from_iter(iterator);
-        }
-
-        let (src_buf, src_ptr, src_cap, mut dst_buf, dst_end, dst_cap) = unsafe {
-            let inner = iterator.as_inner().as_into_iter();
-            (
-                inner.buf.as_ptr(),
-                inner.ptr,
-                inner.cap,
-                inner.buf.as_ptr() as *mut T,
-                inner.end as *const T,
-                inner.cap * mem::size_of::<I::Src>() / mem::size_of::<T>(),
-            )
+    default fn from_iter(iterator: I) -> Self {
+        // Select the implementation in const eval to avoid codegen of the dead branch to improve compile times.
+        let fun: fn(I) -> Vec<T> = const {
+            // See "Layout constraints" section in the module documentation. We use const conditions here
+            // since these conditions currently cannot be expressed as trait bounds
+            if in_place_collectible::<T, I::Src>(I::MERGE_BY, I::EXPAND_BY) {
+                from_iter_in_place
+            } else {
+                // fallback
+                SpecFromIterNested::<T, I>::from_iter
+            }
         };
 
-        // SAFETY: `dst_buf` and `dst_end` are the start and end of the buffer.
-        let len = unsafe { SpecInPlaceCollect::collect_in_place(&mut iterator, dst_buf, dst_end) };
+        fun(iterator)
+    }
+}
 
-        let src = unsafe { iterator.as_inner().as_into_iter() };
-        // check if SourceIter contract was upheld
-        // caveat: if they weren't we might not even make it to this point
-        debug_assert_eq!(src_buf, src.buf.as_ptr());
-        // check InPlaceIterable contract. This is only possible if the iterator advanced the
-        // source pointer at all. If it uses unchecked access via TrustedRandomAccess
-        // then the source pointer will stay in its initial position and we can't use it as reference
-        if src.ptr != src_ptr {
-            debug_assert!(
-                unsafe { dst_buf.add(len) as *const _ } <= src.ptr.as_ptr(),
-                "InPlaceIterable contract violation, write pointer advanced beyond read pointer"
-            );
-        }
+fn from_iter_in_place<I, T>(mut iterator: I) -> Vec<T>
+where
+    I: Iterator<Item = T> + InPlaceCollect,
+    <I as SourceIter>::Source: AsVecIntoIter,
+{
+    let (src_buf, src_ptr, src_cap, mut dst_buf, dst_end, dst_cap) = unsafe {
+        let inner = iterator.as_inner().as_into_iter();
+        (
+            inner.buf.as_ptr(),
+            inner.ptr,
+            inner.cap,
+            inner.buf.as_ptr() as *mut T,
+            inner.end as *const T,
+            inner.cap * mem::size_of::<I::Src>() / mem::size_of::<T>(),
+        )
+    };
 
-        // The ownership of the source allocation and the new `T` values is temporarily moved into `dst_guard`.
-        // This is safe because
-        // * `forget_allocation_drop_remaining` immediately forgets the allocation
-        // before any panic can occur in order to avoid any double free, and then proceeds to drop
-        // any remaining values at the tail of the source.
-        // * the shrink either panics without invalidating the allocation, aborts or
-        //   succeeds. In the last case we disarm the guard.
-        //
-        // Note: This access to the source wouldn't be allowed by the TrustedRandomIteratorNoCoerce
-        // contract (used by SpecInPlaceCollect below). But see the "O(1) collect" section in the
-        // module documentation why this is ok anyway.
-        let dst_guard =
-            InPlaceDstDataSrcBufDrop { ptr: dst_buf, len, src_cap, src: PhantomData::<I::Src> };
-        src.forget_allocation_drop_remaining();
+    // SAFETY: `dst_buf` and `dst_end` are the start and end of the buffer.
+    let len = unsafe { SpecInPlaceCollect::collect_in_place(&mut iterator, dst_buf, dst_end) };
 
-        // Adjust the allocation if the source had a capacity in bytes that wasn't a multiple
-        // of the destination type size.
-        // Since the discrepancy should generally be small this should only result in some
-        // bookkeeping updates and no memmove.
-        if needs_realloc::<I::Src, T>(src_cap, dst_cap) {
-            let alloc = Global;
-            debug_assert_ne!(src_cap, 0);
-            debug_assert_ne!(dst_cap, 0);
-            unsafe {
-                // The old allocation exists, therefore it must have a valid layout.
-                let src_align = mem::align_of::<I::Src>();
-                let src_size = mem::size_of::<I::Src>().unchecked_mul(src_cap);
-                let old_layout = Layout::from_size_align_unchecked(src_size, src_align);
+    let src = unsafe { iterator.as_inner().as_into_iter() };
+    // check if SourceIter contract was upheld
+    // caveat: if they weren't we might not even make it to this point
+    debug_assert_eq!(src_buf, src.buf.as_ptr());
+    // check InPlaceIterable contract. This is only possible if the iterator advanced the
+    // source pointer at all. If it uses unchecked access via TrustedRandomAccess
+    // then the source pointer will stay in its initial position and we can't use it as reference
+    if src.ptr != src_ptr {
+        debug_assert!(
+            unsafe { dst_buf.add(len) as *const _ } <= src.ptr.as_ptr(),
+            "InPlaceIterable contract violation, write pointer advanced beyond read pointer"
+        );
+    }
 
-                // The allocation must be equal or smaller for in-place iteration to be possible
-                // therefore the new layout must be ≤ the old one and therefore valid.
-                let dst_align = mem::align_of::<T>();
-                let dst_size = mem::size_of::<T>().unchecked_mul(dst_cap);
-                let new_layout = Layout::from_size_align_unchecked(dst_size, dst_align);
+    // The ownership of the source allocation and the new `T` values is temporarily moved into `dst_guard`.
+    // This is safe because
+    // * `forget_allocation_drop_remaining` immediately forgets the allocation
+    // before any panic can occur in order to avoid any double free, and then proceeds to drop
+    // any remaining values at the tail of the source.
+    // * the shrink either panics without invalidating the allocation, aborts or
+    //   succeeds. In the last case we disarm the guard.
+    //
+    // Note: This access to the source wouldn't be allowed by the TrustedRandomIteratorNoCoerce
+    // contract (used by SpecInPlaceCollect below). But see the "O(1) collect" section in the
+    // module documentation why this is ok anyway.
+    let dst_guard =
+        InPlaceDstDataSrcBufDrop { ptr: dst_buf, len, src_cap, src: PhantomData::<I::Src> };
+    src.forget_allocation_drop_remaining();
 
-                let result = alloc.shrink(
-                    NonNull::new_unchecked(dst_buf as *mut u8),
-                    old_layout,
-                    new_layout,
-                );
-                let Ok(reallocated) = result else { handle_alloc_error(new_layout) };
-                dst_buf = reallocated.as_ptr() as *mut T;
-            }
-        } else {
-            debug_assert_eq!(src_cap * mem::size_of::<I::Src>(), dst_cap * mem::size_of::<T>());
+    // Adjust the allocation if the source had a capacity in bytes that wasn't a multiple
+    // of the destination type size.
+    // Since the discrepancy should generally be small this should only result in some
+    // bookkeeping updates and no memmove.
+    if needs_realloc::<I::Src, T>(src_cap, dst_cap) {
+        let alloc = Global;
+        debug_assert_ne!(src_cap, 0);
+        debug_assert_ne!(dst_cap, 0);
+        unsafe {
+            // The old allocation exists, therefore it must have a valid layout.
+            let src_align = mem::align_of::<I::Src>();
+            let src_size = mem::size_of::<I::Src>().unchecked_mul(src_cap);
+            let old_layout = Layout::from_size_align_unchecked(src_size, src_align);
+
+            // The allocation must be equal or smaller for in-place iteration to be possible
+            // therefore the new layout must be ≤ the old one and therefore valid.
+            let dst_align = mem::align_of::<T>();
+            let dst_size = mem::size_of::<T>().unchecked_mul(dst_cap);
+            let new_layout = Layout::from_size_align_unchecked(dst_size, dst_align);
+
+            let result =
+                alloc.shrink(NonNull::new_unchecked(dst_buf as *mut u8), old_layout, new_layout);
+            let Ok(reallocated) = result else { handle_alloc_error(new_layout) };
+            dst_buf = reallocated.as_ptr() as *mut T;
         }
+    } else {
+        debug_assert_eq!(src_cap * mem::size_of::<I::Src>(), dst_cap * mem::size_of::<T>());
+    }
 
-        mem::forget(dst_guard);
+    mem::forget(dst_guard);
 
-        let vec = unsafe { Vec::from_raw_parts(dst_buf, len, dst_cap) };
+    let vec = unsafe { Vec::from_raw_parts(dst_buf, len, dst_cap) };
 
-        vec
-    }
+    vec
 }
 
 fn write_in_place_with_drop<T>(
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index db56b8d07c7..94bed825bb2 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -1541,6 +1541,9 @@ impl<T, A: Allocator> Vec<T, A> {
         }
 
         let len = self.len();
+        if index > len {
+            assert_failed(index, len);
+        }
 
         // space for the new element
         if len == self.buf.capacity() {
@@ -1556,10 +1559,6 @@ impl<T, A: Allocator> Vec<T, A> {
                     // Shift everything over to make space. (Duplicating the
                     // `index`th element into two consecutive places.)
                     ptr::copy(p, p.add(1), len - index);
-                } else if index == len {
-                    // No elements need shifting.
-                } else {
-                    assert_failed(index, len);
                 }
                 // Write it in, overwriting the first copy of the `index`th
                 // element.
diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs
index aa95b4e9770..f1f841fe190 100644
--- a/library/alloc/tests/vec.rs
+++ b/library/alloc/tests/vec.rs
@@ -2643,3 +2643,44 @@ fn test_vec_from_array_ref() {
 fn test_vec_from_array_mut_ref() {
     assert_eq!(Vec::from(&mut [1, 2, 3]), vec![1, 2, 3]);
 }
+
+/// This assortment of tests, in combination with miri, verifies we handle UB on fishy arguments
+/// in the stdlib. Draining and extending the allocation are fairly well-tested earlier, but
+/// `vec.insert(usize::MAX, val)` once slipped by!
+///
+/// All code that manipulates the collection types should be tested with "trivially wrong" args.
+#[test]
+fn max_dont_panic() {
+    let mut v = vec![0];
+    let _ = v.get(usize::MAX);
+    v.shrink_to(usize::MAX);
+    v.truncate(usize::MAX);
+}
+
+#[test]
+#[should_panic]
+fn max_insert() {
+    let mut v = vec![0];
+    v.insert(usize::MAX, 1);
+}
+
+#[test]
+#[should_panic]
+fn max_remove() {
+    let mut v = vec![0];
+    v.remove(usize::MAX);
+}
+
+#[test]
+#[should_panic]
+fn max_splice() {
+    let mut v = vec![0];
+    v.splice(usize::MAX.., core::iter::once(1));
+}
+
+#[test]
+#[should_panic]
+fn max_swap_remove() {
+    let mut v = vec![0];
+    v.swap_remove(usize::MAX);
+}
diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs
index a1fff6707bd..8df3ace54ff 100644
--- a/library/core/src/alloc/global.rs
+++ b/library/core/src/alloc/global.rs
@@ -24,10 +24,7 @@ use crate::ptr;
 /// use std::alloc::{GlobalAlloc, Layout};
 /// use std::cell::UnsafeCell;
 /// use std::ptr::null_mut;
-/// use std::sync::atomic::{
-///     AtomicUsize,
-///     Ordering::{Acquire, SeqCst},
-/// };
+/// use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
 ///
 /// const ARENA_SIZE: usize = 128 * 1024;
 /// const MAX_SUPPORTED_ALIGN: usize = 4096;
@@ -61,7 +58,7 @@ use crate::ptr;
 ///         let mut allocated = 0;
 ///         if self
 ///             .remaining
-///             .fetch_update(SeqCst, SeqCst, |mut remaining| {
+///             .fetch_update(Relaxed, Relaxed, |mut remaining| {
 ///                 if size > remaining {
 ///                     return None;
 ///                 }
@@ -81,7 +78,7 @@ use crate::ptr;
 ///
 /// fn main() {
 ///     let _s = format!("allocating a string!");
-///     let currently = ALLOCATOR.remaining.load(Acquire);
+///     let currently = ALLOCATOR.remaining.load(Relaxed);
 ///     println!("allocated so far: {}", ARENA_SIZE - currently);
 /// }
 /// ```
diff --git a/library/core/src/char/convert.rs b/library/core/src/char/convert.rs
index 70b9e89f9ea..8f612929110 100644
--- a/library/core/src/char/convert.rs
+++ b/library/core/src/char/convert.rs
@@ -4,9 +4,9 @@ use crate::char::TryFromCharError;
 use crate::convert::TryFrom;
 use crate::error::Error;
 use crate::fmt;
-use crate::intrinsics::assert_unsafe_precondition;
 use crate::mem::transmute;
 use crate::str::FromStr;
+use crate::ub_checks::assert_unsafe_precondition;
 
 /// Converts a `u32` to a `char`. See [`char::from_u32`].
 #[must_use]
diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs
index ffe059bf65c..b27d0db4619 100644
--- a/library/core/src/hint.rs
+++ b/library/core/src/hint.rs
@@ -4,6 +4,7 @@
 //! Hints may be compile time or runtime.
 
 use crate::intrinsics;
+use crate::ub_checks;
 
 /// Informs the compiler that the site which is calling this function is not
 /// reachable, possibly enabling further optimizations.
@@ -98,7 +99,7 @@ use crate::intrinsics;
 #[rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0")]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 pub const unsafe fn unreachable_unchecked() -> ! {
-    intrinsics::assert_unsafe_precondition!(
+    ub_checks::assert_unsafe_precondition!(
         check_language_ub,
         "hint::unreachable_unchecked must never be reached",
         () => false
@@ -148,7 +149,7 @@ pub const unsafe fn unreachable_unchecked() -> ! {
 pub const unsafe fn assert_unchecked(cond: bool) {
     // SAFETY: The caller promised `cond` is true.
     unsafe {
-        intrinsics::assert_unsafe_precondition!(
+        ub_checks::assert_unsafe_precondition!(
             check_language_ub,
             "hint::assert_unchecked must never be called when the condition is false",
             (cond: bool = cond) => cond,
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 613d0ab212a..dec31548fc8 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -66,6 +66,8 @@
 use crate::marker::DiscriminantKind;
 use crate::marker::Tuple;
 use crate::mem::align_of;
+use crate::ptr;
+use crate::ub_checks;
 
 pub mod mir;
 pub mod simd;
@@ -1163,14 +1165,6 @@ extern "rust-intrinsic" {
     /// may lead to unexpected and unstable compilation results. This makes `transmute` **incredibly
     /// unsafe**. `transmute` should be the absolute last resort.
     ///
-    /// Transmuting pointers *to* integers in a `const` context is [undefined behavior][ub],
-    /// unless the pointer was originally created *from* an integer.
-    /// (That includes this function specifically, integer-to-pointer casts, and helpers like [`invalid`][crate::ptr::dangling],
-    /// but also semantically-equivalent conversions such as punning through `repr(C)` union fields.)
-    /// Any attempt to use the resulting value for integer operations will abort const-evaluation.
-    /// (And even outside `const`, such transmutation is touching on many unspecified aspects of the
-    /// Rust memory model and should be avoided. See below for alternatives.)
-    ///
     /// Because `transmute` is a by-value operation, alignment of the *transmuted values
     /// themselves* is not a concern. As with any other function, the compiler already ensures
     /// both `Src` and `Dst` are properly aligned. However, when transmuting values that *point
@@ -1181,6 +1175,39 @@ extern "rust-intrinsic" {
     ///
     /// [ub]: ../../reference/behavior-considered-undefined.html
     ///
+    /// # Transmutation between pointers and integers
+    ///
+    /// Special care has to be taken when transmuting between pointers and integers, e.g.
+    /// transmuting between `*const ()` and `usize`.
+    ///
+    /// Transmuting *pointers to integers* in a `const` context is [undefined behavior][ub], unless
+    /// the pointer was originally created *from* an integer. (That includes this function
+    /// specifically, integer-to-pointer casts, and helpers like [`dangling`][crate::ptr::dangling],
+    /// but also semantically-equivalent conversions such as punning through `repr(C)` union
+    /// fields.) Any attempt to use the resulting value for integer operations will abort
+    /// const-evaluation. (And even outside `const`, such transmutation is touching on many
+    /// unspecified aspects of the Rust memory model and should be avoided. See below for
+    /// alternatives.)
+    ///
+    /// Transmuting *integers to pointers* is a largely unspecified operation. It is likely *not*
+    /// equivalent to an `as` cast. Doing non-zero-sized memory accesses with a pointer constructed
+    /// this way is currently considered undefined behavior.
+    ///
+    /// All this also applies when the integer is nested inside an array, tuple, struct, or enum.
+    /// However, `MaybeUninit<usize>` is not considered an integer type for the purpose of this
+    /// section. Transmuting `*const ()` to `MaybeUninit<usize>` is fine---but then calling
+    /// `assume_init()` on that result is considered as completing the pointer-to-integer transmute
+    /// and thus runs into the issues discussed above.
+    ///
+    /// In particular, doing a pointer-to-integer-to-pointer roundtrip via `transmute` is *not* a
+    /// lossless process. If you want to round-trip a pointer through an integer in a way that you
+    /// can get back the original pointer, you need to use `as` casts, or replace the integer type
+    /// by `MaybeUninit<$int>` (and never call `assume_init()`). If you are looking for a way to
+    /// store data of arbitrary type, also use `MaybeUninit<T>` (that will also handle uninitialized
+    /// memory due to padding). If you specifically need to store something that is "either an
+    /// integer or a pointer", use `*mut ()`: integers can be converted to pointers and back without
+    /// any loss (via `as` casts or via `transmute`).
+    ///
     /// # Examples
     ///
     /// There are a few things that `transmute` is really useful for.
@@ -2638,38 +2665,43 @@ pub const fn is_val_statically_known<T: Copy>(_arg: T) -> bool {
     false
 }
 
-/// Returns whether we should check for library UB. This evaluate to the value of `cfg!(debug_assertions)`
-/// during monomorphization.
+/// Non-overlapping *typed* swap of a single value.
 ///
-/// This intrinsic is evaluated after monomorphization, and therefore branching on this value can
-/// be used to implement debug assertions that are included in the precompiled standard library,
-/// but can be optimized out by builds that monomorphize the standard library code with debug
-/// assertions disabled. This intrinsic is primarily used by [`assert_unsafe_precondition`].
+/// The codegen backends will replace this with a better implementation when
+/// `T` is a simple type that can be loaded and stored as an immediate.
 ///
-/// We have separate intrinsics for library UB and language UB because checkers like the const-eval
-/// interpreter and Miri already implement checks for language UB. Since such checkers do not know
-/// about library preconditions, checks guarded by this intrinsic let them find more UB.
-#[rustc_const_unstable(feature = "ub_checks", issue = "none")]
-#[unstable(feature = "core_intrinsics", issue = "none")]
-#[inline(always)]
-#[rustc_intrinsic]
-pub(crate) const fn check_library_ub() -> bool {
-    cfg!(debug_assertions)
-}
-
-/// Returns whether we should check for language UB. This evaluate to the value of `cfg!(debug_assertions)`
-/// during monomorphization.
+/// The stabilized form of this intrinsic is [`crate::mem::swap`].
 ///
-/// Since checks implemented at the source level must come strictly before the operation that
-/// executes UB, if we enabled language UB checks in const-eval/Miri we would miss out on the
-/// interpreter's improved diagnostics for the cases that our source-level checks catch.
+/// # Safety
 ///
-/// See `check_library_ub` for more information.
-#[rustc_const_unstable(feature = "ub_checks", issue = "none")]
+/// `x` and `y` are readable and writable as `T`, and non-overlapping.
+#[rustc_nounwind]
+#[inline]
+#[cfg_attr(not(bootstrap), rustc_intrinsic)]
+// This has fallback `const fn` MIR, so shouldn't need stability, see #122652
+#[rustc_const_unstable(feature = "const_typed_swap", issue = "none")]
+pub const unsafe fn typed_swap<T>(x: *mut T, y: *mut T) {
+    // SAFETY: The caller provided single non-overlapping items behind
+    // pointers, so swapping them with `count: 1` is fine.
+    unsafe { ptr::swap_nonoverlapping(x, y, 1) };
+}
+
+/// Returns whether we should perform some UB-checking at runtime. This evaluate to the value of
+/// `cfg!(debug_assertions)` during monomorphization.
+///
+/// This intrinsic is evaluated after monomorphization, which is relevant when mixing crates
+/// compiled with and without debug_assertions. The common case here is a user program built with
+/// debug_assertions linked against the distributed sysroot which is built without debug_assertions.
+/// For code that gets monomorphized in the user crate (i.e., generic functions and functions with
+/// `#[inline]`), gating assertions on `ub_checks()` rather than `cfg!(debug_assertions)` means that
+/// assertions are enabled whenever the *user crate* has debug assertions enabled. However if the
+/// user has debug assertions disabled, the checks will still get optimized out. This intrinsic is
+/// primarily used by [`ub_checks::assert_unsafe_precondition`].
+#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[inline(always)]
-#[rustc_intrinsic]
-pub(crate) const fn check_language_ub() -> bool {
+#[cfg_attr(not(bootstrap), rustc_intrinsic)] // just make it a regular fn in bootstrap
+pub(crate) const fn ub_checks() -> bool {
     cfg!(debug_assertions)
 }
 
@@ -2733,132 +2765,6 @@ pub unsafe fn vtable_align(_ptr: *const ()) -> usize {
 // (`transmute` also falls into this category, but it cannot be wrapped due to the
 // check that `T` and `U` have the same size.)
 
-/// Check that the preconditions of an unsafe function are followed. The check is enabled at
-/// runtime if debug assertions are enabled when the caller is monomorphized. In const-eval/Miri
-/// checks implemented with this macro for language UB are always ignored.
-///
-/// This macro should be called as
-/// `assert_unsafe_precondition!(check_{library,lang}_ub, "message", (ident: type = expr, ident: type = expr) => check_expr)`
-/// where each `expr` will be evaluated and passed in as function argument `ident: type`. Then all
-/// those arguments are passed to a function with the body `check_expr`.
-/// Pick `check_language_ub` when this is guarding a violation of language UB, i.e., immediate UB
-/// according to the Rust Abstract Machine. Pick `check_library_ub` when this is guarding a violation
-/// of a documented library precondition that does not *immediately* lead to language UB.
-///
-/// If `check_library_ub` is used but the check is actually guarding language UB, the check will
-/// slow down const-eval/Miri and we'll get the panic message instead of the interpreter's nice
-/// diagnostic, but our ability to detect UB is unchanged.
-/// But if `check_language_ub` is used when the check is actually for library UB, the check is
-/// omitted in const-eval/Miri and thus if we eventually execute language UB which relies on the
-/// library UB, the backtrace Miri reports may be far removed from original cause.
-///
-/// These checks are behind a condition which is evaluated at codegen time, not expansion time like
-/// [`debug_assert`]. This means that a standard library built with optimizations and debug
-/// assertions disabled will have these checks optimized out of its monomorphizations, but if a
-/// caller of the standard library has debug assertions enabled and monomorphizes an expansion of
-/// this macro, that monomorphization will contain the check.
-///
-/// Since these checks cannot be optimized out in MIR, some care must be taken in both call and
-/// implementation to mitigate their compile-time overhead. Calls to this macro always expand to
-/// this structure:
-/// ```ignore (pseudocode)
-/// if ::core::intrinsics::check_language_ub() {
-///     precondition_check(args)
-/// }
-/// ```
-/// where `precondition_check` is monomorphic with the attributes `#[rustc_nounwind]`, `#[inline]` and
-/// `#[rustc_no_mir_inline]`. This combination of attributes ensures that the actual check logic is
-/// compiled only once and generates a minimal amount of IR because the check cannot be inlined in
-/// MIR, but *can* be inlined and fully optimized by a codegen backend.
-///
-/// Callers should avoid introducing any other `let` bindings or any code outside this macro in
-/// order to call it. Since the precompiled standard library is built with full debuginfo and these
-/// variables cannot be optimized out in MIR, an innocent-looking `let` can produce enough
-/// debuginfo to have a measurable compile-time impact on debug builds.
-#[allow_internal_unstable(ub_checks)] // permit this to be called in stably-const fn
-macro_rules! assert_unsafe_precondition {
-    ($kind:ident, $message:expr, ($($name:ident:$ty:ty = $arg:expr),*$(,)?) => $e:expr $(,)?) => {
-        {
-            // This check is inlineable, but not by the MIR inliner.
-            // The reason for this is that the MIR inliner is in an exceptionally bad position
-            // to think about whether or not to inline this. In MIR, this call is gated behind `debug_assertions`,
-            // which will codegen to `false` in release builds. Inlining the check would be wasted work in that case and
-            // would be bad for compile times.
-            //
-            // LLVM on the other hand sees the constant branch, so if it's `false`, it can immediately delete it without
-            // inlining the check. If it's `true`, it can inline it and get significantly better performance.
-            #[rustc_no_mir_inline]
-            #[inline]
-            #[rustc_nounwind]
-            #[rustc_const_unstable(feature = "ub_checks", issue = "none")]
-            const fn precondition_check($($name:$ty),*) {
-                if !$e {
-                    ::core::panicking::panic_nounwind(
-                        concat!("unsafe precondition(s) violated: ", $message)
-                    );
-                }
-            }
-
-            if ::core::intrinsics::$kind() {
-                precondition_check($($arg,)*);
-            }
-        }
-    };
-}
-pub(crate) use assert_unsafe_precondition;
-
-/// Checks whether `ptr` is properly aligned with respect to
-/// `align_of::<T>()`.
-///
-/// In `const` this is approximate and can fail spuriously. It is primarily intended
-/// for `assert_unsafe_precondition!` with `check_language_ub`, in which case the
-/// check is anyway not executed in `const`.
-#[inline]
-pub(crate) const fn is_aligned_and_not_null(ptr: *const (), align: usize) -> bool {
-    !ptr.is_null() && ptr.is_aligned_to(align)
-}
-
-#[inline]
-pub(crate) const fn is_valid_allocation_size(size: usize, len: usize) -> bool {
-    let max_len = if size == 0 { usize::MAX } else { isize::MAX as usize / size };
-    len <= max_len
-}
-
-/// Checks whether the regions of memory starting at `src` and `dst` of size
-/// `count * size` do *not* overlap.
-///
-/// Note that in const-eval this function just returns `true` and therefore must
-/// only be used with `assert_unsafe_precondition!`, similar to `is_aligned_and_not_null`.
-#[inline]
-pub(crate) const fn is_nonoverlapping(
-    src: *const (),
-    dst: *const (),
-    size: usize,
-    count: usize,
-) -> bool {
-    #[inline]
-    fn runtime(src: *const (), dst: *const (), size: usize, count: usize) -> bool {
-        let src_usize = src.addr();
-        let dst_usize = dst.addr();
-        let Some(size) = size.checked_mul(count) else {
-            crate::panicking::panic_nounwind(
-                "is_nonoverlapping: `size_of::<T>() * count` overflows a usize",
-            )
-        };
-        let diff = src_usize.abs_diff(dst_usize);
-        // If the absolute distance between the ptrs is at least as big as the size of the buffer,
-        // they do not overlap.
-        diff >= size
-    }
-
-    #[inline]
-    const fn comptime(_: *const (), _: *const (), _: usize, _: usize) -> bool {
-        true
-    }
-
-    const_eval_select((src, dst, size, count), comptime, runtime)
-}
-
 /// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
 /// and destination must *not* overlap.
 ///
@@ -2957,7 +2863,7 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
         pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
     }
 
-    assert_unsafe_precondition!(
+    ub_checks::assert_unsafe_precondition!(
         check_language_ub,
         "ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null \
         and the specified memory ranges do not overlap",
@@ -2968,9 +2874,9 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
             align: usize = align_of::<T>(),
             count: usize = count,
         ) =>
-        is_aligned_and_not_null(src, align)
-            && is_aligned_and_not_null(dst, align)
-            && is_nonoverlapping(src, dst, size, count)
+        ub_checks::is_aligned_and_not_null(src, align)
+            && ub_checks::is_aligned_and_not_null(dst, align)
+            && ub_checks::is_nonoverlapping(src, dst, size, count)
     );
 
     // SAFETY: the safety contract for `copy_nonoverlapping` must be
@@ -3061,7 +2967,7 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
 
     // SAFETY: the safety contract for `copy` must be upheld by the caller.
     unsafe {
-        assert_unsafe_precondition!(
+        ub_checks::assert_unsafe_precondition!(
             check_language_ub,
             "ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null \
             and the specified memory ranges do not overlap",
@@ -3070,8 +2976,8 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
                 dst: *mut () = dst as *mut (),
                 align: usize = align_of::<T>(),
             ) =>
-            is_aligned_and_not_null(src, align)
-                && is_aligned_and_not_null(dst, align)
+            ub_checks::is_aligned_and_not_null(src, align)
+                && ub_checks::is_aligned_and_not_null(dst, align)
         );
         copy(src, dst, count)
     }
@@ -3142,13 +3048,13 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
 
     // SAFETY: the safety contract for `write_bytes` must be upheld by the caller.
     unsafe {
-        assert_unsafe_precondition!(
+        ub_checks::assert_unsafe_precondition!(
             check_language_ub,
             "ptr::write_bytes requires that the destination pointer is aligned and non-null",
             (
                 addr: *const () = dst as *const (),
                 align: usize = align_of::<T>(),
-            ) => is_aligned_and_not_null(addr, align)
+            ) => ub_checks::is_aligned_and_not_null(addr, align)
         );
         write_bytes(dst, val, count)
     }
diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs
index b69f4f853b9..427a95f4665 100644
--- a/library/core/src/intrinsics/simd.rs
+++ b/library/core/src/intrinsics/simd.rs
@@ -470,7 +470,7 @@ extern "rust-intrinsic" {
     /// No matter whether the output is an array or an unsigned integer, it is treated as a single
     /// contiguous list of bits. The bitmask is always packed on the least-significant side of the
     /// output, and padded with 0s in the most-significant bits. The order of the bits depends on
-    /// endianess:
+    /// endianness:
     ///
     /// * On little endian, the least significant bit corresponds to the first vector element.
     /// * On big endian, the least significant bit corresponds to the last vector element.
diff --git a/library/core/src/iter/traits/marker.rs b/library/core/src/iter/traits/marker.rs
index 8bdbca120d7..ad4d63d83b5 100644
--- a/library/core/src/iter/traits/marker.rs
+++ b/library/core/src/iter/traits/marker.rs
@@ -28,6 +28,7 @@ pub unsafe trait TrustedFused {}
 #[rustc_unsafe_specialization_marker]
 // FIXME: this should be a #[marker] and have another blanket impl for T: TrustedFused
 // but that ICEs iter::Fuse specializations.
+#[cfg_attr(not(bootstrap), lang = "fused_iterator")]
 pub trait FusedIterator: Iterator {}
 
 #[stable(feature = "fused", since = "1.26.0")]
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 2718dd11473..f0448a98981 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -170,6 +170,8 @@
 #![feature(const_try)]
 #![feature(const_type_id)]
 #![feature(const_type_name)]
+#![feature(const_typed_swap)]
+#![feature(const_ub_checks)]
 #![feature(const_unicode_case_lookup)]
 #![feature(const_unsafecell_get_mut)]
 #![feature(const_waker)]
@@ -189,7 +191,6 @@
 #![feature(ptr_metadata)]
 #![feature(set_ptr_value)]
 #![feature(slice_ptr_get)]
-#![feature(slice_split_at_unchecked)]
 #![feature(split_at_checked)]
 #![feature(str_internals)]
 #![feature(str_split_inclusive_remainder)]
@@ -366,6 +367,7 @@ pub mod hint;
 pub mod intrinsics;
 pub mod mem;
 pub mod ptr;
+mod ub_checks;
 
 /* Core language traits */
 
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 0ee7e190e3d..a78842c8f8d 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -1704,14 +1704,26 @@ pub(crate) mod builtin {
     }
 
     /// Unstable placeholder for type ascription.
-    #[rustc_builtin_macro]
+    #[allow_internal_unstable(builtin_syntax)]
     #[unstable(
         feature = "type_ascription",
         issue = "23416",
         reason = "placeholder syntax for type ascription"
     )]
     pub macro type_ascribe($expr:expr, $ty:ty) {
-        /* compiler built-in */
+        builtin # type_ascribe($expr, $ty)
+    }
+
+    #[cfg(not(bootstrap))]
+    /// Unstable placeholder for deref patterns.
+    #[allow_internal_unstable(builtin_syntax)]
+    #[unstable(
+        feature = "deref_patterns",
+        issue = "87121",
+        reason = "placeholder syntax for deref patterns"
+    )]
+    pub macro deref($pat:pat) {
+        builtin # deref($pat)
     }
 
     /// Unstable implementation detail of the `rustc` compiler, do not use.
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index d1dc6720271..75d42edbaa0 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -726,63 +726,9 @@ pub unsafe fn uninitialized<T>() -> T {
 #[rustc_const_unstable(feature = "const_swap", issue = "83163")]
 #[rustc_diagnostic_item = "mem_swap"]
 pub const fn swap<T>(x: &mut T, y: &mut T) {
-    // NOTE(eddyb) SPIR-V's Logical addressing model doesn't allow for arbitrary
-    // reinterpretation of values as (chunkable) byte arrays, and the loop in the
-    // block optimization in `swap_slice` is hard to rewrite back
-    // into the (unoptimized) direct swapping implementation, so we disable it.
-    #[cfg(not(any(target_arch = "spirv")))]
-    {
-        // For types that are larger multiples of their alignment, the simple way
-        // tends to copy the whole thing to stack rather than doing it one part
-        // at a time, so instead treat them as one-element slices and piggy-back
-        // the slice optimizations that will split up the swaps.
-        if const { size_of::<T>() / align_of::<T>() > 2 } {
-            // SAFETY: exclusive references always point to one non-overlapping
-            // element and are non-null and properly aligned.
-            return unsafe { ptr::swap_nonoverlapping(x, y, 1) };
-        }
-    }
-
-    // If a scalar consists of just a small number of alignment units, let
-    // the codegen just swap those pieces directly, as it's likely just a
-    // few instructions and anything else is probably overcomplicated.
-    //
-    // Most importantly, this covers primitives and simd types that tend to
-    // have size=align where doing anything else can be a pessimization.
-    // (This will also be used for ZSTs, though any solution works for them.)
-    swap_simple(x, y);
-}
-
-/// Same as [`swap`] semantically, but always uses the simple implementation.
-///
-/// Used elsewhere in `mem` and `ptr` at the bottom layer of calls.
-#[rustc_const_unstable(feature = "const_swap", issue = "83163")]
-#[inline]
-pub(crate) const fn swap_simple<T>(x: &mut T, y: &mut T) {
-    // We arrange for this to typically be called with small types,
-    // so this reads-and-writes approach is actually better than using
-    // copy_nonoverlapping as it easily puts things in LLVM registers
-    // directly and doesn't end up inlining allocas.
-    // And LLVM actually optimizes it to 3×memcpy if called with
-    // a type larger than it's willing to keep in a register.
-    // Having typed reads and writes in MIR here is also good as
-    // it lets Miri and CTFE understand them better, including things
-    // like enforcing type validity for them.
-    // Importantly, read+copy_nonoverlapping+write introduces confusing
-    // asymmetry to the behaviour where one value went through read+write
-    // whereas the other was copied over by the intrinsic (see #94371).
-    // Furthermore, using only read+write here benefits limited backends
-    // such as SPIR-V that work on an underlying *typed* view of memory,
-    // and thus have trouble with Rust's untyped memory operations.
-
-    // SAFETY: exclusive references are always valid to read/write,
-    // including being aligned, and nothing here panics so it's drop-safe.
-    unsafe {
-        let a = ptr::read(x);
-        let b = ptr::read(y);
-        ptr::write(x, b);
-        ptr::write(y, a);
-    }
+    // SAFETY: `&mut` guarantees these are typed readable and writable
+    // as well as non-overlapping.
+    unsafe { intrinsics::typed_swap(x, y) }
 }
 
 /// Replaces `dest` with the default value of `T`, returning the previous `dest` value.
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index a8f637280df..c65ffbb98f2 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -9,6 +9,7 @@ use crate::ops::{BitOr, BitOrAssign, Div, DivAssign, Neg, Rem, RemAssign};
 use crate::panic::{RefUnwindSafe, UnwindSafe};
 use crate::ptr;
 use crate::str::FromStr;
+use crate::ub_checks;
 
 use super::from_str_radix;
 use super::{IntErrorKind, ParseIntError};
@@ -369,7 +370,7 @@ where
             None => {
                 // SAFETY: The caller guarantees that `n` is non-zero, so this is unreachable.
                 unsafe {
-                    intrinsics::assert_unsafe_precondition!(
+                    ub_checks::assert_unsafe_precondition!(
                         check_language_ub,
                         "NonZero::new_unchecked requires the argument to be non-zero",
                         () => false,
@@ -409,7 +410,7 @@ where
             None => {
                 // SAFETY: The caller guarantees that `n` references a value that is non-zero, so this is unreachable.
                 unsafe {
-                    intrinsics::assert_unsafe_precondition!(
+                    ub_checks::assert_unsafe_precondition!(
                         check_library_ub,
                         "NonZero::from_mut_unchecked requires the argument to dereference as non-zero",
                         () => false,
diff --git a/library/core/src/ops/index_range.rs b/library/core/src/ops/index_range.rs
index b28d88fa5bf..65bda9177c7 100644
--- a/library/core/src/ops/index_range.rs
+++ b/library/core/src/ops/index_range.rs
@@ -1,6 +1,7 @@
-use crate::intrinsics::{assert_unsafe_precondition, unchecked_add, unchecked_sub};
+use crate::intrinsics::{unchecked_add, unchecked_sub};
 use crate::iter::{FusedIterator, TrustedLen};
 use crate::num::NonZero;
+use crate::ub_checks;
 
 /// Like a `Range<usize>`, but with a safety invariant that `start <= end`.
 ///
@@ -19,7 +20,7 @@ impl IndexRange {
     /// - `start <= end`
     #[inline]
     pub const unsafe fn new_unchecked(start: usize, end: usize) -> Self {
-        assert_unsafe_precondition!(
+        ub_checks::assert_unsafe_precondition!(
             check_library_ub,
             "IndexRange::new_unchecked requires `start <= end`",
             (start: usize = start, end: usize = end) => start <= end,
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 5027e326a9d..0083d15efae 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -558,17 +558,16 @@ use crate::panicking::{panic, panic_str};
 use crate::pin::Pin;
 use crate::{
     cmp, convert, hint, mem,
-    num::NonZero,
     ops::{self, ControlFlow, Deref, DerefMut},
     slice,
 };
 
 /// The `Option` type. See [the module level documentation](self) for more.
-#[derive(Copy, PartialOrd, Eq, Ord, Debug, Hash)]
+#[derive(Copy, Eq, Debug, Hash)]
 #[rustc_diagnostic_item = "Option"]
 #[lang = "Option"]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[allow(clippy::derived_hash_with_manual_eq)] // PartialEq is specialized
+#[allow(clippy::derived_hash_with_manual_eq)] // PartialEq is manually implemented equivalently
 pub enum Option<T> {
     /// No value.
     #[lang = "None"]
@@ -2146,83 +2145,52 @@ impl<'a, T> From<&'a mut Option<T>> for Option<&'a mut T> {
     }
 }
 
+// Ideally, LLVM should be able to optimize our derive code to this.
+// Once https://github.com/llvm/llvm-project/issues/52622 is fixed, we can
+// go back to deriving `PartialEq`.
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> crate::marker::StructuralPartialEq for Option<T> {}
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: PartialEq> PartialEq for Option<T> {
     #[inline]
     fn eq(&self, other: &Self) -> bool {
-        SpecOptionPartialEq::eq(self, other)
-    }
-}
-
-/// This specialization trait is a workaround for LLVM not currently (2023-01)
-/// being able to optimize this itself, even though Alive confirms that it would
-/// be legal to do so: <https://github.com/llvm/llvm-project/issues/52622>
-///
-/// Once that's fixed, `Option` should go back to deriving `PartialEq`, as
-/// it used to do before <https://github.com/rust-lang/rust/pull/103556>.
-#[unstable(feature = "spec_option_partial_eq", issue = "none", reason = "exposed only for rustc")]
-#[doc(hidden)]
-pub trait SpecOptionPartialEq: Sized {
-    fn eq(l: &Option<Self>, other: &Option<Self>) -> bool;
-}
-
-#[unstable(feature = "spec_option_partial_eq", issue = "none", reason = "exposed only for rustc")]
-impl<T: PartialEq> SpecOptionPartialEq for T {
-    #[inline]
-    default fn eq(l: &Option<T>, r: &Option<T>) -> bool {
-        match (l, r) {
+        // Spelling out the cases explicitly optimizes better than
+        // `_ => false`
+        match (self, other) {
             (Some(l), Some(r)) => *l == *r,
+            (Some(_), None) => false,
+            (None, Some(_)) => false,
             (None, None) => true,
-            _ => false,
         }
     }
 }
 
-macro_rules! non_zero_option {
-    ( $( #[$stability: meta] $NZ:ty; )+ ) => {
-        $(
-            #[$stability]
-            impl SpecOptionPartialEq for $NZ {
-                #[inline]
-                fn eq(l: &Option<Self>, r: &Option<Self>) -> bool {
-                    l.map(Self::get).unwrap_or(0) == r.map(Self::get).unwrap_or(0)
-                }
-            }
-        )+
-    };
-}
-
-non_zero_option! {
-    #[stable(feature = "nonzero", since = "1.28.0")] NonZero<u8>;
-    #[stable(feature = "nonzero", since = "1.28.0")] NonZero<u16>;
-    #[stable(feature = "nonzero", since = "1.28.0")] NonZero<u32>;
-    #[stable(feature = "nonzero", since = "1.28.0")] NonZero<u64>;
-    #[stable(feature = "nonzero", since = "1.28.0")] NonZero<u128>;
-    #[stable(feature = "nonzero", since = "1.28.0")] NonZero<usize>;
-    #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZero<i8>;
-    #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZero<i16>;
-    #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZero<i32>;
-    #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZero<i64>;
-    #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZero<i128>;
-    #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZero<isize>;
-}
-
-#[stable(feature = "nonnull", since = "1.25.0")]
-impl<T> SpecOptionPartialEq for crate::ptr::NonNull<T> {
+// Manually implementing here somewhat improves codegen for
+// https://github.com/rust-lang/rust/issues/49892, although still
+// not optimal.
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: PartialOrd> PartialOrd for Option<T> {
     #[inline]
-    fn eq(l: &Option<Self>, r: &Option<Self>) -> bool {
-        l.map(Self::as_ptr).unwrap_or_else(|| crate::ptr::null_mut())
-            == r.map(Self::as_ptr).unwrap_or_else(|| crate::ptr::null_mut())
+    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
+        match (self, other) {
+            (Some(l), Some(r)) => l.partial_cmp(r),
+            (Some(_), None) => Some(cmp::Ordering::Greater),
+            (None, Some(_)) => Some(cmp::Ordering::Less),
+            (None, None) => Some(cmp::Ordering::Equal),
+        }
     }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl SpecOptionPartialEq for cmp::Ordering {
+impl<T: Ord> Ord for Option<T> {
     #[inline]
-    fn eq(l: &Option<Self>, r: &Option<Self>) -> bool {
-        l.map_or(2, |x| x as i8) == r.map_or(2, |x| x as i8)
+    fn cmp(&self, other: &Self) -> cmp::Ordering {
+        match (self, other) {
+            (Some(l), Some(r)) => l.cmp(r),
+            (Some(_), None) => cmp::Ordering::Greater,
+            (None, Some(_)) => cmp::Ordering::Less,
+            (None, None) => cmp::Ordering::Equal,
+        }
     }
 }
 
diff --git a/library/core/src/panic/panic_info.rs b/library/core/src/panic/panic_info.rs
index c77e9675a6a..40326221258 100644
--- a/library/core/src/panic/panic_info.rs
+++ b/library/core/src/panic/panic_info.rs
@@ -161,11 +161,12 @@ impl fmt::Display for PanicInfo<'_> {
     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
         formatter.write_str("panicked at ")?;
         self.location.fmt(formatter)?;
+        formatter.write_str(":")?;
         if let Some(message) = self.message {
-            formatter.write_str(":\n")?;
+            formatter.write_str("\n")?;
             formatter.write_fmt(*message)?;
         } else if let Some(payload) = self.payload.downcast_ref::<&'static str>() {
-            formatter.write_str(":\n")?;
+            formatter.write_str("\n")?;
             formatter.write_str(payload)?;
         }
         // NOTE: we cannot use downcast_ref::<String>() here
diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs
index 9e8dac88816..a8940d9cd1e 100644
--- a/library/core/src/panicking.rs
+++ b/library/core/src/panicking.rs
@@ -132,11 +132,11 @@ pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: boo
 #[rustc_const_unstable(feature = "panic_internals", issue = "none")]
 #[lang = "panic"] // needed by codegen for panic on overflow and other `Assert` MIR terminators
 pub const fn panic(expr: &'static str) -> ! {
-    // Use Arguments::new_v1 instead of format_args!("{expr}") to potentially
+    // Use Arguments::new_const instead of format_args!("{expr}") to potentially
     // reduce size overhead. The format_args! macro uses str's Display trait to
     // write expr, which calls Formatter::pad, which must accommodate string
     // truncation and padding (even though none is used here). Using
-    // Arguments::new_v1 may allow the compiler to omit Formatter::pad from the
+    // Arguments::new_const may allow the compiler to omit Formatter::pad from the
     // output binary, saving up to a few kilobytes.
     panic_fmt(fmt::Arguments::new_const(&[expr]));
 }
diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs
index a0227d9130b..d14cac9afb5 100644
--- a/library/core/src/pin.rs
+++ b/library/core/src/pin.rs
@@ -144,7 +144,7 @@
 //!     * e.g. [`drop`]ping the [`Future`] [^pin-drop-future]
 //!
 //! There are two possible ways to ensure the invariants required for 2. and 3. above (which
-//! apply to any address-sensitive type, not just self-referrential types) do not get broken.
+//! apply to any address-sensitive type, not just self-referential types) do not get broken.
 //!
 //! 1. Have the value detect when it is moved and update all the pointers that point to itself.
 //! 2. Guarantee that the address of the value does not change (and that memory is not re-used
@@ -170,7 +170,7 @@
 //! become viral throughout all code that interacts with the object.
 //!
 //! The second option is a viable solution to the problem for some use cases, in particular
-//! for self-referrential types. Under this model, any type that has an address sensitive state
+//! for self-referential types. Under this model, any type that has an address sensitive state
 //! would ultimately store its data in something like a [`Box<T>`], carefully manage internal
 //! access to that data to ensure no *moves* or other invalidation occurs, and finally
 //! provide a safe interface on top.
@@ -186,8 +186,8 @@
 //!
 //! Although there were other reason as well, this issue of expensive composition is the key thing
 //! that drove Rust towards adopting a different model. It is particularly a problem
-//! when one considers, for exapmle, the implications of composing together the [`Future`]s which
-//! will eventaully make up an asynchronous task (including address-sensitive `async fn` state
+//! when one considers, for example, the implications of composing together the [`Future`]s which
+//! will eventually make up an asynchronous task (including address-sensitive `async fn` state
 //! machines). It is plausible that there could be many layers of [`Future`]s composed together,
 //! including multiple layers of `async fn`s handling different parts of a task. It was deemed
 //! unacceptable to force indirection and allocation for each layer of composition in this case.
@@ -359,7 +359,7 @@
 //! Builtin types that are [`Unpin`] include all of the primitive types, like [`bool`], [`i32`],
 //! and [`f32`], references (<code>[&]T</code> and <code>[&mut] T</code>), etc., as well as many
 //! core and standard library types like [`Box<T>`], [`String`], and more.
-//! These types are marked [`Unpin`] because they do not have an ddress-sensitive state like the
+//! These types are marked [`Unpin`] because they do not have an address-sensitive state like the
 //! ones we discussed above. If they did have such a state, those parts of their interface would be
 //! unsound without being expressed through pinning, and they would then need to not
 //! implement [`Unpin`].
@@ -953,7 +953,7 @@ use crate::{
 /// discussed below.
 ///
 /// We call such a [`Pin`]-wrapped pointer a **pinning pointer** (or pinning ref, or pinning
-/// [`Box`], etc.) because its existince is the thing that is pinning the underlying pointee in
+/// [`Box`], etc.) because its existence is the thing that is pinning the underlying pointee in
 /// place: it is the metaphorical "pin" securing the data in place on the pinboard (in memory).
 ///
 /// It is important to stress that the thing in the [`Pin`] is not the value which we want to pin
@@ -962,7 +962,7 @@ use crate::{
 ///
 /// The most common set of types which require pinning related guarantees for soundness are the
 /// compiler-generated state machines that implement [`Future`] for the return value of
-/// `async fn`s. These compiler-generated [`Future`]s may contain self-referrential pointers, one
+/// `async fn`s. These compiler-generated [`Future`]s may contain self-referential pointers, one
 /// of the most common use cases for [`Pin`]. More details on this point are provided in the
 /// [`pin` module] docs, but suffice it to say they require the guarantees provided by pinning to
 /// be implemented soundly.
diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs
index 10525a16f3a..29f73bb4942 100644
--- a/library/core/src/prelude/v1.rs
+++ b/library/core/src/prelude/v1.rs
@@ -103,3 +103,11 @@ pub use crate::macros::builtin::cfg_eval;
     reason = "placeholder syntax for type ascription"
 )]
 pub use crate::macros::builtin::type_ascribe;
+
+#[cfg(not(bootstrap))]
+#[unstable(
+    feature = "deref_patterns",
+    issue = "87121",
+    reason = "placeholder syntax for deref patterns"
+)]
+pub use crate::macros::builtin::deref;
diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs
index 8f44b7eb7c2..bc84fb5ccb0 100644
--- a/library/core/src/ptr/alignment.rs
+++ b/library/core/src/ptr/alignment.rs
@@ -1,7 +1,7 @@
 use crate::convert::{TryFrom, TryInto};
-#[cfg(debug_assertions)]
-use crate::intrinsics::assert_unsafe_precondition;
 use crate::num::NonZero;
+#[cfg(debug_assertions)]
+use crate::ub_checks::assert_unsafe_precondition;
 use crate::{cmp, fmt, hash, mem, num};
 
 /// A type storing a `usize` which is a power of two, and thus
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 69c61602073..a6c00ff28d4 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -818,7 +818,7 @@ impl<T: ?Sized> *const T {
             intrinsics::const_eval_select((this, origin), comptime, runtime)
         }
 
-        assert_unsafe_precondition!(
+        ub_checks::assert_unsafe_precondition!(
             check_language_ub,
             "ptr::sub_ptr requires `self >= origin`",
             (
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 1f0204daf72..56378b437e7 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -388,10 +388,9 @@
 use crate::cmp::Ordering;
 use crate::fmt;
 use crate::hash;
-use crate::intrinsics::{
-    self, assert_unsafe_precondition, is_aligned_and_not_null, is_nonoverlapping,
-};
+use crate::intrinsics;
 use crate::marker::FnPtr;
+use crate::ub_checks;
 
 use crate::mem::{self, align_of, size_of, MaybeUninit};
 
@@ -1019,7 +1018,7 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
         };
     }
 
-    assert_unsafe_precondition!(
+    ub_checks::assert_unsafe_precondition!(
         check_language_ub,
         "ptr::swap_nonoverlapping requires that both pointer arguments are aligned and non-null \
         and the specified memory ranges do not overlap",
@@ -1030,9 +1029,9 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
             align: usize = align_of::<T>(),
             count: usize = count,
         ) =>
-        is_aligned_and_not_null(x, align)
-            && is_aligned_and_not_null(y, align)
-            && is_nonoverlapping(x, y, size, count)
+        ub_checks::is_aligned_and_not_null(x, align)
+            && ub_checks::is_aligned_and_not_null(y, align)
+            && ub_checks::is_nonoverlapping(x, y, size, count)
     );
 
     // Split up the slice into small power-of-two-sized chunks that LLVM is able
@@ -1062,11 +1061,26 @@ const unsafe fn swap_nonoverlapping_simple_untyped<T>(x: *mut T, y: *mut T, coun
     let mut i = 0;
     while i < count {
         // SAFETY: By precondition, `i` is in-bounds because it's below `n`
-        let x = unsafe { &mut *x.add(i) };
+        let x = unsafe { x.add(i) };
         // SAFETY: By precondition, `i` is in-bounds because it's below `n`
         // and it's distinct from `x` since the ranges are non-overlapping
-        let y = unsafe { &mut *y.add(i) };
-        mem::swap_simple::<MaybeUninit<T>>(x, y);
+        let y = unsafe { y.add(i) };
+
+        // If we end up here, it's because we're using a simple type -- like
+        // a small power-of-two-sized thing -- or a special type with particularly
+        // large alignment, particularly SIMD types.
+        // Thus we're fine just reading-and-writing it, as either it's small
+        // and that works well anyway or it's special and the type's author
+        // presumably wanted things to be done in the larger chunk.
+
+        // SAFETY: we're only ever given pointers that are valid to read/write,
+        // including being aligned, and nothing here panics so it's drop-safe.
+        unsafe {
+            let a: MaybeUninit<T> = read(x);
+            let b: MaybeUninit<T> = read(y);
+            write(x, b);
+            write(y, a);
+        }
 
         i += 1;
     }
@@ -1120,13 +1134,13 @@ pub const unsafe fn replace<T>(dst: *mut T, src: T) -> T {
     // and cannot overlap `src` since `dst` must point to a distinct
     // allocated object.
     unsafe {
-        assert_unsafe_precondition!(
+        ub_checks::assert_unsafe_precondition!(
             check_language_ub,
             "ptr::replace requires that the pointer argument is aligned and non-null",
             (
                 addr: *const () = dst as *const (),
                 align: usize = align_of::<T>(),
-            ) => is_aligned_and_not_null(addr, align)
+            ) => ub_checks::is_aligned_and_not_null(addr, align)
         );
         mem::replace(&mut *dst, src)
     }
@@ -1272,13 +1286,13 @@ pub const unsafe fn read<T>(src: *const T) -> T {
     // SAFETY: the caller must guarantee that `src` is valid for reads.
     unsafe {
         #[cfg(debug_assertions)] // Too expensive to always enable (for now?)
-        assert_unsafe_precondition!(
+        ub_checks::assert_unsafe_precondition!(
             check_language_ub,
             "ptr::read requires that the pointer argument is aligned and non-null",
             (
                 addr: *const () = src as *const (),
                 align: usize = align_of::<T>(),
-            ) => is_aligned_and_not_null(addr, align)
+            ) => ub_checks::is_aligned_and_not_null(addr, align)
         );
         crate::intrinsics::read_via_copy(src)
     }
@@ -1481,13 +1495,13 @@ pub const unsafe fn write<T>(dst: *mut T, src: T) {
     // to `dst` while `src` is owned by this function.
     unsafe {
         #[cfg(debug_assertions)] // Too expensive to always enable (for now?)
-        assert_unsafe_precondition!(
+        ub_checks::assert_unsafe_precondition!(
             check_language_ub,
             "ptr::write requires that the pointer argument is aligned and non-null",
             (
                 addr: *mut () = dst as *mut (),
                 align: usize = align_of::<T>(),
-            ) => is_aligned_and_not_null(addr, align)
+            ) => ub_checks::is_aligned_and_not_null(addr, align)
         );
         intrinsics::write_via_move(dst, src)
     }
@@ -1653,13 +1667,13 @@ pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
 pub unsafe fn read_volatile<T>(src: *const T) -> T {
     // SAFETY: the caller must uphold the safety contract for `volatile_load`.
     unsafe {
-        assert_unsafe_precondition!(
+        ub_checks::assert_unsafe_precondition!(
             check_language_ub,
             "ptr::read_volatile requires that the pointer argument is aligned and non-null",
             (
                 addr: *const () = src as *const (),
                 align: usize = align_of::<T>(),
-            ) => is_aligned_and_not_null(addr, align)
+            ) => ub_checks::is_aligned_and_not_null(addr, align)
         );
         intrinsics::volatile_load(src)
     }
@@ -1732,13 +1746,13 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
 pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
     // SAFETY: the caller must uphold the safety contract for `volatile_store`.
     unsafe {
-        assert_unsafe_precondition!(
+        ub_checks::assert_unsafe_precondition!(
             check_language_ub,
             "ptr::write_volatile requires that the pointer argument is aligned and non-null",
             (
                 addr: *mut () = dst as *mut (),
                 align: usize = align_of::<T>(),
-            ) => is_aligned_and_not_null(addr, align)
+            ) => ub_checks::is_aligned_and_not_null(addr, align)
         );
         intrinsics::volatile_store(dst, src);
     }
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 9c0236c172a..e9488917acc 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -2,7 +2,6 @@ use crate::cmp::Ordering;
 use crate::fmt;
 use crate::hash;
 use crate::intrinsics;
-use crate::intrinsics::assert_unsafe_precondition;
 use crate::marker::Unsize;
 use crate::mem::{MaybeUninit, SizedTypeProperties};
 use crate::num::NonZero;
@@ -10,6 +9,7 @@ use crate::ops::{CoerceUnsized, DispatchFromDyn};
 use crate::ptr;
 use crate::ptr::Unique;
 use crate::slice::{self, SliceIndex};
+use crate::ub_checks::assert_unsafe_precondition;
 
 /// `*mut T` but non-zero and [covariant].
 ///
@@ -1575,6 +1575,25 @@ impl<T> NonNull<[T]> {
         self.as_ptr().len()
     }
 
+    /// Returns `true` if the non-null raw slice has a length of 0.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(slice_ptr_is_empty_nonnull)]
+    /// use std::ptr::NonNull;
+    ///
+    /// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3);
+    /// assert!(!slice.is_empty());
+    /// ```
+    #[unstable(feature = "slice_ptr_is_empty_nonnull", issue = "71146")]
+    #[rustc_const_unstable(feature = "const_slice_ptr_is_empty_nonnull", issue = "71146")]
+    #[must_use]
+    #[inline]
+    pub const fn is_empty(self) -> bool {
+        self.len() == 0
+    }
+
     /// Returns a non-null pointer to the slice's buffer.
     ///
     /// # Examples
diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs
index 210118817ab..127a407dae5 100644
--- a/library/core/src/slice/index.rs
+++ b/library/core/src/slice/index.rs
@@ -1,10 +1,10 @@
 //! Indexing implementations for `[T]`.
 
-use crate::intrinsics::assert_unsafe_precondition;
 use crate::intrinsics::const_eval_select;
 use crate::intrinsics::unchecked_sub;
 use crate::ops;
 use crate::ptr;
+use crate::ub_checks::assert_unsafe_precondition;
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T, I> ops::Index<I> for [T]
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 4a574bf0347..a16005abf46 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -9,7 +9,6 @@
 use crate::cmp::Ordering::{self, Equal, Greater, Less};
 use crate::fmt;
 use crate::hint;
-use crate::intrinsics::assert_unsafe_precondition;
 use crate::intrinsics::exact_div;
 use crate::mem::{self, SizedTypeProperties};
 use crate::num::NonZero;
@@ -17,6 +16,7 @@ use crate::ops::{Bound, OneSidedRange, Range, RangeBounds};
 use crate::ptr;
 use crate::simd::{self, Simd};
 use crate::slice;
+use crate::ub_checks::assert_unsafe_precondition;
 
 #[unstable(
     feature = "slice_internals",
@@ -1944,8 +1944,6 @@ impl<T> [T] {
     /// # Examples
     ///
     /// ```
-    /// #![feature(slice_split_at_unchecked)]
-    ///
     /// let v = [1, 2, 3, 4, 5, 6];
     ///
     /// unsafe {
@@ -1966,7 +1964,7 @@ impl<T> [T] {
     ///     assert_eq!(right, []);
     /// }
     /// ```
-    #[unstable(feature = "slice_split_at_unchecked", reason = "new API", issue = "76014")]
+    #[stable(feature = "slice_split_at_unchecked", since = "CURRENT_RUSTC_VERSION")]
     #[rustc_const_stable(feature = "const_slice_split_at_unchecked", since = "1.77.0")]
     #[inline]
     #[must_use]
@@ -2008,8 +2006,6 @@ impl<T> [T] {
     /// # Examples
     ///
     /// ```
-    /// #![feature(slice_split_at_unchecked)]
-    ///
     /// let mut v = [1, 0, 3, 0, 5, 6];
     /// // scoped to restrict the lifetime of the borrows
     /// unsafe {
@@ -2021,7 +2017,7 @@ impl<T> [T] {
     /// }
     /// assert_eq!(v, [1, 2, 3, 4, 5, 6]);
     /// ```
-    #[unstable(feature = "slice_split_at_unchecked", reason = "new API", issue = "76014")]
+    #[stable(feature = "slice_split_at_unchecked", since = "CURRENT_RUSTC_VERSION")]
     #[rustc_const_unstable(feature = "const_slice_split_at_mut", issue = "101804")]
     #[inline]
     #[must_use]
diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs
index 2199614ce27..29a12f106c5 100644
--- a/library/core/src/slice/raw.rs
+++ b/library/core/src/slice/raw.rs
@@ -1,12 +1,10 @@
 //! Free functions to create `&[T]` and `&mut [T]`.
 
 use crate::array;
-use crate::intrinsics::{
-    assert_unsafe_precondition, is_aligned_and_not_null, is_valid_allocation_size,
-};
 use crate::mem::{align_of, size_of};
 use crate::ops::Range;
 use crate::ptr;
+use crate::ub_checks;
 
 /// Forms a slice from a pointer and a length.
 ///
@@ -95,7 +93,7 @@ use crate::ptr;
 pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
     // SAFETY: the caller must uphold the safety contract for `from_raw_parts`.
     unsafe {
-        assert_unsafe_precondition!(
+        ub_checks::assert_unsafe_precondition!(
             check_language_ub,
             "slice::from_raw_parts requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`",
             (
@@ -104,8 +102,8 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T]
                 align: usize = align_of::<T>(),
                 len: usize = len,
             ) =>
-                is_aligned_and_not_null(data, align)
-                && is_valid_allocation_size(size, len)
+            ub_checks::is_aligned_and_not_null(data, align)
+                && ub_checks::is_valid_allocation_size(size, len)
         );
         &*ptr::slice_from_raw_parts(data, len)
     }
@@ -149,7 +147,7 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T]
 pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
     // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`.
     unsafe {
-        assert_unsafe_precondition!(
+        ub_checks::assert_unsafe_precondition!(
             check_language_ub,
             "slice::from_raw_parts_mut requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`",
             (
@@ -158,8 +156,8 @@ pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a m
                 align: usize = align_of::<T>(),
                 len: usize = len,
             ) =>
-                is_aligned_and_not_null(data, align)
-                && is_valid_allocation_size(size, len)
+            ub_checks::is_aligned_and_not_null(data, align)
+                && ub_checks::is_valid_allocation_size(size, len)
         );
         &mut *ptr::slice_from_raw_parts_mut(data, len)
     }
diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs
index ec81fd095d5..672af752149 100644
--- a/library/core/src/str/traits.rs
+++ b/library/core/src/str/traits.rs
@@ -1,10 +1,10 @@
 //! Trait implementations for `str`.
 
 use crate::cmp::Ordering;
-use crate::intrinsics::assert_unsafe_precondition;
 use crate::ops;
 use crate::ptr;
 use crate::slice::SliceIndex;
+use crate::ub_checks::assert_unsafe_precondition;
 
 use super::ParseBoolError;
 
diff --git a/library/core/src/ub_checks.rs b/library/core/src/ub_checks.rs
new file mode 100644
index 00000000000..ff6b2d30539
--- /dev/null
+++ b/library/core/src/ub_checks.rs
@@ -0,0 +1,158 @@
+//! Provides the [`assert_unsafe_precondition`] macro as well as some utility functions that cover
+//! common preconditions.
+
+use crate::intrinsics::{self, const_eval_select};
+
+/// Check that the preconditions of an unsafe function are followed. The check is enabled at
+/// runtime if debug assertions are enabled when the caller is monomorphized. In const-eval/Miri
+/// checks implemented with this macro for language UB are always ignored.
+///
+/// This macro should be called as
+/// `assert_unsafe_precondition!(check_{library,lang}_ub, "message", (ident: type = expr, ident: type = expr) => check_expr)`
+/// where each `expr` will be evaluated and passed in as function argument `ident: type`. Then all
+/// those arguments are passed to a function with the body `check_expr`.
+/// Pick `check_language_ub` when this is guarding a violation of language UB, i.e., immediate UB
+/// according to the Rust Abstract Machine. Pick `check_library_ub` when this is guarding a violation
+/// of a documented library precondition that does not *immediately* lead to language UB.
+///
+/// If `check_library_ub` is used but the check is actually guarding language UB, the check will
+/// slow down const-eval/Miri and we'll get the panic message instead of the interpreter's nice
+/// diagnostic, but our ability to detect UB is unchanged.
+/// But if `check_language_ub` is used when the check is actually for library UB, the check is
+/// omitted in const-eval/Miri and thus if we eventually execute language UB which relies on the
+/// library UB, the backtrace Miri reports may be far removed from original cause.
+///
+/// These checks are behind a condition which is evaluated at codegen time, not expansion time like
+/// [`debug_assert`]. This means that a standard library built with optimizations and debug
+/// assertions disabled will have these checks optimized out of its monomorphizations, but if a
+/// caller of the standard library has debug assertions enabled and monomorphizes an expansion of
+/// this macro, that monomorphization will contain the check.
+///
+/// Since these checks cannot be optimized out in MIR, some care must be taken in both call and
+/// implementation to mitigate their compile-time overhead. Calls to this macro always expand to
+/// this structure:
+/// ```ignore (pseudocode)
+/// if ::core::intrinsics::check_language_ub() {
+///     precondition_check(args)
+/// }
+/// ```
+/// where `precondition_check` is monomorphic with the attributes `#[rustc_nounwind]`, `#[inline]` and
+/// `#[rustc_no_mir_inline]`. This combination of attributes ensures that the actual check logic is
+/// compiled only once and generates a minimal amount of IR because the check cannot be inlined in
+/// MIR, but *can* be inlined and fully optimized by a codegen backend.
+///
+/// Callers should avoid introducing any other `let` bindings or any code outside this macro in
+/// order to call it. Since the precompiled standard library is built with full debuginfo and these
+/// variables cannot be optimized out in MIR, an innocent-looking `let` can produce enough
+/// debuginfo to have a measurable compile-time impact on debug builds.
+#[allow_internal_unstable(const_ub_checks)] // permit this to be called in stably-const fn
+macro_rules! assert_unsafe_precondition {
+    ($kind:ident, $message:expr, ($($name:ident:$ty:ty = $arg:expr),*$(,)?) => $e:expr $(,)?) => {
+        {
+            // This check is inlineable, but not by the MIR inliner.
+            // The reason for this is that the MIR inliner is in an exceptionally bad position
+            // to think about whether or not to inline this. In MIR, this call is gated behind `debug_assertions`,
+            // which will codegen to `false` in release builds. Inlining the check would be wasted work in that case and
+            // would be bad for compile times.
+            //
+            // LLVM on the other hand sees the constant branch, so if it's `false`, it can immediately delete it without
+            // inlining the check. If it's `true`, it can inline it and get significantly better performance.
+            #[rustc_no_mir_inline]
+            #[inline]
+            #[rustc_nounwind]
+            #[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
+            const fn precondition_check($($name:$ty),*) {
+                if !$e {
+                    ::core::panicking::panic_nounwind(
+                        concat!("unsafe precondition(s) violated: ", $message)
+                    );
+                }
+            }
+
+            if ::core::ub_checks::$kind() {
+                precondition_check($($arg,)*);
+            }
+        }
+    };
+}
+pub(crate) use assert_unsafe_precondition;
+
+/// Checking library UB is always enabled when UB-checking is done
+/// (and we use a reexport so that there is no unnecessary wrapper function).
+pub(crate) use intrinsics::ub_checks as check_library_ub;
+
+/// Determines whether we should check for language UB.
+///
+/// The intention is to not do that when running in the interpreter, as that one has its own
+/// language UB checks which generally produce better errors.
+#[rustc_const_unstable(feature = "const_ub_checks", issue = "none")]
+#[inline]
+pub(crate) const fn check_language_ub() -> bool {
+    #[inline]
+    fn runtime() -> bool {
+        // Disable UB checks in Miri.
+        !cfg!(miri)
+    }
+
+    #[inline]
+    const fn comptime() -> bool {
+        // Always disable UB checks.
+        false
+    }
+
+    // Only used for UB checks so we may const_eval_select.
+    intrinsics::ub_checks() && const_eval_select((), comptime, runtime)
+}
+
+/// Checks whether `ptr` is properly aligned with respect to
+/// `align_of::<T>()`.
+///
+/// In `const` this is approximate and can fail spuriously. It is primarily intended
+/// for `assert_unsafe_precondition!` with `check_language_ub`, in which case the
+/// check is anyway not executed in `const`.
+#[inline]
+pub(crate) const fn is_aligned_and_not_null(ptr: *const (), align: usize) -> bool {
+    !ptr.is_null() && ptr.is_aligned_to(align)
+}
+
+#[inline]
+pub(crate) const fn is_valid_allocation_size(size: usize, len: usize) -> bool {
+    let max_len = if size == 0 { usize::MAX } else { isize::MAX as usize / size };
+    len <= max_len
+}
+
+/// Checks whether the regions of memory starting at `src` and `dst` of size
+/// `count * size` do *not* overlap.
+///
+/// Note that in const-eval this function just returns `true` and therefore must
+/// only be used with `assert_unsafe_precondition!`, similar to `is_aligned_and_not_null`.
+#[inline]
+pub(crate) const fn is_nonoverlapping(
+    src: *const (),
+    dst: *const (),
+    size: usize,
+    count: usize,
+) -> bool {
+    #[inline]
+    fn runtime(src: *const (), dst: *const (), size: usize, count: usize) -> bool {
+        let src_usize = src.addr();
+        let dst_usize = dst.addr();
+        let Some(size) = size.checked_mul(count) else {
+            crate::panicking::panic_nounwind(
+                "is_nonoverlapping: `size_of::<T>() * count` overflows a usize",
+            )
+        };
+        let diff = src_usize.abs_diff(dst_usize);
+        // If the absolute distance between the ptrs is at least as big as the size of the buffer,
+        // they do not overlap.
+        diff >= size
+    }
+
+    #[inline]
+    const fn comptime(_: *const (), _: *const (), _: usize, _: usize) -> bool {
+        true
+    }
+
+    // This is just for safety checks so we can const_eval_select.
+    const_eval_select((src, dst, size, count), comptime, runtime)
+}
diff --git a/library/panic_unwind/src/emcc.rs b/library/panic_unwind/src/emcc.rs
index af18e19337c..fed4c52e83c 100644
--- a/library/panic_unwind/src/emcc.rs
+++ b/library/panic_unwind/src/emcc.rs
@@ -84,7 +84,7 @@ pub unsafe fn cleanup(ptr: *mut u8) -> Box<dyn Any + Send> {
         super::__rust_foreign_exception();
     }
 
-    let was_caught = (*adjusted_ptr).caught.swap(true, Ordering::SeqCst);
+    let was_caught = (*adjusted_ptr).caught.swap(true, Ordering::Relaxed);
     if was_caught {
         // Since cleanup() isn't allowed to panic, we just abort instead.
         intrinsics::abort();
diff --git a/library/portable-simd/.github/workflows/ci.yml b/library/portable-simd/.github/workflows/ci.yml
index 90543044ea8..b292be2d6f9 100644
--- a/library/portable-simd/.github/workflows/ci.yml
+++ b/library/portable-simd/.github/workflows/ci.yml
@@ -141,6 +141,11 @@ jobs:
       - name: Test (release)
         run: cargo test --verbose --target=${{ matrix.target }} --release
 
+      - name: Generate docs
+        run: cargo doc --verbose --target=${{ matrix.target }}
+        env:
+          RUSTDOCFLAGS: -Dwarnings
+
   wasm-tests:
     name: "wasm (firefox, ${{ matrix.name }})"
     runs-on: ubuntu-latest
diff --git a/library/portable-simd/Cargo.lock b/library/portable-simd/Cargo.lock
index 46312c09657..1584c704fb2 100644
--- a/library/portable-simd/Cargo.lock
+++ b/library/portable-simd/Cargo.lock
@@ -177,6 +177,9 @@ name = "std_float"
 version = "0.1.0"
 dependencies = [
  "core_simd",
+ "test_helpers",
+ "wasm-bindgen",
+ "wasm-bindgen-test",
 ]
 
 [[package]]
diff --git a/library/portable-simd/crates/core_simd/src/lib.rs b/library/portable-simd/crates/core_simd/src/lib.rs
index a25723e11ce..7a161b7e01d 100644
--- a/library/portable-simd/crates/core_simd/src/lib.rs
+++ b/library/portable-simd/crates/core_simd/src/lib.rs
@@ -13,11 +13,12 @@
     simd_ffi,
     staged_api,
     strict_provenance,
+    prelude_import,
     ptr_metadata
 )]
 #![cfg_attr(
     all(
-        any(target_arch = "aarch64", target_arch = "arm",),
+        any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "arm",),
         any(
             all(target_feature = "v6", not(target_feature = "mclass")),
             all(target_feature = "mclass", target_feature = "dsp"),
@@ -33,12 +34,21 @@
     any(target_arch = "powerpc", target_arch = "powerpc64"),
     feature(stdarch_powerpc)
 )]
+#![cfg_attr(
+    all(target_arch = "x86_64", target_feature = "avx512f"),
+    feature(stdarch_x86_avx512)
+)]
 #![warn(missing_docs, clippy::missing_inline_in_public_items)] // basically all items, really
 #![deny(unsafe_op_in_unsafe_fn, clippy::undocumented_unsafe_blocks)]
+#![doc(test(attr(deny(warnings))))]
 #![allow(internal_features)]
 #![unstable(feature = "portable_simd", issue = "86656")]
 //! Portable SIMD module.
 
+#[prelude_import]
+#[allow(unused_imports)]
+use core::prelude::v1::*;
+
 #[path = "mod.rs"]
 mod core_simd;
 pub use self::core_simd::simd;
diff --git a/library/portable-simd/crates/core_simd/src/masks.rs b/library/portable-simd/crates/core_simd/src/masks.rs
index e480c25a51e..e6e27c76a5e 100644
--- a/library/portable-simd/crates/core_simd/src/masks.rs
+++ b/library/portable-simd/crates/core_simd/src/masks.rs
@@ -34,6 +34,7 @@ mod sealed {
         fn eq(self, other: Self) -> bool;
 
         fn to_usize(self) -> usize;
+        fn max_unsigned() -> u64;
 
         type Unsigned: SimdElement;
 
@@ -78,6 +79,11 @@ macro_rules! impl_element {
                 self as usize
             }
 
+            #[inline]
+            fn max_unsigned() -> u64 {
+                <$unsigned>::MAX as u64
+            }
+
             type Unsigned = $unsigned;
 
             const TRUE: Self = -1;
diff --git a/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs b/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs
index ae9ff6894b0..8a1079042f0 100644
--- a/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs
+++ b/library/portable-simd/crates/core_simd/src/swizzle_dyn.rs
@@ -16,7 +16,10 @@ where
     #[inline]
     pub fn swizzle_dyn(self, idxs: Simd<u8, N>) -> Self {
         #![allow(unused_imports, unused_unsafe)]
-        #[cfg(all(target_arch = "aarch64", target_endian = "little"))]
+        #[cfg(all(
+            any(target_arch = "aarch64", target_arch = "arm64ec"),
+            target_endian = "little"
+        ))]
         use core::arch::aarch64::{uint8x8_t, vqtbl1q_u8, vtbl1_u8};
         #[cfg(all(
             target_arch = "arm",
@@ -37,6 +40,7 @@ where
                 #[cfg(all(
                     any(
                         target_arch = "aarch64",
+                        target_arch = "arm64ec",
                         all(target_arch = "arm", target_feature = "v7")
                     ),
                     target_feature = "neon",
@@ -48,7 +52,7 @@ where
                 #[cfg(target_feature = "simd128")]
                 16 => transize(wasm::i8x16_swizzle, self, idxs),
                 #[cfg(all(
-                    target_arch = "aarch64",
+                    any(target_arch = "aarch64", target_arch = "arm64ec"),
                     target_feature = "neon",
                     target_endian = "little"
                 ))]
diff --git a/library/portable-simd/crates/core_simd/src/vector.rs b/library/portable-simd/crates/core_simd/src/vector.rs
index 9e97a3161bb..6c8205b112c 100644
--- a/library/portable-simd/crates/core_simd/src/vector.rs
+++ b/library/portable-simd/crates/core_simd/src/vector.rs
@@ -1,5 +1,6 @@
 use crate::simd::{
     cmp::SimdPartialOrd,
+    num::SimdUint,
     ptr::{SimdConstPtr, SimdMutPtr},
     LaneCount, Mask, MaskElement, SupportedLaneCount, Swizzle,
 };
@@ -262,6 +263,7 @@ where
     /// # Panics
     ///
     /// Panics if the slice's length is less than the vector's `Simd::N`.
+    /// Use `load_or_default` for an alternative that does not panic.
     ///
     /// # Example
     ///
@@ -315,6 +317,143 @@ where
         unsafe { self.store(slice.as_mut_ptr().cast()) }
     }
 
+    /// Reads contiguous elements from `slice`. Elements are read so long as they're in-bounds for
+    /// the `slice`. Otherwise, the default value for the element type is returned.
+    ///
+    /// # Examples
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::Simd;
+    /// let vec: Vec<i32> = vec![10, 11];
+    ///
+    /// let result = Simd::<i32, 4>::load_or_default(&vec);
+    /// assert_eq!(result, Simd::from_array([10, 11, 0, 0]));
+    /// ```
+    #[must_use]
+    #[inline]
+    pub fn load_or_default(slice: &[T]) -> Self
+    where
+        T: Default,
+    {
+        Self::load_or(slice, Default::default())
+    }
+
+    /// Reads contiguous elements from `slice`. Elements are read so long as they're in-bounds for
+    /// the `slice`. Otherwise, the corresponding value from `or` is passed through.
+    ///
+    /// # Examples
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::Simd;
+    /// let vec: Vec<i32> = vec![10, 11];
+    /// let or = Simd::from_array([-5, -4, -3, -2]);
+    ///
+    /// let result = Simd::load_or(&vec, or);
+    /// assert_eq!(result, Simd::from_array([10, 11, -3, -2]));
+    /// ```
+    #[must_use]
+    #[inline]
+    pub fn load_or(slice: &[T], or: Self) -> Self {
+        Self::load_select(slice, Mask::splat(true), or)
+    }
+
+    /// Reads contiguous elements from `slice`. Each element is read from memory if its
+    /// corresponding element in `enable` is `true`.
+    ///
+    /// When the element is disabled or out of bounds for the slice, that memory location
+    /// is not accessed and the corresponding value from `or` is passed through.
+    ///
+    /// # Examples
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::{Simd, Mask};
+    /// let vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
+    /// let enable = Mask::from_array([true, true, false, true]);
+    /// let or = Simd::from_array([-5, -4, -3, -2]);
+    ///
+    /// let result = Simd::load_select(&vec, enable, or);
+    /// assert_eq!(result, Simd::from_array([10, 11, -3, 13]));
+    /// ```
+    #[must_use]
+    #[inline]
+    pub fn load_select_or_default(slice: &[T], enable: Mask<<T as SimdElement>::Mask, N>) -> Self
+    where
+        T: Default,
+    {
+        Self::load_select(slice, enable, Default::default())
+    }
+
+    /// Reads contiguous elements from `slice`. Each element is read from memory if its
+    /// corresponding element in `enable` is `true`.
+    ///
+    /// When the element is disabled or out of bounds for the slice, that memory location
+    /// is not accessed and the corresponding value from `or` is passed through.
+    ///
+    /// # Examples
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::{Simd, Mask};
+    /// let vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
+    /// let enable = Mask::from_array([true, true, false, true]);
+    /// let or = Simd::from_array([-5, -4, -3, -2]);
+    ///
+    /// let result = Simd::load_select(&vec, enable, or);
+    /// assert_eq!(result, Simd::from_array([10, 11, -3, 13]));
+    /// ```
+    #[must_use]
+    #[inline]
+    pub fn load_select(
+        slice: &[T],
+        mut enable: Mask<<T as SimdElement>::Mask, N>,
+        or: Self,
+    ) -> Self {
+        enable &= mask_up_to(slice.len());
+        // SAFETY: We performed the bounds check by updating the mask. &[T] is properly aligned to
+        // the element.
+        unsafe { Self::load_select_ptr(slice.as_ptr(), enable, or) }
+    }
+
+    /// Reads contiguous elements from `slice`. Each element is read from memory if its
+    /// corresponding element in `enable` is `true`.
+    ///
+    /// When the element is disabled, that memory location is not accessed and the corresponding
+    /// value from `or` is passed through.
+    #[must_use]
+    #[inline]
+    pub unsafe fn load_select_unchecked(
+        slice: &[T],
+        enable: Mask<<T as SimdElement>::Mask, N>,
+        or: Self,
+    ) -> Self {
+        let ptr = slice.as_ptr();
+        // SAFETY: The safety of reading elements from `slice` is ensured by the caller.
+        unsafe { Self::load_select_ptr(ptr, enable, or) }
+    }
+
+    /// Reads contiguous elements starting at `ptr`. Each element is read from memory if its
+    /// corresponding element in `enable` is `true`.
+    ///
+    /// When the element is disabled, that memory location is not accessed and the corresponding
+    /// value from `or` is passed through.
+    #[must_use]
+    #[inline]
+    pub unsafe fn load_select_ptr(
+        ptr: *const T,
+        enable: Mask<<T as SimdElement>::Mask, N>,
+        or: Self,
+    ) -> Self {
+        // SAFETY: The safety of reading elements through `ptr` is ensured by the caller.
+        unsafe { core::intrinsics::simd::simd_masked_load(enable.to_int(), ptr, or) }
+    }
+
     /// Reads from potentially discontiguous indices in `slice` to construct a SIMD vector.
     /// If an index is out-of-bounds, the element is instead selected from the `or` vector.
     ///
@@ -493,6 +632,77 @@ where
         unsafe { core::intrinsics::simd::simd_gather(or, source, enable.to_int()) }
     }
 
+    /// Conditionally write contiguous elements to `slice`. The `enable` mask controls
+    /// which elements are written, as long as they're in-bounds of the `slice`.
+    /// If the element is disabled or out of bounds, no memory access to that location
+    /// is made.
+    ///
+    /// # Examples
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::{Simd, Mask};
+    /// let mut arr = [0i32; 4];
+    /// let write = Simd::from_array([-5, -4, -3, -2]);
+    /// let enable = Mask::from_array([false, true, true, true]);
+    ///
+    /// write.store_select(&mut arr[..3], enable);
+    /// assert_eq!(arr, [0, -4, -3, 0]);
+    /// ```
+    #[inline]
+    pub fn store_select(self, slice: &mut [T], mut enable: Mask<<T as SimdElement>::Mask, N>) {
+        enable &= mask_up_to(slice.len());
+        // SAFETY: We performed the bounds check by updating the mask. &[T] is properly aligned to
+        // the element.
+        unsafe { self.store_select_ptr(slice.as_mut_ptr(), enable) }
+    }
+
+    /// Conditionally write contiguous elements to `slice`. The `enable` mask controls
+    /// which elements are written.
+    ///
+    /// # Safety
+    ///
+    /// Every enabled element must be in bounds for the `slice`.
+    ///
+    /// # Examples
+    /// ```
+    /// # #![feature(portable_simd)]
+    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
+    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
+    /// # use simd::{Simd, Mask};
+    /// let mut arr = [0i32; 4];
+    /// let write = Simd::from_array([-5, -4, -3, -2]);
+    /// let enable = Mask::from_array([false, true, true, true]);
+    ///
+    /// unsafe { write.store_select_unchecked(&mut arr, enable) };
+    /// assert_eq!(arr, [0, -4, -3, -2]);
+    /// ```
+    #[inline]
+    pub unsafe fn store_select_unchecked(
+        self,
+        slice: &mut [T],
+        enable: Mask<<T as SimdElement>::Mask, N>,
+    ) {
+        let ptr = slice.as_mut_ptr();
+        // SAFETY: The safety of writing elements in `slice` is ensured by the caller.
+        unsafe { self.store_select_ptr(ptr, enable) }
+    }
+
+    /// Conditionally write contiguous elements starting from `ptr`.
+    /// The `enable` mask controls which elements are written.
+    /// When disabled, the memory location corresponding to that element is not accessed.
+    ///
+    /// # Safety
+    ///
+    /// Memory addresses for element are calculated [`pointer::wrapping_offset`] and
+    /// each enabled element must satisfy the same conditions as [`core::ptr::write`].
+    #[inline]
+    pub unsafe fn store_select_ptr(self, ptr: *mut T, enable: Mask<<T as SimdElement>::Mask, N>) {
+        // SAFETY: The safety of writing elements through `ptr` is ensured by the caller.
+        unsafe { core::intrinsics::simd::simd_masked_store(enable.to_int(), ptr, self) }
+    }
+
     /// Writes the values in a SIMD vector to potentially discontiguous indices in `slice`.
     /// If an index is out-of-bounds, the write is suppressed without panicking.
     /// If two elements in the scattered vector would write to the same index
@@ -980,3 +1190,37 @@ where
 {
     type Mask = isize;
 }
+
+#[inline]
+fn lane_indices<const N: usize>() -> Simd<usize, N>
+where
+    LaneCount<N>: SupportedLaneCount,
+{
+    let mut index = [0; N];
+    for i in 0..N {
+        index[i] = i;
+    }
+    Simd::from_array(index)
+}
+
+#[inline]
+fn mask_up_to<M, const N: usize>(len: usize) -> Mask<M, N>
+where
+    LaneCount<N>: SupportedLaneCount,
+    M: MaskElement,
+{
+    let index = lane_indices::<N>();
+    let max_value: u64 = M::max_unsigned();
+    macro_rules! case {
+        ($ty:ty) => {
+            if N < <$ty>::MAX as usize && max_value as $ty as u64 == max_value {
+                return index.cast().simd_lt(Simd::splat(len.min(N) as $ty)).cast();
+            }
+        };
+    }
+    case!(u8);
+    case!(u16);
+    case!(u32);
+    case!(u64);
+    index.simd_lt(Simd::splat(len)).cast()
+}
diff --git a/library/portable-simd/crates/core_simd/src/vendor.rs b/library/portable-simd/crates/core_simd/src/vendor.rs
index 6223bedb4e1..1a34a3a8de5 100644
--- a/library/portable-simd/crates/core_simd/src/vendor.rs
+++ b/library/portable-simd/crates/core_simd/src/vendor.rs
@@ -24,7 +24,7 @@ mod x86;
 #[cfg(target_arch = "wasm32")]
 mod wasm32;
 
-#[cfg(any(target_arch = "aarch64", target_arch = "arm",))]
+#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "arm",))]
 mod arm;
 
 #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
diff --git a/library/portable-simd/crates/core_simd/src/vendor/arm.rs b/library/portable-simd/crates/core_simd/src/vendor/arm.rs
index ee5c6421373..f8878d11f09 100644
--- a/library/portable-simd/crates/core_simd/src/vendor/arm.rs
+++ b/library/portable-simd/crates/core_simd/src/vendor/arm.rs
@@ -4,12 +4,13 @@ use crate::simd::*;
 #[cfg(target_arch = "arm")]
 use core::arch::arm::*;
 
-#[cfg(target_arch = "aarch64")]
+#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))]
 use core::arch::aarch64::*;
 
 #[cfg(all(
     any(
         target_arch = "aarch64",
+        target_arch = "arm64ec",
         all(target_arch = "arm", target_feature = "v7"),
     ),
     target_endian = "little"
@@ -69,7 +70,10 @@ mod simd32 {
     from_transmute! { unsafe Simd<i8, 4> => int8x4_t }
 }
 
-#[cfg(target_arch = "aarch64")]
+#[cfg(all(
+    any(target_arch = "aarch64", target_arch = "arm64ec"),
+    target_endian = "little"
+))]
 mod aarch64 {
     use super::neon::*;
     use super::*;
diff --git a/library/portable-simd/crates/core_simd/tests/masked_load_store.rs b/library/portable-simd/crates/core_simd/tests/masked_load_store.rs
new file mode 100644
index 00000000000..3d38658e945
--- /dev/null
+++ b/library/portable-simd/crates/core_simd/tests/masked_load_store.rs
@@ -0,0 +1,35 @@
+#![feature(portable_simd)]
+use core_simd::simd::prelude::*;
+
+#[cfg(target_arch = "wasm32")]
+use wasm_bindgen_test::*;
+
+#[cfg(target_arch = "wasm32")]
+wasm_bindgen_test_configure!(run_in_browser);
+
+#[test]
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+fn masked_load_store() {
+    let mut arr = [u8::MAX; 7];
+
+    u8x4::splat(0).store_select(&mut arr[5..], Mask::from_array([false, true, false, true]));
+    // write to index 8 is OOB and dropped
+    assert_eq!(arr, [255u8, 255, 255, 255, 255, 255, 0]);
+
+    u8x4::from_array([0, 1, 2, 3]).store_select(&mut arr[1..], Mask::splat(true));
+    assert_eq!(arr, [255u8, 0, 1, 2, 3, 255, 0]);
+
+    // read from index 8 is OOB and dropped
+    assert_eq!(
+        u8x4::load_or(&arr[4..], u8x4::splat(42)),
+        u8x4::from_array([3, 255, 0, 42])
+    );
+    assert_eq!(
+        u8x4::load_select(
+            &arr[4..],
+            Mask::from_array([true, false, true, true]),
+            u8x4::splat(42)
+        ),
+        u8x4::from_array([3, 42, 0, 42])
+    );
+}
diff --git a/library/portable-simd/crates/core_simd/tests/swizzle_dyn.rs b/library/portable-simd/crates/core_simd/tests/swizzle_dyn.rs
index f21a937f01c..19ffe1417c8 100644
--- a/library/portable-simd/crates/core_simd/tests/swizzle_dyn.rs
+++ b/library/portable-simd/crates/core_simd/tests/swizzle_dyn.rs
@@ -1,6 +1,6 @@
 #![feature(portable_simd)]
 use core::{fmt, ops::RangeInclusive};
-use test_helpers::{self, biteq, make_runner, prop_assert_biteq};
+use test_helpers::{biteq, make_runner, prop_assert_biteq};
 
 fn swizzle_dyn_scalar_ver<const N: usize>(values: [u8; N], idxs: [u8; N]) -> [u8; N] {
     let mut array = [0; N];
diff --git a/library/portable-simd/crates/std_float/Cargo.toml b/library/portable-simd/crates/std_float/Cargo.toml
index 84c69774cbd..0896094ee63 100644
--- a/library/portable-simd/crates/std_float/Cargo.toml
+++ b/library/portable-simd/crates/std_float/Cargo.toml
@@ -8,6 +8,13 @@ edition = "2021"
 [dependencies]
 core_simd = { path = "../core_simd", default-features = false }
 
+[dev-dependencies.test_helpers]
+path = "../test_helpers"
+
+[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
+wasm-bindgen = "0.2"
+wasm-bindgen-test = "0.3"
+
 [features]
 default = ["as_crate"]
 as_crate = []
diff --git a/library/portable-simd/crates/std_float/src/lib.rs b/library/portable-simd/crates/std_float/src/lib.rs
index 4c547777fde..148aa5f9f17 100644
--- a/library/portable-simd/crates/std_float/src/lib.rs
+++ b/library/portable-simd/crates/std_float/src/lib.rs
@@ -1,4 +1,3 @@
-#![cfg_attr(feature = "as_crate", no_std)] // We are std!
 #![cfg_attr(
     feature = "as_crate",
     feature(core_intrinsics),
@@ -44,7 +43,7 @@ use crate::sealed::Sealed;
 /// For now this trait is available to permit experimentation with SIMD float
 /// operations that may lack hardware support, such as `mul_add`.
 pub trait StdFloat: Sealed + Sized {
-    /// Fused multiply-add.  Computes `(self * a) + b` with only one rounding error,
+    /// Elementwise fused multiply-add. Computes `(self * a) + b` with only one rounding error,
     /// yielding a more accurate result than an unfused multiply-add.
     ///
     /// Using `mul_add` *may* be more performant than an unfused multiply-add if the target
@@ -57,22 +56,65 @@ pub trait StdFloat: Sealed + Sized {
         unsafe { intrinsics::simd_fma(self, a, b) }
     }
 
-    /// Produces a vector where every lane has the square root value
-    /// of the equivalently-indexed lane in `self`
+    /// Produces a vector where every element has the square root value
+    /// of the equivalently-indexed element in `self`
     #[inline]
     #[must_use = "method returns a new vector and does not mutate the original value"]
     fn sqrt(self) -> Self {
         unsafe { intrinsics::simd_fsqrt(self) }
     }
 
-    /// Returns the smallest integer greater than or equal to each lane.
+    /// Produces a vector where every element has the sine of the value
+    /// in the equivalently-indexed element in `self`.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn sin(self) -> Self;
+
+    /// Produces a vector where every element has the cosine of the value
+    /// in the equivalently-indexed element in `self`.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn cos(self) -> Self;
+
+    /// Produces a vector where every element has the exponential (base e) of the value
+    /// in the equivalently-indexed element in `self`.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn exp(self) -> Self;
+
+    /// Produces a vector where every element has the exponential (base 2) of the value
+    /// in the equivalently-indexed element in `self`.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn exp2(self) -> Self;
+
+    /// Produces a vector where every element has the natural logarithm of the value
+    /// in the equivalently-indexed element in `self`.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn ln(self) -> Self;
+
+    /// Produces a vector where every element has the logarithm with respect to an arbitrary
+    /// in the equivalently-indexed elements in `self` and `base`.
+    #[inline]
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn log(self, base: Self) -> Self {
+        unsafe { intrinsics::simd_div(self.ln(), base.ln()) }
+    }
+
+    /// Produces a vector where every element has the base-2 logarithm of the value
+    /// in the equivalently-indexed element in `self`.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn log2(self) -> Self;
+
+    /// Produces a vector where every element has the base-10 logarithm of the value
+    /// in the equivalently-indexed element in `self`.
+    #[must_use = "method returns a new vector and does not mutate the original value"]
+    fn log10(self) -> Self;
+
+    /// Returns the smallest integer greater than or equal to each element.
     #[must_use = "method returns a new vector and does not mutate the original value"]
     #[inline]
     fn ceil(self) -> Self {
         unsafe { intrinsics::simd_ceil(self) }
     }
 
-    /// Returns the largest integer value less than or equal to each lane.
+    /// Returns the largest integer value less than or equal to each element.
     #[must_use = "method returns a new vector and does not mutate the original value"]
     #[inline]
     fn floor(self) -> Self {
@@ -101,46 +143,65 @@ pub trait StdFloat: Sealed + Sized {
 impl<const N: usize> Sealed for Simd<f32, N> where LaneCount<N>: SupportedLaneCount {}
 impl<const N: usize> Sealed for Simd<f64, N> where LaneCount<N>: SupportedLaneCount {}
 
-// We can safely just use all the defaults.
-impl<const N: usize> StdFloat for Simd<f32, N>
-where
-    LaneCount<N>: SupportedLaneCount,
-{
-    /// Returns the floating point's fractional value, with its integer part removed.
-    #[must_use = "method returns a new vector and does not mutate the original value"]
-    #[inline]
-    fn fract(self) -> Self {
-        self - self.trunc()
-    }
-}
-
-impl<const N: usize> StdFloat for Simd<f64, N>
-where
-    LaneCount<N>: SupportedLaneCount,
-{
-    /// Returns the floating point's fractional value, with its integer part removed.
-    #[must_use = "method returns a new vector and does not mutate the original value"]
-    #[inline]
-    fn fract(self) -> Self {
-        self - self.trunc()
+macro_rules! impl_float {
+    {
+        $($fn:ident: $intrinsic:ident,)*
+    } => {
+        impl<const N: usize> StdFloat for Simd<f32, N>
+        where
+            LaneCount<N>: SupportedLaneCount,
+        {
+            #[inline]
+            fn fract(self) -> Self {
+                self - self.trunc()
+            }
+
+            $(
+            #[inline]
+            fn $fn(self) -> Self {
+                unsafe { intrinsics::$intrinsic(self) }
+            }
+            )*
+        }
+
+        impl<const N: usize> StdFloat for Simd<f64, N>
+        where
+            LaneCount<N>: SupportedLaneCount,
+        {
+            #[inline]
+            fn fract(self) -> Self {
+                self - self.trunc()
+            }
+
+            $(
+            #[inline]
+            fn $fn(self) -> Self {
+                // https://github.com/llvm/llvm-project/issues/83729
+                #[cfg(target_arch = "aarch64")]
+                {
+                    let mut ln = Self::splat(0f64);
+                    for i in 0..N {
+                        ln[i] = self[i].$fn()
+                    }
+                    ln
+                }
+
+                #[cfg(not(target_arch = "aarch64"))]
+                {
+                    unsafe { intrinsics::$intrinsic(self) }
+                }
+            }
+            )*
+        }
     }
 }
 
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use simd::prelude::*;
-
-    #[test]
-    fn everything_works() {
-        let x = f32x4::from_array([0.1, 0.5, 0.6, -1.5]);
-        let x2 = x + x;
-        let _xc = x.ceil();
-        let _xf = x.floor();
-        let _xr = x.round();
-        let _xt = x.trunc();
-        let _xfma = x.mul_add(x, x);
-        let _xsqrt = x.sqrt();
-        let _ = x2.abs() * x2;
-    }
+impl_float! {
+    sin: simd_fsin,
+    cos: simd_fcos,
+    exp: simd_fexp,
+    exp2: simd_fexp2,
+    ln: simd_flog,
+    log2: simd_flog2,
+    log10: simd_flog10,
 }
diff --git a/library/portable-simd/crates/std_float/tests/float.rs b/library/portable-simd/crates/std_float/tests/float.rs
new file mode 100644
index 00000000000..c66c968f8c6
--- /dev/null
+++ b/library/portable-simd/crates/std_float/tests/float.rs
@@ -0,0 +1,74 @@
+#![feature(portable_simd)]
+
+macro_rules! unary_test {
+    { $scalar:tt, $($func:tt),+ } => {
+        test_helpers::test_lanes! {
+            $(
+            fn $func<const LANES: usize>() {
+                test_helpers::test_unary_elementwise(
+                    &core_simd::simd::Simd::<$scalar, LANES>::$func,
+                    &$scalar::$func,
+                    &|_| true,
+                )
+            }
+            )*
+        }
+    }
+}
+
+macro_rules! binary_test {
+    { $scalar:tt, $($func:tt),+ } => {
+        test_helpers::test_lanes! {
+            $(
+            fn $func<const LANES: usize>() {
+                test_helpers::test_binary_elementwise(
+                    &core_simd::simd::Simd::<$scalar, LANES>::$func,
+                    &$scalar::$func,
+                    &|_, _| true,
+                )
+            }
+            )*
+        }
+    }
+}
+
+macro_rules! ternary_test {
+    { $scalar:tt, $($func:tt),+ } => {
+        test_helpers::test_lanes! {
+            $(
+            fn $func<const LANES: usize>() {
+                test_helpers::test_ternary_elementwise(
+                    &core_simd::simd::Simd::<$scalar, LANES>::$func,
+                    &$scalar::$func,
+                    &|_, _, _| true,
+                )
+            }
+            )*
+        }
+    }
+}
+
+macro_rules! impl_tests {
+    { $scalar:tt } => {
+        mod $scalar {
+            use std_float::StdFloat;
+
+            unary_test! { $scalar, sqrt, sin, cos, exp, exp2, ln, log2, log10, ceil, floor, round, trunc }
+            binary_test! { $scalar, log }
+            ternary_test! { $scalar, mul_add }
+
+            test_helpers::test_lanes! {
+                fn fract<const LANES: usize>() {
+                    test_helpers::test_unary_elementwise_flush_subnormals(
+                        &core_simd::simd::Simd::<$scalar, LANES>::fract,
+                        &$scalar::fract,
+                        &|_| true,
+                    )
+                }
+            }
+        }
+    }
+}
+
+impl_tests! { f32 }
+impl_tests! { f64 }
diff --git a/library/proc_macro/src/bridge/handle.rs b/library/proc_macro/src/bridge/handle.rs
index 894acae217e..8c53bb609f6 100644
--- a/library/proc_macro/src/bridge/handle.rs
+++ b/library/proc_macro/src/bridge/handle.rs
@@ -21,7 +21,7 @@ impl<T> OwnedStore<T> {
     pub(super) fn new(counter: &'static AtomicU32) -> Self {
         // Ensure the handle counter isn't 0, which would panic later,
         // when `NonZero::new` (aka `Handle::new`) is called in `alloc`.
-        assert_ne!(counter.load(Ordering::SeqCst), 0);
+        assert_ne!(counter.load(Ordering::Relaxed), 0);
 
         OwnedStore { counter, data: BTreeMap::new() }
     }
@@ -29,7 +29,7 @@ impl<T> OwnedStore<T> {
 
 impl<T> OwnedStore<T> {
     pub(super) fn alloc(&mut self, x: T) -> Handle {
-        let counter = self.counter.fetch_add(1, Ordering::SeqCst);
+        let counter = self.counter.fetch_add(1, Ordering::Relaxed);
         let handle = Handle::new(counter).expect("`proc_macro` handle counter overflowed");
         assert!(self.data.insert(handle, x).is_none());
         handle
diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs
index a834b36697c..dc0e302a810 100644
--- a/library/std/src/alloc.rs
+++ b/library/std/src/alloc.rs
@@ -329,7 +329,7 @@ static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
 /// ```
 #[unstable(feature = "alloc_error_hook", issue = "51245")]
 pub fn set_alloc_error_hook(hook: fn(Layout)) {
-    HOOK.store(hook as *mut (), Ordering::SeqCst);
+    HOOK.store(hook as *mut (), Ordering::Release);
 }
 
 /// Unregisters the current allocation error hook, returning it.
@@ -339,7 +339,7 @@ pub fn set_alloc_error_hook(hook: fn(Layout)) {
 /// If no custom hook is registered, the default hook will be returned.
 #[unstable(feature = "alloc_error_hook", issue = "51245")]
 pub fn take_alloc_error_hook() -> fn(Layout) {
-    let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst);
+    let hook = HOOK.swap(ptr::null_mut(), Ordering::Acquire);
     if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } }
 }
 
@@ -362,7 +362,7 @@ fn default_alloc_error_hook(layout: Layout) {
 #[alloc_error_handler]
 #[unstable(feature = "alloc_internals", issue = "none")]
 pub fn rust_oom(layout: Layout) -> ! {
-    let hook = HOOK.load(Ordering::SeqCst);
+    let hook = HOOK.load(Ordering::Acquire);
     let hook: fn(Layout) =
         if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } };
     hook(layout);
diff --git a/library/std/src/net/test.rs b/library/std/src/net/test.rs
index 37937b5ea95..d318d457f35 100644
--- a/library/std/src/net/test.rs
+++ b/library/std/src/net/test.rs
@@ -7,12 +7,12 @@ use crate::sync::atomic::{AtomicUsize, Ordering};
 static PORT: AtomicUsize = AtomicUsize::new(0);
 
 pub fn next_test_ip4() -> SocketAddr {
-    let port = PORT.fetch_add(1, Ordering::SeqCst) as u16 + base_port();
+    let port = PORT.fetch_add(1, Ordering::Relaxed) as u16 + base_port();
     SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), port))
 }
 
 pub fn next_test_ip6() -> SocketAddr {
-    let port = PORT.fetch_add(1, Ordering::SeqCst) as u16 + base_port();
+    let port = PORT.fetch_add(1, Ordering::Relaxed) as u16 + base_port();
     SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), port, 0, 0))
 }
 
diff --git a/library/std/src/os/freebsd/net.rs b/library/std/src/os/freebsd/net.rs
index 33990d54caa..b7e0fdc0a9a 100644
--- a/library/std/src/os/freebsd/net.rs
+++ b/library/std/src/os/freebsd/net.rs
@@ -2,6 +2,7 @@
 
 #![unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
 
+use crate::ffi::CStr;
 use crate::io;
 use crate::os::unix::net;
 use crate::sealed::Sealed;
@@ -40,6 +41,15 @@ pub trait UnixSocketExt: Sealed {
     /// ```
     #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
     fn set_local_creds_persistent(&self, local_creds_persistent: bool) -> io::Result<()>;
+
+    /// Get a filter name if one had been set previously on the socket.
+    #[unstable(feature = "acceptfilter", issue = "121891")]
+    fn acceptfilter(&self) -> io::Result<&CStr>;
+
+    /// Set or disable a filter on the socket to filter incoming connections
+    /// to defer it before accept(2)
+    #[unstable(feature = "acceptfilter", issue = "121891")]
+    fn set_acceptfilter(&self, name: &CStr) -> io::Result<()>;
 }
 
 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
@@ -51,6 +61,14 @@ impl UnixSocketExt for net::UnixDatagram {
     fn set_local_creds_persistent(&self, local_creds_persistent: bool) -> io::Result<()> {
         self.as_inner().set_local_creds_persistent(local_creds_persistent)
     }
+
+    fn acceptfilter(&self) -> io::Result<&CStr> {
+        self.as_inner().acceptfilter()
+    }
+
+    fn set_acceptfilter(&self, name: &CStr) -> io::Result<()> {
+        self.as_inner().set_acceptfilter(name)
+    }
 }
 
 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
@@ -62,4 +80,12 @@ impl UnixSocketExt for net::UnixStream {
     fn set_local_creds_persistent(&self, local_creds_persistent: bool) -> io::Result<()> {
         self.as_inner().set_local_creds_persistent(local_creds_persistent)
     }
+
+    fn acceptfilter(&self) -> io::Result<&CStr> {
+        self.as_inner().acceptfilter()
+    }
+
+    fn set_acceptfilter(&self, name: &CStr) -> io::Result<()> {
+        self.as_inner().set_acceptfilter(name)
+    }
 }
diff --git a/library/std/src/os/netbsd/net.rs b/library/std/src/os/netbsd/net.rs
index 5c82f43077d..b9679c7b3af 100644
--- a/library/std/src/os/netbsd/net.rs
+++ b/library/std/src/os/netbsd/net.rs
@@ -2,6 +2,7 @@
 
 #![unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
 
+use crate::ffi::CStr;
 use crate::io;
 use crate::os::unix::net;
 use crate::sealed::Sealed;
@@ -40,6 +41,15 @@ pub trait UnixSocketExt: Sealed {
     /// ```
     #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
     fn set_local_creds(&self, local_creds: bool) -> io::Result<()>;
+
+    /// Get a filter name if one had been set previously on the socket.
+    #[unstable(feature = "acceptfilter", issue = "121891")]
+    fn acceptfilter(&self) -> io::Result<&CStr>;
+
+    /// Set or disable a filter on the socket to filter incoming connections
+    /// to defer it before accept(2)
+    #[unstable(feature = "acceptfilter", issue = "121891")]
+    fn set_acceptfilter(&self, name: &CStr) -> io::Result<()>;
 }
 
 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
@@ -51,6 +61,14 @@ impl UnixSocketExt for net::UnixDatagram {
     fn set_local_creds(&self, local_creds: bool) -> io::Result<()> {
         self.as_inner().set_local_creds(local_creds)
     }
+
+    fn acceptfilter(&self) -> io::Result<&CStr> {
+        self.as_inner().acceptfilter()
+    }
+
+    fn set_acceptfilter(&self, name: &CStr) -> io::Result<()> {
+        self.as_inner().set_acceptfilter(name)
+    }
 }
 
 #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
@@ -62,4 +80,12 @@ impl UnixSocketExt for net::UnixStream {
     fn set_local_creds(&self, local_creds: bool) -> io::Result<()> {
         self.as_inner().set_local_creds(local_creds)
     }
+
+    fn acceptfilter(&self) -> io::Result<&CStr> {
+        self.as_inner().acceptfilter()
+    }
+
+    fn set_acceptfilter(&self, name: &CStr) -> io::Result<()> {
+        self.as_inner().set_acceptfilter(name)
+    }
 }
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index 464a46264cb..e6e1d32fa54 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -272,7 +272,7 @@ fn default_hook(info: &PanicInfo<'_>) {
                 drop(backtrace::print(err, crate::backtrace_rs::PrintFmt::Full))
             }
             Some(BacktraceStyle::Off) => {
-                if FIRST_PANIC.swap(false, Ordering::SeqCst) {
+                if FIRST_PANIC.swap(false, Ordering::Relaxed) {
                     let _ = writeln!(
                         err,
                         "note: run with `RUST_BACKTRACE=1` environment variable to display a \
@@ -746,7 +746,13 @@ fn rust_panic_with_hook(
             panic_count::MustAbort::PanicInHook => {
                 // Don't try to print the message in this case
                 // - perhaps that is causing the recursive panics.
-                rtprintpanic!("thread panicked while processing panic. aborting.\n");
+                let panicinfo = PanicInfo::internal_constructor(
+                    None,     // no message
+                    location, // but we want to show the location!
+                    can_unwind,
+                    force_no_backtrace,
+                );
+                rtprintpanic!("{panicinfo}\nthread panicked while processing panic. aborting.\n");
             }
             panic_count::MustAbort::AlwaysAbort => {
                 // Unfortunately, this does not print a backtrace, because creating
diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs
index 7a7a7737635..36fa4e88b5b 100644
--- a/library/std/src/prelude/v1.rs
+++ b/library/std/src/prelude/v1.rs
@@ -91,6 +91,15 @@ pub use core::prelude::v1::cfg_eval;
 )]
 pub use core::prelude::v1::type_ascribe;
 
+#[cfg(not(bootstrap))]
+// Do not `doc(no_inline)` either.
+#[unstable(
+    feature = "deref_patterns",
+    issue = "87121",
+    reason = "placeholder syntax for deref patterns"
+)]
+pub use core::prelude::v1::deref;
+
 // The file so far is equivalent to core/src/prelude/v1.rs. It is duplicated
 // rather than glob imported because we want docs to show these re-exports as
 // pointing to within `std`.
diff --git a/library/std/src/sync/condvar/tests.rs b/library/std/src/sync/condvar/tests.rs
index 24f467f0b03..12d13a6b20b 100644
--- a/library/std/src/sync/condvar/tests.rs
+++ b/library/std/src/sync/condvar/tests.rs
@@ -170,14 +170,14 @@ fn wait_timeout_wake() {
         let t = thread::spawn(move || {
             let _g = m2.lock().unwrap();
             thread::sleep(Duration::from_millis(1));
-            notified_copy.store(true, Ordering::SeqCst);
+            notified_copy.store(true, Ordering::Relaxed);
             c2.notify_one();
         });
         let (g, timeout_res) = c.wait_timeout(g, Duration::from_millis(u64::MAX)).unwrap();
         assert!(!timeout_res.timed_out());
         // spurious wakeups mean this isn't necessarily true
         // so execute test again, if not notified
-        if !notified.load(Ordering::SeqCst) {
+        if !notified.load(Ordering::Relaxed) {
             t.join().unwrap();
             continue;
         }
diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs
index 895fcbd6b7e..d417034f5af 100644
--- a/library/std/src/sync/mutex.rs
+++ b/library/std/src/sync/mutex.rs
@@ -396,7 +396,7 @@ impl<T: ?Sized> Mutex<T> {
         self.poison.get()
     }
 
-    /// Clear the poisoned state from a mutex
+    /// Clear the poisoned state from a mutex.
     ///
     /// If the mutex is poisoned, it will remain poisoned until this function is called. This
     /// allows recovering from a poisoned state and marking that it has recovered. For example, if
diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs
index f7f098c082a..d648cd08994 100644
--- a/library/std/src/sync/rwlock.rs
+++ b/library/std/src/sync/rwlock.rs
@@ -439,7 +439,7 @@ impl<T: ?Sized> RwLock<T> {
         self.poison.get()
     }
 
-    /// Clear the poisoned state from a lock
+    /// Clear the poisoned state from a lock.
     ///
     /// If the lock is poisoned, it will remain poisoned until this function is called. This allows
     /// recovering from a poisoned state and marking that it has recovered. For example, if the
diff --git a/library/std/src/sys/pal/sgx/net.rs b/library/std/src/sys/pal/sgx/net.rs
index c4d5da1627c..edb28e2300f 100644
--- a/library/std/src/sys/pal/sgx/net.rs
+++ b/library/std/src/sys/pal/sgx/net.rs
@@ -524,6 +524,7 @@ pub mod netc {
 
     #[derive(Copy, Clone)]
     pub struct sockaddr_in {
+        #[allow(dead_code)]
         pub sin_family: sa_family_t,
         pub sin_port: u16,
         pub sin_addr: in_addr,
@@ -536,6 +537,7 @@ pub mod netc {
 
     #[derive(Copy, Clone)]
     pub struct sockaddr_in6 {
+        #[allow(dead_code)]
         pub sin6_family: sa_family_t,
         pub sin6_port: u16,
         pub sin6_addr: in6_addr,
diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs
index ba53ed88f37..23aa4da14a7 100644
--- a/library/std/src/sys/pal/uefi/helpers.rs
+++ b/library/std/src/sys/pal/uefi/helpers.rs
@@ -10,14 +10,16 @@
 //! - More information about protocols can be found [here](https://edk2-docs.gitbook.io/edk-ii-uefi-driver-writer-s-guide/3_foundation/36_protocols_and_handles)
 
 use r_efi::efi::{self, Guid};
+use r_efi::protocols::{device_path, device_path_to_text};
 
+use crate::ffi::OsString;
+use crate::io::{self, const_io_error};
 use crate::mem::{size_of, MaybeUninit};
-use crate::os::uefi;
+use crate::os::uefi::{self, env::boot_services, ffi::OsStringExt};
 use crate::ptr::NonNull;
-use crate::{
-    io::{self, const_io_error},
-    os::uefi::env::boot_services,
-};
+use crate::slice;
+use crate::sync::atomic::{AtomicPtr, Ordering};
+use crate::sys_common::wstr::WStrUnits;
 
 const BOOT_SERVICES_UNAVAILABLE: io::Error =
     const_io_error!(io::ErrorKind::Other, "Boot Services are no longer available");
@@ -142,9 +144,74 @@ pub(crate) unsafe fn close_event(evt: NonNull<crate::ffi::c_void>) -> io::Result
 
 /// Get the Protocol for current system handle.
 /// Note: Some protocols need to be manually freed. It is the callers responsibility to do so.
-pub(crate) fn image_handle_protocol<T>(protocol_guid: Guid) -> Option<NonNull<T>> {
-    let system_handle = uefi::env::try_image_handle()?;
-    open_protocol(system_handle, protocol_guid).ok()
+pub(crate) fn image_handle_protocol<T>(protocol_guid: Guid) -> io::Result<NonNull<T>> {
+    let system_handle = uefi::env::try_image_handle().ok_or(io::const_io_error!(
+        io::ErrorKind::NotFound,
+        "Protocol not found in Image handle"
+    ))?;
+    open_protocol(system_handle, protocol_guid)
+}
+
+pub(crate) fn device_path_to_text(path: NonNull<device_path::Protocol>) -> io::Result<OsString> {
+    fn path_to_text(
+        protocol: NonNull<device_path_to_text::Protocol>,
+        path: NonNull<device_path::Protocol>,
+    ) -> io::Result<OsString> {
+        let path_ptr: *mut r_efi::efi::Char16 = unsafe {
+            ((*protocol.as_ptr()).convert_device_path_to_text)(
+                path.as_ptr(),
+                // DisplayOnly
+                r_efi::efi::Boolean::FALSE,
+                // AllowShortcuts
+                r_efi::efi::Boolean::FALSE,
+            )
+        };
+
+        // SAFETY: `convert_device_path_to_text` returns a pointer to a null-terminated UTF-16
+        // string, and that string cannot be deallocated prior to dropping the `WStrUnits`, so
+        // it's safe for `WStrUnits` to use.
+        let path_len = unsafe {
+            WStrUnits::new(path_ptr)
+                .ok_or(io::const_io_error!(io::ErrorKind::InvalidData, "Invalid path"))?
+                .count()
+        };
+
+        let path = OsString::from_wide(unsafe { slice::from_raw_parts(path_ptr.cast(), path_len) });
+
+        if let Some(boot_services) = crate::os::uefi::env::boot_services() {
+            let boot_services: NonNull<r_efi::efi::BootServices> = boot_services.cast();
+            unsafe {
+                ((*boot_services.as_ptr()).free_pool)(path_ptr.cast());
+            }
+        }
+
+        Ok(path)
+    }
+
+    static LAST_VALID_HANDLE: AtomicPtr<crate::ffi::c_void> =
+        AtomicPtr::new(crate::ptr::null_mut());
+
+    if let Some(handle) = NonNull::new(LAST_VALID_HANDLE.load(Ordering::Acquire)) {
+        if let Ok(protocol) = open_protocol::<device_path_to_text::Protocol>(
+            handle,
+            device_path_to_text::PROTOCOL_GUID,
+        ) {
+            return path_to_text(protocol, path);
+        }
+    }
+
+    let device_path_to_text_handles = locate_handles(device_path_to_text::PROTOCOL_GUID)?;
+    for handle in device_path_to_text_handles {
+        if let Ok(protocol) = open_protocol::<device_path_to_text::Protocol>(
+            handle,
+            device_path_to_text::PROTOCOL_GUID,
+        ) {
+            LAST_VALID_HANDLE.store(handle.as_ptr(), Ordering::Release);
+            return path_to_text(protocol, path);
+        }
+    }
+
+    Err(io::const_io_error!(io::ErrorKind::NotFound, "No device path to text protocol found"))
 }
 
 /// Get RuntimeServices
diff --git a/library/std/src/sys/pal/uefi/os.rs b/library/std/src/sys/pal/uefi/os.rs
index e6693db68e6..58838c5876e 100644
--- a/library/std/src/sys/pal/uefi/os.rs
+++ b/library/std/src/sys/pal/uefi/os.rs
@@ -1,4 +1,4 @@
-use super::{unsupported, RawOsError};
+use super::{helpers, unsupported, RawOsError};
 use crate::error::Error as StdError;
 use crate::ffi::{OsStr, OsString};
 use crate::fmt;
@@ -7,6 +7,7 @@ use crate::marker::PhantomData;
 use crate::os::uefi;
 use crate::path::{self, PathBuf};
 use crate::ptr::NonNull;
+use r_efi::efi::protocols::{device_path, loaded_image_device_path};
 use r_efi::efi::Status;
 
 pub fn errno() -> RawOsError {
@@ -164,7 +165,10 @@ impl fmt::Display for JoinPathsError {
 impl StdError for JoinPathsError {}
 
 pub fn current_exe() -> io::Result<PathBuf> {
-    unsupported()
+    let protocol = helpers::image_handle_protocol::<device_path::Protocol>(
+        loaded_image_device_path::PROTOCOL_GUID,
+    )?;
+    helpers::device_path_to_text(protocol).map(PathBuf::from)
 }
 
 pub struct Env(!);
diff --git a/library/std/src/sys/pal/unix/net.rs b/library/std/src/sys/pal/unix/net.rs
index 09750b6ffc8..1f140f7844f 100644
--- a/library/std/src/sys/pal/unix/net.rs
+++ b/library/std/src/sys/pal/unix/net.rs
@@ -453,6 +453,37 @@ impl Socket {
         Ok(raw as u32)
     }
 
+    #[cfg(any(target_os = "freebsd", target_os = "netbsd"))]
+    pub fn set_acceptfilter(&self, name: &CStr) -> io::Result<()> {
+        if !name.to_bytes().is_empty() {
+            const AF_NAME_MAX: usize = 16;
+            let mut buf = [0; AF_NAME_MAX];
+            for (src, dst) in name.to_bytes().iter().zip(&mut buf[..AF_NAME_MAX - 1]) {
+                *dst = *src as i8;
+            }
+            let mut arg: libc::accept_filter_arg = unsafe { mem::zeroed() };
+            arg.af_name = buf;
+            setsockopt(self, libc::SOL_SOCKET, libc::SO_ACCEPTFILTER, &mut arg)
+        } else {
+            setsockopt(
+                self,
+                libc::SOL_SOCKET,
+                libc::SO_ACCEPTFILTER,
+                core::ptr::null_mut() as *mut c_void,
+            )
+        }
+    }
+
+    #[cfg(any(target_os = "freebsd", target_os = "netbsd"))]
+    pub fn acceptfilter(&self) -> io::Result<&CStr> {
+        let arg: libc::accept_filter_arg =
+            getsockopt(self, libc::SOL_SOCKET, libc::SO_ACCEPTFILTER)?;
+        let s: &[u8] =
+            unsafe { core::slice::from_raw_parts(arg.af_name.as_ptr() as *const u8, 16) };
+        let name = CStr::from_bytes_with_nul(s).unwrap();
+        Ok(name)
+    }
+
     #[cfg(any(target_os = "android", target_os = "linux",))]
     pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
         setsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED, passcred as libc::c_int)
diff --git a/library/std/src/sys/pal/unix/thread_local_dtor.rs b/library/std/src/sys/pal/unix/thread_local_dtor.rs
index 79b152cece9..e367ce5f906 100644
--- a/library/std/src/sys/pal/unix/thread_local_dtor.rs
+++ b/library/std/src/sys/pal/unix/thread_local_dtor.rs
@@ -35,7 +35,7 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
     #[cfg(not(sanitizer_cfi_normalize_integers))]
     #[cfi_encoding = "i"]
     #[repr(transparent)]
-    pub struct c_int(pub libc::c_int);
+    pub struct c_int(#[allow(dead_code)] pub libc::c_int);
 
     extern "C" {
         #[linkage = "extern_weak"]
diff --git a/library/std/src/sys/pal/unix/thread_parking/pthread.rs b/library/std/src/sys/pal/unix/thread_parking/pthread.rs
index ae805d84399..bb79cf9548e 100644
--- a/library/std/src/sys/pal/unix/thread_parking/pthread.rs
+++ b/library/std/src/sys/pal/unix/thread_parking/pthread.rs
@@ -5,7 +5,7 @@ use crate::marker::PhantomPinned;
 use crate::pin::Pin;
 use crate::ptr::addr_of_mut;
 use crate::sync::atomic::AtomicUsize;
-use crate::sync::atomic::Ordering::SeqCst;
+use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
 #[cfg(not(target_os = "nto"))]
 use crate::sys::time::TIMESPEC_MAX;
 #[cfg(target_os = "nto")]
@@ -150,16 +150,18 @@ impl Parker {
 
     // This implementation doesn't require `unsafe`, but other implementations
     // may assume this is only called by the thread that owns the Parker.
+    //
+    // For memory ordering, see std/src/sys_common/thread_parking/futex.rs
     pub unsafe fn park(self: Pin<&Self>) {
         // If we were previously notified then we consume this notification and
         // return quickly.
-        if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
+        if self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Relaxed).is_ok() {
             return;
         }
 
         // Otherwise we need to coordinate going to sleep
         lock(self.lock.get());
-        match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
+        match self.state.compare_exchange(EMPTY, PARKED, Relaxed, Relaxed) {
             Ok(_) => {}
             Err(NOTIFIED) => {
                 // We must read here, even though we know it will be `NOTIFIED`.
@@ -168,7 +170,7 @@ impl Parker {
                 // acquire operation that synchronizes with that `unpark` to observe
                 // any writes it made before the call to unpark. To do that we must
                 // read from the write it made to `state`.
-                let old = self.state.swap(EMPTY, SeqCst);
+                let old = self.state.swap(EMPTY, Acquire);
 
                 unlock(self.lock.get());
 
@@ -185,7 +187,7 @@ impl Parker {
         loop {
             wait(self.cvar.get(), self.lock.get());
 
-            match self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) {
+            match self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Relaxed) {
                 Ok(_) => break, // got a notification
                 Err(_) => {}    // spurious wakeup, go back to sleep
             }
@@ -201,16 +203,16 @@ impl Parker {
         // Like `park` above we have a fast path for an already-notified thread, and
         // afterwards we start coordinating for a sleep.
         // return quickly.
-        if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() {
+        if self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Relaxed).is_ok() {
             return;
         }
 
         lock(self.lock.get());
-        match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
+        match self.state.compare_exchange(EMPTY, PARKED, Relaxed, Relaxed) {
             Ok(_) => {}
             Err(NOTIFIED) => {
                 // We must read again here, see `park`.
-                let old = self.state.swap(EMPTY, SeqCst);
+                let old = self.state.swap(EMPTY, Acquire);
                 unlock(self.lock.get());
 
                 assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
@@ -228,7 +230,7 @@ impl Parker {
         // parked.
         wait_timeout(self.cvar.get(), self.lock.get(), dur);
 
-        match self.state.swap(EMPTY, SeqCst) {
+        match self.state.swap(EMPTY, Acquire) {
             NOTIFIED => unlock(self.lock.get()), // got a notification, hurray!
             PARKED => unlock(self.lock.get()),   // no notification, alas
             n => {
@@ -245,7 +247,7 @@ impl Parker {
         // `state` is already `NOTIFIED`. That is why this must be a swap
         // rather than a compare-and-swap that returns if it reads `NOTIFIED`
         // on failure.
-        match self.state.swap(NOTIFIED, SeqCst) {
+        match self.state.swap(NOTIFIED, Release) {
             EMPTY => return,    // no one was waiting
             NOTIFIED => return, // already unparked
             PARKED => {}        // gotta go wake someone up
diff --git a/library/std/src/sys/pal/unsupported/net.rs b/library/std/src/sys/pal/unsupported/net.rs
index 931fe9ba246..87e6106468f 100644
--- a/library/std/src/sys/pal/unsupported/net.rs
+++ b/library/std/src/sys/pal/unsupported/net.rs
@@ -346,6 +346,7 @@ pub mod netc {
 
     #[derive(Copy, Clone)]
     pub struct sockaddr_in {
+        #[allow(dead_code)]
         pub sin_family: sa_family_t,
         pub sin_port: u16,
         pub sin_addr: in_addr,
@@ -358,6 +359,7 @@ pub mod netc {
 
     #[derive(Copy, Clone)]
     pub struct sockaddr_in6 {
+        #[allow(dead_code)]
         pub sin6_family: sa_family_t,
         pub sin6_port: u16,
         pub sin6_addr: in6_addr,
diff --git a/library/std/src/sys/pal/wasi/net.rs b/library/std/src/sys/pal/wasi/net.rs
index 2098d05db0b..b4cf94c8781 100644
--- a/library/std/src/sys/pal/wasi/net.rs
+++ b/library/std/src/sys/pal/wasi/net.rs
@@ -520,6 +520,7 @@ pub mod netc {
 
     #[derive(Copy, Clone)]
     pub struct sockaddr_in {
+        #[allow(dead_code)]
         pub sin_family: sa_family_t,
         pub sin_port: u16,
         pub sin_addr: in_addr,
@@ -532,6 +533,7 @@ pub mod netc {
 
     #[derive(Copy, Clone)]
     pub struct sockaddr_in6 {
+        #[allow(dead_code)]
         pub sin6_family: sa_family_t,
         pub sin6_port: u16,
         pub sin6_addr: in6_addr,
diff --git a/library/std/src/sys/pal/wasm/alloc.rs b/library/std/src/sys/pal/wasm/alloc.rs
index 6dceb1689a8..b74ce0d4742 100644
--- a/library/std/src/sys/pal/wasm/alloc.rs
+++ b/library/std/src/sys/pal/wasm/alloc.rs
@@ -57,7 +57,10 @@ unsafe impl GlobalAlloc for System {
 
 #[cfg(target_feature = "atomics")]
 mod lock {
-    use crate::sync::atomic::{AtomicI32, Ordering::SeqCst};
+    use crate::sync::atomic::{
+        AtomicI32,
+        Ordering::{Acquire, Release},
+    };
 
     static LOCKED: AtomicI32 = AtomicI32::new(0);
 
@@ -65,7 +68,7 @@ mod lock {
 
     pub fn lock() -> DropLock {
         loop {
-            if LOCKED.swap(1, SeqCst) == 0 {
+            if LOCKED.swap(1, Acquire) == 0 {
                 return DropLock;
             }
             // Ok so here's where things get a little depressing. At this point
@@ -143,7 +146,7 @@ mod lock {
 
     impl Drop for DropLock {
         fn drop(&mut self) {
-            let r = LOCKED.swap(0, SeqCst);
+            let r = LOCKED.swap(0, Release);
             debug_assert_eq!(r, 1);
 
             // Note that due to the above logic we don't actually need to wake
diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs
index 013f588676a..dfa938d4d57 100644
--- a/library/std/src/sys/pal/windows/pipe.rs
+++ b/library/std/src/sys/pal/windows/pipe.rs
@@ -7,7 +7,7 @@ use crate::path::Path;
 use crate::ptr;
 use crate::slice;
 use crate::sync::atomic::AtomicUsize;
-use crate::sync::atomic::Ordering::SeqCst;
+use crate::sync::atomic::Ordering::Relaxed;
 use crate::sys::c;
 use crate::sys::fs::{File, OpenOptions};
 use crate::sys::handle::Handle;
@@ -214,11 +214,11 @@ pub fn spawn_pipe_relay(
 fn random_number() -> usize {
     static N: AtomicUsize = AtomicUsize::new(0);
     loop {
-        if N.load(SeqCst) != 0 {
-            return N.fetch_add(1, SeqCst);
+        if N.load(Relaxed) != 0 {
+            return N.fetch_add(1, Relaxed);
         }
 
-        N.store(hashmap_random_keys().0 as usize, SeqCst);
+        N.store(hashmap_random_keys().0 as usize, Relaxed);
     }
 }
 
diff --git a/library/std/src/sys/pal/xous/alloc.rs b/library/std/src/sys/pal/xous/alloc.rs
index 0d540e95520..601411173aa 100644
--- a/library/std/src/sys/pal/xous/alloc.rs
+++ b/library/std/src/sys/pal/xous/alloc.rs
@@ -46,7 +46,10 @@ unsafe impl GlobalAlloc for System {
 }
 
 mod lock {
-    use crate::sync::atomic::{AtomicI32, Ordering::SeqCst};
+    use crate::sync::atomic::{
+        AtomicI32,
+        Ordering::{Acquire, Release},
+    };
 
     static LOCKED: AtomicI32 = AtomicI32::new(0);
 
@@ -54,7 +57,7 @@ mod lock {
 
     pub fn lock() -> DropLock {
         loop {
-            if LOCKED.swap(1, SeqCst) == 0 {
+            if LOCKED.swap(1, Acquire) == 0 {
                 return DropLock;
             }
             crate::os::xous::ffi::do_yield();
@@ -63,7 +66,7 @@ mod lock {
 
     impl Drop for DropLock {
         fn drop(&mut self) {
-            let r = LOCKED.swap(0, SeqCst);
+            let r = LOCKED.swap(0, Release);
             debug_assert_eq!(r, 1);
         }
     }
diff --git a/library/std/src/sys/pal/xous/net/tcpstream.rs b/library/std/src/sys/pal/xous/net/tcpstream.rs
index 7149678118a..aebef02acda 100644
--- a/library/std/src/sys/pal/xous/net/tcpstream.rs
+++ b/library/std/src/sys/pal/xous/net/tcpstream.rs
@@ -406,7 +406,7 @@ impl TcpStream {
     }
 
     pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
-        self.nonblocking.store(nonblocking, Ordering::SeqCst);
+        self.nonblocking.store(nonblocking, Ordering::Relaxed);
         Ok(())
     }
 }
diff --git a/library/std/src/sys/pal/xous/thread_local_key.rs b/library/std/src/sys/pal/xous/thread_local_key.rs
index 59a668c3df6..2aaf46d0244 100644
--- a/library/std/src/sys/pal/xous/thread_local_key.rs
+++ b/library/std/src/sys/pal/xous/thread_local_key.rs
@@ -2,7 +2,7 @@ use crate::mem::ManuallyDrop;
 use crate::ptr;
 use crate::sync::atomic::AtomicPtr;
 use crate::sync::atomic::AtomicUsize;
-use crate::sync::atomic::Ordering::SeqCst;
+use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
 use core::arch::asm;
 
 use crate::os::xous::ffi::{map_memory, unmap_memory, MemoryFlags};
@@ -92,7 +92,7 @@ fn tls_table() -> &'static mut [*mut u8] {
 pub unsafe fn create(dtor: Option<Dtor>) -> Key {
     // Allocate a new TLS key. These keys are shared among all threads.
     #[allow(unused_unsafe)]
-    let key = unsafe { TLS_KEY_INDEX.fetch_add(1, SeqCst) };
+    let key = unsafe { TLS_KEY_INDEX.fetch_add(1, Relaxed) };
     if let Some(f) = dtor {
         unsafe { register_dtor(key, f) };
     }
@@ -154,11 +154,11 @@ unsafe fn register_dtor(key: Key, dtor: Dtor) {
     let mut node = ManuallyDrop::new(Box::new(Node { key, dtor, next: ptr::null_mut() }));
 
     #[allow(unused_unsafe)]
-    let mut head = unsafe { DTORS.load(SeqCst) };
+    let mut head = unsafe { DTORS.load(Acquire) };
     loop {
         node.next = head;
         #[allow(unused_unsafe)]
-        match unsafe { DTORS.compare_exchange(head, &mut **node, SeqCst, SeqCst) } {
+        match unsafe { DTORS.compare_exchange(head, &mut **node, Release, Acquire) } {
             Ok(_) => return, // nothing to drop, we successfully added the node to the list
             Err(cur) => head = cur,
         }
@@ -199,7 +199,7 @@ unsafe fn run_dtors() {
         }
         any_run = false;
         #[allow(unused_unsafe)]
-        let mut cur = unsafe { DTORS.load(SeqCst) };
+        let mut cur = unsafe { DTORS.load(Acquire) };
         while !cur.is_null() {
             let ptr = unsafe { get((*cur).key) };
 
diff --git a/library/std/src/sys/sync/mutex/xous.rs b/library/std/src/sys/sync/mutex/xous.rs
index a8c9518ff0b..1426e48f8b7 100644
--- a/library/std/src/sys/sync/mutex/xous.rs
+++ b/library/std/src/sys/sync/mutex/xous.rs
@@ -1,6 +1,9 @@
 use crate::os::xous::ffi::{blocking_scalar, do_yield};
 use crate::os::xous::services::{ticktimer_server, TicktimerScalar};
-use crate::sync::atomic::{AtomicBool, AtomicUsize, Ordering::Relaxed, Ordering::SeqCst};
+use crate::sync::atomic::{
+    AtomicBool, AtomicUsize,
+    Ordering::{Acquire, Relaxed, Release},
+};
 
 pub struct Mutex {
     /// The "locked" value indicates how many threads are waiting on this
@@ -68,7 +71,7 @@ impl Mutex {
 
     #[inline]
     pub unsafe fn unlock(&self) {
-        let prev = self.locked.fetch_sub(1, SeqCst);
+        let prev = self.locked.fetch_sub(1, Release);
 
         // If the previous value was 1, then this was a "fast path" unlock, so no
         // need to involve the Ticktimer server
@@ -89,12 +92,12 @@ impl Mutex {
 
     #[inline]
     pub unsafe fn try_lock(&self) -> bool {
-        self.locked.compare_exchange(0, 1, SeqCst, SeqCst).is_ok()
+        self.locked.compare_exchange(0, 1, Acquire, Relaxed).is_ok()
     }
 
     #[inline]
     pub unsafe fn try_lock_or_poison(&self) -> bool {
-        self.locked.fetch_add(1, SeqCst) == 0
+        self.locked.fetch_add(1, Acquire) == 0
     }
 }
 
diff --git a/library/std/src/sys_common/thread_local_key.rs b/library/std/src/sys_common/thread_local_key.rs
index 204834984a2..7dcc1141099 100644
--- a/library/std/src/sys_common/thread_local_key.rs
+++ b/library/std/src/sys_common/thread_local_key.rs
@@ -128,7 +128,7 @@ impl StaticKey {
 
     #[inline]
     unsafe fn key(&self) -> imp::Key {
-        match self.key.load(Ordering::Relaxed) {
+        match self.key.load(Ordering::Acquire) {
             KEY_SENTVAL => self.lazy_init() as imp::Key,
             n => n as imp::Key,
         }
@@ -156,8 +156,8 @@ impl StaticKey {
         match self.key.compare_exchange(
             KEY_SENTVAL,
             key as usize,
-            Ordering::SeqCst,
-            Ordering::SeqCst,
+            Ordering::Release,
+            Ordering::Acquire,
         ) {
             // The CAS succeeded, so we've created the actual key
             Ok(_) => key as usize,
diff --git a/library/std/src/thread/local/tests.rs b/library/std/src/thread/local/tests.rs
index 964c7fc5b0c..25019b554bb 100644
--- a/library/std/src/thread/local/tests.rs
+++ b/library/std/src/thread/local/tests.rs
@@ -255,6 +255,9 @@ fn join_orders_after_tls_destructors() {
     // observe the channel in the `THREAD1_WAITING` state. If this does occur,
     // we switch to the “poison” state `THREAD2_JOINED` and panic all around.
     // (This is equivalent to “sending” from an alternate producer thread.)
+    //
+    // Relaxed memory ordering is fine because and spawn()/join() already provide all the
+    // synchronization we need here.
     const FRESH: u8 = 0;
     const THREAD2_LAUNCHED: u8 = 1;
     const THREAD1_WAITING: u8 = 2;
@@ -263,7 +266,7 @@ fn join_orders_after_tls_destructors() {
     static SYNC_STATE: AtomicU8 = AtomicU8::new(FRESH);
 
     for _ in 0..10 {
-        SYNC_STATE.store(FRESH, Ordering::SeqCst);
+        SYNC_STATE.store(FRESH, Ordering::Relaxed);
 
         let jh = thread::Builder::new()
             .name("thread1".into())
@@ -272,7 +275,7 @@ fn join_orders_after_tls_destructors() {
 
                 impl Drop for TlDrop {
                     fn drop(&mut self) {
-                        let mut sync_state = SYNC_STATE.swap(THREAD1_WAITING, Ordering::SeqCst);
+                        let mut sync_state = SYNC_STATE.swap(THREAD1_WAITING, Ordering::Relaxed);
                         loop {
                             match sync_state {
                                 THREAD2_LAUNCHED | THREAD1_WAITING => thread::yield_now(),
@@ -282,7 +285,7 @@ fn join_orders_after_tls_destructors() {
                                 ),
                                 v => unreachable!("sync state: {}", v),
                             }
-                            sync_state = SYNC_STATE.load(Ordering::SeqCst);
+                            sync_state = SYNC_STATE.load(Ordering::Relaxed);
                         }
                     }
                 }
@@ -294,7 +297,7 @@ fn join_orders_after_tls_destructors() {
                 TL_DROP.with(|_| {});
 
                 loop {
-                    match SYNC_STATE.load(Ordering::SeqCst) {
+                    match SYNC_STATE.load(Ordering::Relaxed) {
                         FRESH => thread::yield_now(),
                         THREAD2_LAUNCHED => break,
                         v => unreachable!("sync state: {}", v),
@@ -306,9 +309,9 @@ fn join_orders_after_tls_destructors() {
         let jh2 = thread::Builder::new()
             .name("thread2".into())
             .spawn(move || {
-                assert_eq!(SYNC_STATE.swap(THREAD2_LAUNCHED, Ordering::SeqCst), FRESH);
+                assert_eq!(SYNC_STATE.swap(THREAD2_LAUNCHED, Ordering::Relaxed), FRESH);
                 jh.join().unwrap();
-                match SYNC_STATE.swap(THREAD2_JOINED, Ordering::SeqCst) {
+                match SYNC_STATE.swap(THREAD2_JOINED, Ordering::Relaxed) {
                     MAIN_THREAD_RENDEZVOUS => return,
                     THREAD2_LAUNCHED | THREAD1_WAITING => {
                         panic!("Thread 2 running after thread 1 join before main thread rendezvous")
@@ -322,8 +325,8 @@ fn join_orders_after_tls_destructors() {
             match SYNC_STATE.compare_exchange(
                 THREAD1_WAITING,
                 MAIN_THREAD_RENDEZVOUS,
-                Ordering::SeqCst,
-                Ordering::SeqCst,
+                Ordering::Relaxed,
+                Ordering::Relaxed,
             ) {
                 Ok(_) => break,
                 Err(FRESH) => thread::yield_now(),
diff --git a/library/test/src/console.rs b/library/test/src/console.rs
index 8096e498263..f3918ba333a 100644
--- a/library/test/src/console.rs
+++ b/library/test/src/console.rs
@@ -46,7 +46,6 @@ pub struct ConsoleTestDiscoveryState {
     pub tests: usize,
     pub benchmarks: usize,
     pub ignored: usize,
-    pub options: Options,
 }
 
 impl ConsoleTestDiscoveryState {
@@ -56,13 +55,7 @@ impl ConsoleTestDiscoveryState {
             None => None,
         };
 
-        Ok(ConsoleTestDiscoveryState {
-            log_out,
-            tests: 0,
-            benchmarks: 0,
-            ignored: 0,
-            options: opts.options,
-        })
+        Ok(ConsoleTestDiscoveryState { log_out, tests: 0, benchmarks: 0, ignored: 0 })
     }
 
     pub fn write_log<F, S>(&mut self, msg: F) -> io::Result<()>
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 6e49bcc9744..30d728aa230 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -612,8 +612,14 @@ class RustBuild(object):
                 self.fix_bin_or_dylib("{}/libexec/rust-analyzer-proc-macro-srv".format(bin_root))
                 lib_dir = "{}/lib".format(bin_root)
                 for lib in os.listdir(lib_dir):
-                    if lib.endswith(".so"):
-                        self.fix_bin_or_dylib(os.path.join(lib_dir, lib))
+                    # .so is not necessarily the suffix, there can be version numbers afterwards.
+                    if ".so" in lib:
+                        elf_path = os.path.join(lib_dir, lib)
+                        with open(elf_path, "rb") as f:
+                            magic = f.read(4)
+                            # Patchelf will skip non-ELF files, but issue a warning.
+                            if magic == b"\x7fELF":
+                                self.fix_bin_or_dylib(elf_path)
 
             with output(self.rustc_stamp()) as rust_stamp:
                 rust_stamp.write(key)
@@ -725,7 +731,7 @@ class RustBuild(object):
             os.path.join(os.path.realpath(nix_deps_dir), "lib")
         ]
         patchelf_args = ["--set-rpath", ":".join(rpath_entries)]
-        if not fname.endswith(".so"):
+        if ".so" not in fname:
             # Finally, set the correct .interp for binaries
             with open("{}/nix-support/dynamic-linker".format(nix_deps_dir)) as dynamic_linker:
                 patchelf_args += ["--set-interpreter", dynamic_linker.read().rstrip()]
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 2076444ca0c..d40a3ea4c88 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -2140,18 +2140,9 @@ pub struct CargoTarget<'a> {
 #[derive(Deserialize)]
 #[serde(tag = "reason", rename_all = "kebab-case")]
 pub enum CargoMessage<'a> {
-    CompilerArtifact {
-        package_id: Cow<'a, str>,
-        features: Vec<Cow<'a, str>>,
-        filenames: Vec<Cow<'a, str>>,
-        target: CargoTarget<'a>,
-    },
-    BuildScriptExecuted {
-        package_id: Cow<'a, str>,
-    },
-    BuildFinished {
-        success: bool,
-    },
+    CompilerArtifact { filenames: Vec<Cow<'a, str>>, target: CargoTarget<'a> },
+    BuildScriptExecuted,
+    BuildFinished,
 }
 
 pub fn strip_debug(builder: &Builder<'_>, target: TargetSelection, path: &Path) {
diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index 251138388ca..75e0f646da6 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -1,6 +1,6 @@
 use std::{
     env,
-    ffi::{OsStr, OsString},
+    ffi::OsString,
     fs::{self, File},
     io::{BufRead, BufReader, BufWriter, ErrorKind, Write},
     path::{Path, PathBuf},
@@ -183,7 +183,7 @@ impl Config {
             entries
         };
         patchelf.args(&[OsString::from("--set-rpath"), rpath_entries]);
-        if !fname.extension().map_or(false, |ext| ext == "so") {
+        if !path_is_dylib(fname) {
             // Finally, set the correct .interp for binaries
             let dynamic_linker_path = nix_deps_dir.join("nix-support/dynamic-linker");
             // FIXME: can we support utf8 here? `args` doesn't accept Vec<u8>, only OsString ...
@@ -440,7 +440,7 @@ impl Config {
             let lib_dir = bin_root.join("lib");
             for lib in t!(fs::read_dir(&lib_dir), lib_dir.display().to_string()) {
                 let lib = t!(lib);
-                if lib.path().extension() == Some(OsStr::new("so")) {
+                if path_is_dylib(&lib.path()) {
                     self.fix_bin_or_dylib(&lib.path());
                 }
             }
@@ -545,7 +545,7 @@ impl Config {
                 let lib_dir = bin_root.join("lib");
                 for lib in t!(fs::read_dir(&lib_dir), lib_dir.display().to_string()) {
                     let lib = t!(lib);
-                    if lib.path().extension() == Some(OsStr::new("so")) {
+                    if path_is_dylib(&lib.path()) {
                         self.fix_bin_or_dylib(&lib.path());
                     }
                 }
@@ -697,7 +697,7 @@ download-rustc = false
                 let llvm_lib = llvm_root.join("lib");
                 for entry in t!(fs::read_dir(llvm_lib)) {
                     let lib = t!(entry).path();
-                    if lib.extension().map_or(false, |ext| ext == "so") {
+                    if path_is_dylib(&lib) {
                         self.fix_bin_or_dylib(&lib);
                     }
                 }
@@ -743,3 +743,8 @@ download-rustc = false
         self.unpack(&tarball, &llvm_root, "rust-dev");
     }
 }
+
+fn path_is_dylib(path: &Path) -> bool {
+    // The .so is not necessarily the extension, it might be libLLVM.so.18.1
+    path.to_str().map_or(false, |path| path.contains(".so"))
+}
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 64bb7bf01f7..d8397ab51de 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -1009,15 +1009,23 @@ impl Build {
         let result = if !output.status.success() {
             if print_error {
                 println!(
-                    "\n\ncommand did not execute successfully: {:?}\n\
-                    expected success, got: {}\n\n\
-                    stdout ----\n{}\n\
-                    stderr ----\n{}\n\n",
-                    command.command,
+                    "\n\nCommand did not execute successfully.\
+                    \nExpected success, got: {}",
                     output.status,
-                    String::from_utf8_lossy(&output.stdout),
-                    String::from_utf8_lossy(&output.stderr)
                 );
+
+                if !self.is_verbose() {
+                    println!("Add `-v` to see more details.\n");
+                }
+
+                self.verbose(|| {
+                    println!(
+                        "\nSTDOUT ----\n{}\n\
+                        STDERR ----\n{}\n",
+                        String::from_utf8_lossy(&output.stdout),
+                        String::from_utf8_lossy(&output.stderr)
+                    )
+                });
             }
             Err(())
         } else {
@@ -1389,6 +1397,13 @@ impl Build {
         if let Some(path) = finder.maybe_have("wasmtime") {
             if let Ok(mut path) = path.into_os_string().into_string() {
                 path.push_str(" run -C cache=n --dir .");
+                // Make sure that tests have access to RUSTC_BOOTSTRAP. This (for example) is
+                // required for libtest to work on beta/stable channels.
+                //
+                // NB: with Wasmtime 20 this can change to `-S inherit-env` to
+                // inherit the entire environment rather than just this single
+                // environment variable.
+                path.push_str(" --env RUSTC_BOOTSTRAP");
                 return Some(path);
             }
         }
diff --git a/src/ci/docker/host-x86_64/test-various/Dockerfile b/src/ci/docker/host-x86_64/test-various/Dockerfile
index 944d9aed319..4de9afdb171 100644
--- a/src/ci/docker/host-x86_64/test-various/Dockerfile
+++ b/src/ci/docker/host-x86_64/test-various/Dockerfile
@@ -55,9 +55,9 @@ ENV RUST_CONFIGURE_ARGS \
 ENV NO_DEBUG_ASSERTIONS=1
 ENV NO_OVERFLOW_CHECKS=1
 
-RUN curl -L https://github.com/bytecodealliance/wasmtime/releases/download/v18.0.2/wasmtime-v18.0.2-x86_64-linux.tar.xz | \
+RUN curl -L https://github.com/bytecodealliance/wasmtime/releases/download/v19.0.0/wasmtime-v19.0.0-x86_64-linux.tar.xz | \
   tar -xJ
-ENV PATH "$PATH:/wasmtime-v18.0.2-x86_64-linux"
+ENV PATH "$PATH:/wasmtime-v19.0.0-x86_64-linux"
 
 ENV WASM_TARGETS=wasm32-wasip1
 ENV WASM_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $WASM_TARGETS \
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 274745b9082..75d38dd20bd 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -339,6 +339,7 @@ target | std | host | notes
 `riscv32gc-unknown-linux-gnu` |   |   | RISC-V Linux (kernel 5.4, glibc 2.33)
 `riscv32gc-unknown-linux-musl` |   |   | RISC-V Linux (kernel 5.4, musl 1.2.3 + RISCV32 support patches)
 [`riscv32im-risc0-zkvm-elf`](platform-support/riscv32im-risc0-zkvm-elf.md) | ? |  | RISC Zero's zero-knowledge Virtual Machine (RV32IM ISA)
+[`riscv32ima-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * |  | Bare RISC-V (RV32IMA ISA)
 [`riscv32imac-unknown-xous-elf`](platform-support/riscv32imac-unknown-xous-elf.md) | ? |  | RISC-V Xous (RV32IMAC ISA)
 [`riscv32imc-esp-espidf`](platform-support/esp-idf.md) | ✓ |  | RISC-V ESP-IDF
 [`riscv32imac-esp-espidf`](platform-support/esp-idf.md) | ✓ |  | RISC-V ESP-IDF
diff --git a/src/doc/rustc/src/platform-support/riscv32-unknown-none-elf.md b/src/doc/rustc/src/platform-support/riscv32-unknown-none-elf.md
index 739b12bad8b..9a27a568b57 100644
--- a/src/doc/rustc/src/platform-support/riscv32-unknown-none-elf.md
+++ b/src/doc/rustc/src/platform-support/riscv32-unknown-none-elf.md
@@ -1,9 +1,13 @@
-# `riscv32{i,im,imc,imac,imafc}-unknown-none-elf`
+# `riscv32{i,im,ima,imc,imac,imafc}-unknown-none-elf`
 
 **Tier: 2**
 
 Bare-metal target for RISC-V CPUs with the RV32I, RV32IM, RV32IMC, RV32IMAFC and RV32IMAC ISAs.
 
+**Tier: 3**
+
+Bare-metal target for RISC-V CPUs with the RV32IMA ISA.
+
 ## Target maintainers
 
 * Rust Embedded Working Group, [RISC-V team](https://github.com/rust-embedded/wg#the-risc-v-team)
diff --git a/src/doc/unstable-book/src/language-features/postfix-match.md b/src/doc/unstable-book/src/language-features/postfix-match.md
new file mode 100644
index 00000000000..cd6b6a7442c
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/postfix-match.md
@@ -0,0 +1,22 @@
+# `postfix-match`
+
+`postfix-match` adds the feature for matching upon values postfix
+the expressions that generate the values.
+
+```rust,edition2021
+#![feature(postfix_match)]
+
+enum Foo {
+    Bar,
+    Baz
+}
+
+fn get_foo() -> Foo {
+    Foo::Bar
+}
+
+get_foo().match {
+    Foo::Bar => {},
+    Foo::Baz => panic!(),
+}
+```
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 855fb132fc8..ef707d179ea 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -20,7 +20,7 @@ use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId, LOCAL_CRATE};
 use rustc_hir::PredicateOrigin;
-use rustc_hir_analysis::hir_ty_to_ty;
+use rustc_hir_analysis::lower_ty;
 use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
 use rustc_middle::metadata::Reexport;
 use rustc_middle::middle::resolve_bound_vars as rbv;
@@ -626,7 +626,10 @@ fn is_impl_trait(param: &hir::GenericParam<'_>) -> bool {
 ///
 /// See `lifetime_to_generic_param` in `rustc_ast_lowering` for more information.
 fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool {
-    matches!(param.kind, hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided })
+    matches!(
+        param.kind,
+        hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided(_) }
+    )
 }
 
 pub(crate) fn clean_generics<'tcx>(
@@ -1257,12 +1260,8 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext
             hir::TraitItemKind::Type(bounds, Some(default)) => {
                 let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
                 let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect();
-                let item_type = clean_middle_ty(
-                    ty::Binder::dummy(hir_ty_to_ty(cx.tcx, default)),
-                    cx,
-                    None,
-                    None,
-                );
+                let item_type =
+                    clean_middle_ty(ty::Binder::dummy(lower_ty(cx.tcx, default)), cx, None, None);
                 AssocTypeItem(
                     Box::new(TypeAlias {
                         type_: clean_ty(default, cx),
@@ -1303,12 +1302,8 @@ pub(crate) fn clean_impl_item<'tcx>(
             hir::ImplItemKind::Type(hir_ty) => {
                 let type_ = clean_ty(hir_ty, cx);
                 let generics = clean_generics(impl_.generics, cx);
-                let item_type = clean_middle_ty(
-                    ty::Binder::dummy(hir_ty_to_ty(cx.tcx, hir_ty)),
-                    cx,
-                    None,
-                    None,
-                );
+                let item_type =
+                    clean_middle_ty(ty::Binder::dummy(lower_ty(cx.tcx, hir_ty)), cx, None, None);
                 AssocTypeItem(
                     Box::new(TypeAlias {
                         type_,
@@ -1687,7 +1682,7 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type
         }
         hir::QPath::Resolved(Some(qself), p) => {
             // Try to normalize `<X as Y>::T` to a type
-            let ty = hir_ty_to_ty(cx.tcx, hir_ty);
+            let ty = lower_ty(cx.tcx, hir_ty);
             // `hir_to_ty` can return projection types with escaping vars for GATs, e.g. `<() as Trait>::Gat<'_>`
             if !ty.has_escaping_bound_vars()
                 && let Some(normalized_value) = normalize(cx, ty::Binder::dummy(ty))
@@ -1713,7 +1708,7 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type
             }))
         }
         hir::QPath::TypeRelative(qself, segment) => {
-            let ty = hir_ty_to_ty(cx.tcx, hir_ty);
+            let ty = lower_ty(cx.tcx, hir_ty);
             let self_type = clean_ty(qself, cx);
 
             let (trait_, should_show_cast) = match ty.kind() {
@@ -2058,8 +2053,8 @@ pub(crate) fn clean_middle_ty<'tcx>(
             let n = print_const(cx, n);
             Array(Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None)), n.into())
         }
-        ty::RawPtr(mt) => {
-            RawPointer(mt.mutbl, Box::new(clean_middle_ty(bound_ty.rebind(mt.ty), cx, None, None)))
+        ty::RawPtr(ty, mutbl) => {
+            RawPointer(mutbl, Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None)))
         }
         ty::Ref(r, ty, mutbl) => BorrowedRef {
             lifetime: clean_middle_region(r),
@@ -2739,12 +2734,8 @@ fn clean_maybe_renamed_item<'tcx>(
             ItemKind::TyAlias(hir_ty, generics) => {
                 *cx.current_type_aliases.entry(def_id).or_insert(0) += 1;
                 let rustdoc_ty = clean_ty(hir_ty, cx);
-                let type_ = clean_middle_ty(
-                    ty::Binder::dummy(hir_ty_to_ty(cx.tcx, hir_ty)),
-                    cx,
-                    None,
-                    None,
-                );
+                let type_ =
+                    clean_middle_ty(ty::Binder::dummy(lower_ty(cx.tcx, hir_ty)), cx, None, None);
                 let generics = clean_generics(generics, cx);
                 if let Some(count) = cx.current_type_aliases.get_mut(&def_id) {
                     *count -= 1;
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 365d63d9657..977b4bb45b6 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -329,6 +329,7 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
             elts.iter().map(|p| name_from_pat(p).to_string()).collect::<Vec<String>>().join(", ")
         ),
         PatKind::Box(p) => return name_from_pat(&*p),
+        PatKind::Deref(p) => format!("deref!({})", name_from_pat(&*p)),
         PatKind::Ref(p, _) => return name_from_pat(&*p),
         PatKind::Lit(..) => {
             warn!(
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index c6eb7be08cd..211921715b0 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -20,9 +20,9 @@ use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::sym;
 use rustc_span::{BytePos, FileName, Pos, Span, DUMMY_SP};
 use rustc_target::spec::{Target, TargetTriple};
-use tempfile::Builder as TempFileBuilder;
 
 use std::env;
+use std::fs::File;
 use std::io::{self, Write};
 use std::panic;
 use std::path::{Path, PathBuf};
@@ -31,6 +31,8 @@ use std::str;
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::sync::{Arc, Mutex};
 
+use tempfile::{Builder as TempFileBuilder, TempDir};
+
 use crate::clean::{types::AttributesExt, Attributes};
 use crate::config::Options as RustdocOptions;
 use crate::html::markdown::{self, ErrorCodes, Ignore, LangString};
@@ -48,7 +50,55 @@ pub(crate) struct GlobalTestOptions {
     pub(crate) attrs: Vec<String>,
 }
 
-pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
+pub(crate) fn generate_args_file(file_path: &Path, options: &RustdocOptions) -> Result<(), String> {
+    let mut file = File::create(file_path)
+        .map_err(|error| format!("failed to create args file: {error:?}"))?;
+
+    // We now put the common arguments into the file we created.
+    let mut content = vec!["--crate-type=bin".to_string()];
+
+    for cfg in &options.cfgs {
+        content.push(format!("--cfg={cfg}"));
+    }
+    if !options.check_cfgs.is_empty() {
+        content.push("-Zunstable-options".to_string());
+        for check_cfg in &options.check_cfgs {
+            content.push(format!("--check-cfg={check_cfg}"));
+        }
+    }
+
+    if let Some(sysroot) = &options.maybe_sysroot {
+        content.push(format!("--sysroot={}", sysroot.display()));
+    }
+    for lib_str in &options.lib_strs {
+        content.push(format!("-L{lib_str}"));
+    }
+    for extern_str in &options.extern_strs {
+        content.push(format!("--extern={extern_str}"));
+    }
+    content.push("-Ccodegen-units=1".to_string());
+    for codegen_options_str in &options.codegen_options_strs {
+        content.push(format!("-C{codegen_options_str}"));
+    }
+    for unstable_option_str in &options.unstable_opts_strs {
+        content.push(format!("-Z{unstable_option_str}"));
+    }
+
+    let content = content.join("\n");
+
+    file.write(content.as_bytes())
+        .map_err(|error| format!("failed to write arguments to temporary file: {error:?}"))?;
+    Ok(())
+}
+
+fn get_doctest_dir() -> io::Result<TempDir> {
+    TempFileBuilder::new().prefix("rustdoctest").tempdir()
+}
+
+pub(crate) fn run(
+    dcx: &rustc_errors::DiagCtxt,
+    options: RustdocOptions,
+) -> Result<(), ErrorGuaranteed> {
     let input = config::Input::File(options.input.clone());
 
     let invalid_codeblock_attributes_name = crate::lint::INVALID_CODEBLOCK_ATTRIBUTES.name;
@@ -118,6 +168,15 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
     let externs = options.externs.clone();
     let json_unused_externs = options.json_unused_externs;
 
+    let temp_dir = match get_doctest_dir()
+        .map_err(|error| format!("failed to create temporary directory: {error:?}"))
+    {
+        Ok(temp_dir) => temp_dir,
+        Err(error) => return crate::wrap_return(dcx, Err(error)),
+    };
+    let file_path = temp_dir.path().join("rustdoc-cfgs");
+    crate::wrap_return(dcx, generate_args_file(&file_path, &options))?;
+
     let (tests, unused_extern_reports, compiling_test_count) =
         interface::run_compiler(config, |compiler| {
             compiler.enter(|queries| {
@@ -134,6 +193,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
                         Some(compiler.sess.psess.clone_source_map()),
                         None,
                         enable_per_target_ignores,
+                        file_path,
                     );
 
                     let mut hir_collector = HirCollector {
@@ -322,44 +382,35 @@ fn run_test(
     test: &str,
     crate_name: &str,
     line: usize,
-    rustdoc_options: RustdocOptions,
+    rustdoc_options: IndividualTestOptions,
     mut lang_string: LangString,
     no_run: bool,
-    runtool: Option<String>,
-    runtool_args: Vec<String>,
-    target: TargetTriple,
     opts: &GlobalTestOptions,
     edition: Edition,
-    outdir: DirState,
     path: PathBuf,
-    test_id: &str,
     report_unused_externs: impl Fn(UnusedExterns),
 ) -> Result<(), TestFailure> {
-    let (test, line_offset, supports_color) =
-        make_test(test, Some(crate_name), lang_string.test_harness, opts, edition, Some(test_id));
+    let (test, line_offset, supports_color) = make_test(
+        test,
+        Some(crate_name),
+        lang_string.test_harness,
+        opts,
+        edition,
+        Some(&rustdoc_options.test_id),
+    );
 
     // Make sure we emit well-formed executable names for our target.
-    let rust_out = add_exe_suffix("rust_out".to_owned(), &target);
-    let output_file = outdir.path().join(rust_out);
+    let rust_out = add_exe_suffix("rust_out".to_owned(), &rustdoc_options.target);
+    let output_file = rustdoc_options.outdir.path().join(rust_out);
 
     let rustc_binary = rustdoc_options
         .test_builder
         .as_deref()
         .unwrap_or_else(|| rustc_interface::util::rustc_path().expect("found rustc"));
     let mut compiler = wrapped_rustc_command(&rustdoc_options.test_builder_wrappers, rustc_binary);
-    compiler.arg("--crate-type").arg("bin");
-    for cfg in &rustdoc_options.cfgs {
-        compiler.arg("--cfg").arg(&cfg);
-    }
-    if !rustdoc_options.check_cfgs.is_empty() {
-        compiler.arg("-Z").arg("unstable-options");
-        for check_cfg in &rustdoc_options.check_cfgs {
-            compiler.arg("--check-cfg").arg(&check_cfg);
-        }
-    }
-    if let Some(sysroot) = rustdoc_options.maybe_sysroot {
-        compiler.arg("--sysroot").arg(sysroot);
-    }
+
+    compiler.arg(&format!("@{}", rustdoc_options.arg_file.display()));
+
     compiler.arg("--edition").arg(&edition.to_string());
     compiler.env("UNSTABLE_RUSTDOC_TEST_PATH", path);
     compiler.env("UNSTABLE_RUSTDOC_TEST_LINE", format!("{}", line as isize - line_offset as isize));
@@ -367,29 +418,17 @@ fn run_test(
     if lang_string.test_harness {
         compiler.arg("--test");
     }
-    if rustdoc_options.json_unused_externs.is_enabled() && !lang_string.compile_fail {
+    if rustdoc_options.is_json_unused_externs_enabled && !lang_string.compile_fail {
         compiler.arg("--error-format=json");
         compiler.arg("--json").arg("unused-externs");
-        compiler.arg("-Z").arg("unstable-options");
         compiler.arg("-W").arg("unused_crate_dependencies");
+        compiler.arg("-Z").arg("unstable-options");
     }
-    for lib_str in &rustdoc_options.lib_strs {
-        compiler.arg("-L").arg(&lib_str);
-    }
-    for extern_str in &rustdoc_options.extern_strs {
-        compiler.arg("--extern").arg(&extern_str);
-    }
-    compiler.arg("-Ccodegen-units=1");
-    for codegen_options_str in &rustdoc_options.codegen_options_strs {
-        compiler.arg("-C").arg(&codegen_options_str);
-    }
-    for unstable_option_str in &rustdoc_options.unstable_opts_strs {
-        compiler.arg("-Z").arg(&unstable_option_str);
-    }
-    if no_run && !lang_string.compile_fail && rustdoc_options.persist_doctests.is_none() {
+
+    if no_run && !lang_string.compile_fail && rustdoc_options.should_persist_doctests {
         compiler.arg("--emit=metadata");
     }
-    compiler.arg("--target").arg(match target {
+    compiler.arg("--target").arg(match rustdoc_options.target {
         TargetTriple::TargetTriple(s) => s,
         TargetTriple::TargetJson { path_for_rustdoc, .. } => {
             path_for_rustdoc.to_str().expect("target path must be valid unicode").to_string()
@@ -485,10 +524,10 @@ fn run_test(
     let mut cmd;
 
     let output_file = make_maybe_absolute_path(output_file);
-    if let Some(tool) = runtool {
+    if let Some(tool) = rustdoc_options.runtool {
         let tool = make_maybe_absolute_path(tool.into());
         cmd = Command::new(tool);
-        cmd.args(runtool_args);
+        cmd.args(rustdoc_options.runtool_args);
         cmd.arg(output_file);
     } else {
         cmd = Command::new(output_file);
@@ -897,6 +936,56 @@ fn partition_source(s: &str, edition: Edition) -> (String, String, String) {
     (before, after, crates)
 }
 
+pub(crate) struct IndividualTestOptions {
+    test_builder: Option<PathBuf>,
+    test_builder_wrappers: Vec<PathBuf>,
+    is_json_unused_externs_enabled: bool,
+    should_persist_doctests: bool,
+    error_format: ErrorOutputType,
+    test_run_directory: Option<PathBuf>,
+    nocapture: bool,
+    arg_file: PathBuf,
+    outdir: DirState,
+    runtool: Option<String>,
+    runtool_args: Vec<String>,
+    target: TargetTriple,
+    test_id: String,
+}
+
+impl IndividualTestOptions {
+    fn new(options: &RustdocOptions, arg_file: &Path, test_id: String) -> Self {
+        let outdir = if let Some(ref path) = options.persist_doctests {
+            let mut path = path.clone();
+            path.push(&test_id);
+
+            if let Err(err) = std::fs::create_dir_all(&path) {
+                eprintln!("Couldn't create directory for doctest executables: {err}");
+                panic::resume_unwind(Box::new(()));
+            }
+
+            DirState::Perm(path)
+        } else {
+            DirState::Temp(get_doctest_dir().expect("rustdoc needs a tempdir"))
+        };
+
+        Self {
+            test_builder: options.test_builder.clone(),
+            test_builder_wrappers: options.test_builder_wrappers.clone(),
+            is_json_unused_externs_enabled: options.json_unused_externs.is_enabled(),
+            should_persist_doctests: options.persist_doctests.is_none(),
+            error_format: options.error_format,
+            test_run_directory: options.test_run_directory.clone(),
+            nocapture: options.nocapture,
+            arg_file: arg_file.into(),
+            outdir,
+            runtool: options.runtool.clone(),
+            runtool_args: options.runtool_args.clone(),
+            target: options.target.clone(),
+            test_id,
+        }
+    }
+}
+
 pub(crate) trait Tester {
     fn add_test(&mut self, test: String, config: LangString, line: usize);
     fn get_line(&self) -> usize {
@@ -941,6 +1030,7 @@ pub(crate) struct Collector {
     visited_tests: FxHashMap<(String, usize), usize>,
     unused_extern_reports: Arc<Mutex<Vec<UnusedExterns>>>,
     compiling_test_count: AtomicUsize,
+    arg_file: PathBuf,
 }
 
 impl Collector {
@@ -952,6 +1042,7 @@ impl Collector {
         source_map: Option<Lrc<SourceMap>>,
         filename: Option<PathBuf>,
         enable_per_target_ignores: bool,
+        arg_file: PathBuf,
     ) -> Collector {
         Collector {
             tests: Vec::new(),
@@ -967,6 +1058,7 @@ impl Collector {
             visited_tests: FxHashMap::default(),
             unused_extern_reports: Default::default(),
             compiling_test_count: AtomicUsize::new(0),
+            arg_file,
         }
     }
 
@@ -1009,13 +1101,9 @@ impl Tester for Collector {
         let crate_name = self.crate_name.clone();
         let opts = self.opts.clone();
         let edition = config.edition.unwrap_or(self.rustdoc_options.edition);
-        let rustdoc_options = self.rustdoc_options.clone();
-        let runtool = self.rustdoc_options.runtool.clone();
-        let runtool_args = self.rustdoc_options.runtool_args.clone();
-        let target = self.rustdoc_options.target.clone();
-        let target_str = target.to_string();
+        let target_str = self.rustdoc_options.target.to_string();
         let unused_externs = self.unused_extern_reports.clone();
-        let no_run = config.no_run || rustdoc_options.no_run;
+        let no_run = config.no_run || self.rustdoc_options.no_run;
         if !config.compile_fail {
             self.compiling_test_count.fetch_add(1, Ordering::SeqCst);
         }
@@ -1049,23 +1137,9 @@ impl Tester for Collector {
                 self.visited_tests.entry((file.clone(), line)).and_modify(|v| *v += 1).or_insert(0)
             },
         );
-        let outdir = if let Some(mut path) = rustdoc_options.persist_doctests.clone() {
-            path.push(&test_id);
 
-            if let Err(err) = std::fs::create_dir_all(&path) {
-                eprintln!("Couldn't create directory for doctest executables: {err}");
-                panic::resume_unwind(Box::new(()));
-            }
-
-            DirState::Perm(path)
-        } else {
-            DirState::Temp(
-                TempFileBuilder::new()
-                    .prefix("rustdoctest")
-                    .tempdir()
-                    .expect("rustdoc needs a tempdir"),
-            )
-        };
+        let rustdoc_test_options =
+            IndividualTestOptions::new(&self.rustdoc_options, &self.arg_file, test_id);
 
         debug!("creating test {name}: {test}");
         self.tests.push(test::TestDescAndFn {
@@ -1096,17 +1170,12 @@ impl Tester for Collector {
                     &test,
                     &crate_name,
                     line,
-                    rustdoc_options,
+                    rustdoc_test_options,
                     config,
                     no_run,
-                    runtool,
-                    runtool_args,
-                    target,
                     &opts,
                     edition,
-                    outdir,
                     path,
-                    &test_id,
                     report_unused_externs,
                 );
 
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 18651875130..b78fb4c4eee 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -664,7 +664,7 @@ fn usage(argv0: &str) {
 /// A result type used by several functions under `main()`.
 type MainResult = Result<(), ErrorGuaranteed>;
 
-fn wrap_return(dcx: &rustc_errors::DiagCtxt, res: Result<(), String>) -> MainResult {
+pub(crate) fn wrap_return(dcx: &rustc_errors::DiagCtxt, res: Result<(), String>) -> MainResult {
     match res {
         Ok(()) => dcx.has_errors().map_or(Ok(()), Err),
         Err(err) => Err(dcx.err(err)),
@@ -731,7 +731,7 @@ fn main_args(
 
     match (options.should_test, options.markdown_input()) {
         (true, true) => return wrap_return(&diag, markdown::test(options)),
-        (true, false) => return doctest::run(options),
+        (true, false) => return doctest::run(&diag, options),
         (false, true) => {
             let input = options.input.clone();
             let edition = options.edition;
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index b661ced0169..dcd2cf02a30 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -3,11 +3,13 @@ use std::fs::{create_dir_all, read_to_string, File};
 use std::io::prelude::*;
 use std::path::Path;
 
+use tempfile::tempdir;
+
 use rustc_span::edition::Edition;
 use rustc_span::DUMMY_SP;
 
 use crate::config::{Options, RenderOptions};
-use crate::doctest::{Collector, GlobalTestOptions};
+use crate::doctest::{generate_args_file, Collector, GlobalTestOptions};
 use crate::html::escape::Escape;
 use crate::html::markdown;
 use crate::html::markdown::{
@@ -146,6 +148,12 @@ pub(crate) fn test(options: Options) -> Result<(), String> {
         .map_err(|err| format!("{input}: {err}", input = options.input.display()))?;
     let mut opts = GlobalTestOptions::default();
     opts.no_crate_inject = true;
+
+    let temp_dir =
+        tempdir().map_err(|error| format!("failed to create temporary directory: {error:?}"))?;
+    let file_path = temp_dir.path().join("rustdoc-cfgs");
+    generate_args_file(&file_path, &options)?;
+
     let mut collector = Collector::new(
         options.input.display().to_string(),
         options.clone(),
@@ -154,6 +162,7 @@ pub(crate) fn test(options: Options) -> Result<(), String> {
         None,
         Some(options.input),
         options.enable_per_target_ignores,
+        file_path,
     );
     collector.set_position(DUMMY_SP);
     let codes = ErrorCodes::from(options.unstable_features.is_nightly_build());
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 577d4b89c8d..a5c26429013 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -493,7 +493,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
             ty::Tuple(_) => Res::Primitive(Tuple),
             ty::Array(..) => Res::Primitive(Array),
             ty::Slice(_) => Res::Primitive(Slice),
-            ty::RawPtr(_) => Res::Primitive(RawPointer),
+            ty::RawPtr(_, _) => Res::Primitive(RawPointer),
             ty::Ref(..) => Res::Primitive(Reference),
             ty::FnDef(..) => panic!("type alias to a function definition"),
             ty::FnPtr(_) => Res::Primitive(Fn),
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index 53c08ef5e5c..fbbb6152cfe 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -115,9 +115,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) ->
                     // form that is valid for use in type inference.
                     let ty = tcx.type_of(def_id).instantiate_identity();
                     match ty.kind() {
-                        ty::Slice(ty)
-                        | ty::Ref(_, ty, _)
-                        | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
+                        ty::Slice(ty) | ty::Ref(_, ty, _) | ty::RawPtr(ty, _) => {
                             matches!(ty.kind(), ty::Param(..))
                         }
                         ty::Tuple(tys) => tys.iter().all(|ty| matches!(ty.kind(), ty::Param(..))),
diff --git a/src/llvm-project b/src/llvm-project
-Subproject 84f190a4abf58bbd5301c0fc831f7a96acea246
+Subproject 0af6c732ec6ca189cd7725e4a7d4290793046e8
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index eab9138b8fe..392a5a11967 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -126,6 +126,7 @@ static TARGETS: &[&str] = &[
     "riscv32i-unknown-none-elf",
     "riscv32im-risc0-zkvm-elf",
     "riscv32im-unknown-none-elf",
+    "riscv32ima-unknown-none-elf",
     "riscv32imc-unknown-none-elf",
     "riscv32imac-unknown-none-elf",
     "riscv32imafc-unknown-none-elf",
diff --git a/src/tools/clippy/.github/workflows/clippy.yml b/src/tools/clippy/.github/workflows/clippy.yml
index 603f91a910b..8179e3e65b5 100644
--- a/src/tools/clippy/.github/workflows/clippy.yml
+++ b/src/tools/clippy/.github/workflows/clippy.yml
@@ -26,6 +26,12 @@ env:
   NO_FMT_TEST: 1
   CARGO_INCREMENTAL: 0
 
+concurrency:
+  # For a given workflow, if we push to the same PR, cancel all previous builds on that PR.
+  # If the push is not attached to a PR, we will cancel all builds on the same branch.
+  group: "${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}"
+  cancel-in-progress: true
+
 jobs:
   base:
     # NOTE: If you modify this job, make sure you copy the changes to clippy_bors.yml
@@ -33,10 +39,6 @@ jobs:
 
     steps:
     # Setup
-    - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
-      with:
-        github_token: "${{ secrets.github_token }}"
-
     - name: Checkout
       uses: actions/checkout@v4
 
diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml
index 0bc28c1f9d9..94515987eba 100644
--- a/src/tools/clippy/.github/workflows/clippy_bors.yml
+++ b/src/tools/clippy/.github/workflows/clippy_bors.yml
@@ -12,6 +12,11 @@ env:
   NO_FMT_TEST: 1
   CARGO_INCREMENTAL: 0
 
+concurrency:
+  # For a given workflow, if we push to the same branch, cancel all previous builds on that branch.
+  group: "${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}"
+  cancel-in-progress: true
+
 defaults:
   run:
     shell: bash
@@ -21,10 +26,6 @@ jobs:
     runs-on: ubuntu-latest
 
     steps:
-    - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
-      with:
-        github_token: "${{ secrets.github_token }}"
-
     - name: Checkout
       uses: actions/checkout@v4
       with:
@@ -67,10 +68,6 @@ jobs:
     # NOTE: If you modify this job, make sure you copy the changes to clippy.yml
     steps:
     # Setup
-    - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
-      with:
-        github_token: "${{ secrets.github_token }}"
-
     - name: Checkout
       uses: actions/checkout@v4
 
@@ -131,10 +128,6 @@ jobs:
 
     steps:
      # Setup
-    - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
-      with:
-        github_token: "${{ secrets.github_token }}"
-
     - name: Checkout
       uses: actions/checkout@v4
 
@@ -155,10 +148,6 @@ jobs:
 
     steps:
     # Setup
-    - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
-      with:
-        github_token: "${{ secrets.github_token }}"
-
     - name: Checkout
       uses: actions/checkout@v4
 
@@ -211,10 +200,6 @@ jobs:
 
     steps:
     # Setup
-    - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
-      with:
-        github_token: "${{ secrets.github_token }}"
-
     - name: Checkout
       uses: actions/checkout@v4
 
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index d3b2c0a7bf6..76ef84a48b8 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6,11 +6,65 @@ document.
 
 ## Unreleased / Beta / In Rust Nightly
 
-[a859e5cc...master](https://github.com/rust-lang/rust-clippy/compare/a859e5cc...master)
+[66c29b97...master](https://github.com/rust-lang/rust-clippy/compare/66c29b97...master)
+
+## Rust 1.77
+
+Current stable, released 2024-03-18
+
+[View all 93 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-12-16T18%3A20%3A00Z..2024-01-25T18%3A15%3A56Z+base%3Amaster)
+
+### New Lints
+
+* [`suspicious_open_options`]
+  [#11608](https://github.com/rust-lang/rust-clippy/pull/11608)
+* [`option_as_ref_cloned`]
+  [#12051](https://github.com/rust-lang/rust-clippy/pull/12051)
+* [`thread_local_initializer_can_be_made_const`]
+  [#12026](https://github.com/rust-lang/rust-clippy/pull/12026)
+* [`str_split_at_newline`]
+  [#11987](https://github.com/rust-lang/rust-clippy/pull/11987)
+* [`empty_enum_variants_with_brackets`]
+  [#12047](https://github.com/rust-lang/rust-clippy/pull/12047)
+* [`manual_is_variant_and`]
+  [#11865](https://github.com/rust-lang/rust-clippy/pull/11865)
+* [`pub_underscore_fields`]
+  [#10283](https://github.com/rust-lang/rust-clippy/pull/10283)
+* [`eager_transmute`]
+  [#11981](https://github.com/rust-lang/rust-clippy/pull/11981)
+* [`iter_filter_is_some`]
+  [#12004](https://github.com/rust-lang/rust/pull/12004)
+* [`iter_filter_is_ok`]
+  [#12004](https://github.com/rust-lang/rust/pull/12004)
+* [`result_filter_map`]
+  [#11869](https://github.com/rust-lang/rust-clippy/pull/11869)
+* [`unconditional_recursion`]
+  [#11938](https://github.com/rust-lang/rust-clippy/pull/11938)
+
+### Enhancements
+
+* [`multiple_crate_versions`]: Added the [`allowed-duplicate-crates`] configuration to allow specific crates
+  [#12179](https://github.com/rust-lang/rust-clippy/pull/12179)
+* [`single_call_fn`]: No longer ignores `#[allow]` attributes
+  [#12183](https://github.com/rust-lang/rust-clippy/pull/12183)
+* [`read_zero_byte_vec`]: Updated the heuristics used for linting
+  [#11766](https://github.com/rust-lang/rust-clippy/pull/11766)
+
+### ICE Fixes
+
+* [`unit_arg`]: No longer crashes when checking for const in nested bodies
+  [#11977](https://github.com/rust-lang/rust-clippy/pull/11977)
+* [`indexing_slicing`]: No longer crashes when the array index exceeds `usize`
+  [#12266](https://github.com/rust-lang/rust-clippy/pull/12266)
+
+### Others
+
+* Warnings about invalid fields inside `clippy.toml` files now include suggestions for existing fields
+  [#12180](https://github.com/rust-lang/rust-clippy/pull/12180)
 
 ## Rust 1.76
 
-Current stable, released 2024-02-08
+Released 2024-02-08
 
 [View all 85 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-11-02T20%3A23%3A40Z..2023-12-16T13%3A11%3A08Z+base%3Amaster)
 
@@ -5110,6 +5164,7 @@ Released 2018-09-13
 [`collection_is_never_read`]: https://rust-lang.github.io/rust-clippy/master/index.html#collection_is_never_read
 [`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain
 [`comparison_to_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty
+[`const_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_is_empty
 [`const_static_lifetime`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_static_lifetime
 [`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator
 [`crate_in_macro_def`]: https://rust-lang.github.io/rust-clippy/master/index.html#crate_in_macro_def
@@ -5156,6 +5211,7 @@ Released 2018-09-13
 [`drop_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_ref
 [`duplicate_mod`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_mod
 [`duplicate_underscore_argument`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_underscore_argument
+[`duplicated_attributes`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicated_attributes
 [`duration_subsec`]: https://rust-lang.github.io/rust-clippy/master/index.html#duration_subsec
 [`eager_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#eager_transmute
 [`else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else
@@ -5279,6 +5335,7 @@ Released 2018-09-13
 [`int_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#int_plus_one
 [`integer_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_arithmetic
 [`integer_division`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_division
+[`integer_division_remainder_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_division_remainder_used
 [`into_iter_on_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_array
 [`into_iter_on_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_ref
 [`into_iter_without_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_without_iter
@@ -5376,6 +5433,7 @@ Released 2018-09-13
 [`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap
 [`manual_try_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_try_fold
 [`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or
+[`manual_unwrap_or_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or_default
 [`manual_while_let_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_while_let_some
 [`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names
 [`map_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_clone
@@ -5813,6 +5871,7 @@ Released 2018-09-13
 [`zero_divided_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_divided_by_zero
 [`zero_prefixed_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_prefixed_literal
 [`zero_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_ptr
+[`zero_repeat_side_effects`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_repeat_side_effects
 [`zero_sized_map_values`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_sized_map_values
 [`zero_width_space`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_width_space
 [`zst_offset`]: https://rust-lang.github.io/rust-clippy/master/index.html#zst_offset
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index 5d1d0ce2c42..2b37b54c004 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy"
-version = "0.1.78"
+version = "0.1.79"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
@@ -24,7 +24,7 @@ path = "src/driver.rs"
 clippy_config = { path = "clippy_config" }
 clippy_lints = { path = "clippy_lints" }
 rustc_tools_util = "0.3.0"
-tempfile = { version = "3.2", optional = true }
+tempfile = { version = "3.3", optional = true }
 termize = "0.1"
 color-print = "0.3.4"
 anstream = "0.6.0"
@@ -32,18 +32,18 @@ anstream = "0.6.0"
 [dev-dependencies]
 ui_test = "0.22.2"
 tester = "0.9"
-regex = "1.5"
+regex = "1.5.5"
 toml = "0.7.3"
 walkdir = "2.3"
 # This is used by the `collect-metadata` alias.
-filetime = "0.2"
+filetime = "0.2.9"
 itertools = "0.12"
 
 # UI test dependencies
 clippy_utils = { path = "clippy_utils" }
 if_chain = "1.0"
-quote = "1.0"
-serde = { version = "1.0.125", features = ["derive"] }
+quote = "1.0.25"
+serde = { version = "1.0.145", features = ["derive"] }
 syn = { version = "2.0", features = ["full"] }
 futures = "0.3"
 parking_lot = "0.12"
diff --git a/src/tools/clippy/book/src/development/macro_expansions.md b/src/tools/clippy/book/src/development/macro_expansions.md
index aecca9ef72e..125b6c4bc5b 100644
--- a/src/tools/clippy/book/src/development/macro_expansions.md
+++ b/src/tools/clippy/book/src/development/macro_expansions.md
@@ -52,7 +52,7 @@ if expr.span.from_expansion() {
 
 ### `Span.ctxt` method
 
-The `span`'s context, given by the method [`ctxt`] and returning [SpanContext],
+The `span`'s context, given by the method [`ctxt`] and returning [SyntaxContext],
 represents if the span is from a macro expansion and, if it is, which
 macro call expanded this span.
 
@@ -155,4 +155,4 @@ if in_external_macro(cx.sess(), foo_span) {
 [`from_expansion`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/struct.Span.html#method.from_expansion
 [`in_external_macro`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_middle/lint/fn.in_external_macro.html
 [Span]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/struct.Span.html
-[SpanContext]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/hygiene/struct.SyntaxContext.html
+[SyntaxContext]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/hygiene/struct.SyntaxContext.html
diff --git a/src/tools/clippy/book/src/development/type_checking.md b/src/tools/clippy/book/src/development/type_checking.md
index 136b3fd0270..e6da4322a17 100644
--- a/src/tools/clippy/book/src/development/type_checking.md
+++ b/src/tools/clippy/book/src/development/type_checking.md
@@ -118,10 +118,10 @@ Here the HIR sees the types without "thinking" about them, it knows that the fun
 an `u32`. As far as `hir::Ty` is concerned those might be different types. But at the `ty::Ty` level the compiler
 understands that they're the same type, in-depth lifetimes, etc...
 
-To get from a `hir::Ty` to a `ty::Ty`, you can use the [`hir_ty_to_ty`][hir_ty_to_ty] function outside of bodies or
+To get from a `hir::Ty` to a `ty::Ty`, you can use the [`lower_ty`][lower_ty] function outside of bodies or
 the [`TypeckResults::node_type()`][node_type] method inside of bodies.
 
-> **Warning**: Don't use `hir_ty_to_ty` inside of bodies, because this can cause ICEs.
+> **Warning**: Don't use `lower_ty` inside of bodies, because this can cause ICEs.
 
 ## Creating Types programmatically
 
@@ -162,6 +162,6 @@ in this chapter:
 [Ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html
 [TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/ty_kind/enum.TyKind.html
 [TypeckResults]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html
-[middle_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_middle/ty/struct.Ty.html
-[hir_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir/struct.Ty.html
-[hir_ty_to_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir_analysis/fn.hir_ty_to_ty.html
+[middle_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html
+[hir_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/struct.Ty.html
+[lower_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/fn.lower_ty.html
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index a985346b3c0..a9234899746 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -602,6 +602,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio
 **Affected lints:**
 * [`almost_complete_range`](https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_range)
 * [`approx_constant`](https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant)
+* [`assigning_clones`](https://rust-lang.github.io/rust-clippy/master/index.html#assigning_clones)
 * [`borrow_as_ptr`](https://rust-lang.github.io/rust-clippy/master/index.html#borrow_as_ptr)
 * [`cast_abs_to_unsigned`](https://rust-lang.github.io/rust-clippy/master/index.html#cast_abs_to_unsigned)
 * [`checked_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#checked_conversions)
diff --git a/src/tools/clippy/clippy.toml b/src/tools/clippy/clippy.toml
index 8c405ac6a4e..62ed55beb1f 100644
--- a/src/tools/clippy/clippy.toml
+++ b/src/tools/clippy/clippy.toml
@@ -1,7 +1,10 @@
 avoid-breaking-exported-api = false
 
-# use the various `span_lint_*` methods instead, which also add a link to the docs
-disallowed-methods = [
-    "rustc_lint::context::LintContext::span_lint",
-    "rustc_middle::ty::context::TyCtxt::node_span_lint"
-]
+[[disallowed-methods]]
+path = "rustc_lint::context::LintContext::span_lint"
+reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead"
+
+
+[[disallowed-methods]]
+path = "rustc_middle::ty::context::TyCtxt::node_span_lint"
+reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead"
diff --git a/src/tools/clippy/clippy_config/Cargo.toml b/src/tools/clippy/clippy_config/Cargo.toml
index 2edc5ed592c..8ba2ab56625 100644
--- a/src/tools/clippy/clippy_config/Cargo.toml
+++ b/src/tools/clippy/clippy_config/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_config"
-version = "0.1.78"
+version = "0.1.79"
 edition = "2021"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs
index 673b6328b39..3218fe7f456 100644
--- a/src/tools/clippy/clippy_config/src/conf.rs
+++ b/src/tools/clippy/clippy_config/src/conf.rs
@@ -262,7 +262,7 @@ define_Conf! {
     ///
     /// Suppress lints whenever the suggested change would cause breakage for other crates.
     (avoid_breaking_exported_api: bool = true),
-    /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP, MANUAL_C_STR_LITERALS.
+    /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE, ITER_KV_MAP, MANUAL_C_STR_LITERALS, ASSIGNING_CLONES.
     ///
     /// The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml`
     #[default_text = ""]
diff --git a/src/tools/clippy/clippy_config/src/msrvs.rs b/src/tools/clippy/clippy_config/src/msrvs.rs
index a8a32f7ed20..bf4da5f14fe 100644
--- a/src/tools/clippy/clippy_config/src/msrvs.rs
+++ b/src/tools/clippy/clippy_config/src/msrvs.rs
@@ -23,6 +23,7 @@ msrv_aliases! {
     1,70,0 { OPTION_RESULT_IS_VARIANT_AND, BINARY_HEAP_RETAIN }
     1,68,0 { PATH_MAIN_SEPARATOR_STR }
     1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS }
+    1,63,0 { ASSIGNING_CLONES }
     1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE }
     1,59,0 { THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST }
     1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY }
diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs
index 2222abff7ad..76ae26dddf4 100644
--- a/src/tools/clippy/clippy_dev/src/update_lints.rs
+++ b/src/tools/clippy/clippy_dev/src/update_lints.rs
@@ -689,6 +689,8 @@ fn gen_deprecated_lints_test(lints: &[DeprecatedLint]) -> String {
 fn gen_renamed_lints_test(lints: &[RenamedLint]) -> String {
     let mut seen_lints = HashSet::new();
     let mut res: String = GENERATED_FILE_COMMENT.into();
+
+    res.push_str("#![allow(clippy::duplicated_attributes)]\n");
     for lint in lints {
         if seen_lints.insert(&lint.new_name) {
             writeln!(res, "#![allow({})]", lint.new_name).unwrap();
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index 6ae089b3e03..1d954607eee 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_lints"
-version = "0.1.78"
+version = "0.1.79"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
index b1c552c7a8d..8e27b3ccefd 100644
--- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs
+++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
@@ -1,3 +1,4 @@
+use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::HirNode;
 use clippy_utils::sugg::Sugg;
@@ -6,7 +7,7 @@ use rustc_errors::Applicability;
 use rustc_hir::{self as hir, Expr, ExprKind, Node};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, Instance, Mutability};
-use rustc_session::declare_lint_pass;
+use rustc_session::impl_lint_pass;
 use rustc_span::def_id::DefId;
 use rustc_span::symbol::sym;
 use rustc_span::ExpnKind;
@@ -49,7 +50,19 @@ declare_clippy_lint! {
     perf,
     "assigning the result of cloning may be inefficient"
 }
-declare_lint_pass!(AssigningClones => [ASSIGNING_CLONES]);
+
+pub struct AssigningClones {
+    msrv: Msrv,
+}
+
+impl AssigningClones {
+    #[must_use]
+    pub fn new(msrv: Msrv) -> Self {
+        Self { msrv }
+    }
+}
+
+impl_lint_pass!(AssigningClones => [ASSIGNING_CLONES]);
 
 impl<'tcx> LateLintPass<'tcx> for AssigningClones {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, assign_expr: &'tcx hir::Expr<'_>) {
@@ -68,10 +81,12 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones {
             return;
         };
 
-        if is_ok_to_suggest(cx, lhs, &call) {
+        if is_ok_to_suggest(cx, lhs, &call, &self.msrv) {
             suggest(cx, assign_expr, lhs, &call);
         }
     }
+
+    extract_msrv_attr!(LateContext);
 }
 
 // Try to resolve the call to `Clone::clone` or `ToOwned::to_owned`.
@@ -135,14 +150,20 @@ fn extract_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<
 
 // Return true if we find that the called method has a custom implementation and isn't derived or
 // provided by default by the corresponding trait.
-fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallCandidate<'tcx>) -> bool {
+fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallCandidate<'tcx>, msrv: &Msrv) -> bool {
+    // For calls to .to_owned we suggest using .clone_into(), which was only stablilized in 1.63.
+    // If the current MSRV is below that, don't suggest the lint.
+    if !msrv.meets(msrvs::ASSIGNING_CLONES) && matches!(call.target, TargetTrait::ToOwned) {
+        return false;
+    }
+
     // If the left-hand side is a local variable, it might be uninitialized at this point.
     // In that case we do not want to suggest the lint.
     if let Some(local) = path_to_local(lhs) {
         // TODO: This check currently bails if the local variable has no initializer.
         // That is overly conservative - the lint should fire even if there was no initializer,
         // but the variable has been initialized before `lhs` was evaluated.
-        if let Some(Node::Local(local)) = cx.tcx.hir().parent_id_iter(local).next().map(|p| cx.tcx.hir_node(p))
+        if let Some(Node::LetStmt(local)) = cx.tcx.hir().parent_id_iter(local).next().map(|p| cx.tcx.hir_node(p))
             && local.init.is_none()
         {
             return false;
diff --git a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs
new file mode 100644
index 00000000000..3c5ac597fd5
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs
@@ -0,0 +1,64 @@
+use super::DUPLICATED_ATTRIBUTES;
+use clippy_utils::diagnostics::span_lint_and_then;
+use rustc_ast::{Attribute, MetaItem};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_lint::EarlyContext;
+use rustc_span::{sym, Span};
+use std::collections::hash_map::Entry;
+
+fn emit_if_duplicated(
+    cx: &EarlyContext<'_>,
+    attr: &MetaItem,
+    attr_paths: &mut FxHashMap<String, Span>,
+    complete_path: String,
+) {
+    match attr_paths.entry(complete_path) {
+        Entry::Vacant(v) => {
+            v.insert(attr.span);
+        },
+        Entry::Occupied(o) => {
+            span_lint_and_then(cx, DUPLICATED_ATTRIBUTES, attr.span, "duplicated attribute", |diag| {
+                diag.span_note(*o.get(), "first defined here");
+                diag.span_help(attr.span, "remove this attribute");
+            });
+        },
+    }
+}
+
+fn check_duplicated_attr(
+    cx: &EarlyContext<'_>,
+    attr: &MetaItem,
+    attr_paths: &mut FxHashMap<String, Span>,
+    parent: &mut Vec<String>,
+) {
+    let Some(ident) = attr.ident() else { return };
+    let name = ident.name;
+    if name == sym::doc || name == sym::cfg_attr {
+        // FIXME: Would be nice to handle `cfg_attr` as well. Only problem is to check that cfg
+        // conditions are the same.
+        return;
+    }
+    if let Some(value) = attr.value_str() {
+        emit_if_duplicated(cx, attr, attr_paths, format!("{}:{name}={value}", parent.join(":")));
+    } else if let Some(sub_attrs) = attr.meta_item_list() {
+        parent.push(name.as_str().to_string());
+        for sub_attr in sub_attrs {
+            if let Some(meta) = sub_attr.meta_item() {
+                check_duplicated_attr(cx, meta, attr_paths, parent);
+            }
+        }
+        parent.pop();
+    } else {
+        emit_if_duplicated(cx, attr, attr_paths, format!("{}:{name}", parent.join(":")));
+    }
+}
+
+pub fn check(cx: &EarlyContext<'_>, attrs: &[Attribute]) {
+    let mut attr_paths = FxHashMap::default();
+
+    for attr in attrs {
+        if let Some(meta) = attr.meta() {
+            check_duplicated_attr(cx, &meta, &mut attr_paths, &mut Vec::new());
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs
index c4c65d3248a..675c428948f 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs
@@ -4,6 +4,7 @@ mod allow_attributes_without_reason;
 mod blanket_clippy_restriction_lints;
 mod deprecated_cfg_attr;
 mod deprecated_semver;
+mod duplicated_attributes;
 mod empty_line_after;
 mod inline_always;
 mod maybe_misused_cfg;
@@ -16,7 +17,7 @@ mod useless_attribute;
 mod utils;
 
 use clippy_config::msrvs::Msrv;
-use rustc_ast::{Attribute, MetaItemKind, NestedMetaItem};
+use rustc_ast::{Attribute, Crate, MetaItemKind, NestedMetaItem};
 use rustc_hir::{ImplItem, Item, ItemKind, TraitItem};
 use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, impl_lint_pass};
@@ -489,6 +490,32 @@ declare_clippy_lint! {
     "item has both inner and outer attributes"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for attributes that appear two or more times.
+    ///
+    /// ### Why is this bad?
+    /// Repeating an attribute on the same item (or globally on the same crate)
+    /// is unnecessary and doesn't have an effect.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// #[allow(dead_code)]
+    /// #[allow(dead_code)]
+    /// fn foo() {}
+    /// ```
+    ///
+    /// Use instead:
+    /// ```no_run
+    /// #[allow(dead_code)]
+    /// fn foo() {}
+    /// ```
+    #[clippy::version = "1.78.0"]
+    pub DUPLICATED_ATTRIBUTES,
+    suspicious,
+    "duplicated attribute"
+}
+
 declare_lint_pass!(Attributes => [
     ALLOW_ATTRIBUTES_WITHOUT_REASON,
     INLINE_ALWAYS,
@@ -568,12 +595,18 @@ impl_lint_pass!(EarlyAttributes => [
     DEPRECATED_CLIPPY_CFG_ATTR,
     UNNECESSARY_CLIPPY_CFG,
     MIXED_ATTRIBUTES_STYLE,
+    DUPLICATED_ATTRIBUTES,
 ]);
 
 impl EarlyLintPass for EarlyAttributes {
+    fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) {
+        duplicated_attributes::check(cx, &krate.attrs);
+    }
+
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::Item) {
         empty_line_after::check(cx, item);
         mixed_attributes_style::check(cx, item);
+        duplicated_attributes::check(cx, &item.attrs);
     }
 
     fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) {
diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs
index 779ae03c464..8683cb86e8a 100644
--- a/src/tools/clippy/clippy_lints/src/box_default.rs
+++ b/src/tools/clippy/clippy_lints/src/box_default.rs
@@ -6,7 +6,7 @@ use clippy_utils::{is_default_equivalent, path_def_id};
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::intravisit::{walk_ty, Visitor};
-use rustc_hir::{Block, Expr, ExprKind, Local, Node, QPath, Ty, TyKind};
+use rustc_hir::{Block, Expr, ExprKind, LetStmt, Node, QPath, Ty, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::print::with_forced_trimmed_paths;
@@ -70,7 +70,9 @@ impl LateLintPass<'_> for BoxDefault {
                 "try",
                 if is_plain_default(cx, arg_path) || given_type(cx, expr) {
                     "Box::default()".into()
-                } else if let Some(arg_ty) = cx.typeck_results().expr_ty(arg).make_suggestable(cx.tcx, true) {
+                } else if let Some(arg_ty) =
+                    cx.typeck_results().expr_ty(arg).make_suggestable(cx.tcx, true, None)
+                {
                     // Check if we can copy from the source expression in the replacement.
                     // We need the call to have no argument (see `explicit_default_type`).
                     if inner_call_args.is_empty()
@@ -137,7 +139,7 @@ impl<'tcx> Visitor<'tcx> for InferVisitor {
 
 fn given_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     match cx.tcx.parent_hir_node(expr.hir_id) {
-        Node::Local(Local { ty: Some(ty), .. }) => {
+        Node::LetStmt(LetStmt { ty: Some(ty), .. }) => {
             let mut v = InferVisitor::default();
             v.visit_ty(ty);
             !v.0
diff --git a/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs b/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs
index 8bfb7383f14..a667ea04af0 100644
--- a/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs
@@ -4,18 +4,13 @@ use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::LateContext;
 use rustc_middle::mir::Mutability;
-use rustc_middle::ty::{self, Ty, TypeAndMut};
+use rustc_middle::ty::{self, Ty};
 
 use super::AS_PTR_CAST_MUT;
 
 pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_to: Ty<'_>) {
-    if let ty::RawPtr(TypeAndMut {
-        mutbl: Mutability::Mut,
-        ty: ptrty,
-    }) = cast_to.kind()
-        && let ty::RawPtr(TypeAndMut {
-            mutbl: Mutability::Not, ..
-        }) = cx.typeck_results().node_type(cast_expr.hir_id).kind()
+    if let ty::RawPtr(ptrty, Mutability::Mut) = cast_to.kind()
+        && let ty::RawPtr(_, Mutability::Not) = cx.typeck_results().node_type(cast_expr.hir_id).kind()
         && let ExprKind::MethodCall(method_name, receiver, [], _) = cast_expr.peel_blocks().kind
         && method_name.ident.name == rustc_span::sym::as_ptr
         && let Some(as_ptr_did) = cx
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
index fe2455f4b23..86f4332d05a 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
@@ -1,12 +1,12 @@
 use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::in_constant;
-use clippy_utils::source::snippet_opt;
+use clippy_utils::source::{snippet_opt, snippet_with_applicability};
 use clippy_utils::ty::is_isize_or_usize;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind};
+use rustc_hir::{Expr, ExprKind, QPath, TyKind};
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, FloatTy, Ty};
+use rustc_middle::ty::{self, FloatTy, Ty, UintTy};
 
 use super::{utils, CAST_LOSSLESS};
 
@@ -16,6 +16,7 @@ pub(super) fn check(
     cast_op: &Expr<'_>,
     cast_from: Ty<'_>,
     cast_to: Ty<'_>,
+    cast_to_hir: &rustc_hir::Ty<'_>,
     msrv: &Msrv,
 ) {
     if !should_lint(cx, expr, cast_from, cast_to, msrv) {
@@ -24,11 +25,11 @@ pub(super) fn check(
 
     // The suggestion is to use a function call, so if the original expression
     // has parens on the outside, they are no longer needed.
-    let mut applicability = Applicability::MachineApplicable;
+    let mut app = Applicability::MachineApplicable;
     let opt = snippet_opt(cx, cast_op.span.source_callsite());
     let sugg = opt.as_ref().map_or_else(
         || {
-            applicability = Applicability::HasPlaceholders;
+            app = Applicability::HasPlaceholders;
             ".."
         },
         |snip| {
@@ -40,10 +41,27 @@ pub(super) fn check(
         },
     );
 
+    // Display the type alias instead of the aliased type. Fixes #11285
+    //
+    // FIXME: Once `lazy_type_alias` is stabilized(?) we should use `rustc_middle` types instead,
+    // this will allow us to display the right type with `cast_from` as well.
+    let cast_to_fmt = if let TyKind::Path(QPath::Resolved(None, path)) = cast_to_hir.kind
+        // It's a bit annoying but the turbofish is optional for types. A type in an `as` cast
+        // shouldn't have these if they're primitives, which are the only things we deal with.
+        //
+        // This could be removed for performance if this check is determined to have a pretty major
+        // effect.
+        && path.segments.iter().all(|segment| segment.args.is_none())
+    {
+        snippet_with_applicability(cx, cast_to_hir.span, "..", &mut app)
+    } else {
+        cast_to.to_string().into()
+    };
+
     let message = if cast_from.is_bool() {
-        format!("casting `{cast_from:}` to `{cast_to:}` is more cleanly stated with `{cast_to:}::from(_)`")
+        format!("casting `{cast_from}` to `{cast_to_fmt}` is more cleanly stated with `{cast_to_fmt}::from(_)`")
     } else {
-        format!("casting `{cast_from}` to `{cast_to}` may become silently lossy if you later change the type")
+        format!("casting `{cast_from}` to `{cast_to_fmt}` may become silently lossy if you later change the type")
     };
 
     span_lint_and_sugg(
@@ -52,14 +70,17 @@ pub(super) fn check(
         expr.span,
         &message,
         "try",
-        format!("{cast_to}::from({sugg})"),
-        applicability,
+        format!("{cast_to_fmt}::from({sugg})"),
+        app,
     );
 }
 
 fn should_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, msrv: &Msrv) -> bool {
     // Do not suggest using From in consts/statics until it is valid to do so (see #2267).
-    if in_constant(cx, expr.hir_id) {
+    //
+    // If destination is u128, do not lint because source type cannot be larger
+    // If source is bool, still lint due to the lint message differing (refers to style)
+    if in_constant(cx, expr.hir_id) || (!cast_from.is_bool() && matches!(cast_to.kind(), ty::Uint(UintTy::U128))) {
         return false;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
index f12f03fbe79..4d1a0f678f4 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
@@ -33,13 +33,13 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
 }
 
 fn lint_cast_ptr_alignment<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, cast_from: Ty<'tcx>, cast_to: Ty<'tcx>) {
-    if let ty::RawPtr(from_ptr_ty) = &cast_from.kind()
-        && let ty::RawPtr(to_ptr_ty) = &cast_to.kind()
-        && let Ok(from_layout) = cx.layout_of(from_ptr_ty.ty)
-        && let Ok(to_layout) = cx.layout_of(to_ptr_ty.ty)
+    if let ty::RawPtr(from_ptr_ty, _) = *cast_from.kind()
+        && let ty::RawPtr(to_ptr_ty, _) = *cast_to.kind()
+        && let Ok(from_layout) = cx.layout_of(from_ptr_ty)
+        && let Ok(to_layout) = cx.layout_of(to_ptr_ty)
         && from_layout.align.abi < to_layout.align.abi
         // with c_void, we inherently need to trust the user
-        && !is_c_void(cx, from_ptr_ty.ty)
+        && !is_c_void(cx, from_ptr_ty)
         // when casting from a ZST, we don't know enough to properly lint
         && !from_layout.is_zst()
         && !is_used_as_unaligned(cx, expr)
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs b/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
index a31943f0021..76d5c329179 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
@@ -87,7 +87,7 @@ fn is_child_of_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 /// the type is one of those slices
 fn get_raw_slice_ty_mut(ty: Ty<'_>) -> Option<TypeAndMut<'_>> {
     match ty.kind() {
-        ty::RawPtr(TypeAndMut { ty: slice_ty, mutbl }) => match slice_ty.kind() {
+        ty::RawPtr(slice_ty, mutbl) => match slice_ty.kind() {
             ty::Slice(ty) => Some(TypeAndMut { ty: *ty, mutbl: *mutbl }),
             _ => None,
         },
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs b/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs
index 3db1e3e6d97..48629b6c5cc 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs
@@ -25,8 +25,8 @@ fn raw_parts_kind(cx: &LateContext<'_>, did: DefId) -> Option<RawPartsKind> {
 
 pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_to: Ty<'_>, msrv: &Msrv) {
     if msrv.meets(msrvs::PTR_SLICE_RAW_PARTS)
-        && let ty::RawPtr(ptrty) = cast_to.kind()
-        && let ty::Slice(_) = ptrty.ty.kind()
+        && let ty::RawPtr(ptrty, _) = cast_to.kind()
+        && let ty::Slice(_) = ptrty.kind()
         && let ExprKind::Call(fun, [ptr_arg, len_arg]) = cast_expr.peel_blocks().kind
         && let ExprKind::Path(ref qpath) = fun.kind
         && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id()
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index 14f2f4a7f59..063aab28238 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -791,7 +791,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
                     cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
                     cast_nan_to_int::check(cx, expr, cast_expr, cast_from, cast_to);
                 }
-                cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
+                cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, cast_to_hir, &self.msrv);
                 cast_enum_constructor::check(cx, expr, cast_expr, cast_from);
             }
 
diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
index 35e36e9ef3f..5a121e6a7eb 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
@@ -6,7 +6,7 @@ use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, Mutability, QPath, TyKind};
 use rustc_hir_pretty::qpath_to_string;
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, TypeAndMut};
+use rustc_middle::ty;
 use rustc_span::sym;
 
 use super::PTR_AS_PTR;
@@ -33,8 +33,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) {
 
     if let ExprKind::Cast(cast_expr, cast_to_hir_ty) = expr.kind
         && let (cast_from, cast_to) = (cx.typeck_results().expr_ty(cast_expr), cx.typeck_results().expr_ty(expr))
-        && let ty::RawPtr(TypeAndMut { mutbl: from_mutbl, .. }) = cast_from.kind()
-        && let ty::RawPtr(TypeAndMut { ty: to_pointee_ty, mutbl: to_mutbl }) = cast_to.kind()
+        && let ty::RawPtr(_, from_mutbl) = cast_from.kind()
+        && let ty::RawPtr(to_pointee_ty, to_mutbl) = cast_to.kind()
         && matches!((from_mutbl, to_mutbl),
             (Mutability::Not, Mutability::Not) | (Mutability::Mut, Mutability::Mut))
         // The `U` in `pointer::cast` have to be `Sized`
diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs
index ff069860a11..e88146331ca 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs
@@ -4,7 +4,7 @@ use clippy_utils::sugg::Sugg;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, Mutability};
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty, TypeAndMut};
+use rustc_middle::ty::{self, Ty};
 
 use super::PTR_CAST_CONSTNESS;
 
@@ -17,14 +17,8 @@ pub(super) fn check<'tcx>(
     msrv: &Msrv,
 ) {
     if msrv.meets(msrvs::POINTER_CAST_CONSTNESS)
-        && let ty::RawPtr(TypeAndMut {
-            mutbl: from_mutbl,
-            ty: from_ty,
-        }) = cast_from.kind()
-        && let ty::RawPtr(TypeAndMut {
-            mutbl: to_mutbl,
-            ty: to_ty,
-        }) = cast_to.kind()
+        && let ty::RawPtr(from_ty, from_mutbl) = cast_from.kind()
+        && let ty::RawPtr(to_ty, to_mutbl) = cast_to.kind()
         && matches!(
             (from_mutbl, to_mutbl),
             (Mutability::Not, Mutability::Mut) | (Mutability::Mut, Mutability::Not)
diff --git a/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs
index 9d5a486336d..f42bafce4dd 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ref_as_ptr.rs
@@ -5,7 +5,7 @@ use clippy_utils::{expr_use_ctxt, is_no_std_crate, ExprUseNode};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, Mutability, Ty, TyKind};
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, TypeAndMut};
+use rustc_middle::ty;
 
 use super::REF_AS_PTR;
 
@@ -21,10 +21,10 @@ pub(super) fn check<'tcx>(
     );
 
     if matches!(cast_from.kind(), ty::Ref(..))
-        && let ty::RawPtr(TypeAndMut { mutbl: to_mutbl, .. }) = cast_to.kind()
+        && let ty::RawPtr(_, to_mutbl) = cast_to.kind()
         && let Some(use_cx) = expr_use_ctxt(cx, expr)
         // TODO: only block the lint if `cast_expr` is a temporary
-        && !matches!(use_cx.node, ExprUseNode::Local(_) | ExprUseNode::ConstStatic(_))
+        && !matches!(use_cx.node, ExprUseNode::LetStmt(_) | ExprUseNode::ConstStatic(_))
     {
         let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" };
         let fn_name = match to_mutbl {
diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
index 08341ff32f3..148d52cb5dd 100644
--- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
@@ -66,7 +66,7 @@ pub(super) fn check<'tcx>(
         && let QPath::Resolved(None, Path { res, .. }) = qpath
         && let Res::Local(hir_id) = res
         && let parent = cx.tcx.parent_hir_node(*hir_id)
-        && let Node::Local(local) = parent
+        && let Node::LetStmt(local) = parent
     {
         if let Some(ty) = local.ty
             && let TyKind::Path(qpath) = ty.kind
@@ -275,7 +275,7 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx
                 }
             // Local usage
             } else if let Res::Local(hir_id) = res
-                && let Node::Local(l) = cx.tcx.parent_hir_node(hir_id)
+                && let Node::LetStmt(l) = cx.tcx.parent_hir_node(hir_id)
             {
                 if let Some(e) = l.init
                     && is_cast_from_ty_alias(cx, e, cast_from)
diff --git a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs
index d820413e111..e921b9b46a6 100644
--- a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs
+++ b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs
@@ -3,7 +3,7 @@ use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
 use clippy_utils::visitors::for_each_expr_with_closures;
 use clippy_utils::{get_enclosing_block, path_to_local_id};
 use core::ops::ControlFlow;
-use rustc_hir::{Block, ExprKind, HirId, LangItem, Local, Node, PatKind};
+use rustc_hir::{Block, ExprKind, HirId, LangItem, LetStmt, Node, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::symbol::sym;
@@ -58,7 +58,7 @@ static COLLECTIONS: [Symbol; 9] = [
 ];
 
 impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead {
-    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
         // Look for local variables whose type is a container. Search surrounding bock for read access.
         if match_acceptable_type(cx, local, &COLLECTIONS)
             && let PatKind::Binding(_, local_id, _, _) = local.pat.kind
@@ -70,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead {
     }
 }
 
-fn match_acceptable_type(cx: &LateContext<'_>, local: &Local<'_>, collections: &[rustc_span::Symbol]) -> bool {
+fn match_acceptable_type(cx: &LateContext<'_>, local: &LetStmt<'_>, collections: &[rustc_span::Symbol]) -> bool {
     let ty = cx.typeck_results().pat_ty(local.pat);
     collections.iter().any(|&sym| is_type_diagnostic_item(cx, ty, sym))
     // String type is a lang item but not a diagnostic item for now so we need a separate check
diff --git a/src/tools/clippy/clippy_lints/src/dbg_macro.rs b/src/tools/clippy/clippy_lints/src/dbg_macro.rs
index ec66556cebf..e2296767431 100644
--- a/src/tools/clippy/clippy_lints/src/dbg_macro.rs
+++ b/src/tools/clippy/clippy_lints/src/dbg_macro.rs
@@ -1,12 +1,14 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::macros::root_macro_call_first_node;
+use clippy_utils::macros::{macro_backtrace, MacroCall};
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::{is_in_cfg_test, is_in_test_function};
+use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, Node};
+use rustc_hir::{Expr, ExprKind, HirId, Node};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
-use rustc_span::sym;
+use rustc_span::{sym, Span, SyntaxContext};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -31,31 +33,38 @@ declare_clippy_lint! {
     "`dbg!` macro is intended as a debugging tool"
 }
 
-#[derive(Copy, Clone)]
+#[derive(Clone)]
 pub struct DbgMacro {
     allow_dbg_in_tests: bool,
+    /// Tracks the `dbg!` macro callsites that are already checked.
+    checked_dbg_call_site: FxHashSet<Span>,
+    /// Tracks the previous `SyntaxContext`, to avoid walking the same context chain.
+    prev_ctxt: SyntaxContext,
 }
 
 impl_lint_pass!(DbgMacro => [DBG_MACRO]);
 
 impl DbgMacro {
     pub fn new(allow_dbg_in_tests: bool) -> Self {
-        DbgMacro { allow_dbg_in_tests }
+        DbgMacro {
+            allow_dbg_in_tests,
+            checked_dbg_call_site: FxHashSet::default(),
+            prev_ctxt: SyntaxContext::root(),
+        }
     }
 }
 
 impl LateLintPass<'_> for DbgMacro {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
-        let Some(macro_call) = root_macro_call_first_node(cx, expr) else {
-            return;
-        };
-        if cx.tcx.is_diagnostic_item(sym::dbg_macro, macro_call.def_id) {
+        let cur_syntax_ctxt = expr.span.ctxt();
+
+        if cur_syntax_ctxt != self.prev_ctxt &&
+            let Some(macro_call) = first_dbg_macro_in_expansion(cx, expr.span) &&
+            !in_external_macro(cx.sess(), macro_call.span) &&
+            self.checked_dbg_call_site.insert(macro_call.span) &&
             // allows `dbg!` in test code if allow-dbg-in-test is set to true in clippy.toml
-            if self.allow_dbg_in_tests
-                && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id))
-            {
-                return;
-            }
+            !(self.allow_dbg_in_tests && is_in_test(cx, expr.hir_id))
+        {
             let mut applicability = Applicability::MachineApplicable;
 
             let (sugg_span, suggestion) = match expr.peel_drop_temps().kind {
@@ -101,6 +110,8 @@ impl LateLintPass<'_> for DbgMacro {
                 _ => return,
             };
 
+            self.prev_ctxt = cur_syntax_ctxt;
+
             span_lint_and_sugg(
                 cx,
                 DBG_MACRO,
@@ -112,4 +123,16 @@ impl LateLintPass<'_> for DbgMacro {
             );
         }
     }
+
+    fn check_crate_post(&mut self, _: &LateContext<'_>) {
+        self.checked_dbg_call_site = FxHashSet::default();
+    }
+}
+
+fn is_in_test(cx: &LateContext<'_>, hir_id: HirId) -> bool {
+    is_in_test_function(cx.tcx, hir_id) || is_in_cfg_test(cx.tcx, hir_id)
+}
+
+fn first_dbg_macro_in_expansion(cx: &LateContext<'_>, span: Span) -> Option<MacroCall> {
+    macro_backtrace(span).find(|mc| cx.tcx.is_diagnostic_item(sym::dbg_macro, mc.def_id))
 }
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 2b324f5f96e..c8e148598a2 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -54,6 +54,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::attrs::DEPRECATED_CFG_ATTR_INFO,
     crate::attrs::DEPRECATED_CLIPPY_CFG_ATTR_INFO,
     crate::attrs::DEPRECATED_SEMVER_INFO,
+    crate::attrs::DUPLICATED_ATTRIBUTES_INFO,
     crate::attrs::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO,
     crate::attrs::EMPTY_LINE_AFTER_OUTER_ATTR_INFO,
     crate::attrs::INLINE_ALWAYS_INFO,
@@ -235,6 +236,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::instant_subtraction::MANUAL_INSTANT_ELAPSED_INFO,
     crate::instant_subtraction::UNCHECKED_DURATION_SUBTRACTION_INFO,
     crate::int_plus_one::INT_PLUS_ONE_INFO,
+    crate::integer_division_remainder_used::INTEGER_DIVISION_REMAINDER_USED_INFO,
     crate::invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS_INFO,
     crate::item_name_repetitions::ENUM_VARIANT_NAMES_INFO,
     crate::item_name_repetitions::MODULE_INCEPTION_INFO,
@@ -310,6 +312,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::manual_slice_size_calculation::MANUAL_SLICE_SIZE_CALCULATION_INFO,
     crate::manual_string_new::MANUAL_STRING_NEW_INFO,
     crate::manual_strip::MANUAL_STRIP_INFO,
+    crate::manual_unwrap_or_default::MANUAL_UNWRAP_OR_DEFAULT_INFO,
     crate::map_unit_fn::OPTION_MAP_UNIT_FN_INFO,
     crate::map_unit_fn::RESULT_MAP_UNIT_FN_INFO,
     crate::match_result_ok::MATCH_RESULT_OK_INFO,
@@ -353,6 +356,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::CLONE_ON_COPY_INFO,
     crate::methods::CLONE_ON_REF_PTR_INFO,
     crate::methods::COLLAPSIBLE_STR_REPLACE_INFO,
+    crate::methods::CONST_IS_EMPTY_INFO,
     crate::methods::DRAIN_COLLECT_INFO,
     crate::methods::ERR_EXPECT_INFO,
     crate::methods::EXPECT_FUN_CALL_INFO,
@@ -750,5 +754,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::write::WRITE_LITERAL_INFO,
     crate::write::WRITE_WITH_NEWLINE_INFO,
     crate::zero_div_zero::ZERO_DIVIDED_BY_ZERO_INFO,
+    crate::zero_repeat_side_effects::ZERO_REPEAT_SIDE_EFFECTS_INFO,
     crate::zero_sized_map_values::ZERO_SIZED_MAP_VALUES_INFO,
 ];
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index f0f2c7d6658..c554edc8fce 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -11,7 +11,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::traits::Reveal;
 use rustc_middle::ty::{
-    self, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv, ToPredicate, TraitPredicate, Ty,
+    self, ClauseKind, GenericArgKind, GenericParamDefKind, ParamEnv, ToPredicate, TraitPredicate, Ty,
     TyCtxt,
 };
 use rustc_session::declare_lint_pass;
@@ -502,7 +502,7 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) ->
             params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| {
                 ClauseKind::Trait(TraitPredicate {
                     trait_ref: ty::TraitRef::new(tcx, eq_trait_id, [tcx.mk_param_from_def(param)]),
-                    polarity: ImplPolarity::Positive,
+                    polarity: ty::PredicatePolarity::Positive,
                 })
                 .to_predicate(tcx)
             }),
diff --git a/src/tools/clippy/clippy_lints/src/doc/markdown.rs b/src/tools/clippy/clippy_lints/src/doc/markdown.rs
index d2f14756591..1add02af310 100644
--- a/src/tools/clippy/clippy_lints/src/doc/markdown.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/markdown.rs
@@ -8,7 +8,14 @@ use url::Url;
 
 use crate::doc::DOC_MARKDOWN;
 
-pub fn check(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, text: &str, span: Span, code_level: isize) {
+pub fn check(
+    cx: &LateContext<'_>,
+    valid_idents: &FxHashSet<String>,
+    text: &str,
+    span: Span,
+    code_level: isize,
+    blockquote_level: isize,
+) {
     for orig_word in text.split(|c: char| c.is_whitespace() || c == '\'') {
         // Trim punctuation as in `some comment (see foo::bar).`
         //                                                   ^^
@@ -46,11 +53,11 @@ pub fn check(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, text: &str,
             span.parent(),
         );
 
-        check_word(cx, word, span, code_level);
+        check_word(cx, word, span, code_level, blockquote_level);
     }
 }
 
-fn check_word(cx: &LateContext<'_>, word: &str, span: Span, code_level: isize) {
+fn check_word(cx: &LateContext<'_>, word: &str, span: Span, code_level: isize, blockquote_level: isize) {
     /// Checks if a string is upper-camel-case, i.e., starts with an uppercase and
     /// contains at least two uppercase letters (`Clippy` is ok) and one lower-case
     /// letter (`NASA` is ok).
@@ -97,7 +104,9 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span, code_level: isize) {
     }
 
     // We assume that mixed-case words are not meant to be put inside backticks. (Issue #2343)
-    if code_level > 0 || (has_underscore(word) && has_hyphen(word)) {
+    //
+    // We also assume that backticks are not necessary if inside a quote. (Issue #10262)
+    if code_level > 0 || blockquote_level > 0 || (has_underscore(word) && has_hyphen(word)) {
         return;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index 003d26b7b89..b135e4e3577 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -7,14 +7,14 @@ use clippy_utils::{is_entrypoint_fn, method_chain_args};
 use pulldown_cmark::Event::{
     Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text,
 };
-use pulldown_cmark::Tag::{CodeBlock, Heading, Item, Link, Paragraph};
+use pulldown_cmark::Tag::{BlockQuote, CodeBlock, Heading, Item, Link, Paragraph};
 use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options};
 use rustc_ast::ast::Attribute;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{AnonConst, Expr};
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
@@ -538,7 +538,16 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
 
     suspicious_doc_comments::check(cx, attrs);
 
-    let (fragments, _) = attrs_to_doc_fragments(attrs.iter().map(|attr| (attr, None)), true);
+    let (fragments, _) = attrs_to_doc_fragments(
+        attrs.iter().filter_map(|attr| {
+            if in_external_macro(cx.sess(), attr.span) {
+                None
+            } else {
+                Some((attr, None))
+            }
+        }),
+        true,
+    );
     let mut doc = fragments.iter().fold(String::new(), |mut acc, fragment| {
         add_doc_fragment(&mut acc, fragment);
         acc
@@ -602,6 +611,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
     let mut text_to_check: Vec<(CowStr<'_>, Range<usize>, isize)> = Vec::new();
     let mut paragraph_range = 0..0;
     let mut code_level = 0;
+    let mut blockquote_level = 0;
 
     for (event, range) in events {
         match event {
@@ -610,8 +620,14 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                     code_level += 1;
                 } else if tag.starts_with("</code") {
                     code_level -= 1;
+                } else if tag.starts_with("<blockquote") || tag.starts_with("<q") {
+                    blockquote_level += 1;
+                } else if tag.starts_with("</blockquote") || tag.starts_with("</q") {
+                    blockquote_level -= 1;
                 }
             },
+            Start(BlockQuote) => blockquote_level += 1,
+            End(BlockQuote) => blockquote_level -= 1,
             Start(CodeBlock(ref kind)) => {
                 in_code = true;
                 if let CodeBlockKind::Fenced(lang) = kind {
@@ -663,7 +679,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                 } else {
                     for (text, range, assoc_code_level) in text_to_check {
                         if let Some(span) = fragments.span(cx, range) {
-                            markdown::check(cx, valid_idents, &text, span, assoc_code_level);
+                            markdown::check(cx, valid_idents, &text, span, assoc_code_level, blockquote_level);
                         }
                     }
                 }
diff --git a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs
index 47780cab9ed..a6ca7fe9e0b 100644
--- a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs
+++ b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs
@@ -49,24 +49,22 @@ declare_clippy_lint! {
 declare_lint_pass!(ElseIfWithoutElse => [ELSE_IF_WITHOUT_ELSE]);
 
 impl EarlyLintPass for ElseIfWithoutElse {
-    fn check_expr(&mut self, cx: &EarlyContext<'_>, mut item: &Expr) {
+    fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) {
         if in_external_macro(cx.sess(), item.span) {
             return;
         }
 
-        while let ExprKind::If(_, _, Some(ref els)) = item.kind {
-            if let ExprKind::If(_, _, None) = els.kind {
-                span_lint_and_help(
-                    cx,
-                    ELSE_IF_WITHOUT_ELSE,
-                    els.span,
-                    "`if` expression with an `else if`, but without a final `else`",
-                    None,
-                    "add an `else` block here",
-                );
-            }
-
-            item = els;
+        if let ExprKind::If(_, _, Some(ref els)) = item.kind
+            && let ExprKind::If(_, _, None) = els.kind
+        {
+            span_lint_and_help(
+                cx,
+                ELSE_IF_WITHOUT_ELSE,
+                els.span,
+                "`if` expression with an `else if`, but without a final `else`",
+                None,
+                "add an `else` block here",
+            );
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs
index ebda2ad8387..dafbf6c8846 100644
--- a/src/tools/clippy/clippy_lints/src/entry.rs
+++ b/src/tools/clippy/clippy_lints/src/entry.rs
@@ -358,7 +358,7 @@ struct InsertSearcher<'cx, 'tcx> {
     can_use_entry: bool,
     /// Whether this expression is the final expression in this code path. This may be a statement.
     in_tail_pos: bool,
-    // Is this expression a single insert. A slightly better suggestion can be made in this case.
+    /// Is this expression a single insert. A slightly better suggestion can be made in this case.
     is_single_insert: bool,
     /// If the visitor has seen the map being used.
     is_map_used: bool,
@@ -431,6 +431,9 @@ impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> {
                     self.is_single_insert = false;
                     self.visit_expr(e);
                 }
+                if let Some(els) = &l.els {
+                    self.visit_block(els);
+                }
             },
             StmtKind::Item(_) => {
                 self.allow_insert_closure &= !self.in_tail_pos;
diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
index 4e728d61b85..37442bf3e28 100644
--- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
+++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
@@ -55,7 +55,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
         | PatKind::Err(_) => false,
         PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)),
         PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a),
-        PatKind::Ref(x, _) | PatKind::Box(x) => unary_pattern(x),
+        PatKind::Ref(x, _) | PatKind::Box(x) | PatKind::Deref(x) => unary_pattern(x),
         PatKind::Path(_) | PatKind::Lit(_) => true,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 40be71a0e5d..eccfc31fdd3 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -9,7 +9,7 @@ use rustc_hir::{BindingAnnotation, Expr, ExprKind, FnRetTy, Param, PatKind, QPat
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{
-    self, Binder, ClosureArgs, ClosureKind, FnSig, GenericArg, GenericArgKind, ImplPolarity, List, Region, RegionKind,
+    self, Binder, ClosureArgs, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, RegionKind,
     Ty, TypeVisitableExt, TypeckResults,
 };
 use rustc_session::declare_lint_pass;
@@ -173,7 +173,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
                             if let Ok((ClosureKind::FnMut, _)) = cx.tcx.infer_ctxt().build().type_implements_fn_trait(
                                 cx.param_env,
                                 Binder::bind_with_vars(callee_ty_adjusted, List::empty()),
-                                ImplPolarity::Positive,
+                                ty::PredicatePolarity::Positive,
                             ) && path_to_local(callee).map_or(false, |l| {
                                 local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr)
                             }) {
diff --git a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
index c8d10dc4b92..286ba2306c9 100644
--- a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
@@ -4,7 +4,7 @@ use clippy_utils::ty::is_c_void;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{Expr, ExprKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{RawPtr, TypeAndMut};
+use rustc_middle::ty::{RawPtr};
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
 
@@ -44,7 +44,7 @@ impl LateLintPass<'_> for FromRawWithVoidPtr {
             && seg.ident.name == sym!(from_raw)
             && let Some(type_str) = path_def_id(cx, ty).and_then(|id| def_id_matches_type(cx, id))
             && let arg_kind = cx.typeck_results().expr_ty(arg).kind()
-            && let RawPtr(TypeAndMut { ty, .. }) = arg_kind
+            && let RawPtr(ty, _) = arg_kind
             && is_c_void(cx, *ty)
         {
             let msg = format!("creating a `{type_str}` from a void raw pointer");
diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs
index 96da2ec2a1a..9cc51fa8cd5 100644
--- a/src/tools/clippy/clippy_lints/src/functions/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs
@@ -250,7 +250,7 @@ declare_clippy_lint! {
     ///
     /// ### Why is this bad?
     /// A `Result` is at least as large as the `Err`-variant. While we
-    /// expect that variant to be seldomly used, the compiler needs to reserve
+    /// expect that variant to be seldom used, the compiler needs to reserve
     /// and move that much memory every single time.
     /// Furthermore, errors are often simply passed up the call-stack, making
     /// use of the `?`-operator and its type-conversion mechanics. If the
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 3aaf63ce340..d752d010f9f 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -207,7 +207,7 @@ fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, tys: &mut DefIdSet)
         },
         ty::Tuple(args) => args.iter().any(|ty| is_mutable_ty(cx, ty, tys)),
         ty::Array(ty, _) | ty::Slice(ty) => is_mutable_ty(cx, ty, tys),
-        ty::RawPtr(ty::TypeAndMut { ty, mutbl }) | ty::Ref(_, ty, mutbl) => {
+        ty::RawPtr(ty, mutbl) | ty::Ref(_, ty, mutbl) => {
             mutbl == hir::Mutability::Mut || is_mutable_ty(cx, ty, tys)
         },
         // calling something constitutes a side effect, so return true on all callables
diff --git a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
index f2aa7b597a7..2d757883f26 100644
--- a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
@@ -75,7 +75,7 @@ fn check_raw_ptr<'tcx>(
 }
 
 fn raw_ptr_arg(cx: &LateContext<'_>, arg: &hir::Param<'_>) -> Option<hir::HirId> {
-    if let (&hir::PatKind::Binding(_, id, _, _), Some(&ty::RawPtr(_))) = (
+    if let (&hir::PatKind::Binding(_, id, _, _), Some(&ty::RawPtr(_, _))) = (
         &arg.pat.kind,
         cx.maybe_typeck_results()
             .map(|typeck_results| typeck_results.pat_ty(arg.pat).kind()),
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 9fb59a320d4..18f4e51ebd6 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
         }
         let ret_ty = return_ty(cx, cx.tcx.local_def_id_to_hir_id(fn_def_id).expect_owner());
         if let ty::Alias(ty::Opaque, AliasTy { def_id, args, .. }) = *ret_ty.kind() {
-            let preds = cx.tcx.explicit_item_bounds(def_id);
+            let preds = cx.tcx.explicit_item_super_predicates(def_id);
             let mut is_future = false;
             for (p, _span) in preds.iter_instantiated_copied(cx.tcx, args) {
                 if let Some(trait_pred) = p.as_trait_clause() {
diff --git a/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs b/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs
index 80a537b9f94..a32201d8079 100644
--- a/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs
@@ -46,7 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for IgnoredUnitPatterns {
                 // Ignore function parameters
                 return;
             },
-            Node::Local(local) if local.ty.is_some() => {
+            Node::LetStmt(local) if local.ty.is_some() => {
                 // Ignore let bindings with explicit type
                 return;
             },
diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
index a79bf66ae01..8acb138332c 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
@@ -5,7 +5,7 @@ use rustc_errors::Diag;
 use rustc_hir as hir;
 use rustc_hir::intravisit::{walk_body, walk_expr, walk_inf, walk_ty, Visitor};
 use rustc_hir::{Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind};
-use rustc_hir_analysis::hir_ty_to_ty;
+use rustc_hir_analysis::lower_ty;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{Ty, TypeckResults};
@@ -227,7 +227,7 @@ impl<'tcx> ImplicitHasherType<'tcx> {
                 .collect();
             let params_len = params.len();
 
-            let ty = hir_ty_to_ty(cx.tcx, hir_ty);
+            let ty = lower_ty(cx.tcx, hir_ty);
 
             if is_type_diagnostic_item(cx, ty, sym::HashMap) && params_len == 2 {
                 Some(ImplicitHasherType::HashMap(
diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
index 74582f7f1de..9f4d7b51271 100644
--- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
@@ -6,7 +6,7 @@ use rustc_hir::{
     GenericArg, GenericBound, GenericBounds, ItemKind, PredicateOrigin, TraitBoundModifier, TyKind, TypeBinding,
     WherePredicate,
 };
-use rustc_hir_analysis::hir_ty_to_ty;
+use rustc_hir_analysis::lower_ty;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, ClauseKind, Generics, Ty, TyCtxt};
 use rustc_session::declare_lint_pass;
@@ -146,7 +146,7 @@ fn try_resolve_type<'tcx>(
     index: usize,
 ) -> Option<Ty<'tcx>> {
     match args.get(index - 1) {
-        Some(GenericArg::Type(ty)) => Some(hir_ty_to_ty(tcx, ty)),
+        Some(GenericArg::Type(ty)) => Some(lower_ty(tcx, ty)),
         Some(_) => None,
         None => Some(tcx.type_of(generics.params[index].def_id).skip_binder()),
     }
diff --git a/src/tools/clippy/clippy_lints/src/integer_division_remainder_used.rs b/src/tools/clippy/clippy_lints/src/integer_division_remainder_used.rs
new file mode 100644
index 00000000000..36dc45ca788
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/integer_division_remainder_used.rs
@@ -0,0 +1,50 @@
+use clippy_utils::diagnostics::span_lint;
+use rustc_ast::BinOpKind;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::{self};
+use rustc_session::declare_lint_pass;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for the usage of division (/) and remainder (%) operations
+    /// when performed on any integer types using the default Div and Rem trait implementations.
+    ///
+    /// ### Why is this bad?
+    /// In cryptographic contexts, division can result in timing sidechannel vulnerabilities,
+    /// and needs to be replaced with constant-time code instead (e.g. Barrett reduction).
+    ///
+    /// ### Example
+    /// ```no_run
+    /// let my_div = 10 / 2;
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// let my_div = 10 >> 1;
+    /// ```
+    #[clippy::version = "1.78.0"]
+    pub INTEGER_DIVISION_REMAINDER_USED,
+    restriction,
+    "use of disallowed default division and remainder operations"
+}
+
+declare_lint_pass!(IntegerDivisionRemainderUsed => [INTEGER_DIVISION_REMAINDER_USED]);
+
+impl LateLintPass<'_> for IntegerDivisionRemainderUsed {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+        if let ExprKind::Binary(op, lhs, rhs) = &expr.kind
+            && let BinOpKind::Div | BinOpKind::Rem = op.node
+            && let lhs_ty = cx.typeck_results().expr_ty(lhs)
+            && let rhs_ty = cx.typeck_results().expr_ty(rhs)
+            && let ty::Int(_) | ty::Uint(_) = lhs_ty.peel_refs().kind()
+            && let ty::Int(_) | ty::Uint(_) = rhs_ty.peel_refs().kind()
+        {
+            span_lint(
+                cx,
+                INTEGER_DIVISION_REMAINDER_USED,
+                expr.span.source_callsite(),
+                &format!("use of {} has been disallowed in this context", op.node.as_str()),
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/let_if_seq.rs b/src/tools/clippy/clippy_lints/src/let_if_seq.rs
index f084d89ccc2..d4ddf76fb8a 100644
--- a/src/tools/clippy/clippy_lints/src/let_if_seq.rs
+++ b/src/tools/clippy/clippy_lints/src/let_if_seq.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::path_to_local_id;
 use clippy_utils::source::snippet;
 use clippy_utils::visitors::is_local_used;
@@ -122,9 +122,10 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq {
                     value=snippet(cx, value.span, "<value>"),
                     default=snippet(cx, default.span, "<default>"),
                 );
-                span_lint_and_then(
+                span_lint_hir_and_then(
                     cx,
                     USELESS_LET_IF_SEQ,
+                    local.hir_id,
                     span,
                     "`if _ { .. } else { .. }` is an expression",
                     |diag| {
diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs
index 0ea53c39280..619e933b4ff 100644
--- a/src/tools/clippy/clippy_lints/src/let_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::ty::{implements_trait, is_must_use_ty, match_type};
 use clippy_utils::{is_from_proc_macro, is_must_use_func_call, paths};
-use rustc_hir::{Local, LocalSource, PatKind};
+use rustc_hir::{LetStmt, LocalSource, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{GenericArgKind, IsSuggestable};
@@ -138,7 +138,7 @@ const SYNC_GUARD_PATHS: [&[&str]; 3] = [
 ];
 
 impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
-    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &Local<'tcx>) {
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &LetStmt<'tcx>) {
         if matches!(local.source, LocalSource::Normal)
             && !in_external_macro(cx.tcx.sess, local.span)
             && let PatKind::Wild = local.pat.kind
diff --git a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
index 5f3f9b43f45..593b29154b4 100644
--- a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::source::snippet;
-use rustc_hir::{Local, TyKind};
+use rustc_hir::{LetStmt, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
@@ -26,7 +26,7 @@ declare_clippy_lint! {
 declare_lint_pass!(UnderscoreTyped => [LET_WITH_TYPE_UNDERSCORE]);
 
 impl LateLintPass<'_> for UnderscoreTyped {
-    fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) {
+    fn check_local(&mut self, cx: &LateContext<'_>, local: &LetStmt<'_>) {
         if !in_external_macro(cx.tcx.sess, local.span)
             && let Some(ty) = local.ty // Ensure that it has a type defined
             && let TyKind::Infer = &ty.kind // that type is '_'
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index b930175c4d8..57fac351042 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -172,6 +172,7 @@ mod init_numbered_fields;
 mod inline_fn_without_body;
 mod instant_subtraction;
 mod int_plus_one;
+mod integer_division_remainder_used;
 mod invalid_upcast_comparisons;
 mod item_name_repetitions;
 mod items_after_statements;
@@ -211,6 +212,7 @@ mod manual_retain;
 mod manual_slice_size_calculation;
 mod manual_string_new;
 mod manual_strip;
+mod manual_unwrap_or_default;
 mod map_unit_fn;
 mod match_result_ok;
 mod matches;
@@ -373,6 +375,7 @@ mod visibility;
 mod wildcard_imports;
 mod write;
 mod zero_div_zero;
+mod zero_repeat_side_effects;
 mod zero_sized_map_values;
 // end lints modules, do not remove this comment, it’s used in `update_lints`
 
@@ -1119,7 +1122,10 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(move |_| Box::new(incompatible_msrv::IncompatibleMsrv::new(msrv())));
     store.register_late_pass(|_| Box::new(to_string_trait_impl::ToStringTraitImpl));
     store.register_early_pass(|| Box::new(multiple_bound_locations::MultipleBoundLocations));
-    store.register_late_pass(|_| Box::new(assigning_clones::AssigningClones));
+    store.register_late_pass(move |_| Box::new(assigning_clones::AssigningClones::new(msrv())));
+    store.register_late_pass(|_| Box::new(zero_repeat_side_effects::ZeroRepeatSideEffects));
+    store.register_late_pass(|_| Box::new(manual_unwrap_or_default::ManualUnwrapOrDefault));
+    store.register_late_pass(|_| Box::new(integer_division_remainder_used::IntegerDivisionRemainderUsed));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
index 814ccaa36f5..eea5f2a94ea 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
@@ -10,7 +10,7 @@ use rustc_errors::Applicability;
 use rustc_hir::{Expr, Mutability};
 use rustc_lint::LateContext;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
-use rustc_middle::ty::{self, EarlyBinder, Ty, TypeAndMut};
+use rustc_middle::ty::{self, EarlyBinder, Ty};
 use rustc_span::sym;
 
 pub(super) fn check(
@@ -160,7 +160,7 @@ fn is_ref_iterable<'tcx>(
                 let self_ty = if mutbl.is_mut() {
                     self_ty
                 } else {
-                    Ty::new_ref(cx.tcx, region, TypeAndMut { ty, mutbl })
+                    Ty::new_ref(cx.tcx, region, ty, mutbl)
                 };
                 if implements_trait(cx, self_ty, trait_id, &[])
                     && let Some(ty) =
@@ -175,7 +175,7 @@ fn is_ref_iterable<'tcx>(
             && !self_ty.is_ref()
         {
             // Attempt to borrow
-            let self_ty = Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, TypeAndMut { ty: self_ty, mutbl });
+            let self_ty = Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, self_ty, mutbl);
             if implements_trait(cx, self_ty, trait_id, &[])
                 && let Some(ty) = make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [self_ty])
                 && ty == res_ty
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
index 47dc3807e62..cf34c904dfe 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
@@ -273,7 +273,7 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> {
                     }
                     return false; // no need to walk further *on the variable*
                 },
-                Res::Def(DefKind::Static{..} | DefKind::Const, ..) => {
+                Res::Def(DefKind::Static { .. } | DefKind::Const, ..) => {
                     if index_used_directly {
                         self.indexed_directly.insert(
                             seqvar.segments[0].ident.name,
diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
index 6cc79440f39..8aae7be4593 100644
--- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
@@ -255,9 +255,7 @@ fn never_loop_expr<'tcx>(
             InlineAsmOperand::Const { .. } | InlineAsmOperand::SymFn { .. } | InlineAsmOperand::SymStatic { .. } => {
                 NeverLoopResult::Normal
             },
-            InlineAsmOperand::Label { block } => {
-                never_loop_block(cx, block, local_labels, main_loop_id)
-            }
+            InlineAsmOperand::Label { block } => never_loop_block(cx, block, local_labels, main_loop_id),
         })),
         ExprKind::OffsetOf(_, _)
         | ExprKind::Yield(_, _)
diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
index 0f35514b8ad..670a78d58c3 100644
--- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
@@ -62,7 +62,7 @@ pub(super) fn check<'tcx>(
                         if let Node::Pat(pat) = node
                             && let PatKind::Binding(bind_ann, ..) = pat.kind
                             && !matches!(bind_ann, BindingAnnotation(_, Mutability::Mut))
-                            && let Node::Local(parent_let_expr) = cx.tcx.parent_hir_node(hir_id)
+                            && let Node::LetStmt(parent_let_expr) = cx.tcx.parent_hir_node(hir_id)
                             && let Some(init) = parent_let_expr.init
                         {
                             match init.kind {
diff --git a/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs b/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs
index dd7fae79d9b..31f0f1cfeba 100644
--- a/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs
@@ -1,62 +1,41 @@
 use super::UNUSED_ENUMERATE_INDEX;
 use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
 use clippy_utils::source::snippet;
-use clippy_utils::{pat_is_wild, sugg};
+use clippy_utils::{match_def_path, pat_is_wild, sugg};
 use rustc_hir::def::DefKind;
 use rustc_hir::{Expr, ExprKind, Pat, PatKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
 
 /// Checks for the `UNUSED_ENUMERATE_INDEX` lint.
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx Expr<'_>, body: &'tcx Expr<'_>) {
-    let PatKind::Tuple([index, elem], _) = pat.kind else {
-        return;
-    };
-
-    let ExprKind::MethodCall(_method, self_arg, [], _) = arg.kind else {
-        return;
-    };
-
-    let ty = cx.typeck_results().expr_ty(arg);
-
-    if !pat_is_wild(cx, &index.kind, body) {
-        return;
-    }
-
-    let name = match *ty.kind() {
-        ty::Adt(base, _substs) => cx.tcx.def_path_str(base.did()),
-        _ => return,
-    };
-
-    if name != "std::iter::Enumerate" && name != "core::iter::Enumerate" {
-        return;
+///
+/// The lint is also partially implemented in `clippy_lints/src/methods/unused_enumerate_index.rs`.
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>, arg: &Expr<'_>, body: &'tcx Expr<'tcx>) {
+    if let PatKind::Tuple([index, elem], _) = pat.kind
+        && let ExprKind::MethodCall(_method, self_arg, [], _) = arg.kind
+        && let ty = cx.typeck_results().expr_ty(arg)
+        && pat_is_wild(cx, &index.kind, body)
+        && let ty::Adt(base, _) = *ty.kind()
+        && match_def_path(cx, base.did(), &clippy_utils::paths::CORE_ITER_ENUMERATE_STRUCT)
+        && let Some((DefKind::AssocFn, call_id)) = cx.typeck_results().type_dependent_def(arg.hir_id)
+        && match_def_path(cx, call_id, &clippy_utils::paths::CORE_ITER_ENUMERATE_METHOD)
+    {
+        span_lint_and_then(
+            cx,
+            UNUSED_ENUMERATE_INDEX,
+            arg.span,
+            "you seem to use `.enumerate()` and immediately discard the index",
+            |diag| {
+                let base_iter = sugg::Sugg::hir(cx, self_arg, "base iter");
+                multispan_sugg(
+                    diag,
+                    "remove the `.enumerate()` call",
+                    vec![
+                        (pat.span, snippet(cx, elem.span, "..").into_owned()),
+                        (arg.span, base_iter.to_string()),
+                    ],
+                );
+            },
+        );
     }
-
-    let Some((DefKind::AssocFn, call_id)) = cx.typeck_results().type_dependent_def(arg.hir_id) else {
-        return;
-    };
-
-    let call_name = cx.tcx.def_path_str(call_id);
-
-    if call_name != "std::iter::Iterator::enumerate" && call_name != "core::iter::Iterator::enumerate" {
-        return;
-    }
-
-    span_lint_and_then(
-        cx,
-        UNUSED_ENUMERATE_INDEX,
-        arg.span,
-        "you seem to use `.enumerate()` and immediately discard the index",
-        |diag| {
-            let base_iter = sugg::Sugg::hir(cx, self_arg, "base iter");
-            multispan_sugg(
-                diag,
-                "remove the `.enumerate()` call",
-                vec![
-                    (pat.span, snippet(cx, elem.span, "..").into_owned()),
-                    (arg.span, base_iter.to_string()),
-                ],
-            );
-        },
-    );
 }
diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs
index 8bca33754e8..7b45cc95431 100644
--- a/src/tools/clippy/clippy_lints/src/loops/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs
@@ -3,7 +3,7 @@ use clippy_utils::{get_parent_expr, is_integer_const, path_to_local, path_to_loc
 use rustc_ast::ast::{LitIntType, LitKind};
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_expr, walk_local, Visitor};
-use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, HirIdMap, Local, Mutability, PatKind};
+use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, HirIdMap, LetStmt, Mutability, PatKind};
 use rustc_lint::LateContext;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{self, Ty};
@@ -141,7 +141,7 @@ impl<'a, 'tcx> InitializeVisitor<'a, 'tcx> {
 impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
-    fn visit_local(&mut self, l: &'tcx Local<'_>) {
+    fn visit_local(&mut self, l: &'tcx LetStmt<'_>) {
         // Look for declarations of the variable
         if l.pat.hir_id == self.var_id
             && let PatKind::Binding(.., ident, _) = l.pat.kind
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs
index 3511d24e813..3dff826cb85 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs
@@ -101,7 +101,7 @@ impl<'a, 'tcx> VarCollectorVisitor<'a, 'tcx> {
                 Res::Local(hir_id) => {
                     self.ids.insert(hir_id);
                 },
-                Res::Def(DefKind::Static{..}, def_id) => {
+                Res::Def(DefKind::Static { .. }, def_id) => {
                     let mutable = self.cx.tcx.is_mutable_static(def_id);
                     self.def_ids.insert(def_id, mutable);
                 },
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs
index 93774b89768..bd04827a1f0 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs
@@ -5,13 +5,13 @@ use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::needs_ordered_drop;
 use clippy_utils::visitors::any_temporaries_need_ordered_drop;
 use rustc_errors::Applicability;
-use rustc_hir::{Block, Expr, ExprKind, Local, MatchSource, Pat, StmtKind};
+use rustc_hir::{Block, Expr, ExprKind, LetStmt, MatchSource, Pat, StmtKind};
 use rustc_lint::LateContext;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) {
     let (init, has_trailing_exprs) = match (loop_block.stmts, loop_block.expr) {
         ([stmt, stmts @ ..], expr) => {
-            if let StmtKind::Let(&Local {
+            if let StmtKind::Let(&LetStmt {
                 init: Some(e),
                 els: None,
                 ..
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
index d070ee74985..194dd4752f9 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
@@ -6,7 +6,7 @@ use clippy_utils::{get_enclosing_loop_or_multi_call_closure, higher, is_refutabl
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::{Closure, Expr, ExprKind, HirId, LangItem, Local, Mutability, PatKind, UnOp};
+use rustc_hir::{Closure, Expr, ExprKind, HirId, LangItem, LetStmt, Mutability, PatKind, UnOp};
 use rustc_lint::LateContext;
 use rustc_middle::hir::nested_filter::OnlyBodies;
 use rustc_middle::ty::adjustment::Adjust;
@@ -286,7 +286,7 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &
             self.cx.tcx.hir()
         }
 
-        fn visit_local(&mut self, l: &'tcx Local<'_>) {
+        fn visit_local(&mut self, l: &'tcx LetStmt<'_>) {
             if !self.after_loop {
                 l.pat.each_binding_or_first(&mut |_, id, _, _| {
                     if id == self.local_id {
diff --git a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs
index 5cbab0ec977..f8f33cfc82e 100644
--- a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs
@@ -4,7 +4,7 @@ use clippy_utils::source::snippet_opt;
 use clippy_utils::visitors::{is_local_used, local_used_once};
 use clippy_utils::{is_trait_method, path_to_local_id};
 use rustc_errors::Applicability;
-use rustc_hir::{BindingAnnotation, ExprKind, Local, Node, PatKind, StmtKind};
+use rustc_hir::{BindingAnnotation, ExprKind, LetStmt, Node, PatKind, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
 use rustc_span::sym;
@@ -60,7 +60,7 @@ impl ManualHashOne {
 impl_lint_pass!(ManualHashOne => [MANUAL_HASH_ONE]);
 
 impl LateLintPass<'_> for ManualHashOne {
-    fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) {
+    fn check_local(&mut self, cx: &LateContext<'_>, local: &LetStmt<'_>) {
         // `let mut hasher = seg.build_hasher();`
         if let PatKind::Binding(BindingAnnotation::MUT, hasher, _, None) = local.pat.kind
             && let Some(init) = local.init
diff --git a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
index 0bde62bd554..ab9bca170cf 100644
--- a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
@@ -81,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
             // Apply only to params or locals with annotated types
             match cx.tcx.parent_hir_node(hir_id) {
                 Node::Param(..) => (),
-                Node::Local(local) => {
+                Node::LetStmt(local) => {
                     let Some(ty) = local.ty else { return };
                     if matches!(ty.kind, TyKind::Infer) {
                         return;
diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs
index 6f15fca089e..3ddb06a1e08 100644
--- a/src/tools/clippy/clippy_lints/src/manual_retain.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs
@@ -2,7 +2,7 @@ use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
-use clippy_utils::{get_parent_expr, match_def_path, paths, SpanlessEq};
+use clippy_utils::{match_def_path, paths, SpanlessEq};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
@@ -69,17 +69,16 @@ impl_lint_pass!(ManualRetain => [MANUAL_RETAIN]);
 
 impl<'tcx> LateLintPass<'tcx> for ManualRetain {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
-        if let Some(parent_expr) = get_parent_expr(cx, expr)
-            && let Assign(left_expr, collect_expr, _) = &parent_expr.kind
+        if let Assign(left_expr, collect_expr, _) = &expr.kind
             && let hir::ExprKind::MethodCall(seg, ..) = &collect_expr.kind
             && seg.args.is_none()
             && let hir::ExprKind::MethodCall(_, target_expr, [], _) = &collect_expr.kind
             && let Some(collect_def_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id)
             && cx.tcx.is_diagnostic_item(sym::iterator_collect_fn, collect_def_id)
         {
-            check_into_iter(cx, left_expr, target_expr, parent_expr.span, &self.msrv);
-            check_iter(cx, left_expr, target_expr, parent_expr.span, &self.msrv);
-            check_to_owned(cx, left_expr, target_expr, parent_expr.span, &self.msrv);
+            check_into_iter(cx, left_expr, target_expr, expr.span, &self.msrv);
+            check_iter(cx, left_expr, target_expr, expr.span, &self.msrv);
+            check_to_owned(cx, left_expr, target_expr, expr.span, &self.msrv);
         }
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs b/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs
new file mode 100644
index 00000000000..ddaf97c463a
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs
@@ -0,0 +1,181 @@
+use rustc_errors::Applicability;
+use rustc_hir::def::Res;
+use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, MatchSource, Pat, PatKind, QPath};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::declare_lint_pass;
+use rustc_span::sym;
+
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_default_equivalent;
+use clippy_utils::source::snippet_opt;
+use clippy_utils::ty::implements_trait;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks if a `match` or `if let` expression can be simplified using
+    /// `.unwrap_or_default()`.
+    ///
+    /// ### Why is this bad?
+    /// It can be done in one call with `.unwrap_or_default()`.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// let x: Option<String> = Some(String::new());
+    /// let y: String = match x {
+    ///     Some(v) => v,
+    ///     None => String::new(),
+    /// };
+    ///
+    /// let x: Option<Vec<String>> = Some(Vec::new());
+    /// let y: Vec<String> = if let Some(v) = x {
+    ///     v
+    /// } else {
+    ///     Vec::new()
+    /// };
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// let x: Option<String> = Some(String::new());
+    /// let y: String = x.unwrap_or_default();
+    ///
+    /// let x: Option<Vec<String>> = Some(Vec::new());
+    /// let y: Vec<String> = x.unwrap_or_default();
+    /// ```
+    #[clippy::version = "1.78.0"]
+    pub MANUAL_UNWRAP_OR_DEFAULT,
+    suspicious,
+    "check if a `match` or `if let` can be simplified with `unwrap_or_default`"
+}
+
+declare_lint_pass!(ManualUnwrapOrDefault => [MANUAL_UNWRAP_OR_DEFAULT]);
+
+fn get_some<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option<HirId> {
+    if let PatKind::TupleStruct(QPath::Resolved(_, path), &[pat], _) = pat.kind
+        && let Some(def_id) = path.res.opt_def_id()
+        // Since it comes from a pattern binding, we need to get the parent to actually match
+        // against it.
+        && let Some(def_id) = cx.tcx.opt_parent(def_id)
+        && cx.tcx.lang_items().get(LangItem::OptionSome) == Some(def_id)
+    {
+        let mut bindings = Vec::new();
+        pat.each_binding(|_, id, _, _| bindings.push(id));
+        if let &[id] = bindings.as_slice() {
+            Some(id)
+        } else {
+            None
+        }
+    } else {
+        None
+    }
+}
+
+fn get_none<'tcx>(cx: &LateContext<'tcx>, arm: &Arm<'tcx>) -> Option<&'tcx Expr<'tcx>> {
+    if let PatKind::Path(QPath::Resolved(_, path)) = arm.pat.kind
+        && let Some(def_id) = path.res.opt_def_id()
+        // Since it comes from a pattern binding, we need to get the parent to actually match
+        // against it.
+        && let Some(def_id) = cx.tcx.opt_parent(def_id)
+        && cx.tcx.lang_items().get(LangItem::OptionNone) == Some(def_id)
+    {
+        Some(arm.body)
+    } else if let PatKind::Wild = arm.pat.kind {
+        // We consider that the `Some` check will filter it out if it's not right.
+        Some(arm.body)
+    } else {
+        None
+    }
+}
+
+fn get_some_and_none_bodies<'tcx>(
+    cx: &LateContext<'tcx>,
+    arm1: &'tcx Arm<'tcx>,
+    arm2: &'tcx Arm<'tcx>,
+) -> Option<((&'tcx Expr<'tcx>, HirId), &'tcx Expr<'tcx>)> {
+    if let Some(binding_id) = get_some(cx, arm1.pat)
+        && let Some(body_none) = get_none(cx, arm2)
+    {
+        Some(((arm1.body, binding_id), body_none))
+    } else if let Some(binding_id) = get_some(cx, arm2.pat)
+        && let Some(body_none) = get_none(cx, arm1)
+    {
+        Some(((arm2.body, binding_id), body_none))
+    } else {
+        None
+    }
+}
+
+fn handle_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
+    let ExprKind::Match(match_expr, [arm1, arm2], MatchSource::Normal | MatchSource::ForLoopDesugar) = expr.kind else {
+        return false;
+    };
+    // We don't want conditions on the arms to simplify things.
+    if arm1.guard.is_none()
+        && arm2.guard.is_none()
+        // We check that the returned type implements the `Default` trait.
+        && let match_ty = cx.typeck_results().expr_ty(expr)
+        && let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default)
+        && implements_trait(cx, match_ty, default_trait_id, &[])
+        // We now get the bodies for both the `Some` and `None` arms.
+        && let Some(((body_some, binding_id), body_none)) = get_some_and_none_bodies(cx, arm1, arm2)
+        // We check that the `Some(x) => x` doesn't do anything apart "returning" the value in `Some`.
+        && let ExprKind::Path(QPath::Resolved(_, path)) = body_some.peel_blocks().kind
+        && let Res::Local(local_id) = path.res
+        && local_id == binding_id
+        // We now check the `None` arm is calling a method equivalent to `Default::default`.
+        && let body_none = body_none.peel_blocks()
+        && is_default_equivalent(cx, body_none)
+        && let Some(match_expr_snippet) = snippet_opt(cx, match_expr.span)
+    {
+        span_lint_and_sugg(
+            cx,
+            MANUAL_UNWRAP_OR_DEFAULT,
+            expr.span,
+            "match can be simplified with `.unwrap_or_default()`",
+            "replace it with",
+            format!("{match_expr_snippet}.unwrap_or_default()"),
+            Applicability::MachineApplicable,
+        );
+    }
+    true
+}
+
+fn handle_if_let<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+    if let ExprKind::If(cond, if_block, Some(else_expr)) = expr.kind
+        && let ExprKind::Let(let_) = cond.kind
+        && let ExprKind::Block(_, _) = else_expr.kind
+        // We check that the returned type implements the `Default` trait.
+        && let match_ty = cx.typeck_results().expr_ty(expr)
+        && let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default)
+        && implements_trait(cx, match_ty, default_trait_id, &[])
+        && let Some(binding_id) = get_some(cx, let_.pat)
+        // We check that the `Some(x) => x` doesn't do anything apart "returning" the value in `Some`.
+        && let ExprKind::Path(QPath::Resolved(_, path)) = if_block.peel_blocks().kind
+        && let Res::Local(local_id) = path.res
+        && local_id == binding_id
+        // We now check the `None` arm is calling a method equivalent to `Default::default`.
+        && let body_else = else_expr.peel_blocks()
+        && is_default_equivalent(cx, body_else)
+        && let Some(if_let_expr_snippet) = snippet_opt(cx, let_.init.span)
+    {
+        span_lint_and_sugg(
+            cx,
+            MANUAL_UNWRAP_OR_DEFAULT,
+            expr.span,
+            "if let can be simplified with `.unwrap_or_default()`",
+            "replace it with",
+            format!("{if_let_expr_snippet}.unwrap_or_default()"),
+            Applicability::MachineApplicable,
+        );
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOrDefault {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+        if expr.span.from_expansion() {
+            return;
+        }
+        if !handle_match(cx, expr) {
+            handle_if_let(cx, expr);
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs b/src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs
index c8a48246e67..0f242e0b9e1 100644
--- a/src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs
@@ -2,12 +2,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::{path_to_local_id, peel_blocks, strip_pat_refs};
 use rustc_errors::Applicability;
-use rustc_hir::{ByRef, ExprKind, Local, MatchSource, PatKind, QPath};
+use rustc_hir::{ByRef, ExprKind, LetStmt, MatchSource, PatKind, QPath};
 use rustc_lint::LateContext;
 
 use super::INFALLIBLE_DESTRUCTURING_MATCH;
 
-pub(crate) fn check(cx: &LateContext<'_>, local: &Local<'_>) -> bool {
+pub(crate) fn check(cx: &LateContext<'_>, local: &LetStmt<'_>) -> bool {
     if !local.span.from_expansion()
         && let Some(expr) = local.init
         && let ExprKind::Match(target, arms, MatchSource::Normal) = expr.kind
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
index c7c453b7f6e..cd61e733694 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
@@ -243,7 +243,7 @@ impl<'a> NormalizedPat<'a> {
     fn from_pat(cx: &LateContext<'_>, arena: &'a DroplessArena, pat: &'a Pat<'_>) -> Self {
         match pat.kind {
             PatKind::Wild | PatKind::Binding(.., None) => Self::Wild,
-            PatKind::Binding(.., Some(pat)) | PatKind::Box(pat) | PatKind::Ref(pat, _) => {
+            PatKind::Binding(.., Some(pat)) | PatKind::Box(pat) | PatKind::Deref(pat) | PatKind::Ref(pat, _) => {
                 Self::from_pat(cx, arena, pat)
             },
             PatKind::Never => Self::Never,
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs b/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
index 61977045fd4..864923b2773 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
@@ -148,7 +148,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
 fn opt_parent_assign_span<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<AssignmentExpr> {
     if let Node::Expr(parent_arm_expr) = cx.tcx.parent_hir_node(ex.hir_id) {
         return match cx.tcx.parent_hir_node(parent_arm_expr.hir_id) {
-            Node::Local(parent_let_expr) => Some(AssignmentExpr::Local {
+            Node::LetStmt(parent_let_expr) => Some(AssignmentExpr::Local {
                 span: parent_let_expr.span,
                 pat_span: parent_let_expr.pat.span(),
             }),
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index 50494f4819f..580d4a64296 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -27,7 +27,7 @@ mod wild_in_or_pats;
 use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::source::{snippet_opt, walk_span_to_context};
 use clippy_utils::{higher, in_constant, is_direct_expn_of, is_span_match, tokenize_with_text};
-use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat};
+use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat};
 use rustc_lexer::TokenKind;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
@@ -1124,7 +1124,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
         }
     }
 
-    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) {
         self.infallible_destructuring_match_linted |=
             local.els.is_none() && infallible_destructuring_match::check(cx, local);
     }
diff --git a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
index 3d3f29e5fc6..cee77f62b61 100644
--- a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
@@ -125,7 +125,7 @@ fn strip_return<'hir>(expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> {
 fn expr_ty_matches_p_ty(cx: &LateContext<'_>, expr: &Expr<'_>, p_expr: &Expr<'_>) -> bool {
     match cx.tcx.parent_hir_node(p_expr.hir_id) {
         // Compare match_expr ty with local in `let local = match match_expr {..}`
-        Node::Local(local) => {
+        Node::LetStmt(local) => {
             let results = cx.typeck_results();
             return same_type_and_consts(results.node_type(local.hir_id), results.expr_ty(expr));
         },
diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
index b770ad0ddb5..10c3203725a 100644
--- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
@@ -149,7 +149,7 @@ impl<'a, 'tcx> SigDropChecker<'a, 'tcx> {
                 false
             },
             rustc_middle::ty::Array(ty, _)
-            | rustc_middle::ty::RawPtr(TypeAndMut { ty, .. })
+            | rustc_middle::ty::RawPtr(ty, _)
             | rustc_middle::ty::Ref(_, ty, _)
             | rustc_middle::ty::Slice(ty) => self.has_sig_drop_attr(cx, *ty),
             _ => false,
diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
index 86c414dafcc..a0db8e2db1f 100644
--- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
@@ -55,23 +55,15 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
         };
 
         let ty = cx.typeck_results().expr_ty(ex);
-        if *ty.kind() != ty::Bool || is_lint_allowed(cx, MATCH_BOOL, ex.hir_id) {
-            check_single_pattern(cx, ex, arms, expr, els);
-            check_opt_like(cx, ex, arms, expr, ty, els);
+        if (*ty.kind() != ty::Bool || is_lint_allowed(cx, MATCH_BOOL, ex.hir_id)) &&
+            (check_single_pattern(arms) || check_opt_like(cx, arms, ty)) {
+            report_single_pattern(cx, ex, arms, expr, els);
         }
     }
 }
 
-fn check_single_pattern(
-    cx: &LateContext<'_>,
-    ex: &Expr<'_>,
-    arms: &[Arm<'_>],
-    expr: &Expr<'_>,
-    els: Option<&Expr<'_>>,
-) {
-    if is_wild(arms[1].pat) {
-        report_single_pattern(cx, ex, arms, expr, els);
-    }
+fn check_single_pattern(arms: &[Arm<'_>]) -> bool {
+    is_wild(arms[1].pat)
 }
 
 fn report_single_pattern(
@@ -140,19 +132,10 @@ fn report_single_pattern(
     span_lint_and_sugg(cx, lint, expr.span, msg, "try", sugg, app);
 }
 
-fn check_opt_like<'a>(
-    cx: &LateContext<'a>,
-    ex: &Expr<'_>,
-    arms: &[Arm<'_>],
-    expr: &Expr<'_>,
-    ty: Ty<'a>,
-    els: Option<&Expr<'_>>,
-) {
+fn check_opt_like<'a>(cx: &LateContext<'a>, arms: &[Arm<'_>], ty: Ty<'a>) -> bool {
     // We don't want to lint if the second arm contains an enum which could
     // have more variants in the future.
-    if form_exhaustive_matches(cx, ty, arms[0].pat, arms[1].pat) {
-        report_single_pattern(cx, ex, arms, expr, els);
-    }
+    form_exhaustive_matches(cx, ty, arms[0].pat, arms[1].pat)
 }
 
 /// Returns `true` if all of the types in the pattern are enums which we know
diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
index fb5c0c544a9..d4a5de3d1de 100644
--- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
@@ -69,7 +69,7 @@ pub(super) fn check(
                 _ => false,
             },
             // local binding capturing a reference
-            Node::Local(l) if matches!(l.pat.kind, PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..)) => {
+            Node::LetStmt(l) if matches!(l.pat.kind, PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..)) => {
                 return;
             },
             _ => false,
diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
index e2c2997594a..4d8fb217f7f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
@@ -91,7 +91,7 @@ pub(super) fn check<'tcx>(
             },
             hir::ExprKind::Path(ref p) => matches!(
                 cx.qpath_res(p, arg.hir_id),
-                hir::def::Res::Def(hir::def::DefKind::Const | hir::def::DefKind::Static{..}, _)
+                hir::def::Res::Def(hir::def::DefKind::Const | hir::def::DefKind::Static { .. }, _)
             ),
             _ => false,
         }
diff --git a/src/tools/clippy/clippy_lints/src/methods/is_empty.rs b/src/tools/clippy/clippy_lints/src/methods/is_empty.rs
new file mode 100644
index 00000000000..7fe66062251
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/is_empty.rs
@@ -0,0 +1,49 @@
+use clippy_utils::consts::constant_is_empty;
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::{find_binding_init, path_to_local};
+use rustc_hir::{Expr, HirId};
+use rustc_lint::{LateContext, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_span::sym;
+
+use super::CONST_IS_EMPTY;
+
+/// Expression whose initialization depend on a constant conditioned by a `#[cfg(…)]` directive will
+/// not trigger the lint.
+pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, receiver: &Expr<'_>) {
+    if in_external_macro(cx.sess(), expr.span) || !receiver.span.eq_ctxt(expr.span) {
+        return;
+    }
+    let init_expr = expr_or_init(cx, receiver);
+    if !receiver.span.eq_ctxt(init_expr.span) {
+        return;
+    }
+    if let Some(init_is_empty) = constant_is_empty(cx, init_expr) {
+        span_lint(
+            cx,
+            CONST_IS_EMPTY,
+            expr.span,
+            &format!("this expression always evaluates to {init_is_empty:?}"),
+        );
+    }
+}
+
+fn is_under_cfg(cx: &LateContext<'_>, id: HirId) -> bool {
+    cx.tcx
+        .hir()
+        .parent_id_iter(id)
+        .any(|id| cx.tcx.hir().attrs(id).iter().any(|attr| attr.has_name(sym::cfg)))
+}
+
+/// Similar to [`clippy_utils::expr_or_init`], but does not go up the chain if the initialization
+/// value depends on a `#[cfg(…)]` directive.
+fn expr_or_init<'a, 'b, 'tcx: 'b>(cx: &LateContext<'tcx>, mut expr: &'a Expr<'b>) -> &'a Expr<'b> {
+    while let Some(init) = path_to_local(expr)
+        .and_then(|id| find_binding_init(cx, id))
+        .filter(|init| cx.typeck_results().expr_adjustments(init).is_empty())
+        .filter(|init| !is_under_cfg(cx, init.hir_id))
+    {
+        expr = init;
+    }
+    expr
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs b/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs
index 12104310405..5b0b70b4b96 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs
@@ -1,10 +1,10 @@
-use super::utils::derefs_to_slice;
-use crate::methods::iter_nth_zero;
-use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::ty::get_type_diagnostic_name;
+use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 use rustc_span::symbol::sym;
+use rustc_span::Span;
 
 use super::ITER_NTH;
 
@@ -12,28 +12,33 @@ pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &hir::Expr<'_>,
     iter_recv: &'tcx hir::Expr<'tcx>,
-    nth_recv: &hir::Expr<'_>,
-    nth_arg: &hir::Expr<'_>,
-    is_mut: bool,
-) {
-    let mut_str = if is_mut { "_mut" } else { "" };
-    let caller_type = if derefs_to_slice(cx, iter_recv, cx.typeck_results().expr_ty(iter_recv)).is_some() {
-        "slice"
-    } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(iter_recv), sym::Vec) {
-        "`Vec`"
-    } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(iter_recv), sym::VecDeque) {
-        "`VecDeque`"
-    } else {
-        iter_nth_zero::check(cx, expr, nth_recv, nth_arg);
-        return; // caller is not a type that we want to lint
+    iter_method: &str,
+    iter_span: Span,
+    nth_span: Span,
+) -> bool {
+    let caller_type = match get_type_diagnostic_name(cx, cx.typeck_results().expr_ty(iter_recv).peel_refs()) {
+        Some(sym::Vec) => "`Vec`",
+        Some(sym::VecDeque) => "`VecDeque`",
+        _ if cx.typeck_results().expr_ty_adjusted(iter_recv).peel_refs().is_slice() => "slice",
+        // caller is not a type that we want to lint
+        _ => return false,
     };
 
-    span_lint_and_help(
+    span_lint_and_then(
         cx,
         ITER_NTH,
         expr.span,
-        &format!("called `.iter{mut_str}().nth()` on a {caller_type}"),
-        None,
-        &format!("calling `.get{mut_str}()` is both faster and more readable"),
+        &format!("called `.{iter_method}().nth()` on a {caller_type}"),
+        |diag| {
+            let get_method = if iter_method == "iter_mut" { "get_mut" } else { "get" };
+            diag.span_suggestion_verbose(
+                iter_span.to(nth_span),
+                format!("`{get_method}` is equivalent but more concise"),
+                get_method,
+                Applicability::MachineApplicable,
+            );
+        },
     );
+
+    true
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs
index 4c7c56e7174..19b7e97339d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs
@@ -50,7 +50,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: &str, re
             | ExprKind::Break(_, _) => true,
             _ => false,
         },
-        Some((Node::Stmt(_) | Node::Local(_), _)) => false,
+        Some((Node::Stmt(_) | Node::LetStmt(_), _)) => false,
         _ => true,
     };
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
index 27e17b43b01..c3c7a3a0033 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
@@ -86,8 +86,11 @@ pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_
                                     }
                                 }
                             },
-                            hir::ExprKind::Call(call, [_]) => {
-                                if let hir::ExprKind::Path(qpath) = call.kind {
+                            hir::ExprKind::Call(call, args) => {
+                                if let hir::ExprKind::Path(qpath) = call.kind
+                                    && let [arg] = args
+                                    && ident_eq(name, arg)
+                                {
                                     handle_path(cx, call, &qpath, e, recv);
                                 }
                             },
@@ -118,7 +121,9 @@ fn handle_path(
         if let ty::Adt(_, args) = cx.typeck_results().expr_ty(recv).kind()
             && let args = args.as_slice()
             && let Some(ty) = args.iter().find_map(|generic_arg| generic_arg.as_type())
-            && ty.is_ref()
+            && let ty::Ref(_, ty, Mutability::Not) = ty.kind()
+            && let ty::FnDef(_, lst) = cx.typeck_results().expr_ty(arg).kind()
+            && lst.iter().all(|l| l.as_type() == Some(*ty))
         {
             lint_path(cx, e.span, recv.span, is_copy(cx, ty.peel_refs()));
         }
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 8a24ccea3a1..b6c474212cd 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -36,6 +36,7 @@ mod inefficient_to_string;
 mod inspect_for_each;
 mod into_iter_on_ref;
 mod is_digit_ascii_radix;
+mod is_empty;
 mod iter_cloned_collect;
 mod iter_count;
 mod iter_filter;
@@ -118,6 +119,7 @@ mod unnecessary_literal_unwrap;
 mod unnecessary_result_map_or_else;
 mod unnecessary_sort_by;
 mod unnecessary_to_owned;
+mod unused_enumerate_index;
 mod unwrap_expect_used;
 mod useless_asref;
 mod utils;
@@ -1235,12 +1237,11 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for usage of `.iter().nth()` (and the related
-    /// `.iter_mut().nth()`) on standard library types with *O*(1) element access.
+    /// Checks for usage of `.iter().nth()`/`.iter_mut().nth()` on standard library types that have
+    /// equivalent `.get()`/`.get_mut()` methods.
     ///
     /// ### Why is this bad?
-    /// `.get()` and `.get_mut()` are more efficient and more
-    /// readable.
+    /// `.get()` and `.get_mut()` are equivalent but more concise.
     ///
     /// ### Example
     /// ```no_run
@@ -1256,7 +1257,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "pre 1.29.0"]
     pub ITER_NTH,
-    perf,
+    style,
     "using `.iter().nth()` on a standard library type with O(1) element access"
 }
 
@@ -2848,7 +2849,7 @@ declare_clippy_lint! {
     /// the file is created from scratch, or ensure `truncate` is
     /// called so that the truncation behaviour is explicit. `truncate(true)`
     /// will ensure the file is entirely overwritten with new data, whereas
-    /// `truncate(false)` will explicitely keep the default behavior.
+    /// `truncate(false)` will explicitly keep the default behavior.
     ///
     /// ### Example
     /// ```rust,no_run
@@ -2862,7 +2863,7 @@ declare_clippy_lint! {
     ///
     /// OpenOptions::new().create(true).truncate(true);
     /// ```
-    #[clippy::version = "1.75.0"]
+    #[clippy::version = "1.77.0"]
     pub SUSPICIOUS_OPEN_OPTIONS,
     suspicious,
     "suspicious combination of options for opening a file"
@@ -3182,8 +3183,8 @@ declare_clippy_lint! {
 declare_clippy_lint! {
     /// ### What it does
     ///
-    /// Checks an argument of `seek` method of `Seek` trait
-    /// and if it start seek from `SeekFrom::Current(0)`, suggests `stream_position` instead.
+    /// Checks if the `seek` method of the `Seek` trait is called with `SeekFrom::Current(0)`,
+    /// and if it is, suggests using `stream_position` instead.
     ///
     /// ### Why is this bad?
     ///
@@ -3590,7 +3591,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.73.0"]
     pub READONLY_WRITE_LOCK,
-    nursery,
+    perf,
     "acquiring a write lock when a read lock would work"
 }
 
@@ -3816,7 +3817,7 @@ declare_clippy_lint! {
     /// ```no_run
     /// let _ = std::iter::empty::<Result<i32, ()>>().flatten();
     /// ```
-    #[clippy::version = "1.76.0"]
+    #[clippy::version = "1.77.0"]
     pub RESULT_FILTER_MAP,
     complexity,
     "filtering `Result` for `Ok` then force-unwrapping, which can be one type-safe operation"
@@ -3825,7 +3826,7 @@ declare_clippy_lint! {
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for usage of `.filter(Option::is_some)` that may be replaced with a `.flatten()` call.
-    /// This lint will require additional changes to the follow-up calls as it appects the type.
+    /// This lint will require additional changes to the follow-up calls as it affects the type.
     ///
     /// ### Why is this bad?
     /// This pattern is often followed by manual unwrapping of the `Option`. The simplification
@@ -3842,7 +3843,7 @@ declare_clippy_lint! {
     /// // example code which does not raise clippy warning
     /// vec![Some(1)].into_iter().flatten();
     /// ```
-    #[clippy::version = "1.76.0"]
+    #[clippy::version = "1.77.0"]
     pub ITER_FILTER_IS_SOME,
     pedantic,
     "filtering an iterator over `Option`s for `Some` can be achieved with `flatten`"
@@ -3851,7 +3852,7 @@ declare_clippy_lint! {
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for usage of `.filter(Result::is_ok)` that may be replaced with a `.flatten()` call.
-    /// This lint will require additional changes to the follow-up calls as it appects the type.
+    /// This lint will require additional changes to the follow-up calls as it affects the type.
     ///
     /// ### Why is this bad?
     /// This pattern is often followed by manual unwrapping of `Result`. The simplification
@@ -3868,7 +3869,7 @@ declare_clippy_lint! {
     /// // example code which does not raise clippy warning
     /// vec![Ok::<i32, String>(1)].into_iter().flatten();
     /// ```
-    #[clippy::version = "1.76.0"]
+    #[clippy::version = "1.77.0"]
     pub ITER_FILTER_IS_OK,
     pedantic,
     "filtering an iterator over `Result`s for `Ok` can be achieved with `flatten`"
@@ -3895,7 +3896,7 @@ declare_clippy_lint! {
     /// option.is_some_and(|a| a > 10);
     /// result.is_ok_and(|a| a > 10);
     /// ```
-    #[clippy::version = "1.76.0"]
+    #[clippy::version = "1.77.0"]
     pub MANUAL_IS_VARIANT_AND,
     pedantic,
     "using `.map(f).unwrap_or_default()`, which is more succinctly expressed as `is_some_and(f)` or `is_ok_and(f)`"
@@ -3925,7 +3926,7 @@ declare_clippy_lint! {
     /// `"\r\n"`), for example during the parsing of a specific file format in which precisely one newline type is
     /// valid.
     /// ```
-    #[clippy::version = "1.76.0"]
+    #[clippy::version = "1.77.0"]
     pub STR_SPLIT_AT_NEWLINE,
     pedantic,
     "splitting a trimmed string at hard-coded newlines"
@@ -4044,6 +4045,31 @@ declare_clippy_lint! {
     "calling `.get().is_some()` or `.get().is_none()` instead of `.contains()` or `.contains_key()`"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// It identifies calls to `.is_empty()` on constant values.
+    ///
+    /// ### Why is this bad?
+    /// String literals and constant values are known at compile time. Checking if they
+    /// are empty will always return the same value. This might not be the intention of
+    /// the expression.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// let value = "";
+    /// if value.is_empty() {
+    ///     println!("the string is empty");
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// println!("the string is empty");
+    /// ```
+    #[clippy::version = "1.78.0"]
+    pub CONST_IS_EMPTY,
+    suspicious,
+    "is_empty() called on strings known at compile time"
+}
 pub struct Methods {
     avoid_breaking_exported_api: bool,
     msrv: Msrv,
@@ -4092,6 +4118,7 @@ impl_lint_pass!(Methods => [
     CLONE_ON_COPY,
     CLONE_ON_REF_PTR,
     COLLAPSIBLE_STR_REPLACE,
+    CONST_IS_EMPTY,
     ITER_OVEREAGER_CLONED,
     CLONED_INSTEAD_OF_COPIED,
     FLAT_MAP_OPTION,
@@ -4403,6 +4430,7 @@ impl Methods {
                     zst_offset::check(cx, expr, recv);
                 },
                 ("all", [arg]) => {
+                    unused_enumerate_index::check(cx, expr, recv, arg);
                     if let Some(("cloned", recv2, [], _, _)) = method_call(recv) {
                         iter_overeager_cloned::check(
                             cx,
@@ -4421,23 +4449,26 @@ impl Methods {
                         unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
                     }
                 },
-                ("any", [arg]) => match method_call(recv) {
-                    Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(
-                        cx,
-                        expr,
-                        recv,
-                        recv2,
-                        iter_overeager_cloned::Op::NeedlessMove(arg),
-                        false,
-                    ),
-                    Some(("chars", recv, _, _, _))
-                        if let ExprKind::Closure(arg) = arg.kind
-                            && let body = cx.tcx.hir().body(arg.body)
-                            && let [param] = body.params =>
-                    {
-                        string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv);
-                    },
-                    _ => {},
+                ("any", [arg]) => {
+                    unused_enumerate_index::check(cx, expr, recv, arg);
+                    match method_call(recv) {
+                        Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(
+                            cx,
+                            expr,
+                            recv,
+                            recv2,
+                            iter_overeager_cloned::Op::NeedlessMove(arg),
+                            false,
+                        ),
+                        Some(("chars", recv, _, _, _))
+                            if let ExprKind::Closure(arg) = arg.kind
+                                && let body = cx.tcx.hir().body(arg.body)
+                                && let [param] = body.params =>
+                        {
+                            string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv);
+                        },
+                        _ => {},
+                    }
                 },
                 ("arg", [arg]) => {
                     suspicious_command_arg_space::check(cx, recv, arg, span);
@@ -4445,7 +4476,7 @@ impl Methods {
                 ("as_deref" | "as_deref_mut", []) => {
                     needless_option_as_deref::check(cx, expr, recv, name);
                 },
-                ("as_bytes" | "is_empty", []) => {
+                ("as_bytes", []) => {
                     if let Some(("as_str", recv, [], as_str_span, _)) = method_call(recv) {
                         redundant_as_str::check(cx, expr, recv, as_str_span, span);
                     }
@@ -4570,14 +4601,17 @@ impl Methods {
                     }
                 },
                 ("filter_map", [arg]) => {
+                    unused_enumerate_index::check(cx, expr, recv, arg);
                     unnecessary_filter_map::check(cx, expr, arg, name);
                     filter_map_bool_then::check(cx, expr, arg, call_span);
                     filter_map_identity::check(cx, expr, arg, span);
                 },
                 ("find_map", [arg]) => {
+                    unused_enumerate_index::check(cx, expr, recv, arg);
                     unnecessary_filter_map::check(cx, expr, arg, name);
                 },
                 ("flat_map", [arg]) => {
+                    unused_enumerate_index::check(cx, expr, recv, arg);
                     flat_map_identity::check(cx, expr, arg, span);
                     flat_map_option::check(cx, expr, arg, span);
                 },
@@ -4599,17 +4633,20 @@ impl Methods {
                     manual_try_fold::check(cx, expr, init, acc, call_span, &self.msrv);
                     unnecessary_fold::check(cx, expr, init, acc, span);
                 },
-                ("for_each", [arg]) => match method_call(recv) {
-                    Some(("inspect", _, [_], span2, _)) => inspect_for_each::check(cx, expr, span2),
-                    Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(
-                        cx,
-                        expr,
-                        recv,
-                        recv2,
-                        iter_overeager_cloned::Op::NeedlessMove(arg),
-                        false,
-                    ),
-                    _ => {},
+                ("for_each", [arg]) => {
+                    unused_enumerate_index::check(cx, expr, recv, arg);
+                    match method_call(recv) {
+                        Some(("inspect", _, [_], span2, _)) => inspect_for_each::check(cx, expr, span2),
+                        Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(
+                            cx,
+                            expr,
+                            recv,
+                            recv2,
+                            iter_overeager_cloned::Op::NeedlessMove(arg),
+                            false,
+                        ),
+                        _ => {},
+                    }
                 },
                 ("get", [arg]) => {
                     get_first::check(cx, expr, recv, arg);
@@ -4619,6 +4656,12 @@ impl Methods {
                 ("hash", [arg]) => {
                     unit_hash::check(cx, expr, recv, arg);
                 },
+                ("is_empty", []) => {
+                    if let Some(("as_str", recv, [], as_str_span, _)) = method_call(recv) {
+                        redundant_as_str::check(cx, expr, recv, as_str_span, span);
+                    }
+                    is_empty::check(cx, expr, recv);
+                },
                 ("is_file", []) => filetype_is_file::check(cx, expr, recv),
                 ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, &self.msrv),
                 ("is_none", []) => check_is_some_is_none(cx, expr, recv, call_span, false),
@@ -4650,6 +4693,7 @@ impl Methods {
                 },
                 (name @ ("map" | "map_err"), [m_arg]) => {
                     if name == "map" {
+                        unused_enumerate_index::check(cx, expr, recv, m_arg);
                         map_clone::check(cx, expr, recv, m_arg, &self.msrv);
                         match method_call(recv) {
                             Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) => {
@@ -4723,8 +4767,11 @@ impl Methods {
                         iter_overeager_cloned::Op::LaterCloned,
                         false,
                     ),
-                    Some(("iter", recv2, [], _, _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
-                    Some(("iter_mut", recv2, [], _, _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
+                    Some((iter_method @ ("iter" | "iter_mut"), iter_recv, [], iter_span, _)) => {
+                        if !iter_nth::check(cx, expr, iter_recv, iter_method, iter_span, span) {
+                            iter_nth_zero::check(cx, expr, recv, n_arg);
+                        }
+                    },
                     _ => iter_nth_zero::check(cx, expr, recv, n_arg),
                 },
                 ("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
index 78540353005..9e2fd92255e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -11,7 +11,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{Applicability, MultiSpan};
 use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
 use rustc_hir::{
-    BindingAnnotation, Block, Expr, ExprKind, HirId, HirIdSet, Local, Mutability, Node, PatKind, Stmt, StmtKind,
+    BindingAnnotation, Block, Expr, ExprKind, HirId, HirIdSet, LetStmt, Mutability, Node, PatKind, Stmt, StmtKind,
 };
 use rustc_lint::LateContext;
 use rustc_middle::hir::nested_filter;
@@ -85,7 +85,7 @@ pub(super) fn check<'tcx>(
                 );
             }
         },
-        Node::Local(l) => {
+        Node::LetStmt(l) => {
             if let PatKind::Binding(BindingAnnotation::NONE | BindingAnnotation::MUT, id, _, None) = l.pat.kind
                 && let ty = cx.typeck_results().expr_ty(collect_expr)
                 && [sym::Vec, sym::VecDeque, sym::BinaryHeap, sym::LinkedList]
@@ -424,7 +424,7 @@ fn get_expr_and_hir_id_from_stmt<'v>(stmt: &'v Stmt<'v>) -> Option<(&'v Expr<'v>
     match stmt.kind {
         StmtKind::Expr(expr) | StmtKind::Semi(expr) => Some((expr, None)),
         StmtKind::Item(..) => None,
-        StmtKind::Let(Local { init, pat, .. }) => {
+        StmtKind::Let(LetStmt { init, pat, .. }) => {
             if let PatKind::Binding(_, hir_id, ..) = pat.kind {
                 init.map(|init_expr| (init_expr, Some(hir_id)))
             } else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/no_effect_replace.rs b/src/tools/clippy/clippy_lints/src/methods/no_effect_replace.rs
index 81df32bdee2..a301a5f7d65 100644
--- a/src/tools/clippy/clippy_lints/src/methods/no_effect_replace.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/no_effect_replace.rs
@@ -25,6 +25,7 @@ pub(super) fn check<'tcx>(
         && param1 == param2.as_str()
     {
         span_lint(cx, NO_EFFECT_REPLACE, expr.span, "replacing text with itself");
+        return;
     }
 
     if SpanlessEq::new(cx).eq_expr(arg1, arg2) {
diff --git a/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs b/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs
index 6c6846c4b47..9b0180d9369 100644
--- a/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs
@@ -24,7 +24,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, receiver
         && let Node::Expr(unwrap_call_expr) = cx.tcx.parent_hir_node(expr.hir_id)
         && is_unwrap_call(cx, unwrap_call_expr)
         && let parent = cx.tcx.parent_hir_node(unwrap_call_expr.hir_id)
-        && let Node::Local(local) = parent
+        && let Node::LetStmt(local) = parent
         && let Some(mir) = enclosing_mir(cx.tcx, expr.hir_id)
         && let Some((local, _)) = mir
             .local_decls
diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
index 55cd1a38ec9..946cdb49d27 100644
--- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
@@ -8,7 +8,7 @@ use clippy_utils::{is_diag_item_method, match_def_path, path_to_local_id, paths}
 use core::ops::ControlFlow;
 use rustc_errors::Applicability;
 use rustc_hir::{
-    BindingAnnotation, Expr, ExprKind, HirId, LangItem, Local, MatchSource, Node, Pat, PatKind, QPath, Stmt, StmtKind,
+    BindingAnnotation, Expr, ExprKind, HirId, LangItem, LetStmt, MatchSource, Node, Pat, PatKind, QPath, Stmt, StmtKind,
 };
 use rustc_lint::LateContext;
 use rustc_middle::ty;
@@ -128,7 +128,7 @@ fn check_manual_split_once_indirect(
 ) -> Option<()> {
     let ctxt = expr.span.ctxt();
     let mut parents = cx.tcx.hir().parent_iter(expr.hir_id);
-    if let (_, Node::Local(local)) = parents.next()?
+    if let (_, Node::LetStmt(local)) = parents.next()?
         && let PatKind::Binding(BindingAnnotation::MUT, iter_binding_id, iter_ident, None) = local.pat.kind
         && let (iter_stmt_id, Node::Stmt(_)) = parents.next()?
         && let (_, Node::Block(enclosing_block)) = parents.next()?
@@ -198,7 +198,7 @@ fn indirect_usage<'tcx>(
     binding: HirId,
     ctxt: SyntaxContext,
 ) -> Option<IndirectUsage<'tcx>> {
-    if let StmtKind::Let(&Local {
+    if let StmtKind::Let(&LetStmt {
         pat: Pat {
             kind: PatKind::Binding(BindingAnnotation::NONE, _, ident, None),
             ..
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
index 988f3e86fcf..ccc8d17970e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
@@ -20,7 +20,7 @@ fn needs_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
 
     // some common cases where turbofish isn't needed:
     // - assigned to a local variable with a type annotation
-    if let hir::Node::Local(local) = parent
+    if let hir::Node::LetStmt(local) = parent
         && local.ty.is_some()
     {
         return false;
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 c234e4f9b11..bc5dd10cad0 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
@@ -18,7 +18,7 @@ use rustc_lint::LateContext;
 use rustc_middle::mir::Mutability;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
 use rustc_middle::ty::{
-    self, ClauseKind, GenericArg, GenericArgKind, GenericArgsRef, ImplPolarity, ParamTy, ProjectionPredicate,
+    self, ClauseKind, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate,
     TraitPredicate, Ty,
 };
 use rustc_span::{sym, Symbol};
@@ -336,12 +336,9 @@ fn check_other_call_arg<'tcx>(
         && let Some((n_refs, receiver_ty)) = if n_refs > 0 || is_copy(cx, receiver_ty) {
             Some((n_refs, receiver_ty))
         } else if trait_predicate.def_id() != deref_trait_id {
-            Some((1, Ty::new_ref(cx.tcx,
+            Some((1, Ty::new_imm_ref(cx.tcx,
                 cx.tcx.lifetimes.re_erased,
-                ty::TypeAndMut {
-                    ty: receiver_ty,
-                    mutbl: Mutability::Not,
-                },
+                receiver_ty,
             )))
         } else {
             None
@@ -669,7 +666,7 @@ fn check_borrow_predicate<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
         && let Some(borrow_id) = cx.tcx.get_diagnostic_item(sym::Borrow)
         && cx.tcx.predicates_of(method_def_id).predicates.iter().any(|(pred, _)| {
             if let ClauseKind::Trait(trait_pred) = pred.kind().skip_binder()
-                && trait_pred.polarity == ImplPolarity::Positive
+                && trait_pred.polarity == ty::PredicatePolarity::Positive
                 && trait_pred.trait_ref.def_id == borrow_id
             {
                 true
diff --git a/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs b/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs
new file mode 100644
index 00000000000..e5cc898612e
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/unused_enumerate_index.rs
@@ -0,0 +1,135 @@
+use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_hir_and_then};
+use clippy_utils::paths::{CORE_ITER_ENUMERATE_METHOD, CORE_ITER_ENUMERATE_STRUCT};
+use clippy_utils::source::{snippet, snippet_opt};
+use clippy_utils::{expr_or_init, is_trait_method, match_def_path, pat_is_wild};
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, FnDecl, PatKind, TyKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty::AdtDef;
+use rustc_span::{sym, Span};
+
+use crate::loops::UNUSED_ENUMERATE_INDEX;
+
+/// Check for the `UNUSED_ENUMERATE_INDEX` lint outside of loops.
+///
+/// The lint is declared in `clippy_lints/src/loops/mod.rs`. There, the following pattern is
+/// checked:
+/// ```ignore
+/// for (_, x) in some_iter.enumerate() {
+///     // Index is ignored
+/// }
+/// ```
+///
+/// This `check` function checks for chained method calls constructs where we can detect that the
+/// index is unused. Currently, this checks only for the following patterns:
+/// ```ignore
+/// some_iter.enumerate().map_function(|(_, x)| ..)
+/// let x = some_iter.enumerate();
+/// x.map_function(|(_, x)| ..)
+/// ```
+/// where `map_function` is one of `all`, `any`, `filter_map`, `find_map`, `flat_map`, `for_each` or
+/// `map`.
+///
+/// # Preconditions
+/// This function must be called not on the `enumerate` call expression itself, but on any of the
+/// map functions listed above. It will ensure that `recv` is a `std::iter::Enumerate` instance and
+/// that the method call is one of the `std::iter::Iterator` trait.
+///
+/// * `call_expr`: The map function call expression
+/// * `recv`: The receiver of the call
+/// * `closure_arg`: The argument to the map function call containing the closure/function to apply
+pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, closure_arg: &Expr<'_>) {
+    let recv_ty = cx.typeck_results().expr_ty(recv);
+    if let Some(recv_ty_defid) = recv_ty.ty_adt_def().map(AdtDef::did)
+        // If we call a method on a `std::iter::Enumerate` instance
+        && match_def_path(cx, recv_ty_defid, &CORE_ITER_ENUMERATE_STRUCT)
+        // If we are calling a method of the `Iterator` trait
+        && is_trait_method(cx, call_expr, sym::Iterator)
+        // And the map argument is a closure
+        && let ExprKind::Closure(closure) = closure_arg.kind
+        && let closure_body = cx.tcx.hir().body(closure.body)
+        // And that closure has one argument ...
+        && let [closure_param] = closure_body.params
+        // .. which is a tuple of 2 elements
+        && let PatKind::Tuple([index, elem], ..) = closure_param.pat.kind
+        // And that the first element (the index) is either `_` or unused in the body
+        && pat_is_wild(cx, &index.kind, closure_body)
+        // Try to find the initializer for `recv`. This is needed in case `recv` is a local_binding. In the
+        // first example below, `expr_or_init` would return `recv`.
+        // ```
+        // iter.enumerate().map(|(_, x)| x)
+        // ^^^^^^^^^^^^^^^^ `recv`, a call to `std::iter::Iterator::enumerate`
+        //
+        // let binding = iter.enumerate();
+        //               ^^^^^^^^^^^^^^^^ `recv_init_expr`
+        // binding.map(|(_, x)| x)
+        // ^^^^^^^ `recv`, not a call to `std::iter::Iterator::enumerate`
+        // ```
+        && let recv_init_expr = expr_or_init(cx, recv)
+        // Make sure the initializer is a method call. It may be that the `Enumerate` comes from something
+        // that we cannot control.
+        // This would for instance happen with:
+        // ```
+        // external_lib::some_function_returning_enumerate().map(|(_, x)| x)
+        // ```
+        && let ExprKind::MethodCall(_, enumerate_recv, _, enumerate_span) = recv_init_expr.kind
+        && let Some(enumerate_defid) = cx.typeck_results().type_dependent_def_id(recv_init_expr.hir_id)
+        // Make sure the method call is `std::iter::Iterator::enumerate`.
+        && match_def_path(cx, enumerate_defid, &CORE_ITER_ENUMERATE_METHOD)
+    {
+        // Check if the tuple type was explicit. It may be the type system _needs_ the type of the element
+        // that would be explicited in the closure.
+        let new_closure_param = match find_elem_explicit_type_span(closure.fn_decl) {
+            // We have an explicit type. Get its snippet, that of the binding name, and do `binding: ty`.
+            // Fallback to `..` if we fail getting either snippet.
+            Some(ty_span) => snippet_opt(cx, elem.span)
+                .and_then(|binding_name| snippet_opt(cx, ty_span).map(|ty_name| format!("{binding_name}: {ty_name}")))
+                .unwrap_or_else(|| "..".to_string()),
+            // Otherwise, we have no explicit type. We can replace with the binding name of the element.
+            None => snippet(cx, elem.span, "..").into_owned(),
+        };
+
+        // Suggest removing the tuple from the closure and the preceding call to `enumerate`, whose span we
+        // can get from the `MethodCall`.
+        span_lint_hir_and_then(
+            cx,
+            UNUSED_ENUMERATE_INDEX,
+            recv_init_expr.hir_id,
+            enumerate_span,
+            "you seem to use `.enumerate()` and immediately discard the index",
+            |diag| {
+                multispan_sugg_with_applicability(
+                    diag,
+                    "remove the `.enumerate()` call",
+                    Applicability::MachineApplicable,
+                    vec![
+                        (closure_param.span, new_closure_param),
+                        (
+                            enumerate_span.with_lo(enumerate_recv.span.source_callsite().hi()),
+                            String::new(),
+                        ),
+                    ],
+                );
+            },
+        );
+    }
+}
+
+/// Find the span of the explicit type of the element.
+///
+/// # Returns
+/// If the tuple argument:
+/// * Has no explicit type, returns `None`
+/// * Has an explicit tuple type with an implicit element type (`(usize, _)`), returns `None`
+/// * Has an explicit tuple type with an explicit element type (`(_, i32)`), returns the span for
+///   the element type.
+fn find_elem_explicit_type_span(fn_decl: &FnDecl<'_>) -> Option<Span> {
+    if let [tuple_ty] = fn_decl.inputs
+        && let TyKind::Tup([_idx_ty, elem_ty]) = tuple_ty.kind
+        && !matches!(elem_ty.kind, TyKind::Err(..) | TyKind::Infer)
+    {
+        Some(elem_ty.span)
+    } else {
+        None
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/zst_offset.rs b/src/tools/clippy/clippy_lints/src/methods/zst_offset.rs
index 0b829d99aef..d33021c2a7b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/zst_offset.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/zst_offset.rs
@@ -6,7 +6,7 @@ use rustc_middle::ty;
 use super::ZST_OFFSET;
 
 pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
-    if let ty::RawPtr(ty::TypeAndMut { ty, .. }) = cx.typeck_results().expr_ty(recv).kind()
+    if let ty::RawPtr(ty, _) = cx.typeck_results().expr_ty(recv).kind()
         && let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(*ty))
         && layout.is_zst()
     {
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index bf4af7946f4..6878fb3349d 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -8,6 +8,7 @@
 use clippy_utils::attrs::is_doc_hidden;
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::is_from_proc_macro;
+use clippy_utils::source::snippet_opt;
 use rustc_ast::ast::{self, MetaItem, MetaItemKind};
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
@@ -32,6 +33,13 @@ declare_clippy_lint! {
     "detects missing documentation for private members"
 }
 
+macro_rules! note_prev_span_then_ret {
+    ($prev_span:expr, $span:expr) => {{
+        $prev_span = Some($span);
+        return;
+    }};
+}
+
 pub struct MissingDoc {
     /// Whether to **only** check for missing documentation in items visible within the current
     /// crate. For example, `pub(crate)` items.
@@ -39,6 +47,8 @@ pub struct MissingDoc {
     /// Stack of whether #[doc(hidden)] is set
     /// at each level which has lint attributes.
     doc_hidden_stack: Vec<bool>,
+    /// Used to keep tracking of the previous item, field or variants etc, to get the search span.
+    prev_span: Option<Span>,
 }
 
 impl Default for MissingDoc {
@@ -54,6 +64,7 @@ impl MissingDoc {
         Self {
             crate_items_only,
             doc_hidden_stack: vec![false],
+            prev_span: None,
         }
     }
 
@@ -108,7 +119,8 @@ impl MissingDoc {
 
         let has_doc = attrs
             .iter()
-            .any(|a| a.doc_str().is_some() || Self::has_include(a.meta()));
+            .any(|a| a.doc_str().is_some() || Self::has_include(a.meta()))
+            || matches!(self.search_span(sp), Some(span) if span_to_snippet_contains_docs(cx, span));
 
         if !has_doc {
             span_lint(
@@ -119,6 +131,32 @@ impl MissingDoc {
             );
         }
     }
+
+    /// Return a span to search for doc comments manually.
+    ///
+    /// # Example
+    /// ```ignore
+    /// fn foo() { ... }
+    /// ^^^^^^^^^^^^^^^^ prev_span
+    ///                ↑
+    /// |  search_span |
+    /// ↓
+    /// fn bar() { ... }
+    /// ^^^^^^^^^^^^^^^^ cur_span
+    /// ```
+    fn search_span(&self, cur_span: Span) -> Option<Span> {
+        let prev_span = self.prev_span?;
+        let start_pos = if prev_span.contains(cur_span) {
+            // In case when the prev_span is an entire struct, or enum,
+            // and the current span is a field, or variant, we need to search from
+            // the starting pos of the previous span.
+            prev_span.lo()
+        } else {
+            prev_span.hi()
+        };
+        let search_span = cur_span.with_lo(start_pos).with_hi(cur_span.lo());
+        Some(search_span)
+    }
 }
 
 impl_lint_pass!(MissingDoc => [MISSING_DOCS_IN_PRIVATE_ITEMS]);
@@ -138,6 +176,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
         self.check_missing_docs_attrs(cx, CRATE_DEF_ID, attrs, cx.tcx.def_span(CRATE_DEF_ID), "the", "crate");
     }
 
+    fn check_crate_post(&mut self, _: &LateContext<'tcx>) {
+        self.prev_span = None;
+    }
+
     fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
         match it.kind {
             hir::ItemKind::Fn(..) => {
@@ -145,7 +187,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
                 if it.ident.name == sym::main {
                     let at_root = cx.tcx.local_parent(it.owner_id.def_id) == CRATE_DEF_ID;
                     if at_root {
-                        return;
+                        note_prev_span_then_ret!(self.prev_span, it.span);
                     }
                 }
             },
@@ -164,7 +206,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
             | hir::ItemKind::ForeignMod { .. }
             | hir::ItemKind::GlobalAsm(..)
             | hir::ItemKind::Impl { .. }
-            | hir::ItemKind::Use(..) => return,
+            | hir::ItemKind::Use(..) => note_prev_span_then_ret!(self.prev_span, it.span),
         };
 
         let (article, desc) = cx.tcx.article_and_description(it.owner_id.to_def_id());
@@ -173,6 +215,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
         if !is_from_proc_macro(cx, it) {
             self.check_missing_docs_attrs(cx, it.owner_id.def_id, attrs, it.span, article, desc);
         }
+        self.prev_span = Some(it.span);
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx hir::TraitItem<'_>) {
@@ -182,16 +225,17 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
         if !is_from_proc_macro(cx, trait_item) {
             self.check_missing_docs_attrs(cx, trait_item.owner_id.def_id, attrs, trait_item.span, article, desc);
         }
+        self.prev_span = Some(trait_item.span);
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
         // If the method is an impl for a trait, don't doc.
         if let Some(cid) = cx.tcx.associated_item(impl_item.owner_id).impl_container(cx.tcx) {
             if cx.tcx.impl_trait_ref(cid).is_some() {
-                return;
+                note_prev_span_then_ret!(self.prev_span, impl_item.span);
             }
         } else {
-            return;
+            note_prev_span_then_ret!(self.prev_span, impl_item.span);
         }
 
         let (article, desc) = cx.tcx.article_and_description(impl_item.owner_id.to_def_id());
@@ -199,6 +243,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
         if !is_from_proc_macro(cx, impl_item) {
             self.check_missing_docs_attrs(cx, impl_item.owner_id.def_id, attrs, impl_item.span, article, desc);
         }
+        self.prev_span = Some(impl_item.span);
     }
 
     fn check_field_def(&mut self, cx: &LateContext<'tcx>, sf: &'tcx hir::FieldDef<'_>) {
@@ -208,6 +253,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
                 self.check_missing_docs_attrs(cx, sf.def_id, attrs, sf.span, "a", "struct field");
             }
         }
+        self.prev_span = Some(sf.span);
     }
 
     fn check_variant(&mut self, cx: &LateContext<'tcx>, v: &'tcx hir::Variant<'_>) {
@@ -215,5 +261,13 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
         if !is_from_proc_macro(cx, v) {
             self.check_missing_docs_attrs(cx, v.def_id, attrs, v.span, "a", "variant");
         }
+        self.prev_span = Some(v.span);
     }
 }
+
+fn span_to_snippet_contains_docs(cx: &LateContext<'_>, search_span: Span) -> bool {
+    let Some(snippet) = snippet_opt(cx, search_span) else {
+        return false;
+    };
+    snippet.lines().rev().any(|line| line.trim().starts_with("///"))
+}
diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
index 12c7c18afde..656fb907fcd 100644
--- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
+++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_note};
 use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id};
 use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Local, Node, Stmt, StmtKind};
+use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, LetStmt, Node, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
@@ -98,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for EvalOrderDependence {
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         match stmt.kind {
             StmtKind::Let(local) => {
-                if let Local { init: Some(e), .. } = local {
+                if let LetStmt { init: Some(e), .. } = local {
                     DivergenceVisitor { cx }.visit_expr(e);
                 }
             },
diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
index 70fd07cd93c..648d780ac09 100644
--- a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
+++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
@@ -109,7 +109,14 @@ fn collect_unsafe_exprs<'tcx>(
             ExprKind::Path(QPath::Resolved(
                 _,
                 hir::Path {
-                    res: Res::Def(DefKind::Static{mutability:Mutability::Mut, ..}, _),
+                    res:
+                        Res::Def(
+                            DefKind::Static {
+                                mutability: Mutability::Mut,
+                                ..
+                            },
+                            _,
+                        ),
                     ..
                 },
             )) => {
@@ -149,7 +156,13 @@ fn collect_unsafe_exprs<'tcx>(
                     ExprKind::Path(QPath::Resolved(
                         _,
                         hir::Path {
-                            res: Res::Def(DefKind::Static{mutability:Mutability::Mut, ..}, _),
+                            res: Res::Def(
+                                DefKind::Static {
+                                    mutability: Mutability::Mut,
+                                    ..
+                                },
+                                _
+                            ),
                             ..
                         }
                     ))
diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs
index c32025fcbb6..79f0a398d55 100644
--- a/src/tools/clippy/clippy_lints/src/mut_key.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_key.rs
@@ -121,7 +121,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType {
         }
     }
 
-    fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::Local<'_>) {
+    fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::LetStmt<'_>) {
         if let hir::PatKind::Wild = local.pat.kind {
             return;
         }
diff --git a/src/tools/clippy/clippy_lints/src/mut_mut.rs b/src/tools/clippy/clippy_lints/src/mut_mut.rs
index 72a2cca1e40..bc7b2c6b7c1 100644
--- a/src/tools/clippy/clippy_lints/src/mut_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_mut.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint;
+use clippy_utils::diagnostics::{span_lint, span_lint_hir};
 use clippy_utils::higher;
 use rustc_hir as hir;
 use rustc_hir::intravisit;
@@ -35,9 +35,34 @@ impl<'tcx> LateLintPass<'tcx> for MutMut {
     }
 
     fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'_>) {
-        use rustc_hir::intravisit::Visitor;
+        if in_external_macro(cx.sess(), ty.span) {
+            return;
+        }
 
-        MutVisitor { cx }.visit_ty(ty);
+        if let hir::TyKind::Ref(
+            _,
+            hir::MutTy {
+                ty: pty,
+                mutbl: hir::Mutability::Mut,
+            },
+        ) = ty.kind
+        {
+            if let hir::TyKind::Ref(
+                _,
+                hir::MutTy {
+                    mutbl: hir::Mutability::Mut,
+                    ..
+                },
+            ) = pty.kind
+            {
+                span_lint(
+                    cx,
+                    MUT_MUT,
+                    ty.span,
+                    "generally you want to avoid `&mut &mut _` if possible",
+                );
+            }
+        }
     }
 }
 
@@ -62,17 +87,19 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> {
             intravisit::walk_expr(self, body);
         } else if let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, e) = expr.kind {
             if let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, _) = e.kind {
-                span_lint(
+                span_lint_hir(
                     self.cx,
                     MUT_MUT,
+                    expr.hir_id,
                     expr.span,
                     "generally you want to avoid `&mut &mut _` if possible",
                 );
             } else if let ty::Ref(_, ty, hir::Mutability::Mut) = self.cx.typeck_results().expr_ty(e).kind() {
                 if ty.peel_refs().is_sized(self.cx.tcx, self.cx.param_env) {
-                    span_lint(
+                    span_lint_hir(
                         self.cx,
                         MUT_MUT,
+                        expr.hir_id,
                         expr.span,
                         "this expression mutably borrows a mutable reference. Consider reborrowing",
                     );
@@ -80,37 +107,4 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> {
             }
         }
     }
-
-    fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) {
-        if in_external_macro(self.cx.sess(), ty.span) {
-            return;
-        }
-
-        if let hir::TyKind::Ref(
-            _,
-            hir::MutTy {
-                ty: pty,
-                mutbl: hir::Mutability::Mut,
-            },
-        ) = ty.kind
-        {
-            if let hir::TyKind::Ref(
-                _,
-                hir::MutTy {
-                    mutbl: hir::Mutability::Mut,
-                    ..
-                },
-            ) = pty.kind
-            {
-                span_lint(
-                    self.cx,
-                    MUT_MUT,
-                    ty.span,
-                    "generally you want to avoid `&mut &mut _` if possible",
-                );
-            }
-        }
-
-        intravisit::walk_ty(self, ty);
-    }
 }
diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs
index f905a4e5b64..14a1e6be738 100644
--- a/src/tools/clippy/clippy_lints/src/mut_reference.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs
@@ -84,9 +84,7 @@ fn check_arguments<'tcx>(
             for (argument, parameter) in iter::zip(arguments, parameters) {
                 match parameter.kind() {
                     ty::Ref(_, _, Mutability::Not)
-                    | ty::RawPtr(ty::TypeAndMut {
-                        mutbl: Mutability::Not, ..
-                    }) => {
+                    | ty::RawPtr(_, Mutability::Not) => {
                         if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) = argument.kind {
                             span_lint(
                                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
index 4ae4fc9b096..61243c83731 100644
--- a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
+++ b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
@@ -127,7 +127,7 @@ fn get_atomic_name(ty: Ty<'_>) -> Option<&'static str> {
                 IntTy::I128 => None,
             }
         },
-        ty::RawPtr(_) => Some("AtomicPtr"),
+        ty::RawPtr(_, _) => Some("AtomicPtr"),
         _ => None,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/needless_late_init.rs b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
index 4cda4b171e3..810799acb2e 100644
--- a/src/tools/clippy/clippy_lints/src/needless_late_init.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
@@ -6,7 +6,7 @@ use clippy_utils::visitors::{for_each_expr, for_each_expr_with_closures, is_loca
 use core::ops::ControlFlow;
 use rustc_errors::{Applicability, MultiSpan};
 use rustc_hir::{
-    BindingAnnotation, Block, Expr, ExprKind, HirId, Local, LocalSource, MatchSource, Node, Pat, PatKind, Stmt,
+    BindingAnnotation, Block, Expr, ExprKind, HirId, LetStmt, LocalSource, MatchSource, Node, Pat, PatKind, Stmt,
     StmtKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
@@ -237,7 +237,7 @@ fn first_usage<'tcx>(
         })
 }
 
-fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &Local<'_>) -> Option<String> {
+fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &LetStmt<'_>) -> Option<String> {
     let span = local.span.with_hi(match local.ty {
         // let <pat>: <ty>;
         // ~~~~~~~~~~~~~~~
@@ -252,7 +252,7 @@ fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &Local<'_>) -> O
 
 fn check<'tcx>(
     cx: &LateContext<'tcx>,
-    local: &'tcx Local<'tcx>,
+    local: &'tcx LetStmt<'tcx>,
     local_stmt: &'tcx Stmt<'tcx>,
     block: &'tcx Block<'tcx>,
     binding_id: HirId,
@@ -363,9 +363,9 @@ fn check<'tcx>(
 }
 
 impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit {
-    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
         let mut parents = cx.tcx.hir().parent_iter(local.hir_id);
-        if let Local {
+        if let LetStmt {
             init: None,
             pat:
                 &Pat {
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index cebd2385656..6cb84bb78b6 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -290,14 +290,21 @@ impl NonCopyConst {
             promoted: None,
         };
         let param_env = cx.tcx.param_env(def_id).with_reveal_all_normalized(cx.tcx);
-        let result = cx.tcx.const_eval_global_id_for_typeck(param_env, cid, rustc_span::DUMMY_SP);
+        let result = cx
+            .tcx
+            .const_eval_global_id_for_typeck(param_env, cid, rustc_span::DUMMY_SP);
         self.is_value_unfrozen_raw(cx, result, ty)
     }
 
     fn is_value_unfrozen_expr<'tcx>(&self, cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool {
         let args = cx.typeck_results().node_args(hir_id);
 
-        let result = Self::const_eval_resolve(cx.tcx, cx.param_env, ty::UnevaluatedConst::new(def_id, args), rustc_span::DUMMY_SP);
+        let result = Self::const_eval_resolve(
+            cx.tcx,
+            cx.param_env,
+            ty::UnevaluatedConst::new(def_id, args),
+            rustc_span::DUMMY_SP,
+        );
         self.is_value_unfrozen_raw(cx, result, ty)
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
index 793a3a9545c..408216229a4 100644
--- a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
+++ b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
@@ -219,7 +219,7 @@ fn ty_allowed_with_raw_pointer_heuristic<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'t
             }
         },
         // Raw pointers are `!Send` but allowed by the heuristic
-        ty::RawPtr(_) => true,
+        ty::RawPtr(_, _) => true,
         _ => false,
     }
 }
@@ -229,7 +229,7 @@ fn contains_pointer_like<'tcx>(cx: &LateContext<'tcx>, target_ty: Ty<'tcx>) -> b
     for ty_node in target_ty.walk() {
         if let GenericArgKind::Type(inner_ty) = ty_node.unpack() {
             match inner_ty.kind() {
-                ty::RawPtr(_) => {
+                ty::RawPtr(_, _) => {
                     return true;
                 },
                 ty::Adt(adt_def, _) => {
diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
index fbca4329342..127801de7de 100644
--- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
+++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use rustc_hir::{intravisit, Body, Expr, ExprKind, FnDecl, Let, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind};
+use rustc_hir::{intravisit, Body, Expr, ExprKind, FnDecl, LetExpr, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
@@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch {
                 }
             }
         }
-        if let ExprKind::Let(Let { pat, .. }) = expr.kind {
+        if let ExprKind::Let(LetExpr { pat, .. }) = expr.kind {
             apply_lint(cx, pat, DerefPossible::Possible);
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 2587b3881bb..896c99a7104 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -604,7 +604,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
 
             match get_expr_use_or_unification_node(self.cx.tcx, e) {
                 Some((Node::Stmt(_), _)) => (),
-                Some((Node::Local(l), _)) => {
+                Some((Node::LetStmt(l), _)) => {
                     // Only trace simple bindings. e.g `let x = y;`
                     if let PatKind::Binding(BindingAnnotation::NONE, id, _, None) = l.pat.kind {
                         self.bindings.insert(id, args_idx);
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index 831c291ed7c..f1db571e113 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -14,7 +14,7 @@ use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk};
 use rustc_hir::{
-    BindingAnnotation, Block, ByRef, Expr, ExprKind, Local, Node, PatKind, PathSegment, QPath, Stmt, StmtKind,
+    BindingAnnotation, Block, ByRef, Expr, ExprKind, LetStmt, Node, PatKind, PathSegment, QPath, Stmt, StmtKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::Ty;
@@ -109,7 +109,7 @@ fn find_let_else_ret_expression<'hir>(block: &'hir Block<'hir>) -> Option<&'hir
 }
 
 fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
-    if let StmtKind::Let(Local {
+    if let StmtKind::Let(LetStmt {
         pat,
         init: Some(init_expr),
         els: Some(els),
diff --git a/src/tools/clippy/clippy_lints/src/raw_strings.rs b/src/tools/clippy/clippy_lints/src/raw_strings.rs
index ac29d27303c..7e71f48c6d9 100644
--- a/src/tools/clippy/clippy_lints/src/raw_strings.rs
+++ b/src/tools/clippy/clippy_lints/src/raw_strings.rs
@@ -108,7 +108,7 @@ impl EarlyLintPass for RawStrings {
                 }
             }
 
-            let req = {
+            let mut req = {
                 let mut following_quote = false;
                 let mut req = 0;
                 // `once` so a raw string ending in hashes is still checked
@@ -136,7 +136,9 @@ impl EarlyLintPass for RawStrings {
                     ControlFlow::Continue(num) | ControlFlow::Break(num) => num,
                 }
             };
-
+            if self.allow_one_hash_in_raw_strings {
+                req = req.max(1);
+            }
             if req < max {
                 span_lint_and_then(
                     cx,
diff --git a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
index d0b37cd92e0..7f4735c6a88 100644
--- a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
+++ b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
@@ -1,9 +1,9 @@
-use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
+use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
 use clippy_utils::get_enclosing_block;
 use clippy_utils::higher::{get_vec_init_kind, VecInitKind};
 use clippy_utils::source::snippet;
 
-use hir::{Expr, ExprKind, HirId, Local, PatKind, PathSegment, QPath, StmtKind};
+use hir::{Expr, ExprKind, HirId, LetStmt, PatKind, PathSegment, QPath, StmtKind};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::def::Res;
@@ -57,7 +57,7 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec {
             }
 
             if let StmtKind::Let(local) = stmt.kind
-                && let Local {
+                && let LetStmt {
                     pat, init: Some(init), ..
                 } = local
                 && let PatKind::Binding(_, id, ident, _) = pat.kind
@@ -77,37 +77,53 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec {
                 if let Some(expr) = visitor.read_zero_expr {
                     let applicability = Applicability::MaybeIncorrect;
                     match vec_init_kind {
-                        VecInitKind::WithConstCapacity(len) => {
-                            span_lint_and_sugg(
+                        VecInitKind::WithConstCapacity(len) => span_lint_hir_and_then(
+                            cx,
+                            READ_ZERO_BYTE_VEC,
+                            expr.hir_id,
+                            expr.span,
+                            "reading zero byte data to `Vec`",
+                            |diag| {
+                                diag.span_suggestion(
+                                    expr.span,
+                                    "try",
+                                    format!("{}.resize({len}, 0); {}", ident.as_str(), snippet(cx, expr.span, "..")),
+                                    applicability,
+                                );
+                            },
+                        ),
+                        VecInitKind::WithExprCapacity(hir_id) => {
+                            let e = cx.tcx.hir().expect_expr(hir_id);
+                            span_lint_hir_and_then(
                                 cx,
                                 READ_ZERO_BYTE_VEC,
+                                expr.hir_id,
                                 expr.span,
                                 "reading zero byte data to `Vec`",
-                                "try",
-                                format!("{}.resize({len}, 0); {}", ident.as_str(), snippet(cx, expr.span, "..")),
-                                applicability,
+                                |diag| {
+                                    diag.span_suggestion(
+                                        expr.span,
+                                        "try",
+                                        format!(
+                                            "{}.resize({}, 0); {}",
+                                            ident.as_str(),
+                                            snippet(cx, e.span, ".."),
+                                            snippet(cx, expr.span, "..")
+                                        ),
+                                        applicability,
+                                    );
+                                },
                             );
                         },
-                        VecInitKind::WithExprCapacity(hir_id) => {
-                            let e = cx.tcx.hir().expect_expr(hir_id);
-                            span_lint_and_sugg(
+                        _ => {
+                            span_lint_hir(
                                 cx,
                                 READ_ZERO_BYTE_VEC,
+                                expr.hir_id,
                                 expr.span,
                                 "reading zero byte data to `Vec`",
-                                "try",
-                                format!(
-                                    "{}.resize({}, 0); {}",
-                                    ident.as_str(),
-                                    snippet(cx, e.span, ".."),
-                                    snippet(cx, expr.span, "..")
-                                ),
-                                applicability,
                             );
                         },
-                        _ => {
-                            span_lint(cx, READ_ZERO_BYTE_VEC, expr.span, "reading zero byte data to `Vec`");
-                        },
                     }
                 }
             }
diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
index c2673bc409f..435899ddaa7 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
@@ -1,5 +1,5 @@
 use crate::rustc_lint::LintContext;
-use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
+use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir};
 use clippy_utils::get_parent_expr;
 use clippy_utils::sugg::Sugg;
 use hir::Param;
@@ -273,9 +273,10 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
                 && ident == path.segments[0].ident
                 && count_closure_usage(cx, block, path) == 1
             {
-                span_lint(
+                span_lint_hir(
                     cx,
                     REDUNDANT_CLOSURE_CALL,
+                    second.hir_id,
                     second.span,
                     "closure called just once immediately after it was declared",
                 );
diff --git a/src/tools/clippy/clippy_lints/src/redundant_else.rs b/src/tools/clippy/clippy_lints/src/redundant_else.rs
index fb434fb7450..3bdf13dbbea 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_else.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_else.rs
@@ -105,7 +105,7 @@ impl<'ast> Visitor<'ast> for BreakVisitor {
     fn visit_expr(&mut self, expr: &'ast Expr) {
         self.is_break = match expr.kind {
             ExprKind::Break(..) | ExprKind::Continue(..) | ExprKind::Ret(..) => true,
-            ExprKind::Match(_, ref arms) => arms.iter().all(|arm|
+            ExprKind::Match(_, ref arms, _) => arms.iter().all(|arm|
                 arm.body.is_none() || arm.body.as_deref().is_some_and(|body| self.check_expr(body))
             ),
             ExprKind::If(_, ref then, Some(ref els)) => self.check_block(then) && self.check_expr(els),
diff --git a/src/tools/clippy/clippy_lints/src/redundant_locals.rs b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
index 6528a7b369f..0f579f779df 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_locals.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
@@ -3,7 +3,7 @@ use clippy_utils::is_from_proc_macro;
 use clippy_utils::ty::needs_ordered_drop;
 use rustc_ast::Mutability;
 use rustc_hir::def::Res;
-use rustc_hir::{BindingAnnotation, ByRef, ExprKind, HirId, Local, Node, Pat, PatKind, QPath};
+use rustc_hir::{BindingAnnotation, ByRef, ExprKind, HirId, LetStmt, Node, Pat, PatKind, QPath};
 use rustc_hir_typeck::expr_use_visitor::PlaceBase;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
@@ -47,7 +47,7 @@ declare_clippy_lint! {
 declare_lint_pass!(RedundantLocals => [REDUNDANT_LOCALS]);
 
 impl<'tcx> LateLintPass<'tcx> for RedundantLocals {
-    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
         if !local.span.is_desugaring(DesugaringKind::Async)
             // the pattern is a single by-value binding
             && let PatKind::Binding(BindingAnnotation(ByRef::No, mutability), _, ident, None) = local.pat.kind
diff --git a/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs b/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs
index 079e6500e3c..96f6f0ec36f 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs
@@ -131,7 +131,7 @@ fn extract_primty(ty_kind: &hir::TyKind<'_>) -> Option<hir::PrimTy> {
 }
 
 impl LateLintPass<'_> for RedundantTypeAnnotations {
-    fn check_local<'tcx>(&mut self, cx: &LateContext<'tcx>, local: &'tcx rustc_hir::Local<'tcx>) {
+    fn check_local<'tcx>(&mut self, cx: &LateContext<'tcx>, local: &'tcx rustc_hir::LetStmt<'tcx>) {
         if !is_lint_allowed(cx, REDUNDANT_TYPE_ANNOTATIONS, local.hir_id)
             // type annotation part
             && !local.span.from_expansion()
diff --git a/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs b/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs
index ca7a0c7c87b..c227b5b22f4 100644
--- a/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs
@@ -4,7 +4,7 @@ use clippy_utils::source::snippet;
 use clippy_utils::{is_from_proc_macro, path_to_local_id};
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
-use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Local, PatKind, QPath, Stmt, StmtKind};
+use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, LetStmt, PatKind, QPath, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
@@ -69,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization {
         self.searcher = None;
     }
 
-    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
         if let Some(init_expr) = local.init
             && let PatKind::Binding(BindingAnnotation::MUT, id, _, None) = local.pat.kind
             && !in_external_macro(cx.sess(), local.span)
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index 19697527467..8bc24eda465 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then};
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
 use clippy_utils::source::{snippet_opt, snippet_with_context};
 use clippy_utils::sugg::has_enclosing_paren;
 use clippy_utils::visitors::{for_each_expr_with_closures, Descend};
@@ -380,7 +380,7 @@ fn check_final_expr<'tcx>(
                 return;
             }
 
-            emit_return_lint(cx, ret_span, semi_spans, &replacement);
+            emit_return_lint(cx, ret_span, semi_spans, &replacement, expr.hir_id);
         },
         ExprKind::If(_, then, else_clause_opt) => {
             check_block_return(cx, &then.kind, peeled_drop_expr.span, semi_spans.clone());
@@ -415,18 +415,31 @@ fn expr_contains_conjunctive_ifs<'tcx>(expr: &'tcx Expr<'tcx>) -> bool {
     contains_if(expr, false)
 }
 
-fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, semi_spans: Vec<Span>, replacement: &RetReplacement<'_>) {
+fn emit_return_lint(
+    cx: &LateContext<'_>,
+    ret_span: Span,
+    semi_spans: Vec<Span>,
+    replacement: &RetReplacement<'_>,
+    at: HirId,
+) {
     if ret_span.from_expansion() {
         return;
     }
 
-    span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded `return` statement", |diag| {
-        let suggestions = std::iter::once((ret_span, replacement.to_string()))
-            .chain(semi_spans.into_iter().map(|span| (span, String::new())))
-            .collect();
+    span_lint_hir_and_then(
+        cx,
+        NEEDLESS_RETURN,
+        at,
+        ret_span,
+        "unneeded `return` statement",
+        |diag| {
+            let suggestions = std::iter::once((ret_span, replacement.to_string()))
+                .chain(semi_spans.into_iter().map(|span| (span, String::new())))
+                .collect();
 
-        diag.multipart_suggestion_verbose(replacement.sugg_help(), suggestions, replacement.applicability());
-    });
+            diag.multipart_suggestion_verbose(replacement.sugg_help(), suggestions, replacement.applicability());
+        },
+    );
 }
 
 fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
@@ -452,8 +465,8 @@ fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>)
 // Go backwards while encountering whitespace and extend the given Span to that point.
 fn extend_span_to_previous_non_ws(cx: &LateContext<'_>, sp: Span) -> Span {
     if let Ok(prev_source) = cx.sess().source_map().span_to_prev_source(sp) {
-        let ws = [' ', '\t', '\n'];
-        if let Some(non_ws_pos) = prev_source.rfind(|c| !ws.contains(&c)) {
+        let ws = [b' ', b'\t', b'\n'];
+        if let Some(non_ws_pos) = prev_source.bytes().rposition(|c| !ws.contains(&c)) {
             let len = prev_source.len() - non_ws_pos - 1;
             return sp.with_lo(sp.lo() - BytePos::from_usize(len));
         }
diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs
index c74364d89d6..d98b37bda35 100644
--- a/src/tools/clippy/clippy_lints/src/shadow.rs
+++ b/src/tools/clippy/clippy_lints/src/shadow.rs
@@ -5,7 +5,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::hir_id::ItemLocalId;
-use rustc_hir::{Block, Body, BodyOwnerKind, Expr, ExprKind, HirId, Let, Node, Pat, PatKind, QPath, UnOp};
+use rustc_hir::{Block, Body, BodyOwnerKind, Expr, ExprKind, HirId, LetExpr, Node, Pat, PatKind, QPath, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
 use rustc_span::{Span, Symbol};
@@ -238,10 +238,10 @@ fn find_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'
         let init = match node {
             Node::Arm(_) | Node::Pat(_) => continue,
             Node::Expr(expr) => match expr.kind {
-                ExprKind::Match(e, _, _) | ExprKind::Let(&Let { init: e, .. }) => Some(e),
+                ExprKind::Match(e, _, _) | ExprKind::Let(&LetExpr { init: e, .. }) => Some(e),
                 _ => None,
             },
-            Node::Local(local) => local.init,
+            Node::LetStmt(local) => local.init,
             _ => None,
         };
         return init;
diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
index f8726aa173a..d3540bc8e1c 100644
--- a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
+++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
@@ -7,7 +7,7 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{self as hir};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::ty::{GenericArgKind, Ty, TypeAndMut};
+use rustc_middle::ty::{GenericArgKind, Ty};
 use rustc_session::impl_lint_pass;
 use rustc_span::symbol::Ident;
 use rustc_span::{sym, Span, DUMMY_SP};
@@ -199,7 +199,7 @@ impl<'cx, 'others, 'tcx> AttrChecker<'cx, 'others, 'tcx> {
                 false
             },
             rustc_middle::ty::Array(ty, _)
-            | rustc_middle::ty::RawPtr(TypeAndMut { ty, .. })
+            | rustc_middle::ty::RawPtr(ty, _)
             | rustc_middle::ty::Ref(_, ty, _)
             | rustc_middle::ty::Slice(ty) => self.has_sig_drop_attr(*ty),
             _ => false,
diff --git a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
index 756e47cbdf0..01f0e3cfadb 100644
--- a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
+++ b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
@@ -4,7 +4,7 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self, Ty, TypeAndMut};
+use rustc_middle::ty::{self, Ty};
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
 
@@ -107,7 +107,7 @@ fn get_pointee_ty_and_count_expr<'tcx>(
         && METHODS.iter().any(|m| *m == method_ident)
 
         // Get the pointee type
-        && let ty::RawPtr(TypeAndMut { ty: pointee_ty, .. }) =
+        && let ty::RawPtr(pointee_ty, _) =
             cx.typeck_results().expr_ty(ptr_self).kind()
     {
         return Some((*pointee_ty, count));
diff --git a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
index c0e4f3c368a..cf839941123 100644
--- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
+++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
@@ -109,6 +109,7 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
                     sym::core => (STD_INSTEAD_OF_CORE, "std", "core"),
                     sym::alloc => (STD_INSTEAD_OF_ALLOC, "std", "alloc"),
                     _ => {
+                        self.prev_span = first_segment.ident.span;
                         return;
                     },
                 },
@@ -116,6 +117,7 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
                     if cx.tcx.crate_name(def_id.krate) == sym::core {
                         (ALLOC_INSTEAD_OF_CORE, "alloc", "core")
                     } else {
+                        self.prev_span = first_segment.ident.span;
                         return;
                     }
                 },
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
index 60e9d262e7e..ab1b3043f0c 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
@@ -552,7 +552,7 @@ fn ident_difference_expr_with_base_location(
         | (Gen(_, _, _), Gen(_, _, _))
         | (Block(_, _), Block(_, _))
         | (Closure(_), Closure(_))
-        | (Match(_, _), Match(_, _))
+        | (Match(_, _, _), Match(_, _, _))
         | (Loop(_, _, _), Loop(_, _, _))
         | (ForLoop { .. }, ForLoop { .. })
         | (While(_, _, _), While(_, _, _))
diff --git a/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs b/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs
index 1af3733ebfa..f8bdb866ca3 100644
--- a/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs
+++ b/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs
@@ -37,7 +37,7 @@ declare_clippy_lint! {
     ///     static BUF: String = const { String::new() };
     /// }
     /// ```
-    #[clippy::version = "1.76.0"]
+    #[clippy::version = "1.77.0"]
     pub THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST,
     perf,
     "suggest using `const` in `thread_local!` macro"
diff --git a/src/tools/clippy/clippy_lints/src/transmute/crosspointer_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/crosspointer_transmute.rs
index c4b9d82fc73..102aee1cb95 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/crosspointer_transmute.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/crosspointer_transmute.rs
@@ -7,8 +7,8 @@ use rustc_middle::ty::{self, Ty};
 /// Checks for `crosspointer_transmute` lint.
 /// Returns `true` if it's triggered, otherwise returns `false`.
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> bool {
-    match (&from_ty.kind(), &to_ty.kind()) {
-        (ty::RawPtr(from_ptr), _) if from_ptr.ty == to_ty => {
+    match (*from_ty.kind(), *to_ty.kind()) {
+        (ty::RawPtr(from_ptr_ty, _), _) if from_ptr_ty == to_ty => {
             span_lint(
                 cx,
                 CROSSPOINTER_TRANSMUTE,
@@ -17,7 +17,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty
             );
             true
         },
-        (_, ty::RawPtr(to_ptr)) if to_ptr.ty == from_ty => {
+        (_, ty::RawPtr(to_ptr_ty, _)) if to_ptr_ty == from_ty => {
             span_lint(
                 cx,
                 CROSSPOINTER_TRANSMUTE,
diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
index e47b14bf63b..3c11b481310 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
@@ -514,7 +514,7 @@ declare_clippy_lint! {
     ///              ^^^^ ^^ `bool::then` only executes the closure if the condition is true!
     /// }
     /// ```
-    #[clippy::version = "1.76.0"]
+    #[clippy::version = "1.77.0"]
     pub EAGER_TRANSMUTE,
     correctness,
     "eager evaluation of `transmute`"
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs
index 4ae4359eea0..1476ea8e7a4 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs
@@ -16,7 +16,7 @@ pub(super) fn check<'tcx>(
     arg: &'tcx Expr<'_>,
 ) -> bool {
     match (&from_ty.kind(), &to_ty.kind()) {
-        (ty::RawPtr(_), ty::RawPtr(to_ty)) => {
+        (ty::RawPtr(_, _), ty::RawPtr(to_ty, to_mutbl)) => {
             span_lint_and_then(
                 cx,
                 TRANSMUTE_PTR_TO_PTR,
@@ -24,7 +24,7 @@ pub(super) fn check<'tcx>(
                 "transmute from a pointer to a pointer",
                 |diag| {
                     if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
-                        let sugg = arg.as_ty(Ty::new_ptr(cx.tcx, *to_ty));
+                        let sugg = arg.as_ty(Ty::new_ptr(cx.tcx, *to_ty, *to_mutbl));
                         diag.span_suggestion(e.span, "try", sugg, Applicability::Unspecified);
                     }
                 },
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
index 4ab3afbe714..cf78709583c 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
@@ -20,7 +20,7 @@ pub(super) fn check<'tcx>(
     msrv: &Msrv,
 ) -> bool {
     match (&from_ty.kind(), &to_ty.kind()) {
-        (ty::RawPtr(from_ptr_ty), ty::Ref(_, to_ref_ty, mutbl)) => {
+        (ty::RawPtr(from_ptr_ty, _), ty::Ref(_, to_ref_ty, mutbl)) => {
             span_lint_and_then(
                 cx,
                 TRANSMUTE_PTR_TO_REF,
@@ -44,7 +44,7 @@ pub(super) fn check<'tcx>(
                         } else {
                             sugg::make_unop(deref, arg.as_ty(format!("{cast} {ty_snip}"))).to_string()
                         }
-                    } else if from_ptr_ty.ty == *to_ref_ty {
+                    } else if *from_ptr_ty == *to_ref_ty {
                         if from_ptr_ty.has_erased_regions() {
                             if msrv.meets(msrvs::POINTER_CAST) {
                                 format!("{deref}{}.cast::<{to_ref_ty}>()", arg.maybe_par())
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs
index 6c885ebdea1..73321c56f3f 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs
@@ -19,7 +19,7 @@ pub(super) fn check<'tcx>(
 ) -> bool {
     let mut triggered = false;
 
-    if let (ty::Ref(_, ty_from, from_mutbl), ty::Ref(_, ty_to, to_mutbl)) = (&from_ty.kind(), &to_ty.kind()) {
+    if let (ty::Ref(_, ty_from, from_mutbl), ty::Ref(_, ty_to, to_mutbl)) = (*from_ty.kind(), *to_ty.kind()) {
         if let ty::Slice(slice_ty) = *ty_from.kind()
             && ty_to.is_str()
             && let ty::Uint(ty::UintTy::U8) = slice_ty.kind()
@@ -27,7 +27,7 @@ pub(super) fn check<'tcx>(
         {
             let Some(top_crate) = std_or_core(cx) else { return true };
 
-            let postfix = if *from_mutbl == Mutability::Mut { "_mut" } else { "" };
+            let postfix = if from_mutbl == Mutability::Mut { "_mut" } else { "" };
 
             let snippet = snippet(cx, arg.span, "..");
 
@@ -53,18 +53,10 @@ pub(super) fn check<'tcx>(
                 "transmute from a reference to a reference",
                 |diag| {
                     if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
-                        let ty_from_and_mut = ty::TypeAndMut {
-                            ty: *ty_from,
-                            mutbl: *from_mutbl,
-                        };
-                        let ty_to_and_mut = ty::TypeAndMut {
-                            ty: *ty_to,
-                            mutbl: *to_mutbl,
-                        };
                         let sugg_paren = arg
-                            .as_ty(Ty::new_ptr(cx.tcx, ty_from_and_mut))
-                            .as_ty(Ty::new_ptr(cx.tcx, ty_to_and_mut));
-                        let sugg = if *to_mutbl == Mutability::Mut {
+                            .as_ty(Ty::new_ptr(cx.tcx, ty_from, from_mutbl))
+                            .as_ty(Ty::new_ptr(cx.tcx, ty_to, to_mutbl));
+                        let sugg = if to_mutbl == Mutability::Mut {
                             sugg_paren.mut_addr_deref()
                         } else {
                             sugg_paren.addr_deref()
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
index a6f03c85b4f..33c4031fa87 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
@@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::ty::is_c_void;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, GenericArgsRef, IntTy, Ty, TypeAndMut, UintTy};
+use rustc_middle::ty::{self, GenericArgsRef, IntTy, Ty, UintTy};
 
 #[expect(clippy::too_many_lines)]
 pub(super) fn check<'tcx>(
@@ -45,8 +45,8 @@ pub(super) fn check<'tcx>(
 
             // ptr <-> ptr
             (ReducedTy::Other(from_sub_ty), ReducedTy::Other(to_sub_ty))
-                if matches!(from_sub_ty.kind(), ty::Ref(..) | ty::RawPtr(_))
-                    && matches!(to_sub_ty.kind(), ty::Ref(..) | ty::RawPtr(_)) =>
+                if matches!(from_sub_ty.kind(), ty::Ref(..) | ty::RawPtr(_, _))
+                    && matches!(to_sub_ty.kind(), ty::Ref(..) | ty::RawPtr(_, _)) =>
             {
                 from_ty = from_sub_ty;
                 to_ty = to_sub_ty;
@@ -196,21 +196,21 @@ fn reduce_refs<'tcx>(cx: &LateContext<'tcx>, mut from_ty: Ty<'tcx>, mut to_ty: T
     let (from_fat_ptr, to_fat_ptr) = loop {
         break match (from_ty.kind(), to_ty.kind()) {
             (
-                &(ty::Ref(_, from_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: from_sub_ty, .. })),
-                &(ty::Ref(_, to_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: to_sub_ty, .. })),
+                &(ty::Ref(_, from_sub_ty, _) | ty::RawPtr(from_sub_ty, _)),
+                &(ty::Ref(_, to_sub_ty, _) | ty::RawPtr(to_sub_ty, _)),
             ) => {
-                from_raw_ptr = matches!(*from_ty.kind(), ty::RawPtr(_));
+                from_raw_ptr = matches!(*from_ty.kind(), ty::RawPtr(_, _));
                 from_ty = from_sub_ty;
-                to_raw_ptr = matches!(*to_ty.kind(), ty::RawPtr(_));
+                to_raw_ptr = matches!(*to_ty.kind(), ty::RawPtr(_, _));
                 to_ty = to_sub_ty;
                 continue;
             },
-            (&(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })), _)
+            (&(ty::Ref(_, unsized_ty, _) | ty::RawPtr(unsized_ty, _)), _)
                 if !unsized_ty.is_sized(cx.tcx, cx.param_env) =>
             {
                 (true, false)
             },
-            (_, &(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })))
+            (_, &(ty::Ref(_, unsized_ty, _) | ty::RawPtr(unsized_ty, _)))
                 if !unsized_ty.is_sized(cx.tcx, cx.param_env) =>
             {
                 (false, true)
diff --git a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs
index 088c8fda87a..70628f3d4f4 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs
@@ -15,7 +15,7 @@ pub(super) fn check<'tcx>(
     to_ty: Ty<'tcx>,
     arg: &'tcx Expr<'_>,
 ) -> bool {
-    match (&from_ty.kind(), &to_ty.kind()) {
+    match (*from_ty.kind(), *to_ty.kind()) {
         _ if from_ty == to_ty && !from_ty.has_erased_regions() => {
             span_lint(
                 cx,
@@ -25,7 +25,7 @@ pub(super) fn check<'tcx>(
             );
             true
         },
-        (ty::Ref(_, rty, rty_mutbl), ty::RawPtr(ptr_ty)) => {
+        (ty::Ref(_, rty, rty_mutbl), ty::RawPtr(ptr_ty, ptr_mutbl)) => {
             // No way to give the correct suggestion here. Avoid linting for now.
             if !rty.has_erased_regions() {
                 span_lint_and_then(
@@ -35,15 +35,10 @@ pub(super) fn check<'tcx>(
                     "transmute from a reference to a pointer",
                     |diag| {
                         if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
-                            let rty_and_mut = ty::TypeAndMut {
-                                ty: *rty,
-                                mutbl: *rty_mutbl,
-                            };
-
-                            let sugg = if *ptr_ty == rty_and_mut {
+                            let sugg = if ptr_ty == rty && rty_mutbl == ptr_mutbl {
                                 arg.as_ty(to_ty)
                             } else {
-                                arg.as_ty(Ty::new_ptr(cx.tcx, rty_and_mut)).as_ty(to_ty)
+                                arg.as_ty(Ty::new_ptr(cx.tcx, rty, rty_mutbl)).as_ty(to_ty)
                             };
 
                             diag.span_suggestion(e.span, "try", sugg, Applicability::Unspecified);
@@ -53,7 +48,7 @@ pub(super) fn check<'tcx>(
             }
             true
         },
-        (ty::Int(_) | ty::Uint(_), ty::RawPtr(_)) => {
+        (ty::Int(_) | ty::Uint(_), ty::RawPtr(_, _)) => {
             span_lint_and_then(
                 cx,
                 USELESS_TRANSMUTE,
diff --git a/src/tools/clippy/clippy_lints/src/transmute/wrong_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/wrong_transmute.rs
index d1965565b92..ed815884a76 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/wrong_transmute.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/wrong_transmute.rs
@@ -8,7 +8,7 @@ use rustc_middle::ty::{self, Ty};
 /// Returns `true` if it's triggered, otherwise returns `false`.
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> bool {
     match (&from_ty.kind(), &to_ty.kind()) {
-        (ty::Float(_) | ty::Char, ty::Ref(..) | ty::RawPtr(_)) => {
+        (ty::Float(_) | ty::Char, ty::Ref(..) | ty::RawPtr(_, _)) => {
             span_lint(
                 cx,
                 WRONG_TRANSMUTE,
diff --git a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
index 0d84a9ab395..564b065d0ba 100644
--- a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
@@ -159,7 +159,7 @@ fn all_bindings_are_for_conv<'tcx>(
         .iter()
         .map(|node| match node {
             Node::Pat(pat) => kind.eq(&pat.kind).then_some(pat.hir_id),
-            Node::Local(l) => Some(l.hir_id),
+            Node::LetStmt(l) => Some(l.hir_id),
             _ => None,
         })
         .all_equal()
@@ -170,7 +170,7 @@ fn all_bindings_are_for_conv<'tcx>(
         && local_parents.first().is_some_and(|node| {
             let Some(ty) = match node {
                 Node::Pat(pat) => Some(pat.hir_id),
-                Node::Local(l) => Some(l.hir_id),
+                Node::LetStmt(l) => Some(l.hir_id),
                 _ => None,
             }
             .map(|hir_id| cx.typeck_results().node_type(hir_id)) else {
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index bdef82e9c5e..0802cb2b7c7 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -12,7 +12,7 @@ mod vec_box;
 use rustc_hir as hir;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
-    Body, FnDecl, FnRetTy, GenericArg, ImplItem, ImplItemKind, Item, ItemKind, Local, MutTy, QPath, TraitItem,
+    Body, FnDecl, FnRetTy, GenericArg, ImplItem, ImplItemKind, Item, ItemKind, LetStmt, MutTy, QPath, TraitItem,
     TraitItemKind, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
@@ -392,6 +392,10 @@ impl<'tcx> LateLintPass<'tcx> for Types {
     }
 
     fn check_field_def(&mut self, cx: &LateContext<'tcx>, field: &hir::FieldDef<'tcx>) {
+        if field.span.from_expansion() {
+            return;
+        }
+
         let is_exported = cx.effective_visibilities.is_exported(field.def_id);
 
         self.check_ty(
@@ -421,7 +425,7 @@ impl<'tcx> LateLintPass<'tcx> for Types {
         }
     }
 
-    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &Local<'tcx>) {
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &LetStmt<'tcx>) {
         if let Some(ty) = local.ty {
             self.check_ty(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
index a0d609501a0..37437cbfbec 100644
--- a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
+++ b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
@@ -4,7 +4,7 @@ use clippy_utils::{path_def_id, qpath_generic_tys};
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{self as hir, QPath, TyKind};
-use rustc_hir_analysis::hir_ty_to_ty;
+use rustc_hir_analysis::lower_ty;
 use rustc_lint::LateContext;
 use rustc_middle::ty::TypeVisitableExt;
 use rustc_span::symbol::sym;
@@ -56,10 +56,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, qpath:
     };
     let inner_span = match qpath_generic_tys(inner_qpath).next() {
         Some(hir_ty) => {
-            // Reallocation of a fat pointer causes it to become thin. `hir_ty_to_ty` is safe to use
+            // Reallocation of a fat pointer causes it to become thin. `lower_ty` is safe to use
             // here because `mod.rs` guarantees this lint is only run on types outside of bodies and
             // is not run on locals.
-            let ty = hir_ty_to_ty(cx.tcx, hir_ty);
+            let ty = lower_ty(cx.tcx, hir_ty);
             if ty.has_escaping_bound_vars() || !ty.is_sized(cx.tcx, cx.param_env) {
                 return false;
             }
diff --git a/src/tools/clippy/clippy_lints/src/types/vec_box.rs b/src/tools/clippy/clippy_lints/src/types/vec_box.rs
index 7926738d68f..29996a6f783 100644
--- a/src/tools/clippy/clippy_lints/src/types/vec_box.rs
+++ b/src/tools/clippy/clippy_lints/src/types/vec_box.rs
@@ -4,7 +4,7 @@ use clippy_utils::source::snippet;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{self as hir, GenericArg, LangItem, QPath, TyKind};
-use rustc_hir_analysis::hir_ty_to_ty;
+use rustc_hir_analysis::lower_ty;
 use rustc_lint::LateContext;
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::TypeVisitableExt;
@@ -35,7 +35,7 @@ pub(super) fn check<'tcx>(
             && let Some(GenericArg::Type(boxed_ty)) = last.args.first()
             // extract allocator from the Box for later
             && let boxed_alloc_ty = last.args.get(1)
-            && let ty_ty = hir_ty_to_ty(cx.tcx, boxed_ty)
+            && let ty_ty = lower_ty(cx.tcx, boxed_ty)
             && !ty_ty.has_escaping_bound_vars()
             && ty_ty.is_sized(cx.tcx, cx.param_env)
             && let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes())
@@ -55,7 +55,7 @@ pub(super) fn check<'tcx>(
                     }
                 },
                 (Some(GenericArg::Type(l)), Some(GenericArg::Type(r))) =>
-                    hir_ty_to_ty(cx.tcx, l) == hir_ty_to_ty(cx.tcx, r),
+                    lower_ty(cx.tcx, l) == lower_ty(cx.tcx, r),
                 _ => false
             }
         {
diff --git a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
index 224ec475c51..8764e3006c6 100644
--- a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::{expr_or_init, get_trait_def_id, path_def_id};
+use clippy_utils::{expr_or_init, fn_def_id_with_node_args, path_def_id};
 use rustc_ast::BinOpKind;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
@@ -7,7 +7,7 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{walk_body, walk_expr, FnKind, Visitor};
 use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, Item, ItemKind, Node, QPath, TyKind};
-use rustc_hir_analysis::hir_ty_to_ty;
+use rustc_hir_analysis::lower_ty;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter;
@@ -19,11 +19,11 @@ use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks that there isn't an infinite recursion in `PartialEq` trait
-    /// implementation.
+    /// Checks that there isn't an infinite recursion in trait
+    /// implementations.
     ///
     /// ### Why is this bad?
-    /// This is a hard to find infinite recursion which will crashing any code
+    /// This is a hard to find infinite recursion that will crash any code.
     /// using it.
     ///
     /// ### Example
@@ -42,7 +42,7 @@ declare_clippy_lint! {
     /// Use instead:
     ///
     /// In such cases, either use `#[derive(PartialEq)]` or don't implement it.
-    #[clippy::version = "1.76.0"]
+    #[clippy::version = "1.77.0"]
     pub UNCONDITIONAL_RECURSION,
     suspicious,
     "detect unconditional recursion in some traits implementation"
@@ -74,7 +74,7 @@ fn get_hir_ty_def_id<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: rustc_hir::Ty<'tcx>) -> Op
     match qpath {
         QPath::Resolved(_, path) => path.res.opt_def_id(),
         QPath::TypeRelative(_, _) => {
-            let ty = hir_ty_to_ty(tcx, &hir_ty);
+            let ty = lower_ty(tcx, &hir_ty);
 
             match ty.kind() {
                 ty::Alias(ty::Projection, proj) => {
@@ -201,7 +201,6 @@ fn check_partial_eq(cx: &LateContext<'_>, method_span: Span, method_def_id: Loca
     }
 }
 
-#[allow(clippy::unnecessary_def_path)]
 fn check_to_string(cx: &LateContext<'_>, method_span: Span, method_def_id: LocalDefId, name: Ident, expr: &Expr<'_>) {
     let args = cx
         .tcx
@@ -224,7 +223,7 @@ fn check_to_string(cx: &LateContext<'_>, method_span: Span, method_def_id: Local
         && let Some(trait_) = impl_.of_trait
         && let Some(trait_def_id) = trait_.trait_def_id()
         // The trait is `ToString`.
-        && Some(trait_def_id) == get_trait_def_id(cx, &["alloc", "string", "ToString"])
+        && cx.tcx.is_diagnostic_item(sym::ToString, trait_def_id)
     {
         let is_bad = match expr.kind {
             ExprKind::MethodCall(segment, _receiver, &[_arg], _) if segment.ident.name == name.name => {
@@ -291,7 +290,6 @@ where
         self.map
     }
 
-    #[allow(clippy::unnecessary_def_path)]
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
         if self.found_default_call {
             return;
@@ -303,7 +301,7 @@ where
             && is_default_method_on_current_ty(self.cx.tcx, qpath, self.implemented_ty_id)
             && let Some(method_def_id) = path_def_id(self.cx, f)
             && let Some(trait_def_id) = self.cx.tcx.trait_of_item(method_def_id)
-            && Some(trait_def_id) == get_trait_def_id(self.cx, &["core", "default", "Default"])
+            && self.cx.tcx.is_diagnostic_item(sym::Default, trait_def_id)
         {
             self.found_default_call = true;
             span_error(self.cx, self.method_span, expr);
@@ -312,10 +310,9 @@ where
 }
 
 impl UnconditionalRecursion {
-    #[allow(clippy::unnecessary_def_path)]
     fn init_default_impl_for_type_if_needed(&mut self, cx: &LateContext<'_>) {
         if self.default_impl_for_type.is_empty()
-            && let Some(default_trait_id) = get_trait_def_id(cx, &["core", "default", "Default"])
+            && let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default)
         {
             let impls = cx.tcx.trait_impls_of(default_trait_id);
             for (ty, impl_def_ids) in impls.non_blanket_impls() {
@@ -394,6 +391,34 @@ impl UnconditionalRecursion {
     }
 }
 
+fn check_from(cx: &LateContext<'_>, method_span: Span, method_def_id: LocalDefId, expr: &Expr<'_>) {
+    let Some(sig) = cx
+        .typeck_results()
+        .liberated_fn_sigs()
+        .get(cx.tcx.local_def_id_to_hir_id(method_def_id))
+    else {
+        return;
+    };
+
+    // Check if we are calling `Into::into` where the node args match with our `From::from` signature:
+    // From::from signature: fn(S1) -> S2
+    // <S1 as Into<S2>>::into(s1), node_args=[S1, S2]
+    // If they do match, then it must mean that it is the blanket impl,
+    // which calls back into our `From::from` again (`Into` is not specializable).
+    // rustc's unconditional_recursion already catches calling `From::from` directly
+    if let Some((fn_def_id, node_args)) = fn_def_id_with_node_args(cx, expr)
+        && let [s1, s2] = **node_args
+        && let (Some(s1), Some(s2)) = (s1.as_type(), s2.as_type())
+        && let Some(trait_def_id) = cx.tcx.trait_of_item(fn_def_id)
+        && cx.tcx.is_diagnostic_item(sym::Into, trait_def_id)
+        && get_impl_trait_def_id(cx, method_def_id) == cx.tcx.get_diagnostic_item(sym::From)
+        && s1 == sig.inputs()[0]
+        && s2 == sig.output()
+    {
+        span_error(cx, method_span, expr);
+    }
+}
+
 impl<'tcx> LateLintPass<'tcx> for UnconditionalRecursion {
     fn check_fn(
         &mut self,
@@ -410,10 +435,11 @@ impl<'tcx> LateLintPass<'tcx> for UnconditionalRecursion {
             // Doesn't have a conditional return.
             && !has_conditional_return(body, expr)
         {
-            if name.name == sym::eq || name.name == sym::ne {
-                check_partial_eq(cx, method_span, method_def_id, name, expr);
-            } else if name.name == sym::to_string {
-                check_to_string(cx, method_span, method_def_id, name, expr);
+            match name.name {
+                sym::eq | sym::ne => check_partial_eq(cx, method_span, method_def_id, name, expr),
+                sym::to_string => check_to_string(cx, method_span, method_def_id, name, expr),
+                sym::from => check_from(cx, method_span, method_def_id, expr),
+                _ => {},
             }
             self.check_default_new(cx, decl, body, method_span, method_def_id);
         }
diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
index 0efa65b28e2..5fe4b74b3a7 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -158,7 +158,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
     }
 
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &hir::Stmt<'tcx>) {
-        let (hir::StmtKind::Let(&hir::Local { init: Some(expr), .. })
+        let (hir::StmtKind::Let(&hir::LetStmt { init: Some(expr), .. })
         | hir::StmtKind::Expr(expr)
         | hir::StmtKind::Semi(expr)) = stmt.kind
         else {
@@ -342,7 +342,7 @@ fn block_parents_have_safety_comment(
 ) -> bool {
     let (span, hir_id) = match cx.tcx.parent_hir_node(id) {
         Node::Expr(expr) => match cx.tcx.parent_hir_node(expr.hir_id) {
-            Node::Local(hir::Local { span, hir_id, .. }) => (*span, *hir_id),
+            Node::LetStmt(hir::LetStmt { span, hir_id, .. }) => (*span, *hir_id),
             Node::Item(hir::Item {
                 kind: hir::ItemKind::Const(..) | ItemKind::Static(..),
                 span,
@@ -358,12 +358,12 @@ fn block_parents_have_safety_comment(
         },
         Node::Stmt(hir::Stmt {
             kind:
-                hir::StmtKind::Let(hir::Local { span, hir_id, .. })
+                hir::StmtKind::Let(hir::LetStmt { span, hir_id, .. })
                 | hir::StmtKind::Expr(hir::Expr { span, hir_id, .. })
                 | hir::StmtKind::Semi(hir::Expr { span, hir_id, .. }),
             ..
         })
-        | Node::Local(hir::Local { span, hir_id, .. }) => (*span, *hir_id),
+        | Node::LetStmt(hir::LetStmt { span, hir_id, .. }) => (*span, *hir_id),
         Node::Item(hir::Item {
             kind: hir::ItemKind::Const(..) | ItemKind::Static(..),
             span,
@@ -603,7 +603,7 @@ fn get_body_search_span(cx: &LateContext<'_>) -> Option<Span> {
     for (_, node) in map.parent_iter(body.hir_id) {
         match node {
             Node::Expr(e) => span = e.span,
-            Node::Block(_) | Node::Arm(_) | Node::Stmt(_) | Node::Local(_) => (),
+            Node::Block(_) | Node::Arm(_) | Node::Stmt(_) | Node::LetStmt(_) => (),
             Node::Item(hir::Item {
                 kind: hir::ItemKind::Const(..) | ItemKind::Static(..),
                 ..
diff --git a/src/tools/clippy/clippy_lints/src/uninhabited_references.rs b/src/tools/clippy/clippy_lints/src/uninhabited_references.rs
index 6732a43a19e..88039372ebd 100644
--- a/src/tools/clippy/clippy_lints/src/uninhabited_references.rs
+++ b/src/tools/clippy/clippy_lints/src/uninhabited_references.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Body, Expr, ExprKind, FnDecl, FnRetTy, TyKind, UnOp};
-use rustc_hir_analysis::hir_ty_to_ty;
+use rustc_hir_analysis::lower_ty;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
@@ -71,7 +71,7 @@ impl LateLintPass<'_> for UninhabitedReferences {
         }
         if let FnRetTy::Return(hir_ty) = fndecl.output
             && let TyKind::Ref(_, mut_ty) = hir_ty.kind
-            && hir_ty_to_ty(cx.tcx, mut_ty.ty).is_privately_uninhabited(cx.tcx, cx.param_env)
+            && lower_ty(cx.tcx, mut_ty.ty).is_privately_uninhabited(cx.tcx, cx.param_env)
         {
             span_lint(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
index 9406d160769..ffb909d7907 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
@@ -4,14 +4,14 @@ use clippy_utils::visitors::{for_each_local_assignment, for_each_value_source};
 use core::ops::ControlFlow;
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{Expr, ExprKind, HirId, HirIdSet, Local, MatchSource, Node, PatKind, QPath, TyKind};
+use rustc_hir::{Expr, ExprKind, HirId, HirIdSet, LetStmt, MatchSource, Node, PatKind, QPath, TyKind};
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::lint::{in_external_macro, is_from_async_await};
 use rustc_middle::ty;
 
 use super::LET_UNIT_VALUE;
 
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) {
     // skip `let () = { ... }`
     if let PatKind::Tuple(fields, ..) = local.pat.kind
         && fields.is_empty()
@@ -102,7 +102,7 @@ fn expr_needs_inferred_result<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -
         return false;
     }
     while let Some(id) = locals_to_check.pop() {
-        if let Node::Local(l) = cx.tcx.parent_hir_node(id) {
+        if let Node::LetStmt(l) = cx.tcx.parent_hir_node(id) {
             if !l.ty.map_or(true, |ty| matches!(ty.kind, TyKind::Infer)) {
                 return false;
             }
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/mod.rs b/src/tools/clippy/clippy_lints/src/unit_types/mod.rs
index 0abd48e6423..e016bd3434b 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/mod.rs
@@ -3,7 +3,7 @@ mod unit_arg;
 mod unit_cmp;
 mod utils;
 
-use rustc_hir::{Expr, Local};
+use rustc_hir::{Expr, LetStmt};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 
@@ -99,7 +99,7 @@ declare_clippy_lint! {
 declare_lint_pass!(UnitTypes => [LET_UNIT_VALUE, UNIT_CMP, UNIT_ARG]);
 
 impl<'tcx> LateLintPass<'tcx> for UnitTypes {
-    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
         let_unit_value::check(cx, local);
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
index 7246214f9bf..d4dd31e1178 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -242,6 +242,8 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us
             |k| matches!(k, Box(_)),
             |k| always_pat!(k, Box(p) => p),
         ),
+        // FIXME(deref_patterns): Should we merge patterns here?
+        Deref(_) => false,
         // Transform `&mut x | ... | &mut y` into `&mut (x | y)`.
         Ref(target, Mutability::Mut) => extend_with_matching(
             target, start, alternatives,
diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
index eb64dd633f6..d8c5f1b7382 100644
--- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
@@ -1,7 +1,7 @@
-use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::macros::{is_panic, root_macro_call_first_node};
 use clippy_utils::{is_res_lang_ctor, is_trait_method, match_trait_method, paths, peel_blocks};
-use hir::{ExprKind, PatKind};
+use hir::{ExprKind, HirId, PatKind};
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
@@ -131,26 +131,26 @@ fn non_consuming_ok_arm<'a>(cx: &LateContext<'a>, arm: &hir::Arm<'a>) -> bool {
 fn check_expr<'a>(cx: &LateContext<'a>, expr: &'a hir::Expr<'a>) {
     match expr.kind {
         hir::ExprKind::If(cond, _, _)
-            if let ExprKind::Let(hir::Let { pat, init, .. }) = cond.kind
+            if let ExprKind::Let(hir::LetExpr { pat, init, .. }) = cond.kind
                 && is_ok_wild_or_dotdot_pattern(cx, pat)
                 && let Some(op) = should_lint(cx, init) =>
         {
-            emit_lint(cx, cond.span, op, &[pat.span]);
+            emit_lint(cx, cond.span, cond.hir_id, op, &[pat.span]);
         },
         // we will capture only the case where the match is Ok( ) or Err( )
         // prefer to match the minimum possible, and expand later if needed
         // to avoid false positives on something as used as this
         hir::ExprKind::Match(expr, [arm1, arm2], hir::MatchSource::Normal) if let Some(op) = should_lint(cx, expr) => {
             if non_consuming_ok_arm(cx, arm1) && non_consuming_err_arm(cx, arm2) {
-                emit_lint(cx, expr.span, op, &[arm1.pat.span]);
+                emit_lint(cx, expr.span, expr.hir_id, op, &[arm1.pat.span]);
             }
             if non_consuming_ok_arm(cx, arm2) && non_consuming_err_arm(cx, arm1) {
-                emit_lint(cx, expr.span, op, &[arm2.pat.span]);
+                emit_lint(cx, expr.span, expr.hir_id, op, &[arm2.pat.span]);
             }
         },
         hir::ExprKind::Match(_, _, hir::MatchSource::Normal) => {},
         _ if let Some(op) = should_lint(cx, expr) => {
-            emit_lint(cx, expr.span, op, &[]);
+            emit_lint(cx, expr.span, expr.hir_id, op, &[]);
         },
         _ => {},
     };
@@ -279,7 +279,7 @@ fn check_io_mode(cx: &LateContext<'_>, call: &hir::Expr<'_>) -> Option<IoOp> {
     }
 }
 
-fn emit_lint(cx: &LateContext<'_>, span: Span, op: IoOp, wild_cards: &[Span]) {
+fn emit_lint(cx: &LateContext<'_>, span: Span, at: HirId, op: IoOp, wild_cards: &[Span]) {
     let (msg, help) = match op {
         IoOp::AsyncRead(false) => (
             "read amount is not handled",
@@ -301,7 +301,7 @@ fn emit_lint(cx: &LateContext<'_>, span: Span, op: IoOp, wild_cards: &[Span]) {
         IoOp::SyncWrite(true) | IoOp::AsyncWrite(true) => ("written amount is not handled", None),
     };
 
-    span_lint_and_then(cx, UNUSED_IO_AMOUNT, span, msg, |diag| {
+    span_lint_hir_and_then(cx, UNUSED_IO_AMOUNT, at, span, msg, |diag| {
         if let Some(help_str) = help {
             diag.help(help_str);
         }
diff --git a/src/tools/clippy/clippy_lints/src/unused_peekable.rs b/src/tools/clippy/clippy_lints/src/unused_peekable.rs
index f1d0c22b1ae..e6f799335d7 100644
--- a/src/tools/clippy/clippy_lints/src/unused_peekable.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_peekable.rs
@@ -1,9 +1,9 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable};
 use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, peel_ref_operators};
 use rustc_ast::Mutability;
 use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::{Block, Expr, ExprKind, HirId, Local, Node, PatKind, PathSegment, StmtKind};
+use rustc_hir::{Block, Expr, ExprKind, HirId, LetStmt, Node, PatKind, PathSegment, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter::OnlyBodies;
 use rustc_session::declare_lint_pass;
@@ -79,13 +79,15 @@ impl<'tcx> LateLintPass<'tcx> for UnusedPeekable {
                 }
 
                 if !vis.found_peek_call {
-                    span_lint_and_help(
+                    span_lint_hir_and_then(
                         cx,
                         UNUSED_PEEKABLE,
+                        local.hir_id,
                         ident.span,
                         "`peek` never called on `Peekable` iterator",
-                        None,
-                        "consider removing the call to `peekable`",
+                        |diag| {
+                            diag.help("consider removing the call to `peekable`");
+                        },
                     );
                 }
             }
@@ -188,7 +190,7 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> {
                             },
                         }
                     },
-                    Node::Local(Local { init: Some(init), .. }) => {
+                    Node::LetStmt(LetStmt { init: Some(init), .. }) => {
                         if arg_is_mut_peekable(self.cx, init) {
                             self.found_peek_call = true;
                         }
diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs
index a1b08d105b9..a6b411d6c0f 100644
--- a/src/tools/clippy/clippy_lints/src/use_self.rs
+++ b/src/tools/clippy/clippy_lints/src/use_self.rs
@@ -8,11 +8,12 @@ use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{walk_inf, walk_ty, Visitor};
 use rustc_hir::{
-    self as hir, Expr, ExprKind, FnRetTy, FnSig, GenericArg, GenericArgsParentheses, GenericParam, GenericParamKind,
-    HirId, Impl, ImplItemKind, Item, ItemKind, Pat, PatKind, Path, QPath, Ty, TyKind,
+    self as hir, Expr, ExprKind, FnRetTy, FnSig, GenericArgsParentheses, GenericParam, GenericParamKind, HirId, Impl,
+    ImplItemKind, Item, ItemKind, Pat, PatKind, Path, QPath, Ty, TyKind,
 };
-use rustc_hir_analysis::hir_ty_to_ty;
+use rustc_hir_analysis::lower_ty;
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::Ty as MiddleTy;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 
@@ -95,10 +96,9 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
         let stack_item = if let ItemKind::Impl(Impl { self_ty, generics, .. }) = item.kind
             && let TyKind::Path(QPath::Resolved(_, item_path)) = self_ty.kind
             && let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args
-            && parameters.as_ref().map_or(true, |params| {
-                params.parenthesized == GenericArgsParentheses::No
-                    && !params.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)))
-            })
+            && parameters
+                .as_ref()
+                .map_or(true, |params| params.parenthesized == GenericArgsParentheses::No)
             && !item.span.from_expansion()
             && !is_from_proc_macro(cx, item)
         // expensive, should be last check
@@ -193,7 +193,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
     }
 
     fn check_body(&mut self, _: &LateContext<'_>, _: &hir::Body<'_>) {
-        // `hir_ty_to_ty` cannot be called in `Body`s or it will panic (sometimes). But in bodies
+        // `lower_ty` cannot be called in `Body`s or it will panic (sometimes). But in bodies
         // we can use `cx.typeck_results.node_type(..)` to get the `ty::Ty` from a `hir::Ty`.
         // However the `node_type()` method can *only* be called in bodies.
         if let Some(&mut StackItem::Check { ref mut in_body, .. }) = self.stack.last_mut() {
@@ -224,9 +224,14 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
             && let ty = if in_body > 0 {
                 cx.typeck_results().node_type(hir_ty.hir_id)
             } else {
-                hir_ty_to_ty(cx.tcx, hir_ty)
+                lower_ty(cx.tcx, hir_ty)
             }
-            && same_type_and_consts(ty, cx.tcx.type_of(impl_id).instantiate_identity())
+            && let impl_ty = cx.tcx.type_of(impl_id).instantiate_identity()
+            && same_type_and_consts(ty, impl_ty)
+            // Ensure the type we encounter and the one from the impl have the same lifetime parameters. It may be that
+            // the lifetime parameters of `ty` are ellided (`impl<'a> Foo<'a> { fn new() -> Self { Foo{..} } }`, in
+            // which case we must still trigger the lint.
+            && (has_no_lifetime(ty) || same_lifetimes(ty, impl_ty))
         {
             span_lint(cx, hir_ty.span);
         }
@@ -318,3 +323,37 @@ fn lint_path_to_variant(cx: &LateContext<'_>, path: &Path<'_>) {
         span_lint(cx, span);
     }
 }
+
+/// Returns `true` if types `a` and `b` have the same lifetime parameters, otherwise returns
+/// `false`.
+///
+/// This function does not check that types `a` and `b` are the same types.
+fn same_lifetimes<'tcx>(a: MiddleTy<'tcx>, b: MiddleTy<'tcx>) -> bool {
+    use rustc_middle::ty::{Adt, GenericArgKind};
+    match (&a.kind(), &b.kind()) {
+        (&Adt(_, args_a), &Adt(_, args_b)) => {
+            args_a
+                .iter()
+                .zip(args_b.iter())
+                .all(|(arg_a, arg_b)| match (arg_a.unpack(), arg_b.unpack()) {
+                    // TODO: Handle inferred lifetimes
+                    (GenericArgKind::Lifetime(inner_a), GenericArgKind::Lifetime(inner_b)) => inner_a == inner_b,
+                    (GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => same_lifetimes(type_a, type_b),
+                    _ => true,
+                })
+        },
+        _ => a == b,
+    }
+}
+
+/// Returns `true` if `ty` has no lifetime parameter, otherwise returns `false`.
+fn has_no_lifetime(ty: MiddleTy<'_>) -> bool {
+    use rustc_middle::ty::{Adt, GenericArgKind};
+    match ty.kind() {
+        &Adt(_, args) => !args
+            .iter()
+            // TODO: Handle inferred lifetimes
+            .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(..))),
+        _ => true,
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 187bfda129c..5319915b2ea 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -689,6 +689,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                 kind!("Box({pat})");
                 self.pat(pat);
             },
+            PatKind::Deref(pat) => {
+                bind!(self, pat);
+                kind!("Deref({pat})");
+                self.pat(pat);
+            },
             PatKind::Ref(pat, muta) => {
                 bind!(self, pat);
                 kind!("Ref({pat}, Mutability::{muta:?})");
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
index 97b509a84f9..c56c8ddc7a9 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -925,7 +925,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for LintResolver<'a, 'hir> {
             && let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(expr))
             && match_type(self.cx, expr_ty, &paths::LINT)
         {
-            if let hir::def::Res::Def(DefKind::Static(..), _) = path.res {
+            if let hir::def::Res::Def(DefKind::Static { .. }, _) = path.res {
                 let lint_name = last_path_segment(qpath).ident.name;
                 self.lints.push(sym_to_string(lint_name).to_ascii_lowercase());
             } else if let Some(local) = get_parent_local(self.cx, expr) {
@@ -1006,7 +1006,7 @@ fn get_parent_local<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -
 
 fn get_parent_local_hir_id<'hir>(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::Local<'hir>> {
     match cx.tcx.parent_hir_node(hir_id) {
-        hir::Node::Local(local) => Some(local),
+        hir::Node::LetStmt(local) => Some(local),
         hir::Node::Pat(pattern) => get_parent_local_hir_id(cx, pattern.hir_id),
         _ => None,
     }
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
index 38c832931fc..304a1379374 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
@@ -217,13 +217,13 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Ve
     match peel_hir_expr_refs(expr).0.kind {
         ExprKind::Path(ref qpath) => match cx.qpath_res(qpath, expr.hir_id) {
             Res::Local(hir_id) => {
-                if let Node::Local(Local { init: Some(init), .. }) = cx.tcx.parent_hir_node(hir_id) {
+                if let Node::LetStmt(Local { init: Some(init), .. }) = cx.tcx.parent_hir_node(hir_id) {
                     path_to_matched_type(cx, init)
                 } else {
                     None
                 }
             },
-            Res::Def(DefKind::Static(_), def_id) => read_mir_alloc_def_path(
+            Res::Def(DefKind::Static { .. }, def_id) => read_mir_alloc_def_path(
                 cx,
                 cx.tcx.eval_static_initializer(def_id).ok()?.inner(),
                 cx.tcx.type_of(def_id).instantiate_identity(),
diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs
index 7cfcf3fe946..27ead55bf39 100644
--- a/src/tools/clippy/clippy_lints/src/vec.rs
+++ b/src/tools/clippy/clippy_lints/src/vec.rs
@@ -9,7 +9,7 @@ use clippy_utils::ty::is_copy;
 use clippy_utils::visitors::for_each_local_use_after_expr;
 use clippy_utils::{get_parent_expr, higher, is_trait_method};
 use rustc_errors::Applicability;
-use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, Local, Mutability, Node, Pat, PatKind};
+use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, LetStmt, Mutability, Node, Pat, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_middle::ty::layout::LayoutOf;
@@ -63,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
         match cx.tcx.parent_hir_node(expr.hir_id) {
             // search for `let foo = vec![_]` expressions where all uses of `foo`
             // adjust to slices or call a method that exist on slices (e.g. len)
-            Node::Local(Local {
+            Node::LetStmt(LetStmt {
                 ty: None,
                 pat:
                     Pat {
@@ -93,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
                 }
             },
             // if the local pattern has a specified type, do not lint.
-            Node::Local(Local { ty: Some(_), .. }) if higher::VecArgs::hir(cx, expr).is_some() => {
+            Node::LetStmt(LetStmt { ty: Some(_), .. }) if higher::VecArgs::hir(cx, expr).is_some() => {
                 self.span_to_lint_map.insert(callsite, None);
             },
             // search for `for _ in vec![...]`
diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
index ac3b2bdaf65..b58a4fb8474 100644
--- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
+++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
@@ -7,7 +7,7 @@ use core::ops::ControlFlow;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{
-    BindingAnnotation, Block, Expr, ExprKind, HirId, Local, Mutability, PatKind, QPath, Stmt, StmtKind, UnOp,
+    BindingAnnotation, Block, Expr, ExprKind, HirId, LetStmt, Mutability, PatKind, QPath, Stmt, StmtKind, UnOp,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
@@ -157,7 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush {
         self.searcher = None;
     }
 
-    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
         if let Some(init_expr) = local.init
             && let PatKind::Binding(BindingAnnotation::MUT, id, name, None) = local.pat.kind
             && !in_external_macro(cx.sess(), local.span)
diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
index 5410e8ac117..436f0cb79fb 100644
--- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
@@ -213,7 +213,7 @@ fn is_super_only_import(segments: &[PathSegment<'_>]) -> bool {
 // Allow skipping imports containing user configured segments,
 // i.e. "...::utils::...::*" if user put `allowed-wildcard-imports = ["utils"]` in `Clippy.toml`
 fn is_allowed_via_config(segments: &[PathSegment<'_>], allowed_segments: &FxHashSet<String>) -> bool {
-    // segment matching need to be exact instead of using 'contains', in case user unintentionaly put
+    // segment matching need to be exact instead of using 'contains', in case user unintentionally put
     // a single character in the config thus skipping most of the warnings.
     segments.iter().any(|seg| allowed_segments.contains(seg.ident.as_str()))
 }
diff --git a/src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs b/src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs
new file mode 100644
index 00000000000..143fecdd237
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs
@@ -0,0 +1,154 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::higher::VecArgs;
+use clippy_utils::source::snippet;
+use clippy_utils::visitors::for_each_expr;
+use rustc_ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{ExprKind, Node};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::{self, ConstKind, Ty};
+use rustc_session::declare_lint_pass;
+use rustc_span::Span;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for array or vec initializations which call a function or method,
+    /// but which have a repeat count of zero.
+    ///
+    /// ### Why is this bad?
+    /// Such an initialization, despite having a repeat length of 0, will still call the inner function.
+    /// This may not be obvious and as such there may be unintended side effects in code.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// fn side_effect() -> i32 {
+    ///     println!("side effect");
+    ///     10
+    /// }
+    /// let a = [side_effect(); 0];
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// fn side_effect() -> i32 {
+    ///     println!("side effect");
+    ///     10
+    /// }
+    /// side_effect();
+    /// let a: [i32; 0] = [];
+    /// ```
+    #[clippy::version = "1.75.0"]
+    pub ZERO_REPEAT_SIDE_EFFECTS,
+    suspicious,
+    "usage of zero-sized initializations of arrays or vecs causing side effects"
+}
+
+declare_lint_pass!(ZeroRepeatSideEffects => [ZERO_REPEAT_SIDE_EFFECTS]);
+
+impl LateLintPass<'_> for ZeroRepeatSideEffects {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ rustc_hir::Expr<'_>) {
+        if let Some(args) = VecArgs::hir(cx, expr)
+            && let VecArgs::Repeat(inner_expr, len) = args
+            && let ExprKind::Lit(l) = len.kind
+            && let LitKind::Int(i, _) = l.node
+            && i.0 == 0
+        {
+            inner_check(cx, expr, inner_expr, true);
+        } else if let ExprKind::Repeat(inner_expr, _) = expr.kind
+            && let ty::Array(_, cst) = cx.typeck_results().expr_ty(expr).kind()
+            && let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind()
+            && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx)
+            && element_count == 0
+        {
+            inner_check(cx, expr, inner_expr, false);
+        }
+    }
+}
+
+fn inner_check(cx: &LateContext<'_>, expr: &'_ rustc_hir::Expr<'_>, inner_expr: &'_ rustc_hir::Expr<'_>, is_vec: bool) {
+    // check if expr is a call or has a call inside it
+    if for_each_expr(inner_expr, |x| {
+        if let ExprKind::Call(_, _) | ExprKind::MethodCall(_, _, _, _) = x.kind {
+            std::ops::ControlFlow::Break(())
+        } else {
+            std::ops::ControlFlow::Continue(())
+        }
+    })
+    .is_some()
+    {
+        let parent_hir_node = cx.tcx.parent_hir_node(expr.hir_id);
+        let return_type = cx.typeck_results().expr_ty(expr);
+
+        if let Node::LetStmt(l) = parent_hir_node {
+            array_span_lint(
+                cx,
+                l.span,
+                inner_expr.span,
+                l.pat.span,
+                Some(return_type),
+                is_vec,
+                false,
+            );
+        } else if let Node::Expr(x) = parent_hir_node
+            && let ExprKind::Assign(l, _, _) = x.kind
+        {
+            array_span_lint(cx, x.span, inner_expr.span, l.span, Some(return_type), is_vec, true);
+        } else {
+            span_lint_and_sugg(
+                cx,
+                ZERO_REPEAT_SIDE_EFFECTS,
+                expr.span.source_callsite(),
+                "function or method calls as the initial value in zero-sized array initializers may cause side effects",
+                "consider using",
+                format!(
+                    "{{ {}; {}[] as {return_type} }}",
+                    snippet(cx, inner_expr.span.source_callsite(), ".."),
+                    if is_vec { "vec!" } else { "" },
+                ),
+                Applicability::Unspecified,
+            );
+        }
+    }
+}
+
+fn array_span_lint(
+    cx: &LateContext<'_>,
+    expr_span: Span,
+    func_call_span: Span,
+    variable_name_span: Span,
+    expr_ty: Option<Ty<'_>>,
+    is_vec: bool,
+    is_assign: bool,
+) {
+    let has_ty = expr_ty.is_some();
+
+    span_lint_and_sugg(
+        cx,
+        ZERO_REPEAT_SIDE_EFFECTS,
+        expr_span.source_callsite(),
+        "function or method calls as the initial value in zero-sized array initializers may cause side effects",
+        "consider using",
+        format!(
+            "{}; {}{}{} = {}[]{}{}",
+            snippet(cx, func_call_span.source_callsite(), ".."),
+            if has_ty && !is_assign { "let " } else { "" },
+            snippet(cx, variable_name_span.source_callsite(), ".."),
+            if let Some(ty) = expr_ty
+                && !is_assign
+            {
+                format!(": {ty}")
+            } else {
+                String::new()
+            },
+            if is_vec { "vec!" } else { "" },
+            if let Some(ty) = expr_ty
+                && is_assign
+            {
+                format!(" as {ty}")
+            } else {
+                String::new()
+            },
+            if is_assign { "" } else { ";" }
+        ),
+        Applicability::Unspecified,
+    );
+}
diff --git a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
index 4aaf3b0a0b6..d1f7c6417c7 100644
--- a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::ty::{is_normalizable, is_type_diagnostic_item};
 use rustc_hir::{self as hir, HirId, ItemKind, Node};
-use rustc_hir_analysis::hir_ty_to_ty;
+use rustc_hir_analysis::lower_ty;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::layout::LayoutOf as _;
 use rustc_middle::ty::{Adt, Ty, TypeVisitableExt};
@@ -91,5 +91,5 @@ fn ty_from_hir_ty<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'t
                 None
             }
         })
-        .unwrap_or_else(|| hir_ty_to_ty(cx.tcx, hir_ty))
+        .unwrap_or_else(|| lower_ty(cx.tcx, hir_ty))
 }
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index bf55040ddbc..d2bb719a517 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_utils"
-version = "0.1.78"
+version = "0.1.79"
 edition = "2021"
 publish = false
 
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index 3874c1169e4..f7532121aeb 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -198,7 +198,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
         },
         (AssignOp(lo, lp, lv), AssignOp(ro, rp, rv)) => lo.node == ro.node && eq_expr(lp, rp) && eq_expr(lv, rv),
         (Field(lp, lf), Field(rp, rf)) => eq_id(*lf, *rf) && eq_expr(lp, rp),
-        (Match(ls, la), Match(rs, ra)) => eq_expr(ls, rs) && over(la, ra, eq_arm),
+        (Match(ls, la, lkind), Match(rs, ra, rkind)) => (lkind == rkind) && eq_expr(ls, rs) && over(la, ra, eq_arm),
         (
             Closure(box ast::Closure {
                 binder: lb,
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index e75d5953fae..6b86630339f 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -10,8 +10,10 @@ use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item
 use rustc_lexer::tokenize;
 use rustc_lint::LateContext;
 use rustc_middle::mir::interpret::{alloc_range, Scalar};
+use rustc_middle::mir::ConstValue;
 use rustc_middle::ty::{self, EarlyBinder, FloatTy, GenericArgsRef, IntTy, List, ScalarInt, Ty, TyCtxt, UintTy};
 use rustc_middle::{bug, mir, span_bug};
+use rustc_span::def_id::DefId;
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::SyntaxContext;
 use rustc_target::abi::Size;
@@ -307,6 +309,12 @@ impl ConstantSource {
     }
 }
 
+/// Attempts to check whether the expression is a constant representing an empty slice, str, array,
+/// etc…
+pub fn constant_is_empty(lcx: &LateContext<'_>, e: &Expr<'_>) -> Option<bool> {
+    ConstEvalLateContext::new(lcx, lcx.typeck_results()).expr_is_empty(e)
+}
+
 /// Attempts to evaluate the expression as a constant.
 pub fn constant<'tcx>(
     lcx: &LateContext<'tcx>,
@@ -406,7 +414,13 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
         match e.kind {
             ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.lcx.tcx.hir().body(body).value),
             ExprKind::DropTemps(e) => self.expr(e),
-            ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)),
+            ExprKind::Path(ref qpath) => {
+                self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.expr_ty(e), |this, result| {
+                    let result = mir_to_const(this.lcx, result)?;
+                    this.source = ConstantSource::Constant;
+                    Some(result)
+                })
+            },
             ExprKind::Block(block, _) => self.block(block),
             ExprKind::Lit(lit) => {
                 if is_direct_expn_of(e.span, "cfg").is_some() {
@@ -472,6 +486,49 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
         }
     }
 
+    /// Simple constant folding to determine if an expression is an empty slice, str, array, …
+    /// `None` will be returned if the constness cannot be determined, or if the resolution
+    /// leaves the local crate.
+    pub fn expr_is_empty(&mut self, e: &Expr<'_>) -> Option<bool> {
+        match e.kind {
+            ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr_is_empty(self.lcx.tcx.hir().body(body).value),
+            ExprKind::DropTemps(e) => self.expr_is_empty(e),
+            ExprKind::Path(ref qpath) => {
+                if !self
+                    .typeck_results
+                    .qpath_res(qpath, e.hir_id)
+                    .opt_def_id()
+                    .is_some_and(DefId::is_local)
+                {
+                    return None;
+                }
+                self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.expr_ty(e), |this, result| {
+                    mir_is_empty(this.lcx, result)
+                })
+            },
+            ExprKind::Lit(lit) => {
+                if is_direct_expn_of(e.span, "cfg").is_some() {
+                    None
+                } else {
+                    match &lit.node {
+                        LitKind::Str(is, _) => Some(is.is_empty()),
+                        LitKind::ByteStr(s, _) | LitKind::CStr(s, _) => Some(s.is_empty()),
+                        _ => None,
+                    }
+                }
+            },
+            ExprKind::Array(vec) => self.multi(vec).map(|v| v.is_empty()),
+            ExprKind::Repeat(..) => {
+                if let ty::Array(_, n) = self.typeck_results.expr_ty(e).kind() {
+                    Some(n.try_eval_target_usize(self.lcx.tcx, self.lcx.param_env)? == 0)
+                } else {
+                    span_bug!(e.span, "typeck error");
+                }
+            },
+            _ => None,
+        }
+    }
+
     #[expect(clippy::cast_possible_wrap)]
     fn constant_not(&self, o: &Constant<'tcx>, ty: Ty<'_>) -> Option<Constant<'tcx>> {
         use self::Constant::{Bool, Int};
@@ -519,8 +576,11 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
         vec.iter().map(|elem| self.expr(elem)).collect::<Option<_>>()
     }
 
-    /// Lookup a possibly constant expression from an `ExprKind::Path`.
-    fn fetch_path(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>) -> Option<Constant<'tcx>> {
+    /// Lookup a possibly constant expression from an `ExprKind::Path` and apply a function on it.
+    fn fetch_path_and_apply<T, F>(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>, f: F) -> Option<T>
+    where
+        F: FnOnce(&mut Self, rustc_middle::mir::Const<'tcx>) -> Option<T>,
+    {
         let res = self.typeck_results.qpath_res(qpath, id);
         match res {
             Res::Def(DefKind::Const | DefKind::AssocConst, def_id) => {
@@ -553,9 +613,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
                     .const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), qpath.span())
                     .ok()
                     .map(|val| rustc_middle::mir::Const::from_value(val, ty))?;
-                let result = mir_to_const(self.lcx, result)?;
-                self.source = ConstantSource::Constant;
-                Some(result)
+                f(self, result)
             },
             _ => None,
         }
@@ -746,7 +804,6 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
 }
 
 pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option<Constant<'tcx>> {
-    use rustc_middle::mir::ConstValue;
     let mir::Const::Val(val, _) = result else {
         // We only work on evaluated consts.
         return None;
@@ -762,7 +819,7 @@ pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) ->
             ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits(
                 int.try_into().expect("invalid f64 bit representation"),
             ))),
-            ty::RawPtr(_) => Some(Constant::RawPtr(int.assert_bits(int.size()))),
+            ty::RawPtr(_, _) => Some(Constant::RawPtr(int.assert_bits(int.size()))),
             _ => None,
         },
         (_, ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Str) => {
@@ -794,6 +851,42 @@ pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) ->
     }
 }
 
+fn mir_is_empty<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option<bool> {
+    let mir::Const::Val(val, _) = result else {
+        // We only work on evaluated consts.
+        return None;
+    };
+    match (val, result.ty().kind()) {
+        (_, ty::Ref(_, inner_ty, _)) => match inner_ty.kind() {
+            ty::Str | ty::Slice(_) => {
+                if let ConstValue::Indirect { alloc_id, offset } = val {
+                    // Get the length from the slice, using the same formula as
+                    // [`ConstValue::try_get_slice_bytes_for_diagnostics`].
+                    let a = lcx.tcx.global_alloc(alloc_id).unwrap_memory().inner();
+                    let ptr_size = lcx.tcx.data_layout.pointer_size;
+                    if a.size() < offset + 2 * ptr_size {
+                        // (partially) dangling reference
+                        return None;
+                    }
+                    let len = a
+                        .read_scalar(&lcx.tcx, alloc_range(offset + ptr_size, ptr_size), false)
+                        .ok()?
+                        .to_target_usize(&lcx.tcx)
+                        .ok()?;
+                    Some(len == 0)
+                } else {
+                    None
+                }
+            },
+            ty::Array(_, len) => Some(len.try_to_target_usize(lcx.tcx)? == 0),
+            _ => None,
+        },
+        (ConstValue::Indirect { .. }, ty::Array(_, len)) => Some(len.try_to_target_usize(lcx.tcx)? == 0),
+        (ConstValue::ZeroSized, _) => Some(true),
+        _ => None,
+    }
+}
+
 fn field_of_struct<'tcx>(
     adt_def: ty::AdtDef<'tcx>,
     lcx: &LateContext<'tcx>,
diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs
index 6ed46e5dde0..0352696f93e 100644
--- a/src/tools/clippy/clippy_utils/src/diagnostics.rs
+++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs
@@ -36,6 +36,20 @@ fn docs_link(diag: &mut Diag<'_, ()>, lint: &'static Lint) {
 /// Usually it's nicer to provide more context for lint messages.
 /// Be sure the output is understandable when you use this method.
 ///
+/// NOTE: Lint emissions are always bound to a node in the HIR, which is used to determine
+/// the lint level.
+/// For the `span_lint` function, the node that was passed into the `LintPass::check_*` function is
+/// used.
+///
+/// If you're emitting the lint at the span of a different node than the one provided by the
+/// `LintPass::check_*` function, consider using [`span_lint_hir`] instead.
+/// This is needed for `#[allow]` and `#[expect]` attributes to work on the node
+/// highlighted in the displayed warning.
+///
+/// If you're unsure which function you should use, you can test if the `#[allow]` attribute works
+/// where you would expect it to.
+/// If it doesn't, you likely need to use [`span_lint_hir`] instead.
+///
 /// # Example
 ///
 /// ```ignore
@@ -61,6 +75,20 @@ pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<Mult
 ///
 /// If you change the signature, remember to update the internal lint `CollapsibleCalls`
 ///
+/// NOTE: Lint emissions are always bound to a node in the HIR, which is used to determine
+/// the lint level.
+/// For the `span_lint_and_help` function, the node that was passed into the `LintPass::check_*`
+/// function is used.
+///
+/// If you're emitting the lint at the span of a different node than the one provided by the
+/// `LintPass::check_*` function, consider using [`span_lint_hir_and_then`] instead.
+/// This is needed for `#[allow]` and `#[expect]` attributes to work on the node
+/// highlighted in the displayed warning.
+///
+/// If you're unsure which function you should use, you can test if the `#[allow]` attribute works
+/// where you would expect it to.
+/// If it doesn't, you likely need to use [`span_lint_hir_and_then`] instead.
+///
 /// # Example
 ///
 /// ```text
@@ -99,6 +127,20 @@ pub fn span_lint_and_help<T: LintContext>(
 ///
 /// If you change the signature, remember to update the internal lint `CollapsibleCalls`
 ///
+/// NOTE: Lint emissions are always bound to a node in the HIR, which is used to determine
+/// the lint level.
+/// For the `span_lint_and_note` function, the node that was passed into the `LintPass::check_*`
+/// function is used.
+///
+/// If you're emitting the lint at the span of a different node than the one provided by the
+/// `LintPass::check_*` function, consider using [`span_lint_hir_and_then`] instead.
+/// This is needed for `#[allow]` and `#[expect]` attributes to work on the node
+/// highlighted in the displayed warning.
+///
+/// If you're unsure which function you should use, you can test if the `#[allow]` attribute works
+/// where you would expect it to.
+/// If it doesn't, you likely need to use [`span_lint_hir_and_then`] instead.
+///
 /// # Example
 ///
 /// ```text
@@ -139,6 +181,20 @@ pub fn span_lint_and_note<T: LintContext>(
 ///
 /// If you need to customize your lint output a lot, use this function.
 /// If you change the signature, remember to update the internal lint `CollapsibleCalls`
+///
+/// NOTE: Lint emissions are always bound to a node in the HIR, which is used to determine
+/// the lint level.
+/// For the `span_lint_and_then` function, the node that was passed into the `LintPass::check_*`
+/// function is used.
+///
+/// If you're emitting the lint at the span of a different node than the one provided by the
+/// `LintPass::check_*` function, consider using [`span_lint_hir_and_then`] instead.
+/// This is needed for `#[allow]` and `#[expect]` attributes to work on the node
+/// highlighted in the displayed warning.
+///
+/// If you're unsure which function you should use, you can test if the `#[allow]` attribute works
+/// where you would expect it to.
+/// If it doesn't, you likely need to use [`span_lint_hir_and_then`] instead.
 pub fn span_lint_and_then<C, S, F>(cx: &C, lint: &'static Lint, sp: S, msg: &str, f: F)
 where
     C: LintContext,
@@ -152,6 +208,30 @@ where
     });
 }
 
+/// Like [`span_lint`], but emits the lint at the node identified by the given `HirId`.
+///
+/// This is in contrast to [`span_lint`], which always emits the lint at the node that was last
+/// passed to the `LintPass::check_*` function.
+///
+/// The `HirId` is used for checking lint level attributes and to fulfill lint expectations defined
+/// via the `#[expect]` attribute.
+///
+/// For example:
+/// ```ignore
+/// fn f() { /* <node_1> */
+///
+///     #[allow(clippy::some_lint)]
+///     let _x = /* <expr_1> */;
+/// }
+/// ```
+/// If `some_lint` does its analysis in `LintPass::check_fn` (at `<node_1>`) and emits a lint at
+/// `<expr_1>` using [`span_lint`], then allowing the lint at `<expr_1>` as attempted in the snippet
+/// will not work!
+/// Even though that is where the warning points at, which would be confusing to users.
+///
+/// Instead, use this function and also pass the `HirId` of `<expr_1>`, which will let
+/// the compiler check lint level attributes at the place of the expression and
+/// the `#[allow]` will work.
 pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: &str) {
     #[expect(clippy::disallowed_methods)]
     cx.tcx.node_span_lint(lint, hir_id, sp, msg.to_string(), |diag| {
@@ -159,6 +239,30 @@ pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, s
     });
 }
 
+/// Like [`span_lint_and_then`], but emits the lint at the node identified by the given `HirId`.
+///
+/// This is in contrast to [`span_lint_and_then`], which always emits the lint at the node that was
+/// last passed to the `LintPass::check_*` function.
+///
+/// The `HirId` is used for checking lint level attributes and to fulfill lint expectations defined
+/// via the `#[expect]` attribute.
+///
+/// For example:
+/// ```ignore
+/// fn f() { /* <node_1> */
+///
+///     #[allow(clippy::some_lint)]
+///     let _x = /* <expr_1> */;
+/// }
+/// ```
+/// If `some_lint` does its analysis in `LintPass::check_fn` (at `<node_1>`) and emits a lint at
+/// `<expr_1>` using [`span_lint`], then allowing the lint at `<expr_1>` as attempted in the snippet
+/// will not work!
+/// Even though that is where the warning points at, which would be confusing to users.
+///
+/// Instead, use this function and also pass the `HirId` of `<expr_1>`, which will let
+/// the compiler check lint level attributes at the place of the expression and
+/// the `#[allow]` will work.
 pub fn span_lint_hir_and_then(
     cx: &LateContext<'_>,
     lint: &'static Lint,
@@ -182,6 +286,20 @@ pub fn span_lint_hir_and_then(
 ///
 /// If you change the signature, remember to update the internal lint `CollapsibleCalls`
 ///
+/// NOTE: Lint emissions are always bound to a node in the HIR, which is used to determine
+/// the lint level.
+/// For the `span_lint_and_sugg` function, the node that was passed into the `LintPass::check_*`
+/// function is used.
+///
+/// If you're emitting the lint at the span of a different node than the one provided by the
+/// `LintPass::check_*` function, consider using [`span_lint_hir_and_then`] instead.
+/// This is needed for `#[allow]` and `#[expect]` attributes to work on the node
+/// highlighted in the displayed warning.
+///
+/// If you're unsure which function you should use, you can test if the `#[allow]` attribute works
+/// where you would expect it to.
+/// If it doesn't, you likely need to use [`span_lint_hir_and_then`] instead.
+///
 /// # Example
 ///
 /// ```text
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index ba682813dad..8ce19998a08 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -102,7 +102,7 @@ impl<'hir> IfLet<'hir> {
         if let ExprKind::If(
             Expr {
                 kind:
-                    ExprKind::Let(&hir::Let {
+                    ExprKind::Let(&hir::LetExpr {
                         pat: let_pat,
                         init: let_expr,
                         span: let_span,
@@ -379,7 +379,7 @@ impl<'hir> WhileLet<'hir> {
                             ExprKind::If(
                                 Expr {
                                     kind:
-                                        ExprKind::Let(&hir::Let {
+                                        ExprKind::Let(&hir::LetExpr {
                                             pat: let_pat,
                                             init: let_expr,
                                             span: let_span,
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 106d1d0d77f..7a4eba9790e 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -8,7 +8,7 @@ use rustc_hir::def::Res;
 use rustc_hir::MatchSource::TryDesugar;
 use rustc_hir::{
     ArrayLen, BinOpKind, BindingAnnotation, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, GenericArg,
-    GenericArgs, HirId, HirIdMap, InlineAsmOperand, Let, Lifetime, LifetimeName, Pat, PatField, PatKind, Path,
+    GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName, Pat, PatField, PatKind, Path,
     PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding,
 };
 use rustc_lexer::{tokenize, TokenKind};
@@ -837,7 +837,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                     }
                 }
             },
-            ExprKind::Let(Let { pat, init, ty, .. }) => {
+            ExprKind::Let(LetExpr { pat, init, ty, .. }) => {
                 self.hash_expr(init);
                 if let Some(ty) = ty {
                     self.hash_ty(ty);
@@ -955,6 +955,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 }
             },
             PatKind::Box(pat) => self.hash_pat(pat),
+            PatKind::Deref(pat) => self.hash_pat(pat),
             PatKind::Lit(expr) => self.hash_expr(expr),
             PatKind::Or(pats) => {
                 for pat in pats {
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index a38db0ebec0..3b1b99caebe 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -99,7 +99,7 @@ use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
 use rustc_hir::{
     self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Destination, Expr,
     ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, Item,
-    ItemKind, LangItem, Local, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy,
+    ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy,
     QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp,
 };
 use rustc_lexer::{tokenize, TokenKind};
@@ -112,7 +112,7 @@ use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::{
     self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, FloatTy, GenericArgsRef, IntTy, ParamEnv,
-    ParamEnvAnd, Ty, TyCtxt, TypeAndMut, TypeVisitableExt, UintTy, UpvarCapture,
+    ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt, UintTy, UpvarCapture,
 };
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::SourceMap;
@@ -184,7 +184,7 @@ pub fn expr_or_init<'a, 'b, 'tcx: 'b>(cx: &LateContext<'tcx>, mut expr: &'a Expr
 pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> {
     if let Node::Pat(pat) = cx.tcx.hir_node(hir_id)
         && matches!(pat.kind, PatKind::Binding(BindingAnnotation::NONE, ..))
-        && let Node::Local(local) = cx.tcx.parent_hir_node(hir_id)
+        && let Node::LetStmt(local) = cx.tcx.parent_hir_node(hir_id)
     {
         return local.init;
     }
@@ -1040,7 +1040,7 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind {
             .get(child_id)
             .map_or(&[][..], |x| &**x)
         {
-            if let rustc_ty::RawPtr(TypeAndMut { mutbl: mutability, .. }) | rustc_ty::Ref(_, _, mutability) =
+            if let rustc_ty::RawPtr(_, mutability) | rustc_ty::Ref(_, _, mutability) =
                 *adjust.last().map_or(target, |a| a.target).kind()
             {
                 return CaptureKind::Ref(mutability);
@@ -1079,7 +1079,7 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind {
                 },
                 _ => break,
             },
-            Node::Local(l) => match pat_capture_kind(cx, l.pat) {
+            Node::LetStmt(l) => match pat_capture_kind(cx, l.pat) {
                 CaptureKind::Value => break,
                 capture @ CaptureKind::Ref(_) => return capture,
             },
@@ -1357,7 +1357,7 @@ pub fn get_enclosing_loop_or_multi_call_closure<'tcx>(
                 ExprKind::Closure { .. } | ExprKind::Loop(..) => return Some(e),
                 _ => (),
             },
-            Node::Stmt(_) | Node::Block(_) | Node::Local(_) | Node::Arm(_) => (),
+            Node::Stmt(_) | Node::Block(_) | Node::LetStmt(_) | Node::Arm(_) => (),
             _ => break,
         }
     }
@@ -1462,7 +1462,7 @@ pub fn is_else_clause(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
 pub fn is_inside_let_else(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
     let mut child_id = expr.hir_id;
     for (parent_id, node) in tcx.hir().parent_iter(child_id) {
-        if let Node::Local(Local {
+        if let Node::LetStmt(LetStmt {
             init: Some(init),
             els: Some(els),
             ..
@@ -1482,7 +1482,7 @@ pub fn is_inside_let_else(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
 pub fn is_else_clause_in_let_else(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
     let mut child_id = expr.hir_id;
     for (parent_id, node) in tcx.hir().parent_iter(child_id) {
-        if let Node::Local(Local { els: Some(els), .. }) = node
+        if let Node::LetStmt(LetStmt { els: Some(els), .. }) = node
             && els.hir_id == child_id
         {
             return true;
@@ -1678,7 +1678,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
     match pat.kind {
         PatKind::Wild | PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable.
         PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)),
-        PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
+        PatKind::Box(pat) | PatKind::Deref(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
         PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id),
         PatKind::Or(pats) => {
             // TODO: should be the honest check, that pats is exhaustive set
@@ -2158,7 +2158,7 @@ pub fn is_expr_used_or_unified(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
             Node::Stmt(Stmt {
                 kind: StmtKind::Expr(_)
                     | StmtKind::Semi(_)
-                    | StmtKind::Let(Local {
+                    | StmtKind::Let(LetStmt {
                         pat: Pat {
                             kind: PatKind::Wild,
                             ..
@@ -2246,8 +2246,21 @@ pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool {
 
 /// Returns the `DefId` of the callee if the given expression is a function or method call.
 pub fn fn_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<DefId> {
+    fn_def_id_with_node_args(cx, expr).map(|(did, _)| did)
+}
+
+/// Returns the `DefId` of the callee if the given expression is a function or method call,
+/// as well as its node args.
+pub fn fn_def_id_with_node_args<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &Expr<'_>,
+) -> Option<(DefId, rustc_ty::GenericArgsRef<'tcx>)> {
+    let typeck = cx.typeck_results();
     match &expr.kind {
-        ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(expr.hir_id),
+        ExprKind::MethodCall(..) => Some((
+            typeck.type_dependent_def_id(expr.hir_id)?,
+            typeck.node_args(expr.hir_id),
+        )),
         ExprKind::Call(
             Expr {
                 kind: ExprKind::Path(qpath),
@@ -2259,9 +2272,9 @@ pub fn fn_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<DefId> {
             // Only return Fn-like DefIds, not the DefIds of statics/consts/etc that contain or
             // deref to fn pointers, dyn Fn, impl Fn - #8850
             if let Res::Def(DefKind::Fn | DefKind::Ctor(..) | DefKind::AssocFn, id) =
-                cx.typeck_results().qpath_res(qpath, *path_hir_id)
+                typeck.qpath_res(qpath, *path_hir_id)
             {
-                Some(id)
+                Some((id, typeck.node_args(*path_hir_id)))
             } else {
                 None
             }
@@ -2626,7 +2639,7 @@ pub struct ExprUseCtxt<'tcx> {
 /// The node which consumes a value.
 pub enum ExprUseNode<'tcx> {
     /// Assignment to, or initializer for, a local
-    Local(&'tcx Local<'tcx>),
+    LetStmt(&'tcx LetStmt<'tcx>),
     /// Initializer for a const or static item.
     ConstStatic(OwnerId),
     /// Implicit or explicit return from a function.
@@ -2658,7 +2671,7 @@ impl<'tcx> ExprUseNode<'tcx> {
     /// Gets the needed type as it's defined without any type inference.
     pub fn defined_ty(&self, cx: &LateContext<'tcx>) -> Option<DefinedTy<'tcx>> {
         match *self {
-            Self::Local(Local { ty: Some(ty), .. }) => Some(DefinedTy::Hir(ty)),
+            Self::LetStmt(LetStmt { ty: Some(ty), .. }) => Some(DefinedTy::Hir(ty)),
             Self::ConstStatic(id) => Some(DefinedTy::Mir(
                 cx.param_env
                     .and(Binder::dummy(cx.tcx.type_of(id).instantiate_identity())),
@@ -2718,7 +2731,7 @@ impl<'tcx> ExprUseNode<'tcx> {
                 let sig = cx.tcx.fn_sig(id).skip_binder();
                 Some(DefinedTy::Mir(cx.tcx.param_env(id).and(sig.input(i))))
             },
-            Self::Local(_) | Self::FieldAccess(..) | Self::Callee | Self::Expr | Self::Other => None,
+            Self::LetStmt(_) | Self::FieldAccess(..) | Self::Callee | Self::Expr | Self::Other => None,
         }
     }
 }
@@ -2757,7 +2770,7 @@ pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> Optio
     .continue_value()
     .map(|(use_node, child_id)| {
         let node = match use_node {
-            Node::Local(l) => ExprUseNode::Local(l),
+            Node::LetStmt(l) => ExprUseNode::LetStmt(l),
             Node::ExprField(field) => ExprUseNode::Field(field),
 
             Node::Item(&Item {
@@ -3145,7 +3158,7 @@ pub fn is_never_expr<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option<
             }
         }
 
-        fn visit_local(&mut self, l: &'tcx Local<'_>) {
+        fn visit_local(&mut self, l: &'tcx LetStmt<'_>) {
             if let Some(e) = l.init {
                 self.visit_expr(e);
             }
@@ -3222,7 +3235,7 @@ fn get_path_to_ty<'tcx>(tcx: TyCtxt<'tcx>, from: LocalDefId, ty: Ty<'tcx>, args:
         rustc_ty::Array(..)
         | rustc_ty::Dynamic(..)
         | rustc_ty::Never
-        | rustc_ty::RawPtr(_)
+        | rustc_ty::RawPtr(_, _)
         | rustc_ty::Ref(..)
         | rustc_ty::Slice(_)
         | rustc_ty::Tuple(_) => format!("<{}>", EarlyBinder::bind(ty).instantiate(tcx, args)),
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index 987f28192a8..456b8019e95 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -19,6 +19,8 @@ pub const BTREESET_ITER: [&str; 6] = ["alloc", "collections", "btree", "set", "B
 pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"];
 pub const CORE_ITER_CLONED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "cloned"];
 pub const CORE_ITER_COPIED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "copied"];
+pub const CORE_ITER_ENUMERATE_METHOD: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "enumerate"];
+pub const CORE_ITER_ENUMERATE_STRUCT: [&str; 5] = ["core", "iter", "adapters", "enumerate", "Enumerate"];
 pub const CORE_ITER_FILTER: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "filter"];
 pub const CORE_RESULT_OK_METHOD: [&str; 4] = ["core", "result", "Result", "ok"];
 pub const CSTRING_AS_C_STR: [&str; 5] = ["alloc", "ffi", "c_str", "CString", "as_c_str"];
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 dadb0d662ce..cabebf89bec 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
@@ -174,7 +174,7 @@ fn check_rvalue<'tcx>(
                 ))
             }
         },
-        Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_) | NullOp::UbCheck(_), _)
+        Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_) | NullOp::UbChecks, _)
         | Rvalue::ShallowInitBox(_, _) => Ok(()),
         Rvalue::UnaryOp(_, operand) => {
             let ty = operand.ty(body, tcx);
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 6e011a28bb7..97ce755adbb 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -96,7 +96,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'
                         return false;
                     }
 
-                    for (predicate, _span) in cx.tcx.explicit_item_bounds(def_id).instantiate_identity_iter_copied() {
+                    for (predicate, _span) in cx.tcx.explicit_item_super_predicates(def_id).instantiate_identity_iter_copied() {
                         match predicate.kind().skip_binder() {
                             // For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
                             // and check substitutions to find `U`.
@@ -321,14 +321,14 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
     match ty.kind() {
         ty::Adt(adt, _) => cx.tcx.has_attr(adt.did(), sym::must_use),
         ty::Foreign(did) => cx.tcx.has_attr(*did, sym::must_use),
-        ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => {
+        ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty, _) | ty::Ref(_, ty, _) => {
             // for the Array case we don't need to care for the len == 0 case
             // because we don't want to lint functions returning empty arrays
             is_must_use_ty(cx, *ty)
         },
         ty::Tuple(args) => args.iter().any(|ty| is_must_use_ty(cx, ty)),
         ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
-            for (predicate, _) in cx.tcx.explicit_item_bounds(def_id).skip_binder() {
+            for (predicate, _) in cx.tcx.explicit_item_super_predicates(def_id).skip_binder() {
                 if let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() {
                     if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) {
                         return true;
@@ -729,7 +729,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
         ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => sig_from_bounds(
             cx,
             ty,
-            cx.tcx.item_bounds(def_id).iter_instantiated(cx.tcx, args),
+            cx.tcx.item_super_predicates(def_id).iter_instantiated(cx.tcx, args),
             cx.tcx.opt_parent(def_id),
         ),
         ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)),
@@ -807,7 +807,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option
 
     for (pred, _) in cx
         .tcx
-        .explicit_item_bounds(ty.def_id)
+        .explicit_item_super_predicates(ty.def_id)
         .iter_instantiated_copied(cx.tcx, ty.args)
     {
         match pred.kind().skip_binder() {
diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
index 7913926928f..762830ffd78 100644
--- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
@@ -242,7 +242,7 @@ fn path_segment_certainty(
             Node::Param(..) => Certainty::Certain(None),
             // A local's type is certain if its type annotation is certain or it has an initializer whose
             // type is certain.
-            Node::Local(local) => {
+            Node::LetStmt(local) => {
                 let lhs = local.ty.map_or(Certainty::Uncertain, |ty| type_certainty(cx, ty));
                 let rhs = local
                     .init
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index ebc38e531fe..0a05ac029ea 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -5,7 +5,7 @@ use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::intravisit::{self, walk_block, walk_expr, Visitor};
 use rustc_hir::{
-    AnonConst, Arm, Block, BlockCheckMode, Body, BodyId, Expr, ExprKind, HirId, ItemId, ItemKind, Let, Pat, QPath,
+    AnonConst, Arm, Block, BlockCheckMode, Body, BodyId, Expr, ExprKind, HirId, ItemId, ItemKind, LetExpr, Pat, QPath,
     Stmt, UnOp, UnsafeSource, Unsafety,
 };
 use rustc_lint::LateContext;
@@ -624,7 +624,7 @@ pub fn for_each_unconsumed_temporary<'tcx, B>(
             | ExprKind::Field(e, _)
             | ExprKind::Unary(UnOp::Deref, e)
             | ExprKind::Match(e, ..)
-            | ExprKind::Let(&Let { init: e, .. }) => {
+            | ExprKind::Let(&LetExpr { init: e, .. }) => {
                 helper(typeck, false, e, f)?;
             },
             ExprKind::Block(&Block { expr: Some(e), .. }, _) | ExprKind::Cast(e, _) | ExprKind::Unary(_, e) => {
diff --git a/src/tools/clippy/declare_clippy_lint/Cargo.toml b/src/tools/clippy/declare_clippy_lint/Cargo.toml
index 296eb8dd340..9a3a41e1d1e 100644
--- a/src/tools/clippy/declare_clippy_lint/Cargo.toml
+++ b/src/tools/clippy/declare_clippy_lint/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "declare_clippy_lint"
-version = "0.1.78"
+version = "0.1.79"
 edition = "2021"
 publish = false
 
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 070b62887d5..a63e66f3214 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2024-03-07"
+channel = "nightly-2024-03-21"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr b/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr
index ae5d6843406..cfc590bed36 100644
--- a/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr
+++ b/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr
@@ -4,6 +4,7 @@ error: use of a disallowed method `rustc_lint::context::LintContext::span_lint`
 LL |     cx.span_lint(lint, span, msg, |_| {});
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead (from clippy.toml)
    = note: `-D clippy::disallowed-methods` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]`
 
@@ -12,6 +13,8 @@ error: use of a disallowed method `rustc_middle::ty::context::TyCtxt::node_span_
    |
 LL |     tcx.node_span_lint(lint, hir_id, span, msg, |_| {});
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead (from clippy.toml)
 
 error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.fixed b/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.fixed
new file mode 100644
index 00000000000..d42b29ba21a
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.fixed
@@ -0,0 +1,38 @@
+//@compile-flags: --test
+#![warn(clippy::dbg_macro)]
+#![allow(clippy::unnecessary_operation, clippy::no_effect)]
+
+fn foo(n: u32) -> u32 {
+    if let Some(n) = n.checked_sub(4) { n } else { n }
+}
+
+fn factorial(n: u32) -> u32 {
+    if n <= 1 {
+        1
+    } else {
+        n * factorial(n - 1)
+    }
+}
+
+fn main() {
+    42;
+    foo(3) + factorial(4);
+    (1, 2, 3, 4, 5);
+}
+
+#[test]
+pub fn issue8481() {
+    dbg!(1);
+}
+
+#[cfg(test)]
+fn foo2() {
+    dbg!(1);
+}
+
+#[cfg(test)]
+mod mod1 {
+    fn func() {
+        dbg!(1);
+    }
+}
diff --git a/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.rs b/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.rs
index 67129e62477..bd189b1576f 100644
--- a/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.rs
+++ b/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.rs
@@ -1,6 +1,7 @@
 //@compile-flags: --test
 #![warn(clippy::dbg_macro)]
-//@no-rustfix
+#![allow(clippy::unnecessary_operation, clippy::no_effect)]
+
 fn foo(n: u32) -> u32 {
     if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n }
 }
@@ -15,9 +16,7 @@ fn factorial(n: u32) -> u32 {
 
 fn main() {
     dbg!(42);
-    dbg!(dbg!(dbg!(42)));
     foo(3) + dbg!(factorial(4));
-    dbg!(1, 2, dbg!(3, 4));
     dbg!(1, 2, 3, 4, 5);
 }
 
diff --git a/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.stderr b/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.stderr
index 8ffc426be2d..129fab5ff97 100644
--- a/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.stderr
+++ b/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.stderr
@@ -1,5 +1,5 @@
 error: the `dbg!` macro is intended as a debugging tool
-  --> tests/ui-toml/dbg_macro/dbg_macro.rs:5:22
+  --> tests/ui-toml/dbg_macro/dbg_macro.rs:6:22
    |
 LL |     if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n }
    |                      ^^^^^^^^^^^^^^^^^^^^^^
@@ -12,7 +12,7 @@ LL |     if let Some(n) = n.checked_sub(4) { n } else { n }
    |                      ~~~~~~~~~~~~~~~~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> tests/ui-toml/dbg_macro/dbg_macro.rs:9:8
+  --> tests/ui-toml/dbg_macro/dbg_macro.rs:10:8
    |
 LL |     if dbg!(n <= 1) {
    |        ^^^^^^^^^^^^
@@ -23,7 +23,7 @@ LL |     if n <= 1 {
    |        ~~~~~~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> tests/ui-toml/dbg_macro/dbg_macro.rs:10:9
+  --> tests/ui-toml/dbg_macro/dbg_macro.rs:11:9
    |
 LL |         dbg!(1)
    |         ^^^^^^^
@@ -34,7 +34,7 @@ LL |         1
    |
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> tests/ui-toml/dbg_macro/dbg_macro.rs:12:9
+  --> tests/ui-toml/dbg_macro/dbg_macro.rs:13:9
    |
 LL |         dbg!(n * factorial(n - 1))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -45,7 +45,7 @@ LL |         n * factorial(n - 1)
    |
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> tests/ui-toml/dbg_macro/dbg_macro.rs:17:5
+  --> tests/ui-toml/dbg_macro/dbg_macro.rs:18:5
    |
 LL |     dbg!(42);
    |     ^^^^^^^^
@@ -56,17 +56,6 @@ LL |     42;
    |     ~~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> tests/ui-toml/dbg_macro/dbg_macro.rs:18:5
-   |
-LL |     dbg!(dbg!(dbg!(42)));
-   |     ^^^^^^^^^^^^^^^^^^^^
-   |
-help: remove the invocation before committing it to a version control system
-   |
-LL |     dbg!(dbg!(42));
-   |     ~~~~~~~~~~~~~~
-
-error: the `dbg!` macro is intended as a debugging tool
   --> tests/ui-toml/dbg_macro/dbg_macro.rs:19:14
    |
 LL |     foo(3) + dbg!(factorial(4));
@@ -80,17 +69,6 @@ LL |     foo(3) + factorial(4);
 error: the `dbg!` macro is intended as a debugging tool
   --> tests/ui-toml/dbg_macro/dbg_macro.rs:20:5
    |
-LL |     dbg!(1, 2, dbg!(3, 4));
-   |     ^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: remove the invocation before committing it to a version control system
-   |
-LL |     (1, 2, dbg!(3, 4));
-   |     ~~~~~~~~~~~~~~~~~~
-
-error: the `dbg!` macro is intended as a debugging tool
-  --> tests/ui-toml/dbg_macro/dbg_macro.rs:21:5
-   |
 LL |     dbg!(1, 2, 3, 4, 5);
    |     ^^^^^^^^^^^^^^^^^^^
    |
@@ -99,5 +77,5 @@ help: remove the invocation before committing it to a version control system
 LL |     (1, 2, 3, 4, 5);
    |     ~~~~~~~~~~~~~~~
 
-error: aborting due to 9 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui-toml/needless_raw_string_hashes_one_allowed/clippy.toml b/src/tools/clippy/tests/ui-toml/needless_raw_string_hashes_one_allowed/clippy.toml
new file mode 100644
index 00000000000..2f3d60be3a7
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/needless_raw_string_hashes_one_allowed/clippy.toml
@@ -0,0 +1 @@
+allow-one-hash-in-raw-strings = true
diff --git a/src/tools/clippy/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.fixed b/src/tools/clippy/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.fixed
new file mode 100644
index 00000000000..fd20bdff6e2
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.fixed
@@ -0,0 +1,9 @@
+#![allow(clippy::no_effect, unused)]
+#![warn(clippy::needless_raw_string_hashes)]
+
+fn main() {
+    r#"\aaa"#;
+    r#"\aaa"#;
+    r#"Hello "world"!"#;
+    r####" "### "## "# "####;
+}
diff --git a/src/tools/clippy/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.rs b/src/tools/clippy/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.rs
new file mode 100644
index 00000000000..3c6c2463700
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.rs
@@ -0,0 +1,9 @@
+#![allow(clippy::no_effect, unused)]
+#![warn(clippy::needless_raw_string_hashes)]
+
+fn main() {
+    r#"\aaa"#;
+    r##"\aaa"##;
+    r##"Hello "world"!"##;
+    r######" "### "## "# "######;
+}
diff --git a/src/tools/clippy/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.stderr b/src/tools/clippy/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.stderr
new file mode 100644
index 00000000000..421ad66e4c9
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.stderr
@@ -0,0 +1,40 @@
+error: unnecessary hashes around raw string literal
+  --> tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.rs:6:5
+   |
+LL |     r##"\aaa"##;
+   |     ^^^^^^^^^^^
+   |
+   = note: `-D clippy::needless-raw-string-hashes` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::needless_raw_string_hashes)]`
+help: remove one hash from both sides of the string literal
+   |
+LL -     r##"\aaa"##;
+LL +     r#"\aaa"#;
+   |
+
+error: unnecessary hashes around raw string literal
+  --> tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.rs:7:5
+   |
+LL |     r##"Hello "world"!"##;
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove one hash from both sides of the string literal
+   |
+LL -     r##"Hello "world"!"##;
+LL +     r#"Hello "world"!"#;
+   |
+
+error: unnecessary hashes around raw string literal
+  --> tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.rs:8:5
+   |
+LL |     r######" "### "## "# "######;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove 2 hashes from both sides of the string literal
+   |
+LL -     r######" "### "## "# "######;
+LL +     r####" "### "## "# "####;
+   |
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/allow_attributes_without_reason.rs b/src/tools/clippy/tests/ui/allow_attributes_without_reason.rs
index 663c2eb2c37..523148d6586 100644
--- a/src/tools/clippy/tests/ui/allow_attributes_without_reason.rs
+++ b/src/tools/clippy/tests/ui/allow_attributes_without_reason.rs
@@ -1,7 +1,7 @@
 //@aux-build:proc_macros.rs
 #![feature(lint_reasons)]
 #![deny(clippy::allow_attributes_without_reason)]
-#![allow(unfulfilled_lint_expectations)]
+#![allow(unfulfilled_lint_expectations, clippy::duplicated_attributes)]
 
 extern crate proc_macros;
 use proc_macros::{external, with_span};
diff --git a/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr b/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr
index 3c81233bf77..770a771ec3d 100644
--- a/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr
+++ b/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr
@@ -1,8 +1,8 @@
 error: `allow` attribute without specifying a reason
   --> tests/ui/allow_attributes_without_reason.rs:4:1
    |
-LL | #![allow(unfulfilled_lint_expectations)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![allow(unfulfilled_lint_expectations, clippy::duplicated_attributes)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: try adding a reason at the end with `, reason = ".."`
 note: the lint level is defined here
diff --git a/src/tools/clippy/tests/ui/assigning_clones.fixed b/src/tools/clippy/tests/ui/assigning_clones.fixed
index c66e0c1f602..160f3b94663 100644
--- a/src/tools/clippy/tests/ui/assigning_clones.fixed
+++ b/src/tools/clippy/tests/ui/assigning_clones.fixed
@@ -128,6 +128,19 @@ fn ignore_generic_clone<T: Clone>(a: &mut T, b: &T) {
     *a = b.clone();
 }
 
+#[clippy::msrv = "1.62"]
+fn msrv_1_62(mut a: String, b: String, c: &str) {
+    a.clone_from(&b);
+    // Should not be linted, as clone_into wasn't stabilized until 1.63
+    a = c.to_owned();
+}
+
+#[clippy::msrv = "1.63"]
+fn msrv_1_63(mut a: String, b: String, c: &str) {
+    a.clone_from(&b);
+    c.clone_into(&mut a);
+}
+
 macro_rules! clone_inside {
     ($a:expr, $b: expr) => {
         $a = $b.clone();
diff --git a/src/tools/clippy/tests/ui/assigning_clones.rs b/src/tools/clippy/tests/ui/assigning_clones.rs
index b9f994d3e03..14ba1d4db9a 100644
--- a/src/tools/clippy/tests/ui/assigning_clones.rs
+++ b/src/tools/clippy/tests/ui/assigning_clones.rs
@@ -128,6 +128,19 @@ fn ignore_generic_clone<T: Clone>(a: &mut T, b: &T) {
     *a = b.clone();
 }
 
+#[clippy::msrv = "1.62"]
+fn msrv_1_62(mut a: String, b: String, c: &str) {
+    a = b.clone();
+    // Should not be linted, as clone_into wasn't stabilized until 1.63
+    a = c.to_owned();
+}
+
+#[clippy::msrv = "1.63"]
+fn msrv_1_63(mut a: String, b: String, c: &str) {
+    a = b.clone();
+    a = c.to_owned();
+}
+
 macro_rules! clone_inside {
     ($a:expr, $b: expr) => {
         $a = $b.clone();
diff --git a/src/tools/clippy/tests/ui/assigning_clones.stderr b/src/tools/clippy/tests/ui/assigning_clones.stderr
index b76323f3606..ba59f067431 100644
--- a/src/tools/clippy/tests/ui/assigning_clones.stderr
+++ b/src/tools/clippy/tests/ui/assigning_clones.stderr
@@ -67,41 +67,59 @@ error: assigning the result of `Clone::clone()` may be inefficient
 LL |         a = b.clone();
    |         ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)`
 
+error: assigning the result of `Clone::clone()` may be inefficient
+  --> tests/ui/assigning_clones.rs:133:5
+   |
+LL |     a = b.clone();
+   |     ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)`
+
+error: assigning the result of `Clone::clone()` may be inefficient
+  --> tests/ui/assigning_clones.rs:140:5
+   |
+LL |     a = b.clone();
+   |     ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)`
+
+error: assigning the result of `ToOwned::to_owned()` may be inefficient
+  --> tests/ui/assigning_clones.rs:141:5
+   |
+LL |     a = c.to_owned();
+   |     ^^^^^^^^^^^^^^^^ help: use `clone_into()`: `c.clone_into(&mut a)`
+
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:145:5
+  --> tests/ui/assigning_clones.rs:158:5
    |
 LL |     *mut_string = ref_str.to_owned();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(mut_string)`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:149:5
+  --> tests/ui/assigning_clones.rs:162:5
    |
 LL |     mut_string = ref_str.to_owned();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut mut_string)`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:170:5
+  --> tests/ui/assigning_clones.rs:183:5
    |
 LL |     **mut_box_string = ref_str.to_owned();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut (*mut_box_string))`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:174:5
+  --> tests/ui/assigning_clones.rs:187:5
    |
 LL |     **mut_box_string = ref_str.to_owned();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut (*mut_box_string))`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:178:5
+  --> tests/ui/assigning_clones.rs:191:5
    |
 LL |     *mut_thing = ToOwned::to_owned(ref_str);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(ref_str, mut_thing)`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:182:5
+  --> tests/ui/assigning_clones.rs:195:5
    |
 LL |     mut_thing = ToOwned::to_owned(ref_str);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(ref_str, &mut mut_thing)`
 
-error: aborting due to 17 previous errors
+error: aborting due to 20 previous errors
 
diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs
index 75f7a20f961..a6f3b164c9b 100644
--- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs
@@ -11,8 +11,8 @@ use quote::{quote, quote_spanned};
 use syn::spanned::Spanned;
 use syn::token::Star;
 use syn::{
-    parse_macro_input, parse_quote, FnArg, ImplItem, ItemFn, ItemImpl, ItemTrait, Lifetime, Pat, PatIdent, PatType,
-    Signature, TraitItem, Type,
+    parse_macro_input, parse_quote, FnArg, ImplItem, ItemFn, ItemImpl, ItemStruct, ItemTrait, Lifetime, Pat, PatIdent,
+    PatType, Signature, TraitItem, Type, Visibility,
 };
 
 #[proc_macro_attribute]
@@ -101,9 +101,7 @@ pub fn fake_main(_attr: TokenStream, item: TokenStream) -> TokenStream {
     let mut item = parse_macro_input!(item as ItemFn);
     let span = item.block.brace_token.span;
 
-    if item.sig.asyncness.is_some() {
-        item.sig.asyncness = None;
-    }
+    item.sig.asyncness = None;
 
     let crate_name = quote! { fake_crate };
     let block = item.block;
@@ -128,7 +126,7 @@ pub fn fake_main(_attr: TokenStream, item: TokenStream) -> TokenStream {
 
 #[proc_macro_attribute]
 pub fn fake_desugar_await(_args: TokenStream, input: TokenStream) -> TokenStream {
-    let mut async_fn = syn::parse_macro_input!(input as syn::ItemFn);
+    let mut async_fn = parse_macro_input!(input as syn::ItemFn);
 
     for stmt in &mut async_fn.block.stmts {
         if let syn::Stmt::Expr(syn::Expr::Match(syn::ExprMatch { expr: scrutinee, .. }), _) = stmt {
@@ -145,3 +143,36 @@ pub fn fake_desugar_await(_args: TokenStream, input: TokenStream) -> TokenStream
 
     quote!(#async_fn).into()
 }
+
+#[proc_macro_attribute]
+pub fn rewrite_struct(_args: TokenStream, input: TokenStream) -> TokenStream {
+    let mut item_struct = parse_macro_input!(input as syn::ItemStruct);
+    // remove struct attributes including doc comments.
+    item_struct.attrs = vec![];
+    if let Visibility::Public(token) = item_struct.vis {
+        // set vis to `pub(crate)` to trigger `missing_docs_in_private_items` lint.
+        let new_vis: Visibility = syn::parse_quote_spanned!(token.span() => pub(crate));
+        item_struct.vis = new_vis;
+    }
+    if let syn::Fields::Named(fields) = &mut item_struct.fields {
+        for field in &mut fields.named {
+            // remove all attributes from fields as well.
+            field.attrs = vec![];
+        }
+    }
+
+    quote!(#item_struct).into()
+}
+
+#[proc_macro_attribute]
+pub fn with_empty_docs(_attr: TokenStream, input: TokenStream) -> TokenStream {
+    let item = parse_macro_input!(input as syn::Item);
+    let attrs: Vec<syn::Attribute> = vec![];
+    let doc_comment = "";
+    quote! {
+        #(#attrs)*
+        #[doc = #doc_comment]
+        #item
+    }
+    .into()
+}
diff --git a/src/tools/clippy/tests/ui/await_holding_lock.rs b/src/tools/clippy/tests/ui/await_holding_lock.rs
index 27b57b64813..8e5510e6cd0 100644
--- a/src/tools/clippy/tests/ui/await_holding_lock.rs
+++ b/src/tools/clippy/tests/ui/await_holding_lock.rs
@@ -1,4 +1,5 @@
 #![warn(clippy::await_holding_lock)]
+#![allow(clippy::readonly_write_lock)]
 
 // When adding or modifying a test, please do the same for parking_lot::Mutex.
 mod std_mutex {
diff --git a/src/tools/clippy/tests/ui/await_holding_lock.stderr b/src/tools/clippy/tests/ui/await_holding_lock.stderr
index e58436345b5..0af48a36acc 100644
--- a/src/tools/clippy/tests/ui/await_holding_lock.stderr
+++ b/src/tools/clippy/tests/ui/await_holding_lock.stderr
@@ -1,12 +1,12 @@
 error: this `MutexGuard` is held across an `await` point
-  --> tests/ui/await_holding_lock.rs:9:13
+  --> tests/ui/await_holding_lock.rs:10:13
    |
 LL |         let guard = x.lock().unwrap();
    |             ^^^^^
    |
    = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
 note: these are all the `await` points this lock is held through
-  --> tests/ui/await_holding_lock.rs:11:15
+  --> tests/ui/await_holding_lock.rs:12:15
    |
 LL |         baz().await
    |               ^^^^^
@@ -14,40 +14,40 @@ LL |         baz().await
    = help: to override `-D warnings` add `#[allow(clippy::await_holding_lock)]`
 
 error: this `MutexGuard` is held across an `await` point
-  --> tests/ui/await_holding_lock.rs:25:13
+  --> tests/ui/await_holding_lock.rs:26:13
    |
 LL |         let guard = x.read().unwrap();
    |             ^^^^^
    |
    = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
 note: these are all the `await` points this lock is held through
-  --> tests/ui/await_holding_lock.rs:27:15
+  --> tests/ui/await_holding_lock.rs:28:15
    |
 LL |         baz().await
    |               ^^^^^
 
 error: this `MutexGuard` is held across an `await` point
-  --> tests/ui/await_holding_lock.rs:31:13
+  --> tests/ui/await_holding_lock.rs:32:13
    |
 LL |         let mut guard = x.write().unwrap();
    |             ^^^^^^^^^
    |
    = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
 note: these are all the `await` points this lock is held through
-  --> tests/ui/await_holding_lock.rs:33:15
+  --> tests/ui/await_holding_lock.rs:34:15
    |
 LL |         baz().await
    |               ^^^^^
 
 error: this `MutexGuard` is held across an `await` point
-  --> tests/ui/await_holding_lock.rs:53:13
+  --> tests/ui/await_holding_lock.rs:54:13
    |
 LL |         let guard = x.lock().unwrap();
    |             ^^^^^
    |
    = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
 note: these are all the `await` points this lock is held through
-  --> tests/ui/await_holding_lock.rs:56:28
+  --> tests/ui/await_holding_lock.rs:57:28
    |
 LL |         let second = baz().await;
    |                            ^^^^^
@@ -56,79 +56,79 @@ LL |         let third = baz().await;
    |                           ^^^^^
 
 error: this `MutexGuard` is held across an `await` point
-  --> tests/ui/await_holding_lock.rs:67:17
+  --> tests/ui/await_holding_lock.rs:68:17
    |
 LL |             let guard = x.lock().unwrap();
    |                 ^^^^^
    |
    = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
 note: these are all the `await` points this lock is held through
-  --> tests/ui/await_holding_lock.rs:69:19
+  --> tests/ui/await_holding_lock.rs:70:19
    |
 LL |             baz().await
    |                   ^^^^^
 
 error: this `MutexGuard` is held across an `await` point
-  --> tests/ui/await_holding_lock.rs:80:17
+  --> tests/ui/await_holding_lock.rs:81:17
    |
 LL |             let guard = x.lock().unwrap();
    |                 ^^^^^
    |
    = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
 note: these are all the `await` points this lock is held through
-  --> tests/ui/await_holding_lock.rs:82:19
+  --> tests/ui/await_holding_lock.rs:83:19
    |
 LL |             baz().await
    |                   ^^^^^
 
 error: this `MutexGuard` is held across an `await` point
-  --> tests/ui/await_holding_lock.rs:93:13
+  --> tests/ui/await_holding_lock.rs:94:13
    |
 LL |         let guard = x.lock();
    |             ^^^^^
    |
    = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
 note: these are all the `await` points this lock is held through
-  --> tests/ui/await_holding_lock.rs:95:15
+  --> tests/ui/await_holding_lock.rs:96:15
    |
 LL |         baz().await
    |               ^^^^^
 
 error: this `MutexGuard` is held across an `await` point
-  --> tests/ui/await_holding_lock.rs:109:13
+  --> tests/ui/await_holding_lock.rs:110:13
    |
 LL |         let guard = x.read();
    |             ^^^^^
    |
    = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
 note: these are all the `await` points this lock is held through
-  --> tests/ui/await_holding_lock.rs:111:15
+  --> tests/ui/await_holding_lock.rs:112:15
    |
 LL |         baz().await
    |               ^^^^^
 
 error: this `MutexGuard` is held across an `await` point
-  --> tests/ui/await_holding_lock.rs:115:13
+  --> tests/ui/await_holding_lock.rs:116:13
    |
 LL |         let mut guard = x.write();
    |             ^^^^^^^^^
    |
    = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
 note: these are all the `await` points this lock is held through
-  --> tests/ui/await_holding_lock.rs:117:15
+  --> tests/ui/await_holding_lock.rs:118:15
    |
 LL |         baz().await
    |               ^^^^^
 
 error: this `MutexGuard` is held across an `await` point
-  --> tests/ui/await_holding_lock.rs:137:13
+  --> tests/ui/await_holding_lock.rs:138:13
    |
 LL |         let guard = x.lock();
    |             ^^^^^
    |
    = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
 note: these are all the `await` points this lock is held through
-  --> tests/ui/await_holding_lock.rs:140:28
+  --> tests/ui/await_holding_lock.rs:141:28
    |
 LL |         let second = baz().await;
    |                            ^^^^^
@@ -137,40 +137,40 @@ LL |         let third = baz().await;
    |                           ^^^^^
 
 error: this `MutexGuard` is held across an `await` point
-  --> tests/ui/await_holding_lock.rs:151:17
+  --> tests/ui/await_holding_lock.rs:152:17
    |
 LL |             let guard = x.lock();
    |                 ^^^^^
    |
    = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
 note: these are all the `await` points this lock is held through
-  --> tests/ui/await_holding_lock.rs:153:19
+  --> tests/ui/await_holding_lock.rs:154:19
    |
 LL |             baz().await
    |                   ^^^^^
 
 error: this `MutexGuard` is held across an `await` point
-  --> tests/ui/await_holding_lock.rs:164:17
+  --> tests/ui/await_holding_lock.rs:165:17
    |
 LL |             let guard = x.lock();
    |                 ^^^^^
    |
    = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
 note: these are all the `await` points this lock is held through
-  --> tests/ui/await_holding_lock.rs:166:19
+  --> tests/ui/await_holding_lock.rs:167:19
    |
 LL |             baz().await
    |                   ^^^^^
 
 error: this `MutexGuard` is held across an `await` point
-  --> tests/ui/await_holding_lock.rs:185:9
+  --> tests/ui/await_holding_lock.rs:186:9
    |
 LL |     let mut guard = x.lock().unwrap();
    |         ^^^^^^^^^
    |
    = help: consider using an async-aware `Mutex` type or ensuring the `MutexGuard` is dropped before calling await
 note: these are all the `await` points this lock is held through
-  --> tests/ui/await_holding_lock.rs:189:11
+  --> tests/ui/await_holding_lock.rs:190:11
    |
 LL |     baz().await;
    |           ^^^^^
diff --git a/src/tools/clippy/tests/ui/bool_assert_comparison.fixed b/src/tools/clippy/tests/ui/bool_assert_comparison.fixed
index 63b8e27e1c6..b05166a055e 100644
--- a/src/tools/clippy/tests/ui/bool_assert_comparison.fixed
+++ b/src/tools/clippy/tests/ui/bool_assert_comparison.fixed
@@ -1,4 +1,4 @@
-#![allow(unused, clippy::assertions_on_constants)]
+#![allow(unused, clippy::assertions_on_constants, clippy::const_is_empty)]
 #![warn(clippy::bool_assert_comparison)]
 
 use std::ops::Not;
diff --git a/src/tools/clippy/tests/ui/bool_assert_comparison.rs b/src/tools/clippy/tests/ui/bool_assert_comparison.rs
index 58f81fedb79..dc51fcf1d36 100644
--- a/src/tools/clippy/tests/ui/bool_assert_comparison.rs
+++ b/src/tools/clippy/tests/ui/bool_assert_comparison.rs
@@ -1,4 +1,4 @@
-#![allow(unused, clippy::assertions_on_constants)]
+#![allow(unused, clippy::assertions_on_constants, clippy::const_is_empty)]
 #![warn(clippy::bool_assert_comparison)]
 
 use std::ops::Not;
diff --git a/src/tools/clippy/tests/ui/builtin_type_shadow.stderr b/src/tools/clippy/tests/ui/builtin_type_shadow.stderr
index 1e15cdee772..033204af925 100644
--- a/src/tools/clippy/tests/ui/builtin_type_shadow.stderr
+++ b/src/tools/clippy/tests/ui/builtin_type_shadow.stderr
@@ -19,6 +19,7 @@ LL |     42
    |
    = note: expected type parameter `u32`
                         found type `{integer}`
+   = note: the caller chooses a type for `u32` which can be different from `i32`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/cast_lossless_bool.fixed b/src/tools/clippy/tests/ui/cast_lossless_bool.fixed
index a4ce1c6f928..51a38a60cf6 100644
--- a/src/tools/clippy/tests/ui/cast_lossless_bool.fixed
+++ b/src/tools/clippy/tests/ui/cast_lossless_bool.fixed
@@ -1,6 +1,8 @@
 #![allow(dead_code)]
 #![warn(clippy::cast_lossless)]
 
+type U8 = u8;
+
 fn main() {
     // Test clippy::cast_lossless with casts to integer types
     let _ = u8::from(true);
@@ -19,6 +21,8 @@ fn main() {
 
     // Test with an expression wrapped in parens
     let _ = u16::from(true | false);
+
+    let _ = U8::from(true);
 }
 
 // The lint would suggest using `u32::from(input)` here but the `XX::from` function is not const,
diff --git a/src/tools/clippy/tests/ui/cast_lossless_bool.rs b/src/tools/clippy/tests/ui/cast_lossless_bool.rs
index e5b1c30c103..cb307bd68e4 100644
--- a/src/tools/clippy/tests/ui/cast_lossless_bool.rs
+++ b/src/tools/clippy/tests/ui/cast_lossless_bool.rs
@@ -1,6 +1,8 @@
 #![allow(dead_code)]
 #![warn(clippy::cast_lossless)]
 
+type U8 = u8;
+
 fn main() {
     // Test clippy::cast_lossless with casts to integer types
     let _ = true as u8;
@@ -19,6 +21,8 @@ fn main() {
 
     // Test with an expression wrapped in parens
     let _ = (true | false) as u16;
+
+    let _ = true as U8;
 }
 
 // The lint would suggest using `u32::from(input)` here but the `XX::from` function is not const,
diff --git a/src/tools/clippy/tests/ui/cast_lossless_bool.stderr b/src/tools/clippy/tests/ui/cast_lossless_bool.stderr
index 792b30b7a38..b47b35461f6 100644
--- a/src/tools/clippy/tests/ui/cast_lossless_bool.stderr
+++ b/src/tools/clippy/tests/ui/cast_lossless_bool.stderr
@@ -1,5 +1,5 @@
 error: casting `bool` to `u8` is more cleanly stated with `u8::from(_)`
-  --> tests/ui/cast_lossless_bool.rs:6:13
+  --> tests/ui/cast_lossless_bool.rs:8:13
    |
 LL |     let _ = true as u8;
    |             ^^^^^^^^^^ help: try: `u8::from(true)`
@@ -8,82 +8,88 @@ LL |     let _ = true as u8;
    = help: to override `-D warnings` add `#[allow(clippy::cast_lossless)]`
 
 error: casting `bool` to `u16` is more cleanly stated with `u16::from(_)`
-  --> tests/ui/cast_lossless_bool.rs:7:13
+  --> tests/ui/cast_lossless_bool.rs:9:13
    |
 LL |     let _ = true as u16;
    |             ^^^^^^^^^^^ help: try: `u16::from(true)`
 
 error: casting `bool` to `u32` is more cleanly stated with `u32::from(_)`
-  --> tests/ui/cast_lossless_bool.rs:8:13
+  --> tests/ui/cast_lossless_bool.rs:10:13
    |
 LL |     let _ = true as u32;
    |             ^^^^^^^^^^^ help: try: `u32::from(true)`
 
 error: casting `bool` to `u64` is more cleanly stated with `u64::from(_)`
-  --> tests/ui/cast_lossless_bool.rs:9:13
+  --> tests/ui/cast_lossless_bool.rs:11:13
    |
 LL |     let _ = true as u64;
    |             ^^^^^^^^^^^ help: try: `u64::from(true)`
 
 error: casting `bool` to `u128` is more cleanly stated with `u128::from(_)`
-  --> tests/ui/cast_lossless_bool.rs:10:13
+  --> tests/ui/cast_lossless_bool.rs:12:13
    |
 LL |     let _ = true as u128;
    |             ^^^^^^^^^^^^ help: try: `u128::from(true)`
 
 error: casting `bool` to `usize` is more cleanly stated with `usize::from(_)`
-  --> tests/ui/cast_lossless_bool.rs:11:13
+  --> tests/ui/cast_lossless_bool.rs:13:13
    |
 LL |     let _ = true as usize;
    |             ^^^^^^^^^^^^^ help: try: `usize::from(true)`
 
 error: casting `bool` to `i8` is more cleanly stated with `i8::from(_)`
-  --> tests/ui/cast_lossless_bool.rs:13:13
+  --> tests/ui/cast_lossless_bool.rs:15:13
    |
 LL |     let _ = true as i8;
    |             ^^^^^^^^^^ help: try: `i8::from(true)`
 
 error: casting `bool` to `i16` is more cleanly stated with `i16::from(_)`
-  --> tests/ui/cast_lossless_bool.rs:14:13
+  --> tests/ui/cast_lossless_bool.rs:16:13
    |
 LL |     let _ = true as i16;
    |             ^^^^^^^^^^^ help: try: `i16::from(true)`
 
 error: casting `bool` to `i32` is more cleanly stated with `i32::from(_)`
-  --> tests/ui/cast_lossless_bool.rs:15:13
+  --> tests/ui/cast_lossless_bool.rs:17:13
    |
 LL |     let _ = true as i32;
    |             ^^^^^^^^^^^ help: try: `i32::from(true)`
 
 error: casting `bool` to `i64` is more cleanly stated with `i64::from(_)`
-  --> tests/ui/cast_lossless_bool.rs:16:13
+  --> tests/ui/cast_lossless_bool.rs:18:13
    |
 LL |     let _ = true as i64;
    |             ^^^^^^^^^^^ help: try: `i64::from(true)`
 
 error: casting `bool` to `i128` is more cleanly stated with `i128::from(_)`
-  --> tests/ui/cast_lossless_bool.rs:17:13
+  --> tests/ui/cast_lossless_bool.rs:19:13
    |
 LL |     let _ = true as i128;
    |             ^^^^^^^^^^^^ help: try: `i128::from(true)`
 
 error: casting `bool` to `isize` is more cleanly stated with `isize::from(_)`
-  --> tests/ui/cast_lossless_bool.rs:18:13
+  --> tests/ui/cast_lossless_bool.rs:20:13
    |
 LL |     let _ = true as isize;
    |             ^^^^^^^^^^^^^ help: try: `isize::from(true)`
 
 error: casting `bool` to `u16` is more cleanly stated with `u16::from(_)`
-  --> tests/ui/cast_lossless_bool.rs:21:13
+  --> tests/ui/cast_lossless_bool.rs:23:13
    |
 LL |     let _ = (true | false) as u16;
    |             ^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::from(true | false)`
 
+error: casting `bool` to `U8` is more cleanly stated with `U8::from(_)`
+  --> tests/ui/cast_lossless_bool.rs:25:13
+   |
+LL |     let _ = true as U8;
+   |             ^^^^^^^^^^ help: try: `U8::from(true)`
+
 error: casting `bool` to `u8` is more cleanly stated with `u8::from(_)`
-  --> tests/ui/cast_lossless_bool.rs:49:13
+  --> tests/ui/cast_lossless_bool.rs:53:13
    |
 LL |     let _ = true as u8;
    |             ^^^^^^^^^^ help: try: `u8::from(true)`
 
-error: aborting due to 14 previous errors
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/cast_lossless_float.fixed b/src/tools/clippy/tests/ui/cast_lossless_float.fixed
index f4f2e4773a5..96a67b1945c 100644
--- a/src/tools/clippy/tests/ui/cast_lossless_float.fixed
+++ b/src/tools/clippy/tests/ui/cast_lossless_float.fixed
@@ -1,11 +1,16 @@
 #![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)]
 #![warn(clippy::cast_lossless)]
 
+type F32 = f32;
+type F64 = f64;
+
 fn main() {
     // Test clippy::cast_lossless with casts to floating-point types
     let x0 = 1i8;
     let _ = f32::from(x0);
     let _ = f64::from(x0);
+    let _ = F32::from(x0);
+    let _ = F64::from(x0);
     let x1 = 1u8;
     let _ = f32::from(x1);
     let _ = f64::from(x1);
diff --git a/src/tools/clippy/tests/ui/cast_lossless_float.rs b/src/tools/clippy/tests/ui/cast_lossless_float.rs
index fdd88ed36fc..d37b2c1d920 100644
--- a/src/tools/clippy/tests/ui/cast_lossless_float.rs
+++ b/src/tools/clippy/tests/ui/cast_lossless_float.rs
@@ -1,11 +1,16 @@
 #![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)]
 #![warn(clippy::cast_lossless)]
 
+type F32 = f32;
+type F64 = f64;
+
 fn main() {
     // Test clippy::cast_lossless with casts to floating-point types
     let x0 = 1i8;
     let _ = x0 as f32;
     let _ = x0 as f64;
+    let _ = x0 as F32;
+    let _ = x0 as F64;
     let x1 = 1u8;
     let _ = x1 as f32;
     let _ = x1 as f64;
diff --git a/src/tools/clippy/tests/ui/cast_lossless_float.stderr b/src/tools/clippy/tests/ui/cast_lossless_float.stderr
index e70f81eb91f..ad7de760adf 100644
--- a/src/tools/clippy/tests/ui/cast_lossless_float.stderr
+++ b/src/tools/clippy/tests/ui/cast_lossless_float.stderr
@@ -1,5 +1,5 @@
 error: casting `i8` to `f32` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_float.rs:7:13
+  --> tests/ui/cast_lossless_float.rs:10:13
    |
 LL |     let _ = x0 as f32;
    |             ^^^^^^^^^ help: try: `f32::from(x0)`
@@ -8,64 +8,76 @@ LL |     let _ = x0 as f32;
    = help: to override `-D warnings` add `#[allow(clippy::cast_lossless)]`
 
 error: casting `i8` to `f64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_float.rs:8:13
+  --> tests/ui/cast_lossless_float.rs:11:13
    |
 LL |     let _ = x0 as f64;
    |             ^^^^^^^^^ help: try: `f64::from(x0)`
 
+error: casting `i8` to `F32` may become silently lossy if you later change the type
+  --> tests/ui/cast_lossless_float.rs:12:13
+   |
+LL |     let _ = x0 as F32;
+   |             ^^^^^^^^^ help: try: `F32::from(x0)`
+
+error: casting `i8` to `F64` may become silently lossy if you later change the type
+  --> tests/ui/cast_lossless_float.rs:13:13
+   |
+LL |     let _ = x0 as F64;
+   |             ^^^^^^^^^ help: try: `F64::from(x0)`
+
 error: casting `u8` to `f32` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_float.rs:10:13
+  --> tests/ui/cast_lossless_float.rs:15:13
    |
 LL |     let _ = x1 as f32;
    |             ^^^^^^^^^ help: try: `f32::from(x1)`
 
 error: casting `u8` to `f64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_float.rs:11:13
+  --> tests/ui/cast_lossless_float.rs:16:13
    |
 LL |     let _ = x1 as f64;
    |             ^^^^^^^^^ help: try: `f64::from(x1)`
 
 error: casting `i16` to `f32` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_float.rs:13:13
+  --> tests/ui/cast_lossless_float.rs:18:13
    |
 LL |     let _ = x2 as f32;
    |             ^^^^^^^^^ help: try: `f32::from(x2)`
 
 error: casting `i16` to `f64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_float.rs:14:13
+  --> tests/ui/cast_lossless_float.rs:19:13
    |
 LL |     let _ = x2 as f64;
    |             ^^^^^^^^^ help: try: `f64::from(x2)`
 
 error: casting `u16` to `f32` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_float.rs:16:13
+  --> tests/ui/cast_lossless_float.rs:21:13
    |
 LL |     let _ = x3 as f32;
    |             ^^^^^^^^^ help: try: `f32::from(x3)`
 
 error: casting `u16` to `f64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_float.rs:17:13
+  --> tests/ui/cast_lossless_float.rs:22:13
    |
 LL |     let _ = x3 as f64;
    |             ^^^^^^^^^ help: try: `f64::from(x3)`
 
 error: casting `i32` to `f64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_float.rs:19:13
+  --> tests/ui/cast_lossless_float.rs:24:13
    |
 LL |     let _ = x4 as f64;
    |             ^^^^^^^^^ help: try: `f64::from(x4)`
 
 error: casting `u32` to `f64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_float.rs:21:13
+  --> tests/ui/cast_lossless_float.rs:26:13
    |
 LL |     let _ = x5 as f64;
    |             ^^^^^^^^^ help: try: `f64::from(x5)`
 
 error: casting `f32` to `f64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_float.rs:24:13
+  --> tests/ui/cast_lossless_float.rs:29:13
    |
 LL |     let _ = 1.0f32 as f64;
    |             ^^^^^^^^^^^^^ help: try: `f64::from(1.0f32)`
 
-error: aborting due to 11 previous errors
+error: aborting due to 13 previous errors
 
diff --git a/src/tools/clippy/tests/ui/cast_lossless_integer.fixed b/src/tools/clippy/tests/ui/cast_lossless_integer.fixed
index 5e7e545e764..291556a9774 100644
--- a/src/tools/clippy/tests/ui/cast_lossless_integer.fixed
+++ b/src/tools/clippy/tests/ui/cast_lossless_integer.fixed
@@ -1,6 +1,9 @@
 #![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)]
 #![warn(clippy::cast_lossless)]
 
+type I64 = i64;
+type U128 = u128;
+
 fn main() {
     // Test clippy::cast_lossless with casts to integer types
     let _ = i16::from(1i8);
@@ -24,6 +27,13 @@ fn main() {
 
     // Test with an expression wrapped in parens
     let _ = u16::from(1u8 + 1u8);
+
+    let _ = I64::from(1i8);
+
+    // Do not lint if destination type is u128
+    // see https://github.com/rust-lang/rust-clippy/issues/12492
+    let _ = 1u8 as u128;
+    let _ = 1u8 as U128;
 }
 
 // The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const,
diff --git a/src/tools/clippy/tests/ui/cast_lossless_integer.rs b/src/tools/clippy/tests/ui/cast_lossless_integer.rs
index 0d69ddbd586..a917c7a371d 100644
--- a/src/tools/clippy/tests/ui/cast_lossless_integer.rs
+++ b/src/tools/clippy/tests/ui/cast_lossless_integer.rs
@@ -1,6 +1,9 @@
 #![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)]
 #![warn(clippy::cast_lossless)]
 
+type I64 = i64;
+type U128 = u128;
+
 fn main() {
     // Test clippy::cast_lossless with casts to integer types
     let _ = 1i8 as i16;
@@ -24,6 +27,13 @@ fn main() {
 
     // Test with an expression wrapped in parens
     let _ = (1u8 + 1u8) as u16;
+
+    let _ = 1i8 as I64;
+
+    // Do not lint if destination type is u128
+    // see https://github.com/rust-lang/rust-clippy/issues/12492
+    let _ = 1u8 as u128;
+    let _ = 1u8 as U128;
 }
 
 // The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const,
diff --git a/src/tools/clippy/tests/ui/cast_lossless_integer.stderr b/src/tools/clippy/tests/ui/cast_lossless_integer.stderr
index 43d4ce3ce91..aaece939285 100644
--- a/src/tools/clippy/tests/ui/cast_lossless_integer.stderr
+++ b/src/tools/clippy/tests/ui/cast_lossless_integer.stderr
@@ -1,5 +1,5 @@
 error: casting `i8` to `i16` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:6:13
+  --> tests/ui/cast_lossless_integer.rs:9:13
    |
 LL |     let _ = 1i8 as i16;
    |             ^^^^^^^^^^ help: try: `i16::from(1i8)`
@@ -8,124 +8,130 @@ LL |     let _ = 1i8 as i16;
    = help: to override `-D warnings` add `#[allow(clippy::cast_lossless)]`
 
 error: casting `i8` to `i32` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:7:13
+  --> tests/ui/cast_lossless_integer.rs:10:13
    |
 LL |     let _ = 1i8 as i32;
    |             ^^^^^^^^^^ help: try: `i32::from(1i8)`
 
 error: casting `i8` to `i64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:8:13
+  --> tests/ui/cast_lossless_integer.rs:11:13
    |
 LL |     let _ = 1i8 as i64;
    |             ^^^^^^^^^^ help: try: `i64::from(1i8)`
 
 error: casting `u8` to `i16` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:9:13
+  --> tests/ui/cast_lossless_integer.rs:12:13
    |
 LL |     let _ = 1u8 as i16;
    |             ^^^^^^^^^^ help: try: `i16::from(1u8)`
 
 error: casting `u8` to `i32` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:10:13
+  --> tests/ui/cast_lossless_integer.rs:13:13
    |
 LL |     let _ = 1u8 as i32;
    |             ^^^^^^^^^^ help: try: `i32::from(1u8)`
 
 error: casting `u8` to `i64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:11:13
+  --> tests/ui/cast_lossless_integer.rs:14:13
    |
 LL |     let _ = 1u8 as i64;
    |             ^^^^^^^^^^ help: try: `i64::from(1u8)`
 
 error: casting `u8` to `u16` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:12:13
+  --> tests/ui/cast_lossless_integer.rs:15:13
    |
 LL |     let _ = 1u8 as u16;
    |             ^^^^^^^^^^ help: try: `u16::from(1u8)`
 
 error: casting `u8` to `u32` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:13:13
+  --> tests/ui/cast_lossless_integer.rs:16:13
    |
 LL |     let _ = 1u8 as u32;
    |             ^^^^^^^^^^ help: try: `u32::from(1u8)`
 
 error: casting `u8` to `u64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:14:13
+  --> tests/ui/cast_lossless_integer.rs:17:13
    |
 LL |     let _ = 1u8 as u64;
    |             ^^^^^^^^^^ help: try: `u64::from(1u8)`
 
 error: casting `i16` to `i32` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:15:13
+  --> tests/ui/cast_lossless_integer.rs:18:13
    |
 LL |     let _ = 1i16 as i32;
    |             ^^^^^^^^^^^ help: try: `i32::from(1i16)`
 
 error: casting `i16` to `i64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:16:13
+  --> tests/ui/cast_lossless_integer.rs:19:13
    |
 LL |     let _ = 1i16 as i64;
    |             ^^^^^^^^^^^ help: try: `i64::from(1i16)`
 
 error: casting `u16` to `i32` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:17:13
+  --> tests/ui/cast_lossless_integer.rs:20:13
    |
 LL |     let _ = 1u16 as i32;
    |             ^^^^^^^^^^^ help: try: `i32::from(1u16)`
 
 error: casting `u16` to `i64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:18:13
+  --> tests/ui/cast_lossless_integer.rs:21:13
    |
 LL |     let _ = 1u16 as i64;
    |             ^^^^^^^^^^^ help: try: `i64::from(1u16)`
 
 error: casting `u16` to `u32` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:19:13
+  --> tests/ui/cast_lossless_integer.rs:22:13
    |
 LL |     let _ = 1u16 as u32;
    |             ^^^^^^^^^^^ help: try: `u32::from(1u16)`
 
 error: casting `u16` to `u64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:20:13
+  --> tests/ui/cast_lossless_integer.rs:23:13
    |
 LL |     let _ = 1u16 as u64;
    |             ^^^^^^^^^^^ help: try: `u64::from(1u16)`
 
 error: casting `i32` to `i64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:21:13
+  --> tests/ui/cast_lossless_integer.rs:24:13
    |
 LL |     let _ = 1i32 as i64;
    |             ^^^^^^^^^^^ help: try: `i64::from(1i32)`
 
 error: casting `u32` to `i64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:22:13
+  --> tests/ui/cast_lossless_integer.rs:25:13
    |
 LL |     let _ = 1u32 as i64;
    |             ^^^^^^^^^^^ help: try: `i64::from(1u32)`
 
 error: casting `u32` to `u64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:23:13
+  --> tests/ui/cast_lossless_integer.rs:26:13
    |
 LL |     let _ = 1u32 as u64;
    |             ^^^^^^^^^^^ help: try: `u64::from(1u32)`
 
 error: casting `u8` to `u16` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:26:13
+  --> tests/ui/cast_lossless_integer.rs:29:13
    |
 LL |     let _ = (1u8 + 1u8) as u16;
    |             ^^^^^^^^^^^^^^^^^^ help: try: `u16::from(1u8 + 1u8)`
 
+error: casting `i8` to `I64` may become silently lossy if you later change the type
+  --> tests/ui/cast_lossless_integer.rs:31:13
+   |
+LL |     let _ = 1i8 as I64;
+   |             ^^^^^^^^^^ help: try: `I64::from(1i8)`
+
 error: casting `i8` to `i32` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:60:13
+  --> tests/ui/cast_lossless_integer.rs:70:13
    |
 LL |     let _ = sign_cast!(x, u8, i8) as i32;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::from(sign_cast!(x, u8, i8))`
 
 error: casting `i8` to `i32` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:61:13
+  --> tests/ui/cast_lossless_integer.rs:71:13
    |
 LL |     let _ = (sign_cast!(x, u8, i8) + 1) as i32;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::from(sign_cast!(x, u8, i8) + 1)`
 
-error: aborting due to 21 previous errors
+error: aborting due to 22 previous errors
 
diff --git a/src/tools/clippy/tests/ui/const_is_empty.rs b/src/tools/clippy/tests/ui/const_is_empty.rs
new file mode 100644
index 00000000000..ae37a82e4f9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/const_is_empty.rs
@@ -0,0 +1,174 @@
+#![feature(inline_const)]
+#![warn(clippy::const_is_empty)]
+#![allow(clippy::needless_late_init, unused_must_use)]
+
+fn test_literal() {
+    if "".is_empty() {
+        //~^ERROR: this expression always evaluates to true
+    }
+    if "foobar".is_empty() {
+        //~^ERROR: this expression always evaluates to false
+    }
+}
+
+fn test_byte_literal() {
+    if b"".is_empty() {
+        //~^ERROR: this expression always evaluates to true
+    }
+    if b"foobar".is_empty() {
+        //~^ERROR: this expression always evaluates to false
+    }
+}
+
+fn test_no_mut() {
+    let mut empty = "";
+    if empty.is_empty() {
+        // No lint because it is mutable
+    }
+}
+
+fn test_propagated() {
+    let empty = "";
+    let non_empty = "foobar";
+    let empty2 = empty;
+    let non_empty2 = non_empty;
+    if empty2.is_empty() {
+        //~^ERROR: this expression always evaluates to true
+    }
+    if non_empty2.is_empty() {
+        //~^ERROR: this expression always evaluates to false
+    }
+}
+
+const EMPTY_STR: &str = "";
+const NON_EMPTY_STR: &str = "foo";
+const EMPTY_BSTR: &[u8] = b"";
+const NON_EMPTY_BSTR: &[u8] = b"foo";
+const EMPTY_U8_SLICE: &[u8] = &[];
+const NON_EMPTY_U8_SLICE: &[u8] = &[1, 2];
+const EMPTY_SLICE: &[u32] = &[];
+const NON_EMPTY_SLICE: &[u32] = &[1, 2];
+const NON_EMPTY_SLICE_REPEAT: &[u32] = &[1; 2];
+const EMPTY_ARRAY: [u32; 0] = [];
+const EMPTY_ARRAY_REPEAT: [u32; 0] = [1; 0];
+const NON_EMPTY_ARRAY: [u32; 2] = [1, 2];
+const NON_EMPTY_ARRAY_REPEAT: [u32; 2] = [1; 2];
+const EMPTY_REF_ARRAY: &[u32; 0] = &[];
+const NON_EMPTY_REF_ARRAY: &[u32; 3] = &[1, 2, 3];
+
+fn test_from_const() {
+    let _ = EMPTY_STR.is_empty();
+    //~^ ERROR: this expression always evaluates to true
+    let _ = NON_EMPTY_STR.is_empty();
+    //~^ ERROR: this expression always evaluates to false
+    let _ = EMPTY_BSTR.is_empty();
+    //~^ ERROR: this expression always evaluates to true
+    let _ = NON_EMPTY_BSTR.is_empty();
+    //~^ ERROR: this expression always evaluates to false
+    let _ = EMPTY_ARRAY.is_empty();
+    //~^ ERROR: this expression always evaluates to true
+    let _ = EMPTY_ARRAY_REPEAT.is_empty();
+    //~^ ERROR: this expression always evaluates to true
+    let _ = EMPTY_U8_SLICE.is_empty();
+    //~^ ERROR: this expression always evaluates to true
+    let _ = NON_EMPTY_U8_SLICE.is_empty();
+    //~^ ERROR: this expression always evaluates to false
+    let _ = NON_EMPTY_ARRAY.is_empty();
+    //~^ ERROR: this expression always evaluates to false
+    let _ = NON_EMPTY_ARRAY_REPEAT.is_empty();
+    //~^ ERROR: this expression always evaluates to false
+    let _ = EMPTY_REF_ARRAY.is_empty();
+    //~^ ERROR: this expression always evaluates to true
+    let _ = NON_EMPTY_REF_ARRAY.is_empty();
+    //~^ ERROR: this expression always evaluates to false
+    let _ = EMPTY_SLICE.is_empty();
+    //~^ ERROR: this expression always evaluates to true
+    let _ = NON_EMPTY_SLICE.is_empty();
+    //~^ ERROR: this expression always evaluates to false
+    let _ = NON_EMPTY_SLICE_REPEAT.is_empty();
+    //~^ ERROR: this expression always evaluates to false
+}
+
+fn main() {
+    let value = "foobar";
+    let _ = value.is_empty();
+    //~^ ERROR: this expression always evaluates to false
+    let x = value;
+    let _ = x.is_empty();
+    //~^ ERROR: this expression always evaluates to false
+    let _ = "".is_empty();
+    //~^ ERROR: this expression always evaluates to true
+    let _ = b"".is_empty();
+    //~^ ERROR: this expression always evaluates to true
+}
+
+fn str_from_arg(var: &str) {
+    var.is_empty();
+    // Do not lint, we know nothiny about var
+}
+
+fn update_str() {
+    let mut value = "duck";
+    value = "penguin";
+
+    let _ = value.is_empty();
+    // Do not lint since value is mutable
+}
+
+fn macros() {
+    // Content from Macro
+    let file = include_str!("const_is_empty.rs");
+    let _ = file.is_empty();
+    // No lint because initializer comes from a macro result
+
+    let var = env!("PATH");
+    let _ = var.is_empty();
+    // No lint because initializer comes from a macro result
+}
+
+fn conditional_value() {
+    let value;
+
+    if true {
+        value = "hey";
+    } else {
+        value = "hej";
+    }
+
+    let _ = value.is_empty();
+    // Do not lint, current constant folding is too simple to detect this
+}
+
+fn cfg_conditioned() {
+    #[cfg(test)]
+    let val = "";
+    #[cfg(not(test))]
+    let val = "foo";
+
+    let _ = val.is_empty();
+    // Do not lint, value depend on a #[cfg(…)] directive
+}
+
+fn not_cfg_conditioned() {
+    let val = "";
+    #[cfg(not(target_os = "inexistent"))]
+    let _ = val.is_empty();
+    //~^ ERROR: this expression always evaluates to true
+}
+
+const fn const_rand() -> &'static str {
+    "17"
+}
+
+fn const_expressions() {
+    let _ = const { if true { "1" } else { "2" } }.is_empty();
+    // Do not lint, we do not recurse into boolean expressions
+
+    let _ = const_rand().is_empty();
+    // Do not lint, we do not recurse into functions
+}
+
+fn constant_from_external_crate() {
+    let _ = std::env::consts::EXE_EXTENSION.is_empty();
+    // Do not lint, `exe_ext` comes from the `std` crate
+}
diff --git a/src/tools/clippy/tests/ui/const_is_empty.stderr b/src/tools/clippy/tests/ui/const_is_empty.stderr
new file mode 100644
index 00000000000..0e09da77bb4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/const_is_empty.stderr
@@ -0,0 +1,161 @@
+error: this expression always evaluates to true
+  --> tests/ui/const_is_empty.rs:6:8
+   |
+LL |     if "".is_empty() {
+   |        ^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::const-is-empty` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::const_is_empty)]`
+
+error: this expression always evaluates to false
+  --> tests/ui/const_is_empty.rs:9:8
+   |
+LL |     if "foobar".is_empty() {
+   |        ^^^^^^^^^^^^^^^^^^^
+
+error: this expression always evaluates to true
+  --> tests/ui/const_is_empty.rs:15:8
+   |
+LL |     if b"".is_empty() {
+   |        ^^^^^^^^^^^^^^
+
+error: this expression always evaluates to false
+  --> tests/ui/const_is_empty.rs:18:8
+   |
+LL |     if b"foobar".is_empty() {
+   |        ^^^^^^^^^^^^^^^^^^^^
+
+error: this expression always evaluates to true
+  --> tests/ui/const_is_empty.rs:35:8
+   |
+LL |     if empty2.is_empty() {
+   |        ^^^^^^^^^^^^^^^^^
+
+error: this expression always evaluates to false
+  --> tests/ui/const_is_empty.rs:38:8
+   |
+LL |     if non_empty2.is_empty() {
+   |        ^^^^^^^^^^^^^^^^^^^^^
+
+error: this expression always evaluates to true
+  --> tests/ui/const_is_empty.rs:60:13
+   |
+LL |     let _ = EMPTY_STR.is_empty();
+   |             ^^^^^^^^^^^^^^^^^^^^
+
+error: this expression always evaluates to false
+  --> tests/ui/const_is_empty.rs:62:13
+   |
+LL |     let _ = NON_EMPTY_STR.is_empty();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this expression always evaluates to true
+  --> tests/ui/const_is_empty.rs:64:13
+   |
+LL |     let _ = EMPTY_BSTR.is_empty();
+   |             ^^^^^^^^^^^^^^^^^^^^^
+
+error: this expression always evaluates to false
+  --> tests/ui/const_is_empty.rs:66:13
+   |
+LL |     let _ = NON_EMPTY_BSTR.is_empty();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this expression always evaluates to true
+  --> tests/ui/const_is_empty.rs:68:13
+   |
+LL |     let _ = EMPTY_ARRAY.is_empty();
+   |             ^^^^^^^^^^^^^^^^^^^^^^
+
+error: this expression always evaluates to true
+  --> tests/ui/const_is_empty.rs:70:13
+   |
+LL |     let _ = EMPTY_ARRAY_REPEAT.is_empty();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this expression always evaluates to true
+  --> tests/ui/const_is_empty.rs:72:13
+   |
+LL |     let _ = EMPTY_U8_SLICE.is_empty();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this expression always evaluates to false
+  --> tests/ui/const_is_empty.rs:74:13
+   |
+LL |     let _ = NON_EMPTY_U8_SLICE.is_empty();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this expression always evaluates to false
+  --> tests/ui/const_is_empty.rs:76:13
+   |
+LL |     let _ = NON_EMPTY_ARRAY.is_empty();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this expression always evaluates to false
+  --> tests/ui/const_is_empty.rs:78:13
+   |
+LL |     let _ = NON_EMPTY_ARRAY_REPEAT.is_empty();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this expression always evaluates to true
+  --> tests/ui/const_is_empty.rs:80:13
+   |
+LL |     let _ = EMPTY_REF_ARRAY.is_empty();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this expression always evaluates to false
+  --> tests/ui/const_is_empty.rs:82:13
+   |
+LL |     let _ = NON_EMPTY_REF_ARRAY.is_empty();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this expression always evaluates to true
+  --> tests/ui/const_is_empty.rs:84:13
+   |
+LL |     let _ = EMPTY_SLICE.is_empty();
+   |             ^^^^^^^^^^^^^^^^^^^^^^
+
+error: this expression always evaluates to false
+  --> tests/ui/const_is_empty.rs:86:13
+   |
+LL |     let _ = NON_EMPTY_SLICE.is_empty();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this expression always evaluates to false
+  --> tests/ui/const_is_empty.rs:88:13
+   |
+LL |     let _ = NON_EMPTY_SLICE_REPEAT.is_empty();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: this expression always evaluates to false
+  --> tests/ui/const_is_empty.rs:94:13
+   |
+LL |     let _ = value.is_empty();
+   |             ^^^^^^^^^^^^^^^^
+
+error: this expression always evaluates to false
+  --> tests/ui/const_is_empty.rs:97:13
+   |
+LL |     let _ = x.is_empty();
+   |             ^^^^^^^^^^^^
+
+error: this expression always evaluates to true
+  --> tests/ui/const_is_empty.rs:99:13
+   |
+LL |     let _ = "".is_empty();
+   |             ^^^^^^^^^^^^^
+
+error: this expression always evaluates to true
+  --> tests/ui/const_is_empty.rs:101:13
+   |
+LL |     let _ = b"".is_empty();
+   |             ^^^^^^^^^^^^^^
+
+error: this expression always evaluates to true
+  --> tests/ui/const_is_empty.rs:155:13
+   |
+LL |     let _ = val.is_empty();
+   |             ^^^^^^^^^^^^^^
+
+error: aborting due to 26 previous errors
+
diff --git a/src/tools/clippy/tests/ui/crashes/ice-12491.fixed b/src/tools/clippy/tests/ui/crashes/ice-12491.fixed
new file mode 100644
index 00000000000..4ea480b0663
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-12491.fixed
@@ -0,0 +1,7 @@
+#![warn(clippy::needless_return)]
+
+fn main() {
+    if (true) {
+        // anything一些中文
+    }
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-12491.rs b/src/tools/clippy/tests/ui/crashes/ice-12491.rs
new file mode 100644
index 00000000000..60add6afa2c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-12491.rs
@@ -0,0 +1,8 @@
+#![warn(clippy::needless_return)]
+
+fn main() {
+    if (true) {
+        // anything一些中文
+        return;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-12491.stderr b/src/tools/clippy/tests/ui/crashes/ice-12491.stderr
new file mode 100644
index 00000000000..7cc418898e8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-12491.stderr
@@ -0,0 +1,19 @@
+error: unneeded `return` statement
+  --> tests/ui/crashes/ice-12491.rs:5:24
+   |
+LL |           // anything一些中文
+   |  ____________________________^
+LL | |         return;
+   | |______________^
+   |
+   = note: `-D clippy::needless-return` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::needless_return)]`
+help: remove `return`
+   |
+LL -         // anything一些中文
+LL -         return;
+LL +         // anything一些中文
+   |
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6179.rs b/src/tools/clippy/tests/ui/crashes/ice-6179.rs
index fffc0f7d0d4..91160eef03d 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-6179.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-6179.rs
@@ -1,5 +1,5 @@
 //! This is a minimal reproducer for the ICE in https://github.com/rust-lang/rust-clippy/pull/6179.
-//! The ICE is mainly caused by using `hir_ty_to_ty`. See the discussion in the PR for details.
+//! The ICE is mainly caused by using `lower_ty`. See the discussion in the PR for details.
 
 #![warn(clippy::use_self)]
 #![allow(dead_code, clippy::let_with_type_underscore)]
diff --git a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.fixed b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.fixed
new file mode 100644
index 00000000000..e3525191423
--- /dev/null
+++ b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.fixed
@@ -0,0 +1,111 @@
+#![warn(clippy::dbg_macro)]
+#![allow(clippy::unnecessary_operation, clippy::no_effect)]
+
+fn foo(n: u32) -> u32 {
+    if let Some(n) = n.checked_sub(4) { n } else { n }
+    //~^ ERROR: the `dbg!` macro is intended as a debugging tool
+}
+fn bar(_: ()) {}
+
+fn factorial(n: u32) -> u32 {
+    if n <= 1 {
+        //~^ ERROR: the `dbg!` macro is intended as a debugging tool
+        1
+        //~^ ERROR: the `dbg!` macro is intended as a debugging tool
+    } else {
+        n * factorial(n - 1)
+        //~^ ERROR: the `dbg!` macro is intended as a debugging tool
+    }
+}
+
+fn main() {
+    42;
+    //~^ ERROR: the `dbg!` macro is intended as a debugging tool
+    foo(3) + factorial(4);
+    //~^ ERROR: the `dbg!` macro is intended as a debugging tool
+    (1, 2, 3, 4, 5);
+    //~^ ERROR: the `dbg!` macro is intended as a debugging tool
+}
+
+fn issue9914() {
+    macro_rules! foo {
+        ($x:expr) => {
+            $x;
+        };
+    }
+    macro_rules! foo2 {
+        ($x:expr) => {
+            $x;
+        };
+    }
+    macro_rules! expand_to_dbg {
+        () => {
+            
+            //~^ ERROR: the `dbg!` macro is intended as a debugging tool
+        };
+    }
+
+    
+    //~^ ERROR: the `dbg!` macro is intended as a debugging tool
+    #[allow(clippy::let_unit_value)]
+    let _ = ();
+    //~^ ERROR: the `dbg!` macro is intended as a debugging tool
+    bar(());
+    //~^ ERROR: the `dbg!` macro is intended as a debugging tool
+    foo!(());
+    //~^ ERROR: the `dbg!` macro is intended as a debugging tool
+    foo2!(foo!(()));
+    //~^ ERROR: the `dbg!` macro is intended as a debugging tool
+    expand_to_dbg!();
+}
+
+mod issue7274 {
+    trait Thing<'b> {
+        fn foo(&self);
+    }
+
+    macro_rules! define_thing {
+        ($thing:ident, $body:expr) => {
+            impl<'a> Thing<'a> for $thing {
+                fn foo<'b>(&self) {
+                    $body
+                }
+            }
+        };
+    }
+
+    struct MyThing;
+    define_thing!(MyThing, {
+        2;
+        //~^ ERROR: the `dbg!` macro is intended as a debugging tool
+    });
+}
+
+#[test]
+pub fn issue8481() {
+    1;
+    //~^ ERROR: the `dbg!` macro is intended as a debugging tool
+}
+
+#[cfg(test)]
+fn foo2() {
+    1;
+    //~^ ERROR: the `dbg!` macro is intended as a debugging tool
+}
+
+#[cfg(test)]
+mod mod1 {
+    fn func() {
+        1;
+        //~^ ERROR: the `dbg!` macro is intended as a debugging tool
+    }
+}
+
+mod issue12131 {
+    fn dbg_in_print(s: &str) {
+        println!("dbg: {:?}", s);
+        //~^ ERROR: the `dbg!` macro is intended as a debugging tool
+        print!("{}", s);
+        //~^ ERROR: the `dbg!` macro is intended as a debugging tool
+    }
+}
diff --git a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.rs b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.rs
index 3f4770c63d0..80606c2db05 100644
--- a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.rs
+++ b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.rs
@@ -1,9 +1,5 @@
-//@no-rustfix
-
 #![warn(clippy::dbg_macro)]
-
-#[path = "auxiliary/submodule.rs"]
-mod submodule;
+#![allow(clippy::unnecessary_operation, clippy::no_effect)]
 
 fn foo(n: u32) -> u32 {
     if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n }
@@ -25,12 +21,8 @@ fn factorial(n: u32) -> u32 {
 fn main() {
     dbg!(42);
     //~^ ERROR: the `dbg!` macro is intended as a debugging tool
-    dbg!(dbg!(dbg!(42)));
-    //~^ ERROR: the `dbg!` macro is intended as a debugging tool
     foo(3) + dbg!(factorial(4));
     //~^ ERROR: the `dbg!` macro is intended as a debugging tool
-    dbg!(1, 2, dbg!(3, 4));
-    //~^ ERROR: the `dbg!` macro is intended as a debugging tool
     dbg!(1, 2, 3, 4, 5);
     //~^ ERROR: the `dbg!` macro is intended as a debugging tool
 }
@@ -49,6 +41,7 @@ fn issue9914() {
     macro_rules! expand_to_dbg {
         () => {
             dbg!();
+            //~^ ERROR: the `dbg!` macro is intended as a debugging tool
         };
     }
 
@@ -107,3 +100,12 @@ mod mod1 {
         //~^ ERROR: the `dbg!` macro is intended as a debugging tool
     }
 }
+
+mod issue12131 {
+    fn dbg_in_print(s: &str) {
+        println!("dbg: {:?}", dbg!(s));
+        //~^ ERROR: the `dbg!` macro is intended as a debugging tool
+        print!("{}", dbg!(s));
+        //~^ ERROR: the `dbg!` macro is intended as a debugging tool
+    }
+}
diff --git a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr
index 5ad0bbfed94..86667701da0 100644
--- a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr
+++ b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr
@@ -1,30 +1,18 @@
 error: the `dbg!` macro is intended as a debugging tool
-  --> tests/ui/dbg_macro/auxiliary/submodule.rs:2:5
-   |
-LL |     dbg!();
-   |     ^^^^^^^
-   |
-   = note: `-D clippy::dbg-macro` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::dbg_macro)]`
-help: remove the invocation before committing it to a version control system
-   |
-LL -     dbg!();
-LL +     
-   |
-
-error: the `dbg!` macro is intended as a debugging tool
-  --> tests/ui/dbg_macro/dbg_macro.rs:9:22
+  --> tests/ui/dbg_macro/dbg_macro.rs:5:22
    |
 LL |     if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n }
    |                      ^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: `-D clippy::dbg-macro` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::dbg_macro)]`
 help: remove the invocation before committing it to a version control system
    |
 LL |     if let Some(n) = n.checked_sub(4) { n } else { n }
    |                      ~~~~~~~~~~~~~~~~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> tests/ui/dbg_macro/dbg_macro.rs:15:8
+  --> tests/ui/dbg_macro/dbg_macro.rs:11:8
    |
 LL |     if dbg!(n <= 1) {
    |        ^^^^^^^^^^^^
@@ -35,7 +23,7 @@ LL |     if n <= 1 {
    |        ~~~~~~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> tests/ui/dbg_macro/dbg_macro.rs:17:9
+  --> tests/ui/dbg_macro/dbg_macro.rs:13:9
    |
 LL |         dbg!(1)
    |         ^^^^^^^
@@ -46,7 +34,7 @@ LL |         1
    |
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> tests/ui/dbg_macro/dbg_macro.rs:20:9
+  --> tests/ui/dbg_macro/dbg_macro.rs:16:9
    |
 LL |         dbg!(n * factorial(n - 1))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -57,7 +45,7 @@ LL |         n * factorial(n - 1)
    |
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> tests/ui/dbg_macro/dbg_macro.rs:26:5
+  --> tests/ui/dbg_macro/dbg_macro.rs:22:5
    |
 LL |     dbg!(42);
    |     ^^^^^^^^
@@ -68,18 +56,7 @@ LL |     42;
    |     ~~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> tests/ui/dbg_macro/dbg_macro.rs:28:5
-   |
-LL |     dbg!(dbg!(dbg!(42)));
-   |     ^^^^^^^^^^^^^^^^^^^^
-   |
-help: remove the invocation before committing it to a version control system
-   |
-LL |     dbg!(dbg!(42));
-   |     ~~~~~~~~~~~~~~
-
-error: the `dbg!` macro is intended as a debugging tool
-  --> tests/ui/dbg_macro/dbg_macro.rs:30:14
+  --> tests/ui/dbg_macro/dbg_macro.rs:24:14
    |
 LL |     foo(3) + dbg!(factorial(4));
    |              ^^^^^^^^^^^^^^^^^^
@@ -90,18 +67,7 @@ LL |     foo(3) + factorial(4);
    |              ~~~~~~~~~~~~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> tests/ui/dbg_macro/dbg_macro.rs:32:5
-   |
-LL |     dbg!(1, 2, dbg!(3, 4));
-   |     ^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: remove the invocation before committing it to a version control system
-   |
-LL |     (1, 2, dbg!(3, 4));
-   |     ~~~~~~~~~~~~~~~~~~
-
-error: the `dbg!` macro is intended as a debugging tool
-  --> tests/ui/dbg_macro/dbg_macro.rs:34:5
+  --> tests/ui/dbg_macro/dbg_macro.rs:26:5
    |
 LL |     dbg!(1, 2, 3, 4, 5);
    |     ^^^^^^^^^^^^^^^^^^^
@@ -112,7 +78,7 @@ LL |     (1, 2, 3, 4, 5);
    |     ~~~~~~~~~~~~~~~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> tests/ui/dbg_macro/dbg_macro.rs:55:5
+  --> tests/ui/dbg_macro/dbg_macro.rs:48:5
    |
 LL |     dbg!();
    |     ^^^^^^^
@@ -124,7 +90,7 @@ LL +
    |
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> tests/ui/dbg_macro/dbg_macro.rs:58:13
+  --> tests/ui/dbg_macro/dbg_macro.rs:51:13
    |
 LL |     let _ = dbg!();
    |             ^^^^^^
@@ -135,7 +101,7 @@ LL |     let _ = ();
    |             ~~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> tests/ui/dbg_macro/dbg_macro.rs:60:9
+  --> tests/ui/dbg_macro/dbg_macro.rs:53:9
    |
 LL |     bar(dbg!());
    |         ^^^^^^
@@ -146,7 +112,7 @@ LL |     bar(());
    |         ~~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> tests/ui/dbg_macro/dbg_macro.rs:62:10
+  --> tests/ui/dbg_macro/dbg_macro.rs:55:10
    |
 LL |     foo!(dbg!());
    |          ^^^^^^
@@ -157,7 +123,7 @@ LL |     foo!(());
    |          ~~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> tests/ui/dbg_macro/dbg_macro.rs:64:16
+  --> tests/ui/dbg_macro/dbg_macro.rs:57:16
    |
 LL |     foo2!(foo!(dbg!()));
    |                ^^^^^^
@@ -168,7 +134,23 @@ LL |     foo2!(foo!(()));
    |                ~~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> tests/ui/dbg_macro/dbg_macro.rs:86:9
+  --> tests/ui/dbg_macro/dbg_macro.rs:43:13
+   |
+LL |             dbg!();
+   |             ^^^^^^^
+...
+LL |     expand_to_dbg!();
+   |     ---------------- in this macro invocation
+   |
+   = note: this error originates in the macro `expand_to_dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: remove the invocation before committing it to a version control system
+   |
+LL -             dbg!();
+LL +             
+   |
+
+error: the `dbg!` macro is intended as a debugging tool
+  --> tests/ui/dbg_macro/dbg_macro.rs:79:9
    |
 LL |         dbg!(2);
    |         ^^^^^^^
@@ -179,7 +161,7 @@ LL |         2;
    |         ~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> tests/ui/dbg_macro/dbg_macro.rs:93:5
+  --> tests/ui/dbg_macro/dbg_macro.rs:86:5
    |
 LL |     dbg!(1);
    |     ^^^^^^^
@@ -190,7 +172,7 @@ LL |     1;
    |     ~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> tests/ui/dbg_macro/dbg_macro.rs:99:5
+  --> tests/ui/dbg_macro/dbg_macro.rs:92:5
    |
 LL |     dbg!(1);
    |     ^^^^^^^
@@ -201,7 +183,7 @@ LL |     1;
    |     ~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> tests/ui/dbg_macro/dbg_macro.rs:106:9
+  --> tests/ui/dbg_macro/dbg_macro.rs:99:9
    |
 LL |         dbg!(1);
    |         ^^^^^^^
@@ -211,5 +193,27 @@ help: remove the invocation before committing it to a version control system
 LL |         1;
    |         ~
 
+error: the `dbg!` macro is intended as a debugging tool
+  --> tests/ui/dbg_macro/dbg_macro.rs:106:31
+   |
+LL |         println!("dbg: {:?}", dbg!(s));
+   |                               ^^^^^^^
+   |
+help: remove the invocation before committing it to a version control system
+   |
+LL |         println!("dbg: {:?}", s);
+   |                               ~
+
+error: the `dbg!` macro is intended as a debugging tool
+  --> tests/ui/dbg_macro/dbg_macro.rs:108:22
+   |
+LL |         print!("{}", dbg!(s));
+   |                      ^^^^^^^
+   |
+help: remove the invocation before committing it to a version control system
+   |
+LL |         print!("{}", s);
+   |                      ~
+
 error: aborting due to 19 previous errors
 
diff --git a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.rs b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.rs
new file mode 100644
index 00000000000..0e83766ccae
--- /dev/null
+++ b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.rs
@@ -0,0 +1,12 @@
+//@no-rustfix
+#![warn(clippy::dbg_macro)]
+
+#[path = "auxiliary/submodule.rs"]
+mod submodule;
+
+fn main() {
+    dbg!(dbg!(dbg!(42)));
+    //~^ ERROR: the `dbg!` macro is intended as a debugging tool
+    dbg!(1, 2, dbg!(3, 4));
+    //~^ ERROR: the `dbg!` macro is intended as a debugging tool
+}
diff --git a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.stderr b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.stderr
new file mode 100644
index 00000000000..d21595c2fcd
--- /dev/null
+++ b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.stderr
@@ -0,0 +1,71 @@
+error: the `dbg!` macro is intended as a debugging tool
+  --> tests/ui/dbg_macro/auxiliary/submodule.rs:2:5
+   |
+LL |     dbg!();
+   |     ^^^^^^^
+   |
+   = note: `-D clippy::dbg-macro` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::dbg_macro)]`
+help: remove the invocation before committing it to a version control system
+   |
+LL -     dbg!();
+LL +     
+   |
+
+error: the `dbg!` macro is intended as a debugging tool
+  --> tests/ui/dbg_macro/dbg_macro_unfixable.rs:8:5
+   |
+LL |     dbg!(dbg!(dbg!(42)));
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the invocation before committing it to a version control system
+   |
+LL |     dbg!(dbg!(42));
+   |     ~~~~~~~~~~~~~~
+
+error: the `dbg!` macro is intended as a debugging tool
+  --> tests/ui/dbg_macro/dbg_macro_unfixable.rs:8:10
+   |
+LL |     dbg!(dbg!(dbg!(42)));
+   |          ^^^^^^^^^^^^^^
+   |
+help: remove the invocation before committing it to a version control system
+   |
+LL |     dbg!(dbg!(42));
+   |          ~~~~~~~~
+
+error: the `dbg!` macro is intended as a debugging tool
+  --> tests/ui/dbg_macro/dbg_macro_unfixable.rs:8:15
+   |
+LL |     dbg!(dbg!(dbg!(42)));
+   |               ^^^^^^^^
+   |
+help: remove the invocation before committing it to a version control system
+   |
+LL |     dbg!(dbg!(42));
+   |               ~~
+
+error: the `dbg!` macro is intended as a debugging tool
+  --> tests/ui/dbg_macro/dbg_macro_unfixable.rs:10:5
+   |
+LL |     dbg!(1, 2, dbg!(3, 4));
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the invocation before committing it to a version control system
+   |
+LL |     (1, 2, dbg!(3, 4));
+   |     ~~~~~~~~~~~~~~~~~~
+
+error: the `dbg!` macro is intended as a debugging tool
+  --> tests/ui/dbg_macro/dbg_macro_unfixable.rs:10:16
+   |
+LL |     dbg!(1, 2, dbg!(3, 4));
+   |                ^^^^^^^^^^
+   |
+help: remove the invocation before committing it to a version control system
+   |
+LL |     dbg!(1, 2, (3, 4));
+   |                ~~~~~~
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/doc/issue_10262.fixed b/src/tools/clippy/tests/ui/doc/issue_10262.fixed
new file mode 100644
index 00000000000..5d067736d55
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc/issue_10262.fixed
@@ -0,0 +1,12 @@
+#![warn(clippy::doc_markdown)]
+
+// Should only warn for the first line!
+/// `AviSynth` documentation:
+//~^ ERROR: item in documentation is missing backticks
+///
+/// > AvisynthPluginInit3 may be called more than once with different IScriptEnvironments.
+///
+/// <blockquote>bla AvisynthPluginInit3 bla</blockquote>
+///
+/// <q>bla AvisynthPluginInit3 bla</q>
+pub struct Foo;
diff --git a/src/tools/clippy/tests/ui/doc/issue_10262.rs b/src/tools/clippy/tests/ui/doc/issue_10262.rs
new file mode 100644
index 00000000000..e2cbd938d5d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc/issue_10262.rs
@@ -0,0 +1,12 @@
+#![warn(clippy::doc_markdown)]
+
+// Should only warn for the first line!
+/// AviSynth documentation:
+//~^ ERROR: item in documentation is missing backticks
+///
+/// > AvisynthPluginInit3 may be called more than once with different IScriptEnvironments.
+///
+/// <blockquote>bla AvisynthPluginInit3 bla</blockquote>
+///
+/// <q>bla AvisynthPluginInit3 bla</q>
+pub struct Foo;
diff --git a/src/tools/clippy/tests/ui/doc/issue_10262.stderr b/src/tools/clippy/tests/ui/doc/issue_10262.stderr
new file mode 100644
index 00000000000..f43d9551e94
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc/issue_10262.stderr
@@ -0,0 +1,15 @@
+error: item in documentation is missing backticks
+  --> tests/ui/doc/issue_10262.rs:4:5
+   |
+LL | /// AviSynth documentation:
+   |     ^^^^^^^^
+   |
+   = note: `-D clippy::doc-markdown` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::doc_markdown)]`
+help: try
+   |
+LL | /// `AviSynth` documentation:
+   |     ~~~~~~~~~~
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui/duplicated_attributes.rs b/src/tools/clippy/tests/ui/duplicated_attributes.rs
new file mode 100644
index 00000000000..0f036c684c1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/duplicated_attributes.rs
@@ -0,0 +1,17 @@
+#![warn(clippy::duplicated_attributes)]
+#![cfg(any(unix, windows))]
+#![allow(dead_code)]
+#![allow(dead_code)] //~ ERROR: duplicated attribute
+#![cfg(any(unix, windows))]
+//~^ ERROR: duplicated attribute
+//~| ERROR: duplicated attribute
+
+#[cfg(any(unix, windows, target_os = "linux"))]
+#[allow(dead_code)]
+#[allow(dead_code)] //~ ERROR: duplicated attribute
+#[cfg(any(unix, windows, target_os = "linux"))]
+//~^ ERROR: duplicated attribute
+//~| ERROR: duplicated attribute
+fn foo() {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/duplicated_attributes.stderr b/src/tools/clippy/tests/ui/duplicated_attributes.stderr
new file mode 100644
index 00000000000..1c6578dbb43
--- /dev/null
+++ b/src/tools/clippy/tests/ui/duplicated_attributes.stderr
@@ -0,0 +1,123 @@
+error: duplicated attribute
+  --> tests/ui/duplicated_attributes.rs:4:10
+   |
+LL | #![allow(dead_code)]
+   |          ^^^^^^^^^
+   |
+note: first defined here
+  --> tests/ui/duplicated_attributes.rs:3:10
+   |
+LL | #![allow(dead_code)]
+   |          ^^^^^^^^^
+help: remove this attribute
+  --> tests/ui/duplicated_attributes.rs:4:10
+   |
+LL | #![allow(dead_code)]
+   |          ^^^^^^^^^
+   = note: `-D clippy::duplicated-attributes` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::duplicated_attributes)]`
+
+error: duplicated attribute
+  --> tests/ui/duplicated_attributes.rs:5:12
+   |
+LL | #![cfg(any(unix, windows))]
+   |            ^^^^
+   |
+note: first defined here
+  --> tests/ui/duplicated_attributes.rs:2:12
+   |
+LL | #![cfg(any(unix, windows))]
+   |            ^^^^
+help: remove this attribute
+  --> tests/ui/duplicated_attributes.rs:5:12
+   |
+LL | #![cfg(any(unix, windows))]
+   |            ^^^^
+
+error: duplicated attribute
+  --> tests/ui/duplicated_attributes.rs:5:18
+   |
+LL | #![cfg(any(unix, windows))]
+   |                  ^^^^^^^
+   |
+note: first defined here
+  --> tests/ui/duplicated_attributes.rs:2:18
+   |
+LL | #![cfg(any(unix, windows))]
+   |                  ^^^^^^^
+help: remove this attribute
+  --> tests/ui/duplicated_attributes.rs:5:18
+   |
+LL | #![cfg(any(unix, windows))]
+   |                  ^^^^^^^
+
+error: duplicated attribute
+  --> tests/ui/duplicated_attributes.rs:11:9
+   |
+LL | #[allow(dead_code)]
+   |         ^^^^^^^^^
+   |
+note: first defined here
+  --> tests/ui/duplicated_attributes.rs:10:9
+   |
+LL | #[allow(dead_code)]
+   |         ^^^^^^^^^
+help: remove this attribute
+  --> tests/ui/duplicated_attributes.rs:11:9
+   |
+LL | #[allow(dead_code)]
+   |         ^^^^^^^^^
+
+error: duplicated attribute
+  --> tests/ui/duplicated_attributes.rs:12:11
+   |
+LL | #[cfg(any(unix, windows, target_os = "linux"))]
+   |           ^^^^
+   |
+note: first defined here
+  --> tests/ui/duplicated_attributes.rs:9:11
+   |
+LL | #[cfg(any(unix, windows, target_os = "linux"))]
+   |           ^^^^
+help: remove this attribute
+  --> tests/ui/duplicated_attributes.rs:12:11
+   |
+LL | #[cfg(any(unix, windows, target_os = "linux"))]
+   |           ^^^^
+
+error: duplicated attribute
+  --> tests/ui/duplicated_attributes.rs:12:17
+   |
+LL | #[cfg(any(unix, windows, target_os = "linux"))]
+   |                 ^^^^^^^
+   |
+note: first defined here
+  --> tests/ui/duplicated_attributes.rs:9:17
+   |
+LL | #[cfg(any(unix, windows, target_os = "linux"))]
+   |                 ^^^^^^^
+help: remove this attribute
+  --> tests/ui/duplicated_attributes.rs:12:17
+   |
+LL | #[cfg(any(unix, windows, target_os = "linux"))]
+   |                 ^^^^^^^
+
+error: duplicated attribute
+  --> tests/ui/duplicated_attributes.rs:12:26
+   |
+LL | #[cfg(any(unix, windows, target_os = "linux"))]
+   |                          ^^^^^^^^^^^^^^^^^^^
+   |
+note: first defined here
+  --> tests/ui/duplicated_attributes.rs:9:26
+   |
+LL | #[cfg(any(unix, windows, target_os = "linux"))]
+   |                          ^^^^^^^^^^^^^^^^^^^
+help: remove this attribute
+  --> tests/ui/duplicated_attributes.rs:12:26
+   |
+LL | #[cfg(any(unix, windows, target_os = "linux"))]
+   |                          ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/else_if_without_else.rs b/src/tools/clippy/tests/ui/else_if_without_else.rs
index e7786f7dd27..b04c22fa2ae 100644
--- a/src/tools/clippy/tests/ui/else_if_without_else.rs
+++ b/src/tools/clippy/tests/ui/else_if_without_else.rs
@@ -1,7 +1,5 @@
-//@compile-flags: -Zdeduplicate-diagnostics=yes
-
-#![warn(clippy::all)]
 #![warn(clippy::else_if_without_else)]
+#![allow(clippy::collapsible_else_if)]
 
 fn bla1() -> bool {
     unimplemented!()
@@ -12,6 +10,12 @@ fn bla2() -> bool {
 fn bla3() -> bool {
     unimplemented!()
 }
+fn bla4() -> bool {
+    unimplemented!()
+}
+fn bla5() -> bool {
+    unimplemented!()
+}
 
 fn main() {
     if bla1() {
@@ -57,4 +61,62 @@ fn main() {
         //~^ ERROR: `if` expression with an `else if`, but without a final `else`
         println!("else if 2");
     }
+
+    if bla1() {
+        println!("if");
+    } else if bla2() {
+        println!("else if 1");
+    } else if bla3() {
+        println!("else if 2");
+    } else if bla4() {
+        println!("else if 3");
+    } else if bla5() {
+        println!("else if 4");
+    } else {
+        println!("else");
+    }
+
+    if bla1() {
+        println!("if");
+    } else if bla2() {
+        println!("else if 1");
+    } else if bla3() {
+        println!("else if 2");
+    } else if bla4() {
+        println!("else if 3");
+    } else if bla5() {
+        //~^ ERROR: `if` expression with an `else if`, but without a final `else`
+        println!("else if 4");
+    }
+
+    if bla1() {
+        println!("if");
+    } else if bla2() {
+        println!("else if 1");
+    } else {
+        if bla3() {
+            println!("else if 2");
+        } else if bla4() {
+            println!("else if 3");
+        } else if bla5() {
+            println!("else if 4");
+        } else {
+            println!("else");
+        }
+    }
+
+    if bla1() {
+        println!("if");
+    } else if bla2() {
+        println!("else if 1");
+    } else {
+        if bla3() {
+            println!("else if 2");
+        } else if bla4() {
+            println!("else if 3");
+        } else if bla5() {
+            //~^ ERROR: `if` expression with an `else if`, but without a final `else`
+            println!("else if 4");
+        }
+    }
 }
diff --git a/src/tools/clippy/tests/ui/else_if_without_else.stderr b/src/tools/clippy/tests/ui/else_if_without_else.stderr
index 3bb840f39e7..bc717485229 100644
--- a/src/tools/clippy/tests/ui/else_if_without_else.stderr
+++ b/src/tools/clippy/tests/ui/else_if_without_else.stderr
@@ -1,5 +1,5 @@
 error: `if` expression with an `else if`, but without a final `else`
-  --> tests/ui/else_if_without_else.rs:47:12
+  --> tests/ui/else_if_without_else.rs:51:12
    |
 LL |       } else if bla2() {
    |  ____________^
@@ -13,7 +13,7 @@ LL | |     }
    = help: to override `-D warnings` add `#[allow(clippy::else_if_without_else)]`
 
 error: `if` expression with an `else if`, but without a final `else`
-  --> tests/ui/else_if_without_else.rs:56:12
+  --> tests/ui/else_if_without_else.rs:60:12
    |
 LL |       } else if bla3() {
    |  ____________^
@@ -24,5 +24,29 @@ LL | |     }
    |
    = help: add an `else` block here
 
-error: aborting due to 2 previous errors
+error: `if` expression with an `else if`, but without a final `else`
+  --> tests/ui/else_if_without_else.rs:87:12
+   |
+LL |       } else if bla5() {
+   |  ____________^
+LL | |
+LL | |         println!("else if 4");
+LL | |     }
+   | |_____^
+   |
+   = help: add an `else` block here
+
+error: `if` expression with an `else if`, but without a final `else`
+  --> tests/ui/else_if_without_else.rs:117:16
+   |
+LL |           } else if bla5() {
+   |  ________________^
+LL | |
+LL | |             println!("else if 4");
+LL | |         }
+   | |_________^
+   |
+   = help: add an `else` block here
+
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/empty_docs.rs b/src/tools/clippy/tests/ui/empty_docs.rs
index 272fab7d5ca..00e64eebc5f 100644
--- a/src/tools/clippy/tests/ui/empty_docs.rs
+++ b/src/tools/clippy/tests/ui/empty_docs.rs
@@ -1,6 +1,9 @@
+//@aux-build:proc_macro_attr.rs
+
 #![allow(unused)]
 #![warn(clippy::empty_docs)]
 #![allow(clippy::mixed_attributes_style)]
+#![feature(extern_types)]
 
 mod outer {
     //!
@@ -67,3 +70,17 @@ mod outer {
         y: i32,
     }
 }
+
+mod issue_12377 {
+    use proc_macro_attr::with_empty_docs;
+
+    #[with_empty_docs]
+    extern "C" {
+        type Test;
+    }
+
+    #[with_empty_docs]
+    struct Foo {
+        a: u8,
+    }
+}
diff --git a/src/tools/clippy/tests/ui/empty_docs.stderr b/src/tools/clippy/tests/ui/empty_docs.stderr
index f12aead6aa7..28ebea22c5d 100644
--- a/src/tools/clippy/tests/ui/empty_docs.stderr
+++ b/src/tools/clippy/tests/ui/empty_docs.stderr
@@ -1,5 +1,5 @@
 error: empty doc comment
-  --> tests/ui/empty_docs.rs:6:5
+  --> tests/ui/empty_docs.rs:9:5
    |
 LL |     //!
    |     ^^^
@@ -9,7 +9,7 @@ LL |     //!
    = help: to override `-D warnings` add `#[allow(clippy::empty_docs)]`
 
 error: empty doc comment
-  --> tests/ui/empty_docs.rs:14:5
+  --> tests/ui/empty_docs.rs:17:5
    |
 LL |     ///
    |     ^^^
@@ -17,7 +17,7 @@ LL |     ///
    = help: consider removing or filling it
 
 error: empty doc comment
-  --> tests/ui/empty_docs.rs:16:9
+  --> tests/ui/empty_docs.rs:19:9
    |
 LL |         ///
    |         ^^^
@@ -25,7 +25,7 @@ LL |         ///
    = help: consider removing or filling it
 
 error: empty doc comment
-  --> tests/ui/empty_docs.rs:27:5
+  --> tests/ui/empty_docs.rs:30:5
    |
 LL |     #[doc = ""]
    |     ^^^^^^^^^^^
@@ -33,7 +33,7 @@ LL |     #[doc = ""]
    = help: consider removing or filling it
 
 error: empty doc comment
-  --> tests/ui/empty_docs.rs:30:5
+  --> tests/ui/empty_docs.rs:33:5
    |
 LL | /     #[doc = ""]
 LL | |     #[doc = ""]
@@ -42,7 +42,7 @@ LL | |     #[doc = ""]
    = help: consider removing or filling it
 
 error: empty doc comment
-  --> tests/ui/empty_docs.rs:37:5
+  --> tests/ui/empty_docs.rs:40:5
    |
 LL |     ///
    |     ^^^
@@ -50,7 +50,7 @@ LL |     ///
    = help: consider removing or filling it
 
 error: empty doc comment
-  --> tests/ui/empty_docs.rs:50:13
+  --> tests/ui/empty_docs.rs:53:13
    |
 LL |             /*! */
    |             ^^^^^^
@@ -58,7 +58,7 @@ LL |             /*! */
    = help: consider removing or filling it
 
 error: empty doc comment
-  --> tests/ui/empty_docs.rs:58:13
+  --> tests/ui/empty_docs.rs:61:13
    |
 LL |             ///
    |             ^^^
@@ -66,7 +66,7 @@ LL |             ///
    = help: consider removing or filling it
 
 error: empty doc comment
-  --> tests/ui/empty_docs.rs:66:9
+  --> tests/ui/empty_docs.rs:69:9
    |
 LL |         ///
    |         ^^^
diff --git a/src/tools/clippy/tests/ui/empty_line_after_doc_comments.rs b/src/tools/clippy/tests/ui/empty_line_after_doc_comments.rs
index e843770f578..dd78491749c 100644
--- a/src/tools/clippy/tests/ui/empty_line_after_doc_comments.rs
+++ b/src/tools/clippy/tests/ui/empty_line_after_doc_comments.rs
@@ -1,6 +1,6 @@
 //@aux-build:proc_macro_attr.rs
 #![warn(clippy::empty_line_after_doc_comments)]
-#![allow(clippy::assertions_on_constants)]
+#![allow(clippy::assertions_on_constants, clippy::duplicated_attributes)]
 #![feature(custom_inner_attributes)]
 #![rustfmt::skip]
 
diff --git a/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.rs b/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.rs
index 269e66ea0a8..f147cf2cd5d 100644
--- a/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.rs
+++ b/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.rs
@@ -1,6 +1,6 @@
 //@aux-build:proc_macro_attr.rs
 #![warn(clippy::empty_line_after_outer_attr)]
-#![allow(clippy::assertions_on_constants)]
+#![allow(clippy::assertions_on_constants, clippy::duplicated_attributes)]
 #![feature(custom_inner_attributes)]
 #![rustfmt::skip]
 
diff --git a/src/tools/clippy/tests/ui/entry.fixed b/src/tools/clippy/tests/ui/entry.fixed
index 71ec13f4610..abdfae2a3e1 100644
--- a/src/tools/clippy/tests/ui/entry.fixed
+++ b/src/tools/clippy/tests/ui/entry.fixed
@@ -176,4 +176,14 @@ pub fn issue_11935() {
     }
 }
 
+fn issue12489(map: &mut HashMap<u64, u64>) -> Option<()> {
+    if let std::collections::hash_map::Entry::Vacant(e) = map.entry(1) {
+        let Some(1) = Some(2) else {
+            return None;
+        };
+        e.insert(42);
+    }
+    Some(())
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/entry.rs b/src/tools/clippy/tests/ui/entry.rs
index 86092b7c055..7774f99a2a2 100644
--- a/src/tools/clippy/tests/ui/entry.rs
+++ b/src/tools/clippy/tests/ui/entry.rs
@@ -180,4 +180,14 @@ pub fn issue_11935() {
     }
 }
 
+fn issue12489(map: &mut HashMap<u64, u64>) -> Option<()> {
+    if !map.contains_key(&1) {
+        let Some(1) = Some(2) else {
+            return None;
+        };
+        map.insert(1, 42);
+    }
+    Some(())
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/entry.stderr b/src/tools/clippy/tests/ui/entry.stderr
index ef4c36bcf54..fb467676606 100644
--- a/src/tools/clippy/tests/ui/entry.stderr
+++ b/src/tools/clippy/tests/ui/entry.stderr
@@ -214,5 +214,26 @@ LL +         v
 LL +     });
    |
 
-error: aborting due to 10 previous errors
+error: usage of `contains_key` followed by `insert` on a `HashMap`
+  --> tests/ui/entry.rs:184:5
+   |
+LL | /     if !map.contains_key(&1) {
+LL | |         let Some(1) = Some(2) else {
+LL | |             return None;
+LL | |         };
+LL | |         map.insert(1, 42);
+LL | |     }
+   | |_____^
+   |
+help: try
+   |
+LL ~     if let std::collections::hash_map::Entry::Vacant(e) = map.entry(1) {
+LL +         let Some(1) = Some(2) else {
+LL +             return None;
+LL +         };
+LL +         e.insert(42);
+LL +     }
+   |
+
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/integer_division_remainder_used.rs b/src/tools/clippy/tests/ui/integer_division_remainder_used.rs
new file mode 100644
index 00000000000..5d1b02095d1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/integer_division_remainder_used.rs
@@ -0,0 +1,41 @@
+#![warn(clippy::integer_division_remainder_used)]
+#![allow(unused_variables)]
+#![allow(clippy::op_ref)]
+
+struct CustomOps(pub i32);
+impl std::ops::Div for CustomOps {
+    type Output = Self;
+
+    fn div(self, rhs: Self) -> Self::Output {
+        Self(self.0 / rhs.0)
+    }
+}
+impl std::ops::Rem for CustomOps {
+    type Output = Self;
+
+    fn rem(self, rhs: Self) -> Self::Output {
+        Self(self.0 % rhs.0)
+    }
+}
+
+fn main() {
+    // should trigger
+    let a = 10;
+    let b = 5;
+    let c = a / b;
+    let d = a % b;
+    let e = &a / b;
+    let f = a % &b;
+    let g = &a / &b;
+    let h = &10 % b;
+    let i = a / &4;
+
+    // should not trigger on custom Div and Rem
+    let w = CustomOps(3);
+    let x = CustomOps(4);
+    let y = w / x;
+
+    let w = CustomOps(3);
+    let x = CustomOps(4);
+    let z = w % x;
+}
diff --git a/src/tools/clippy/tests/ui/integer_division_remainder_used.stderr b/src/tools/clippy/tests/ui/integer_division_remainder_used.stderr
new file mode 100644
index 00000000000..8adfda28893
--- /dev/null
+++ b/src/tools/clippy/tests/ui/integer_division_remainder_used.stderr
@@ -0,0 +1,59 @@
+error: use of / has been disallowed in this context
+  --> tests/ui/integer_division_remainder_used.rs:10:14
+   |
+LL |         Self(self.0 / rhs.0)
+   |              ^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::integer-division-remainder-used` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::integer_division_remainder_used)]`
+
+error: use of % has been disallowed in this context
+  --> tests/ui/integer_division_remainder_used.rs:17:14
+   |
+LL |         Self(self.0 % rhs.0)
+   |              ^^^^^^^^^^^^^^
+
+error: use of / has been disallowed in this context
+  --> tests/ui/integer_division_remainder_used.rs:25:13
+   |
+LL |     let c = a / b;
+   |             ^^^^^
+
+error: use of % has been disallowed in this context
+  --> tests/ui/integer_division_remainder_used.rs:26:13
+   |
+LL |     let d = a % b;
+   |             ^^^^^
+
+error: use of / has been disallowed in this context
+  --> tests/ui/integer_division_remainder_used.rs:27:13
+   |
+LL |     let e = &a / b;
+   |             ^^^^^^
+
+error: use of % has been disallowed in this context
+  --> tests/ui/integer_division_remainder_used.rs:28:13
+   |
+LL |     let f = a % &b;
+   |             ^^^^^^
+
+error: use of / has been disallowed in this context
+  --> tests/ui/integer_division_remainder_used.rs:29:13
+   |
+LL |     let g = &a / &b;
+   |             ^^^^^^^
+
+error: use of % has been disallowed in this context
+  --> tests/ui/integer_division_remainder_used.rs:30:13
+   |
+LL |     let h = &10 % b;
+   |             ^^^^^^^
+
+error: use of / has been disallowed in this context
+  --> tests/ui/integer_division_remainder_used.rs:31:13
+   |
+LL |     let i = a / &4;
+   |             ^^^^^^
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/tests/ui/iter_nth.fixed b/src/tools/clippy/tests/ui/iter_nth.fixed
new file mode 100644
index 00000000000..aff3731a883
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_nth.fixed
@@ -0,0 +1,60 @@
+//@aux-build:option_helpers.rs
+
+#![warn(clippy::iter_nth)]
+#![allow(clippy::useless_vec)]
+
+#[macro_use]
+extern crate option_helpers;
+
+use option_helpers::IteratorFalsePositives;
+use std::collections::VecDeque;
+
+/// Struct to generate false positives for things with `.iter()`.
+#[derive(Copy, Clone)]
+struct HasIter;
+
+impl HasIter {
+    fn iter(self) -> IteratorFalsePositives {
+        IteratorFalsePositives { foo: 0 }
+    }
+
+    fn iter_mut(self) -> IteratorFalsePositives {
+        IteratorFalsePositives { foo: 0 }
+    }
+}
+
+/// Checks implementation of `ITER_NTH` lint.
+fn iter_nth() {
+    let mut some_vec = vec![0, 1, 2, 3];
+    let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]);
+    let mut some_vec_deque: VecDeque<_> = some_vec.iter().cloned().collect();
+
+    {
+        // Make sure we lint `.iter()` for relevant types.
+        let bad_vec = some_vec.get(3);
+        let bad_slice = &some_vec[..].get(3);
+        let bad_boxed_slice = boxed_slice.get(3);
+        let bad_vec_deque = some_vec_deque.get(3);
+    }
+
+    {
+        // Make sure we lint `.iter_mut()` for relevant types.
+        let bad_vec = some_vec.get_mut(3);
+    }
+    {
+        let bad_slice = &some_vec[..].get_mut(3);
+    }
+    {
+        let bad_vec_deque = some_vec_deque.get_mut(3);
+    }
+
+    let vec_ref = &Vec::<String>::new();
+    vec_ref.get(3);
+
+    // Make sure we don't lint for non-relevant types.
+    let false_positive = HasIter;
+    let ok = false_positive.iter().nth(3);
+    let ok_mut = false_positive.iter_mut().nth(3);
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/iter_nth.rs b/src/tools/clippy/tests/ui/iter_nth.rs
index 7c567bb81d8..89d68044ddd 100644
--- a/src/tools/clippy/tests/ui/iter_nth.rs
+++ b/src/tools/clippy/tests/ui/iter_nth.rs
@@ -48,6 +48,9 @@ fn iter_nth() {
         let bad_vec_deque = some_vec_deque.iter_mut().nth(3);
     }
 
+    let vec_ref = &Vec::<String>::new();
+    vec_ref.iter().nth(3);
+
     // Make sure we don't lint for non-relevant types.
     let false_positive = HasIter;
     let ok = false_positive.iter().nth(3);
diff --git a/src/tools/clippy/tests/ui/iter_nth.stderr b/src/tools/clippy/tests/ui/iter_nth.stderr
index c5dd0c99727..178463f5347 100644
--- a/src/tools/clippy/tests/ui/iter_nth.stderr
+++ b/src/tools/clippy/tests/ui/iter_nth.stderr
@@ -4,9 +4,12 @@ error: called `.iter().nth()` on a `Vec`
 LL |         let bad_vec = some_vec.iter().nth(3);
    |                       ^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: calling `.get()` is both faster and more readable
    = note: `-D clippy::iter-nth` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::iter_nth)]`
+help: `get` is equivalent but more concise
+   |
+LL |         let bad_vec = some_vec.get(3);
+   |                                ~~~
 
 error: called `.iter().nth()` on a slice
   --> tests/ui/iter_nth.rs:35:26
@@ -14,7 +17,10 @@ error: called `.iter().nth()` on a slice
 LL |         let bad_slice = &some_vec[..].iter().nth(3);
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: calling `.get()` is both faster and more readable
+help: `get` is equivalent but more concise
+   |
+LL |         let bad_slice = &some_vec[..].get(3);
+   |                                       ~~~
 
 error: called `.iter().nth()` on a slice
   --> tests/ui/iter_nth.rs:36:31
@@ -22,7 +28,10 @@ error: called `.iter().nth()` on a slice
 LL |         let bad_boxed_slice = boxed_slice.iter().nth(3);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: calling `.get()` is both faster and more readable
+help: `get` is equivalent but more concise
+   |
+LL |         let bad_boxed_slice = boxed_slice.get(3);
+   |                                           ~~~
 
 error: called `.iter().nth()` on a `VecDeque`
   --> tests/ui/iter_nth.rs:37:29
@@ -30,7 +39,10 @@ error: called `.iter().nth()` on a `VecDeque`
 LL |         let bad_vec_deque = some_vec_deque.iter().nth(3);
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: calling `.get()` is both faster and more readable
+help: `get` is equivalent but more concise
+   |
+LL |         let bad_vec_deque = some_vec_deque.get(3);
+   |                                            ~~~
 
 error: called `.iter_mut().nth()` on a `Vec`
   --> tests/ui/iter_nth.rs:42:23
@@ -38,7 +50,10 @@ error: called `.iter_mut().nth()` on a `Vec`
 LL |         let bad_vec = some_vec.iter_mut().nth(3);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: calling `.get_mut()` is both faster and more readable
+help: `get_mut` is equivalent but more concise
+   |
+LL |         let bad_vec = some_vec.get_mut(3);
+   |                                ~~~~~~~
 
 error: called `.iter_mut().nth()` on a slice
   --> tests/ui/iter_nth.rs:45:26
@@ -46,7 +61,10 @@ error: called `.iter_mut().nth()` on a slice
 LL |         let bad_slice = &some_vec[..].iter_mut().nth(3);
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: calling `.get_mut()` is both faster and more readable
+help: `get_mut` is equivalent but more concise
+   |
+LL |         let bad_slice = &some_vec[..].get_mut(3);
+   |                                       ~~~~~~~
 
 error: called `.iter_mut().nth()` on a `VecDeque`
   --> tests/ui/iter_nth.rs:48:29
@@ -54,7 +72,21 @@ error: called `.iter_mut().nth()` on a `VecDeque`
 LL |         let bad_vec_deque = some_vec_deque.iter_mut().nth(3);
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: calling `.get_mut()` is both faster and more readable
+help: `get_mut` is equivalent but more concise
+   |
+LL |         let bad_vec_deque = some_vec_deque.get_mut(3);
+   |                                            ~~~~~~~
+
+error: called `.iter().nth()` on a `Vec`
+  --> tests/ui/iter_nth.rs:52:5
+   |
+LL |     vec_ref.iter().nth(3);
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+help: `get` is equivalent but more concise
+   |
+LL |     vec_ref.get(3);
+   |             ~~~
 
-error: aborting due to 7 previous errors
+error: aborting due to 8 previous errors
 
diff --git a/src/tools/clippy/tests/ui/len_zero.fixed b/src/tools/clippy/tests/ui/len_zero.fixed
index 745fc7e1a8b..c16d7a26616 100644
--- a/src/tools/clippy/tests/ui/len_zero.fixed
+++ b/src/tools/clippy/tests/ui/len_zero.fixed
@@ -1,5 +1,11 @@
 #![warn(clippy::len_zero)]
-#![allow(dead_code, unused, clippy::needless_if, clippy::len_without_is_empty)]
+#![allow(
+    dead_code,
+    unused,
+    clippy::needless_if,
+    clippy::len_without_is_empty,
+    clippy::const_is_empty
+)]
 
 extern crate core;
 use core::ops::Deref;
diff --git a/src/tools/clippy/tests/ui/len_zero.rs b/src/tools/clippy/tests/ui/len_zero.rs
index 048ad2f4fd3..5c49a5abf81 100644
--- a/src/tools/clippy/tests/ui/len_zero.rs
+++ b/src/tools/clippy/tests/ui/len_zero.rs
@@ -1,5 +1,11 @@
 #![warn(clippy::len_zero)]
-#![allow(dead_code, unused, clippy::needless_if, clippy::len_without_is_empty)]
+#![allow(
+    dead_code,
+    unused,
+    clippy::needless_if,
+    clippy::len_without_is_empty,
+    clippy::const_is_empty
+)]
 
 extern crate core;
 use core::ops::Deref;
diff --git a/src/tools/clippy/tests/ui/len_zero.stderr b/src/tools/clippy/tests/ui/len_zero.stderr
index b1f04c94de6..dd07a85d62c 100644
--- a/src/tools/clippy/tests/ui/len_zero.stderr
+++ b/src/tools/clippy/tests/ui/len_zero.stderr
@@ -1,5 +1,5 @@
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:82:8
+  --> tests/ui/len_zero.rs:88:8
    |
 LL |     if x.len() == 0 {
    |        ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `x.is_empty()`
@@ -8,13 +8,13 @@ LL |     if x.len() == 0 {
    = help: to override `-D warnings` add `#[allow(clippy::len_zero)]`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:86:8
+  --> tests/ui/len_zero.rs:92:8
    |
 LL |     if "".len() == 0 {}
    |        ^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `"".is_empty()`
 
 error: comparison to empty slice
-  --> tests/ui/len_zero.rs:95:20
+  --> tests/ui/len_zero.rs:101:20
    |
 LL |     println!("{}", *s1 == "");
    |                    ^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s1.is_empty()`
@@ -23,121 +23,121 @@ LL |     println!("{}", *s1 == "");
    = help: to override `-D warnings` add `#[allow(clippy::comparison_to_empty)]`
 
 error: comparison to empty slice
-  --> tests/ui/len_zero.rs:96:20
+  --> tests/ui/len_zero.rs:102:20
    |
 LL |     println!("{}", **s2 == "");
    |                    ^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s2.is_empty()`
 
 error: comparison to empty slice
-  --> tests/ui/len_zero.rs:97:20
+  --> tests/ui/len_zero.rs:103:20
    |
 LL |     println!("{}", ***s3 == "");
    |                    ^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s3.is_empty()`
 
 error: comparison to empty slice
-  --> tests/ui/len_zero.rs:98:20
+  --> tests/ui/len_zero.rs:104:20
    |
 LL |     println!("{}", ****s4 == "");
    |                    ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s4.is_empty()`
 
 error: comparison to empty slice
-  --> tests/ui/len_zero.rs:99:20
+  --> tests/ui/len_zero.rs:105:20
    |
 LL |     println!("{}", *****s5 == "");
    |                    ^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s5.is_empty()`
 
 error: comparison to empty slice
-  --> tests/ui/len_zero.rs:100:20
+  --> tests/ui/len_zero.rs:106:20
    |
 LL |     println!("{}", ******(s6) == "");
    |                    ^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(s6).is_empty()`
 
 error: comparison to empty slice
-  --> tests/ui/len_zero.rs:103:20
+  --> tests/ui/len_zero.rs:109:20
    |
 LL |     println!("{}", &**d2s == "");
    |                    ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(**d2s).is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:118:8
+  --> tests/ui/len_zero.rs:124:8
    |
 LL |     if has_is_empty.len() == 0 {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:121:8
+  --> tests/ui/len_zero.rs:127:8
    |
 LL |     if has_is_empty.len() != 0 {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:124:8
+  --> tests/ui/len_zero.rs:130:8
    |
 LL |     if has_is_empty.len() > 0 {
    |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to one
-  --> tests/ui/len_zero.rs:127:8
+  --> tests/ui/len_zero.rs:133:8
    |
 LL |     if has_is_empty.len() < 1 {
    |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to one
-  --> tests/ui/len_zero.rs:130:8
+  --> tests/ui/len_zero.rs:136:8
    |
 LL |     if has_is_empty.len() >= 1 {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:141:8
+  --> tests/ui/len_zero.rs:147:8
    |
 LL |     if 0 == has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:144:8
+  --> tests/ui/len_zero.rs:150:8
    |
 LL |     if 0 != has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:147:8
+  --> tests/ui/len_zero.rs:153:8
    |
 LL |     if 0 < has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to one
-  --> tests/ui/len_zero.rs:150:8
+  --> tests/ui/len_zero.rs:156:8
    |
 LL |     if 1 <= has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to one
-  --> tests/ui/len_zero.rs:153:8
+  --> tests/ui/len_zero.rs:159:8
    |
 LL |     if 1 > has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:167:8
+  --> tests/ui/len_zero.rs:173:8
    |
 LL |     if with_is_empty.len() == 0 {
    |        ^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `with_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:179:6
+  --> tests/ui/len_zero.rs:185:6
    |
 LL |     (has_is_empty.len() > 0).then(|| println!("This can happen."));
    |      ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:180:6
+  --> tests/ui/len_zero.rs:186:6
    |
 LL |     (has_is_empty.len() == 0).then(|| println!("Or this!"));
    |      ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:184:8
+  --> tests/ui/len_zero.rs:190:8
    |
 LL |     if b.len() != 0 {}
    |        ^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!b.is_empty()`
diff --git a/src/tools/clippy/tests/ui/let_if_seq.rs b/src/tools/clippy/tests/ui/let_if_seq.rs
index 9869d945299..a29d35880b8 100644
--- a/src/tools/clippy/tests/ui/let_if_seq.rs
+++ b/src/tools/clippy/tests/ui/let_if_seq.rs
@@ -57,6 +57,17 @@ fn early_return() -> u8 {
     foo
 }
 
+fn allow_works() -> i32 {
+    #[allow(clippy::useless_let_if_seq)]
+    let x;
+    if true {
+        x = 1;
+    } else {
+        x = 2;
+    }
+    x
+}
+
 fn main() {
     early_return();
     issue975();
diff --git a/src/tools/clippy/tests/ui/let_if_seq.stderr b/src/tools/clippy/tests/ui/let_if_seq.stderr
index 87ad20dc27e..41930108fb1 100644
--- a/src/tools/clippy/tests/ui/let_if_seq.stderr
+++ b/src/tools/clippy/tests/ui/let_if_seq.stderr
@@ -1,5 +1,5 @@
 error: `if _ { .. } else { .. }` is an expression
-  --> tests/ui/let_if_seq.rs:66:5
+  --> tests/ui/let_if_seq.rs:77:5
    |
 LL | /     let mut foo = 0;
 LL | |
@@ -14,7 +14,7 @@ LL | |     }
    = help: to override `-D warnings` add `#[allow(clippy::useless_let_if_seq)]`
 
 error: `if _ { .. } else { .. }` is an expression
-  --> tests/ui/let_if_seq.rs:73:5
+  --> tests/ui/let_if_seq.rs:84:5
    |
 LL | /     let mut bar = 0;
 LL | |
@@ -28,7 +28,7 @@ LL | |     }
    = note: you might not need `mut` at all
 
 error: `if _ { .. } else { .. }` is an expression
-  --> tests/ui/let_if_seq.rs:83:5
+  --> tests/ui/let_if_seq.rs:94:5
    |
 LL | /     let quz;
 LL | |
@@ -40,7 +40,7 @@ LL | |     }
    | |_____^ help: it is more idiomatic to write: `let quz = if f() { 42 } else { 0 };`
 
 error: `if _ { .. } else { .. }` is an expression
-  --> tests/ui/let_if_seq.rs:113:5
+  --> tests/ui/let_if_seq.rs:124:5
    |
 LL | /     let mut baz = 0;
 LL | |
diff --git a/src/tools/clippy/tests/ui/manual_let_else.rs b/src/tools/clippy/tests/ui/manual_let_else.rs
index 1fb252e3f97..2b36c3f3c2f 100644
--- a/src/tools/clippy/tests/ui/manual_let_else.rs
+++ b/src/tools/clippy/tests/ui/manual_let_else.rs
@@ -8,7 +8,8 @@
     clippy::never_loop,
     clippy::needless_if,
     clippy::diverging_sub_expression,
-    clippy::single_match
+    clippy::single_match,
+    clippy::manual_unwrap_or_default
 )]
 #![warn(clippy::manual_let_else)]
 //@no-rustfix
diff --git a/src/tools/clippy/tests/ui/manual_let_else.stderr b/src/tools/clippy/tests/ui/manual_let_else.stderr
index 7012c6b8891..55a410982ad 100644
--- a/src/tools/clippy/tests/ui/manual_let_else.stderr
+++ b/src/tools/clippy/tests/ui/manual_let_else.stderr
@@ -1,5 +1,5 @@
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:28:5
+  --> tests/ui/manual_let_else.rs:29:5
    |
 LL |     let v = if let Some(v_some) = g() { v_some } else { return };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { return };`
@@ -8,7 +8,7 @@ LL |     let v = if let Some(v_some) = g() { v_some } else { return };
    = help: to override `-D warnings` add `#[allow(clippy::manual_let_else)]`
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:31:5
+  --> tests/ui/manual_let_else.rs:32:5
    |
 LL | /     let v = if let Some(v_some) = g() {
 LL | |
@@ -26,7 +26,7 @@ LL +     };
    |
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:38:5
+  --> tests/ui/manual_let_else.rs:39:5
    |
 LL | /     let v = if let Some(v) = g() {
 LL | |
@@ -47,25 +47,25 @@ LL +     };
    |
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:50:9
+  --> tests/ui/manual_let_else.rs:51:9
    |
 LL |         let v = if let Some(v_some) = g() { v_some } else { continue };
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { continue };`
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:52:9
+  --> tests/ui/manual_let_else.rs:53:9
    |
 LL |         let v = if let Some(v_some) = g() { v_some } else { break };
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { break };`
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:57:5
+  --> tests/ui/manual_let_else.rs:58:5
    |
 LL |     let v = if let Some(v_some) = g() { v_some } else { panic!() };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { panic!() };`
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:61:5
+  --> tests/ui/manual_let_else.rs:62:5
    |
 LL | /     let v = if let Some(v_some) = g() {
 LL | |
@@ -83,7 +83,7 @@ LL +     };
    |
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:69:5
+  --> tests/ui/manual_let_else.rs:70:5
    |
 LL | /     let v = if let Some(v_some) = g() {
 LL | |
@@ -101,7 +101,7 @@ LL +     };
    |
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:77:5
+  --> tests/ui/manual_let_else.rs:78:5
    |
 LL | /     let v = if let Some(v_some) = g() {
 LL | |
@@ -121,7 +121,7 @@ LL +     };
    |
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:86:5
+  --> tests/ui/manual_let_else.rs:87:5
    |
 LL | /     let v = if let Some(v_some) = g() {
 LL | |
@@ -141,7 +141,7 @@ LL +     };
    |
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:95:5
+  --> tests/ui/manual_let_else.rs:96:5
    |
 LL | /     let v = if let Some(v_some) = g() {
 LL | |
@@ -168,7 +168,7 @@ LL +     };
    |
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:111:5
+  --> tests/ui/manual_let_else.rs:112:5
    |
 LL | /     let v = if let Some(v_some) = g() {
 LL | |
@@ -190,7 +190,7 @@ LL +     };
    |
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:122:5
+  --> tests/ui/manual_let_else.rs:123:5
    |
 LL | /     let v = if let Some(v_some) = g() {
 LL | |
@@ -217,7 +217,7 @@ LL +     };
    |
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:138:5
+  --> tests/ui/manual_let_else.rs:139:5
    |
 LL | /     let v = if let Some(v_some) = g() {
 LL | |
@@ -239,7 +239,7 @@ LL +     };
    |
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:149:5
+  --> tests/ui/manual_let_else.rs:150:5
    |
 LL | /     let v = if let Some(v_some) = g() {
 LL | |
@@ -257,7 +257,7 @@ LL +     };
    |
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:157:5
+  --> tests/ui/manual_let_else.rs:158:5
    |
 LL | /     let v = if let Some(v_some) = g() {
 LL | |
@@ -278,7 +278,7 @@ LL +     };
    |
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:167:5
+  --> tests/ui/manual_let_else.rs:168:5
    |
 LL | /     let v = if let Some(v_some) = g() {
 LL | |
@@ -299,7 +299,7 @@ LL +     } };
    |
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:177:5
+  --> tests/ui/manual_let_else.rs:178:5
    |
 LL | /     let v = if let Some(v_some) = g() {
 LL | |
@@ -328,7 +328,7 @@ LL +     };
    |
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:195:5
+  --> tests/ui/manual_let_else.rs:196:5
    |
 LL | /     let (v, w) = if let Some(v_some) = g().map(|v| (v, 42)) {
 LL | |
@@ -346,7 +346,7 @@ LL +     };
    |
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:203:5
+  --> tests/ui/manual_let_else.rs:204:5
    |
 LL | /     let (w, S { v }) = if let (Some(v_some), w_some) = (g().map(|_| S { v: 0 }), 0) {
 LL | |
@@ -364,7 +364,7 @@ LL +     };
    |
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:213:13
+  --> tests/ui/manual_let_else.rs:214:13
    |
 LL |             let $n = if let Some(v) = $e { v } else { return };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some($n) = g() else { return };`
@@ -375,19 +375,19 @@ LL |     create_binding_if_some!(w, g());
    = note: this error originates in the macro `create_binding_if_some` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:222:5
+  --> tests/ui/manual_let_else.rs:223:5
    |
 LL |     let v = if let Variant::A(a, 0) = e() { a } else { return };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::A(v, 0) = e() else { return };`
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:226:5
+  --> tests/ui/manual_let_else.rs:227:5
    |
 LL |     let mut v = if let Variant::B(b) = e() { b } else { return };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::B(mut v) = e() else { return };`
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:231:5
+  --> tests/ui/manual_let_else.rs:232:5
    |
 LL | /     let v = if let Ok(Some(Variant::B(b))) | Err(Some(Variant::A(b, _))) = nested {
 LL | |
@@ -405,19 +405,19 @@ LL +     };
    |
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:238:5
+  --> tests/ui/manual_let_else.rs:239:5
    |
 LL |     let v = if let Variant::A(.., a) = e() { a } else { return };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::A(.., v) = e() else { return };`
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:242:5
+  --> tests/ui/manual_let_else.rs:243:5
    |
 LL |     let w = if let (Some(v), ()) = (g(), ()) { v } else { return };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let (Some(w), ()) = (g(), ()) else { return };`
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:246:5
+  --> tests/ui/manual_let_else.rs:247:5
    |
 LL | /     let w = if let Some(S { v: x }) = Some(S { v: 0 }) {
 LL | |
@@ -435,7 +435,7 @@ LL +     };
    |
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:254:5
+  --> tests/ui/manual_let_else.rs:255:5
    |
 LL | /     let v = if let Some(S { v: x }) = Some(S { v: 0 }) {
 LL | |
@@ -453,7 +453,7 @@ LL +     };
    |
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:262:5
+  --> tests/ui/manual_let_else.rs:263:5
    |
 LL | /     let (x, S { v }, w) = if let Some(U { v, w, x }) = None::<U<S<()>>> {
 LL | |
@@ -471,7 +471,7 @@ LL +     };
    |
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:379:5
+  --> tests/ui/manual_let_else.rs:380:5
    |
 LL | /     let _ = match ff {
 LL | |
@@ -481,7 +481,7 @@ LL | |     };
    | |______^ help: consider writing: `let Some(_) = ff else { macro_call!() };`
 
 error: this could be rewritten as `let...else`
-  --> tests/ui/manual_let_else.rs:456:9
+  --> tests/ui/manual_let_else.rs:457:9
    |
 LL |         let v = if let Some(v_some) = g() { v_some } else { return };
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { return };`
diff --git a/src/tools/clippy/tests/ui/manual_retain.fixed b/src/tools/clippy/tests/ui/manual_retain.fixed
index e359dfbb98c..5540029bf6b 100644
--- a/src/tools/clippy/tests/ui/manual_retain.fixed
+++ b/src/tools/clippy/tests/ui/manual_retain.fixed
@@ -1,5 +1,3 @@
-//@compile-flags: -Zdeduplicate-diagnostics=yes
-
 #![warn(clippy::manual_retain)]
 #![allow(unused, clippy::redundant_clone)]
 use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque};
diff --git a/src/tools/clippy/tests/ui/manual_retain.rs b/src/tools/clippy/tests/ui/manual_retain.rs
index 931814f08b7..cee641d9d65 100644
--- a/src/tools/clippy/tests/ui/manual_retain.rs
+++ b/src/tools/clippy/tests/ui/manual_retain.rs
@@ -1,5 +1,3 @@
-//@compile-flags: -Zdeduplicate-diagnostics=yes
-
 #![warn(clippy::manual_retain)]
 #![allow(unused, clippy::redundant_clone)]
 use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque};
diff --git a/src/tools/clippy/tests/ui/manual_retain.stderr b/src/tools/clippy/tests/ui/manual_retain.stderr
index fdbbc53e4df..c25c804df75 100644
--- a/src/tools/clippy/tests/ui/manual_retain.stderr
+++ b/src/tools/clippy/tests/ui/manual_retain.stderr
@@ -1,5 +1,5 @@
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:27:5
+  --> tests/ui/manual_retain.rs:25:5
    |
 LL |     binary_heap = binary_heap.into_iter().filter(|x| x % 2 == 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `binary_heap.retain(|x| x % 2 == 0)`
@@ -8,43 +8,43 @@ LL |     binary_heap = binary_heap.into_iter().filter(|x| x % 2 == 0).collect();
    = help: to override `-D warnings` add `#[allow(clippy::manual_retain)]`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:28:5
+  --> tests/ui/manual_retain.rs:26:5
    |
 LL |     binary_heap = binary_heap.iter().filter(|&x| x % 2 == 0).copied().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `binary_heap.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:29:5
+  --> tests/ui/manual_retain.rs:27:5
    |
 LL |     binary_heap = binary_heap.iter().filter(|&x| x % 2 == 0).cloned().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `binary_heap.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:33:5
+  --> tests/ui/manual_retain.rs:31:5
    |
 LL |     tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(ref x, ref y)| *x == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:34:5
+  --> tests/ui/manual_retain.rs:32:5
    |
 LL |     tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(x, y)| *x == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:64:5
+  --> tests/ui/manual_retain.rs:62:5
    |
 LL |     btree_map = btree_map.into_iter().filter(|(k, _)| k % 2 == 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_map.retain(|k, _| k % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:65:5
+  --> tests/ui/manual_retain.rs:63:5
    |
 LL |     btree_map = btree_map.into_iter().filter(|(_, v)| v % 2 == 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_map.retain(|_, &mut v| v % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:66:5
+  --> tests/ui/manual_retain.rs:64:5
    |
 LL | /     btree_map = btree_map
 LL | |         .into_iter()
@@ -53,49 +53,49 @@ LL | |         .collect();
    | |__________________^ help: consider calling `.retain()` instead: `btree_map.retain(|k, &mut v| (k % 2 == 0) && (v % 2 == 0))`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:91:5
+  --> tests/ui/manual_retain.rs:89:5
    |
 LL |     btree_set = btree_set.iter().filter(|&x| x % 2 == 0).copied().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:92:5
+  --> tests/ui/manual_retain.rs:90:5
    |
 LL |     btree_set = btree_set.iter().filter(|&x| x % 2 == 0).cloned().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:93:5
+  --> tests/ui/manual_retain.rs:91:5
    |
 LL |     btree_set = btree_set.into_iter().filter(|x| x % 2 == 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:97:5
+  --> tests/ui/manual_retain.rs:95:5
    |
 LL |     tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(ref x, ref y)| *x == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:98:5
+  --> tests/ui/manual_retain.rs:96:5
    |
 LL |     tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(x, y)| *x == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:128:5
+  --> tests/ui/manual_retain.rs:126:5
    |
 LL |     hash_map = hash_map.into_iter().filter(|(k, _)| k % 2 == 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_map.retain(|k, _| k % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:129:5
+  --> tests/ui/manual_retain.rs:127:5
    |
 LL |     hash_map = hash_map.into_iter().filter(|(_, v)| v % 2 == 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_map.retain(|_, &mut v| v % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:130:5
+  --> tests/ui/manual_retain.rs:128:5
    |
 LL | /     hash_map = hash_map
 LL | |         .into_iter()
@@ -104,133 +104,133 @@ LL | |         .collect();
    | |__________________^ help: consider calling `.retain()` instead: `hash_map.retain(|k, &mut v| (k % 2 == 0) && (v % 2 == 0))`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:154:5
+  --> tests/ui/manual_retain.rs:152:5
    |
 LL |     hash_set = hash_set.into_iter().filter(|x| x % 2 == 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:155:5
+  --> tests/ui/manual_retain.rs:153:5
    |
 LL |     hash_set = hash_set.iter().filter(|&x| x % 2 == 0).copied().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:156:5
+  --> tests/ui/manual_retain.rs:154:5
    |
 LL |     hash_set = hash_set.iter().filter(|&x| x % 2 == 0).cloned().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:160:5
+  --> tests/ui/manual_retain.rs:158:5
    |
 LL |     tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(ref x, ref y)| *x == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:161:5
+  --> tests/ui/manual_retain.rs:159:5
    |
 LL |     tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(x, y)| *x == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:190:5
+  --> tests/ui/manual_retain.rs:188:5
    |
 LL |     s = s.chars().filter(|&c| c != 'o').to_owned().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `s.retain(|c| c != 'o')`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:202:5
+  --> tests/ui/manual_retain.rs:200:5
    |
 LL |     vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:203:5
+  --> tests/ui/manual_retain.rs:201:5
    |
 LL |     vec = vec.iter().filter(|&x| x % 2 == 0).cloned().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:204:5
+  --> tests/ui/manual_retain.rs:202:5
    |
 LL |     vec = vec.into_iter().filter(|x| x % 2 == 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:208:5
+  --> tests/ui/manual_retain.rs:206:5
    |
 LL |     tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(ref x, ref y)| *x == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:209:5
+  --> tests/ui/manual_retain.rs:207:5
    |
 LL |     tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(x, y)| *x == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:231:5
+  --> tests/ui/manual_retain.rs:229:5
    |
 LL |     vec_deque = vec_deque.iter().filter(|&x| x % 2 == 0).copied().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:232:5
+  --> tests/ui/manual_retain.rs:230:5
    |
 LL |     vec_deque = vec_deque.iter().filter(|&x| x % 2 == 0).cloned().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:233:5
+  --> tests/ui/manual_retain.rs:231:5
    |
 LL |     vec_deque = vec_deque.into_iter().filter(|x| x % 2 == 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:290:5
+  --> tests/ui/manual_retain.rs:288:5
    |
 LL |     vec = vec.into_iter().filter(|(x, y)| *x == 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|(x, y)| *x == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:294:5
+  --> tests/ui/manual_retain.rs:292:5
    |
 LL |     tuples = tuples.into_iter().filter(|(_, n)| *n > 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(_, n)| *n > 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:311:5
+  --> tests/ui/manual_retain.rs:309:5
    |
 LL |     vec = vec.iter().filter(|&&x| x == 0).copied().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|&x| x == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:312:5
+  --> tests/ui/manual_retain.rs:310:5
    |
 LL |     vec = vec.iter().filter(|&&x| x == 0).cloned().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|&x| x == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:313:5
+  --> tests/ui/manual_retain.rs:311:5
    |
 LL |     vec = vec.into_iter().filter(|&x| x == 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|&x| x == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:316:5
+  --> tests/ui/manual_retain.rs:314:5
    |
 LL |     vec = vec.iter().filter(|&x| *x == 0).copied().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| *x == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:317:5
+  --> tests/ui/manual_retain.rs:315:5
    |
 LL |     vec = vec.iter().filter(|&x| *x == 0).cloned().collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| *x == 0)`
 
 error: this expression can be written more simply using `.retain()`
-  --> tests/ui/manual_retain.rs:318:5
+  --> tests/ui/manual_retain.rs:316:5
    |
 LL |     vec = vec.into_iter().filter(|x| *x == 0).collect();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| *x == 0)`
diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or.fixed b/src/tools/clippy/tests/ui/manual_unwrap_or.fixed
index 737d4c90dca..dffd44b6a7c 100644
--- a/src/tools/clippy/tests/ui/manual_unwrap_or.fixed
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or.fixed
@@ -1,5 +1,10 @@
 #![allow(dead_code)]
-#![allow(unused_variables, clippy::unnecessary_wraps, clippy::unnecessary_literal_unwrap)]
+#![allow(
+    unused_variables,
+    clippy::unnecessary_wraps,
+    clippy::unnecessary_literal_unwrap,
+    clippy::manual_unwrap_or_default
+)]
 
 fn option_unwrap_or() {
     // int case
diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or.rs b/src/tools/clippy/tests/ui/manual_unwrap_or.rs
index f59fb87529f..67427132c1a 100644
--- a/src/tools/clippy/tests/ui/manual_unwrap_or.rs
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or.rs
@@ -1,5 +1,10 @@
 #![allow(dead_code)]
-#![allow(unused_variables, clippy::unnecessary_wraps, clippy::unnecessary_literal_unwrap)]
+#![allow(
+    unused_variables,
+    clippy::unnecessary_wraps,
+    clippy::unnecessary_literal_unwrap,
+    clippy::manual_unwrap_or_default
+)]
 
 fn option_unwrap_or() {
     // int case
diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or.stderr b/src/tools/clippy/tests/ui/manual_unwrap_or.stderr
index 511b79881ac..33a099680ce 100644
--- a/src/tools/clippy/tests/ui/manual_unwrap_or.stderr
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or.stderr
@@ -1,5 +1,5 @@
 error: this pattern reimplements `Option::unwrap_or`
-  --> tests/ui/manual_unwrap_or.rs:6:5
+  --> tests/ui/manual_unwrap_or.rs:11:5
    |
 LL | /     match Some(1) {
 LL | |         Some(i) => i,
@@ -11,7 +11,7 @@ LL | |     };
    = help: to override `-D warnings` add `#[allow(clippy::manual_unwrap_or)]`
 
 error: this pattern reimplements `Option::unwrap_or`
-  --> tests/ui/manual_unwrap_or.rs:12:5
+  --> tests/ui/manual_unwrap_or.rs:17:5
    |
 LL | /     match Some(1) {
 LL | |         None => 42,
@@ -20,7 +20,7 @@ LL | |     };
    | |_____^ help: replace with: `Some(1).unwrap_or(42)`
 
 error: this pattern reimplements `Option::unwrap_or`
-  --> tests/ui/manual_unwrap_or.rs:18:5
+  --> tests/ui/manual_unwrap_or.rs:23:5
    |
 LL | /     match Some(1) {
 LL | |         Some(i) => i,
@@ -29,7 +29,7 @@ LL | |     };
    | |_____^ help: replace with: `Some(1).unwrap_or(1 + 42)`
 
 error: this pattern reimplements `Option::unwrap_or`
-  --> tests/ui/manual_unwrap_or.rs:25:5
+  --> tests/ui/manual_unwrap_or.rs:30:5
    |
 LL | /     match Some(1) {
 LL | |         Some(i) => i,
@@ -50,7 +50,7 @@ LL ~     });
    |
 
 error: this pattern reimplements `Option::unwrap_or`
-  --> tests/ui/manual_unwrap_or.rs:35:5
+  --> tests/ui/manual_unwrap_or.rs:40:5
    |
 LL | /     match Some("Bob") {
 LL | |         Some(i) => i,
@@ -59,7 +59,7 @@ LL | |     };
    | |_____^ help: replace with: `Some("Bob").unwrap_or("Alice")`
 
 error: this pattern reimplements `Result::unwrap_or`
-  --> tests/ui/manual_unwrap_or.rs:85:5
+  --> tests/ui/manual_unwrap_or.rs:90:5
    |
 LL | /     match Ok::<i32, &str>(1) {
 LL | |         Ok(i) => i,
@@ -68,7 +68,7 @@ LL | |     };
    | |_____^ help: replace with: `Ok::<i32, &str>(1).unwrap_or(42)`
 
 error: this pattern reimplements `Result::unwrap_or`
-  --> tests/ui/manual_unwrap_or.rs:92:5
+  --> tests/ui/manual_unwrap_or.rs:97:5
    |
 LL | /     match a {
 LL | |         Ok(i) => i,
@@ -77,7 +77,7 @@ LL | |     };
    | |_____^ help: replace with: `a.unwrap_or(42)`
 
 error: this pattern reimplements `Result::unwrap_or`
-  --> tests/ui/manual_unwrap_or.rs:98:5
+  --> tests/ui/manual_unwrap_or.rs:103:5
    |
 LL | /     match Ok(1) as Result<i32, &str> {
 LL | |         Ok(i) => i,
@@ -86,7 +86,7 @@ LL | |     };
    | |_____^ help: replace with: `(Ok(1) as Result<i32, &str>).unwrap_or(42)`
 
 error: this pattern reimplements `Option::unwrap_or`
-  --> tests/ui/manual_unwrap_or.rs:111:5
+  --> tests/ui/manual_unwrap_or.rs:116:5
    |
 LL | /     match s.method() {
 LL | |         Some(i) => i,
@@ -95,7 +95,7 @@ LL | |     };
    | |_____^ help: replace with: `s.method().unwrap_or(42)`
 
 error: this pattern reimplements `Result::unwrap_or`
-  --> tests/ui/manual_unwrap_or.rs:117:5
+  --> tests/ui/manual_unwrap_or.rs:122:5
    |
 LL | /     match Ok::<i32, &str>(1) {
 LL | |         Err(_) => 42,
@@ -104,7 +104,7 @@ LL | |     };
    | |_____^ help: replace with: `Ok::<i32, &str>(1).unwrap_or(42)`
 
 error: this pattern reimplements `Result::unwrap_or`
-  --> tests/ui/manual_unwrap_or.rs:123:5
+  --> tests/ui/manual_unwrap_or.rs:128:5
    |
 LL | /     match Ok::<i32, &str>(1) {
 LL | |         Ok(i) => i,
@@ -113,7 +113,7 @@ LL | |     };
    | |_____^ help: replace with: `Ok::<i32, &str>(1).unwrap_or(1 + 42)`
 
 error: this pattern reimplements `Result::unwrap_or`
-  --> tests/ui/manual_unwrap_or.rs:130:5
+  --> tests/ui/manual_unwrap_or.rs:135:5
    |
 LL | /     match Ok::<i32, &str>(1) {
 LL | |         Ok(i) => i,
@@ -134,7 +134,7 @@ LL ~     });
    |
 
 error: this pattern reimplements `Result::unwrap_or`
-  --> tests/ui/manual_unwrap_or.rs:140:5
+  --> tests/ui/manual_unwrap_or.rs:145:5
    |
 LL | /     match Ok::<&str, &str>("Bob") {
 LL | |         Ok(i) => i,
@@ -143,7 +143,7 @@ LL | |     };
    | |_____^ help: replace with: `Ok::<&str, &str>("Bob").unwrap_or("Alice")`
 
 error: this pattern reimplements `Option::unwrap_or`
-  --> tests/ui/manual_unwrap_or.rs:200:17
+  --> tests/ui/manual_unwrap_or.rs:205:17
    |
 LL |           let _ = match some_macro!() {
    |  _________________^
diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed b/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed
new file mode 100644
index 00000000000..c8456805ee6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed
@@ -0,0 +1,19 @@
+#![warn(clippy::manual_unwrap_or_default)]
+#![allow(clippy::unnecessary_literal_unwrap)]
+
+fn main() {
+    let x: Option<Vec<String>> = None;
+    x.unwrap_or_default();
+
+    let x: Option<Vec<String>> = None;
+    x.unwrap_or_default();
+
+    let x: Option<String> = None;
+    x.unwrap_or_default();
+
+    let x: Option<Vec<String>> = None;
+    x.unwrap_or_default();
+
+    let x: Option<Vec<String>> = None;
+    x.unwrap_or_default();
+}
diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs b/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs
new file mode 100644
index 00000000000..820717be53a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs
@@ -0,0 +1,40 @@
+#![warn(clippy::manual_unwrap_or_default)]
+#![allow(clippy::unnecessary_literal_unwrap)]
+
+fn main() {
+    let x: Option<Vec<String>> = None;
+    match x {
+        //~^ ERROR: match can be simplified with `.unwrap_or_default()`
+        Some(v) => v,
+        None => Vec::default(),
+    };
+
+    let x: Option<Vec<String>> = None;
+    match x {
+        //~^ ERROR: match can be simplified with `.unwrap_or_default()`
+        Some(v) => v,
+        _ => Vec::default(),
+    };
+
+    let x: Option<String> = None;
+    match x {
+        //~^ ERROR: match can be simplified with `.unwrap_or_default()`
+        Some(v) => v,
+        None => String::new(),
+    };
+
+    let x: Option<Vec<String>> = None;
+    match x {
+        //~^ ERROR: match can be simplified with `.unwrap_or_default()`
+        None => Vec::default(),
+        Some(v) => v,
+    };
+
+    let x: Option<Vec<String>> = None;
+    if let Some(v) = x {
+        //~^ ERROR: if let can be simplified with `.unwrap_or_default()`
+        v
+    } else {
+        Vec::default()
+    };
+}
diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or_default.stderr b/src/tools/clippy/tests/ui/manual_unwrap_or_default.stderr
new file mode 100644
index 00000000000..f4eb6583588
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default.stderr
@@ -0,0 +1,56 @@
+error: match can be simplified with `.unwrap_or_default()`
+  --> tests/ui/manual_unwrap_or_default.rs:6:5
+   |
+LL | /     match x {
+LL | |
+LL | |         Some(v) => v,
+LL | |         None => Vec::default(),
+LL | |     };
+   | |_____^ help: replace it with: `x.unwrap_or_default()`
+   |
+   = note: `-D clippy::manual-unwrap-or-default` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::manual_unwrap_or_default)]`
+
+error: match can be simplified with `.unwrap_or_default()`
+  --> tests/ui/manual_unwrap_or_default.rs:13:5
+   |
+LL | /     match x {
+LL | |
+LL | |         Some(v) => v,
+LL | |         _ => Vec::default(),
+LL | |     };
+   | |_____^ help: replace it with: `x.unwrap_or_default()`
+
+error: match can be simplified with `.unwrap_or_default()`
+  --> tests/ui/manual_unwrap_or_default.rs:20:5
+   |
+LL | /     match x {
+LL | |
+LL | |         Some(v) => v,
+LL | |         None => String::new(),
+LL | |     };
+   | |_____^ help: replace it with: `x.unwrap_or_default()`
+
+error: match can be simplified with `.unwrap_or_default()`
+  --> tests/ui/manual_unwrap_or_default.rs:27:5
+   |
+LL | /     match x {
+LL | |
+LL | |         None => Vec::default(),
+LL | |         Some(v) => v,
+LL | |     };
+   | |_____^ help: replace it with: `x.unwrap_or_default()`
+
+error: if let can be simplified with `.unwrap_or_default()`
+  --> tests/ui/manual_unwrap_or_default.rs:34:5
+   |
+LL | /     if let Some(v) = x {
+LL | |
+LL | |         v
+LL | |     } else {
+LL | |         Vec::default()
+LL | |     };
+   | |_____^ help: replace it with: `x.unwrap_or_default()`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/map_clone.fixed b/src/tools/clippy/tests/ui/map_clone.fixed
index 395eea69294..e58b6b2f19e 100644
--- a/src/tools/clippy/tests/ui/map_clone.fixed
+++ b/src/tools/clippy/tests/ui/map_clone.fixed
@@ -6,7 +6,8 @@
     clippy::redundant_clone,
     clippy::redundant_closure,
     clippy::useless_asref,
-    clippy::useless_vec
+    clippy::useless_vec,
+    clippy::empty_loop
 )]
 
 fn main() {
@@ -117,4 +118,17 @@ fn main() {
     let y = x.as_ref().map(|x| String::clone(x));
     let x: Result<String, ()> = Ok(String::new());
     let y = x.as_ref().map(|x| String::clone(x));
+
+    // Issue #12271
+    {
+        // Don't lint these
+        let x: Option<&u8> = None;
+        let y = x.map(|x| String::clone(loop {}));
+        let x: Option<&u8> = None;
+        let y = x.map(|x| u8::clone(loop {}));
+        let x: Vec<&u8> = vec![];
+        let y = x.into_iter().map(|x| String::clone(loop {}));
+        let x: Vec<&u8> = vec![];
+        let y = x.into_iter().map(|x| u8::clone(loop {}));
+    }
 }
diff --git a/src/tools/clippy/tests/ui/map_clone.rs b/src/tools/clippy/tests/ui/map_clone.rs
index 82a103edf5a..e642e4046f8 100644
--- a/src/tools/clippy/tests/ui/map_clone.rs
+++ b/src/tools/clippy/tests/ui/map_clone.rs
@@ -6,7 +6,8 @@
     clippy::redundant_clone,
     clippy::redundant_closure,
     clippy::useless_asref,
-    clippy::useless_vec
+    clippy::useless_vec,
+    clippy::empty_loop
 )]
 
 fn main() {
@@ -117,4 +118,17 @@ fn main() {
     let y = x.as_ref().map(|x| String::clone(x));
     let x: Result<String, ()> = Ok(String::new());
     let y = x.as_ref().map(|x| String::clone(x));
+
+    // Issue #12271
+    {
+        // Don't lint these
+        let x: Option<&u8> = None;
+        let y = x.map(|x| String::clone(loop {}));
+        let x: Option<&u8> = None;
+        let y = x.map(|x| u8::clone(loop {}));
+        let x: Vec<&u8> = vec![];
+        let y = x.into_iter().map(|x| String::clone(loop {}));
+        let x: Vec<&u8> = vec![];
+        let y = x.into_iter().map(|x| u8::clone(loop {}));
+    }
 }
diff --git a/src/tools/clippy/tests/ui/map_clone.stderr b/src/tools/clippy/tests/ui/map_clone.stderr
index 1a26a26a4ca..d9e025de4ab 100644
--- a/src/tools/clippy/tests/ui/map_clone.stderr
+++ b/src/tools/clippy/tests/ui/map_clone.stderr
@@ -1,5 +1,5 @@
 error: you are using an explicit closure for copying elements
-  --> tests/ui/map_clone.rs:13:22
+  --> tests/ui/map_clone.rs:14:22
    |
 LL |     let _: Vec<i8> = vec![5_i8; 6].iter().map(|x| *x).collect();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `vec![5_i8; 6].iter().copied()`
@@ -8,85 +8,85 @@ LL |     let _: Vec<i8> = vec![5_i8; 6].iter().map(|x| *x).collect();
    = help: to override `-D warnings` add `#[allow(clippy::map_clone)]`
 
 error: you are using an explicit closure for cloning elements
-  --> tests/ui/map_clone.rs:14:26
+  --> tests/ui/map_clone.rs:15:26
    |
 LL |     let _: Vec<String> = vec![String::new()].iter().map(|x| x.clone()).collect();
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `vec![String::new()].iter().cloned()`
 
 error: you are using an explicit closure for copying elements
-  --> tests/ui/map_clone.rs:15:23
+  --> tests/ui/map_clone.rs:16:23
    |
 LL |     let _: Vec<u32> = vec![42, 43].iter().map(|&x| x).collect();
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `vec![42, 43].iter().copied()`
 
 error: you are using an explicit closure for copying elements
-  --> tests/ui/map_clone.rs:17:26
+  --> tests/ui/map_clone.rs:18:26
    |
 LL |     let _: Option<u64> = Some(&16).map(|b| *b);
    |                          ^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `Some(&16).copied()`
 
 error: you are using an explicit closure for copying elements
-  --> tests/ui/map_clone.rs:18:25
+  --> tests/ui/map_clone.rs:19:25
    |
 LL |     let _: Option<u8> = Some(&1).map(|x| x.clone());
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `Some(&1).copied()`
 
 error: you are needlessly cloning iterator elements
-  --> tests/ui/map_clone.rs:29:29
+  --> tests/ui/map_clone.rs:30:29
    |
 LL |     let _ = std::env::args().map(|v| v.clone());
    |                             ^^^^^^^^^^^^^^^^^^^ help: remove the `map` call
 
 error: you are explicitly cloning with `.map()`
-  --> tests/ui/map_clone.rs:68:13
+  --> tests/ui/map_clone.rs:69:13
    |
 LL |     let y = x.map(|x| String::clone(x));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()`
 
 error: you are explicitly cloning with `.map()`
-  --> tests/ui/map_clone.rs:70:13
+  --> tests/ui/map_clone.rs:71:13
    |
 LL |     let y = x.map(Clone::clone);
    |             ^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()`
 
 error: you are explicitly cloning with `.map()`
-  --> tests/ui/map_clone.rs:73:13
+  --> tests/ui/map_clone.rs:74:13
    |
 LL |     let y = x.map(String::clone);
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()`
 
 error: you are explicitly cloning with `.map()`
-  --> tests/ui/map_clone.rs:79:13
+  --> tests/ui/map_clone.rs:80:13
    |
 LL |     let y = x.map(|x| u32::clone(x));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `x.copied()`
 
 error: you are explicitly cloning with `.map()`
-  --> tests/ui/map_clone.rs:82:13
+  --> tests/ui/map_clone.rs:83:13
    |
 LL |     let y = x.map(|x| Clone::clone(x));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `x.copied()`
 
 error: you are explicitly cloning with `.map()`
-  --> tests/ui/map_clone.rs:94:13
+  --> tests/ui/map_clone.rs:95:13
    |
 LL |     let y = x.map(|x| String::clone(x));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()`
 
 error: you are explicitly cloning with `.map()`
-  --> tests/ui/map_clone.rs:97:13
+  --> tests/ui/map_clone.rs:98:13
    |
 LL |     let y = x.map(|x| Clone::clone(x));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()`
 
 error: you are explicitly cloning with `.map()`
-  --> tests/ui/map_clone.rs:103:13
+  --> tests/ui/map_clone.rs:104:13
    |
 LL |     let y = x.map(|x| u32::clone(x));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `x.copied()`
 
 error: you are explicitly cloning with `.map()`
-  --> tests/ui/map_clone.rs:106:13
+  --> tests/ui/map_clone.rs:107:13
    |
 LL |     let y = x.map(|x| Clone::clone(x));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `x.copied()`
diff --git a/src/tools/clippy/tests/ui/match_result_ok.fixed b/src/tools/clippy/tests/ui/match_result_ok.fixed
index 8d7cddc0ad7..76b26f5e438 100644
--- a/src/tools/clippy/tests/ui/match_result_ok.fixed
+++ b/src/tools/clippy/tests/ui/match_result_ok.fixed
@@ -1,6 +1,6 @@
 #![warn(clippy::match_result_ok)]
 #![allow(dead_code)]
-#![allow(clippy::boxed_local, clippy::uninlined_format_args)]
+#![allow(clippy::boxed_local, clippy::uninlined_format_args, clippy::manual_unwrap_or_default)]
 
 // Checking `if` cases
 
diff --git a/src/tools/clippy/tests/ui/match_result_ok.rs b/src/tools/clippy/tests/ui/match_result_ok.rs
index 9a18b813aca..d6f2475ba79 100644
--- a/src/tools/clippy/tests/ui/match_result_ok.rs
+++ b/src/tools/clippy/tests/ui/match_result_ok.rs
@@ -1,6 +1,6 @@
 #![warn(clippy::match_result_ok)]
 #![allow(dead_code)]
-#![allow(clippy::boxed_local, clippy::uninlined_format_args)]
+#![allow(clippy::boxed_local, clippy::uninlined_format_args, clippy::manual_unwrap_or_default)]
 
 // Checking `if` cases
 
diff --git a/src/tools/clippy/tests/ui/missing_doc.rs b/src/tools/clippy/tests/ui/missing_doc.rs
index 9bfad3b96cf..9c936d7fa23 100644
--- a/src/tools/clippy/tests/ui/missing_doc.rs
+++ b/src/tools/clippy/tests/ui/missing_doc.rs
@@ -1,5 +1,6 @@
 //@needs-asm-support
 //@aux-build: proc_macros.rs
+//@aux-build: proc_macro_attr.rs
 
 #![warn(clippy::missing_docs_in_private_items)]
 // When denying at the crate level, be sure to not get random warnings from the
@@ -8,6 +9,8 @@
 //! Some garbage docs for the crate here
 #![doc = "More garbage"]
 
+#[macro_use]
+extern crate proc_macro_attr;
 extern crate proc_macros;
 
 use proc_macros::with_span;
@@ -112,3 +115,12 @@ with_span!(span pub enum FooPm3 { A, B(u32), C { field: u32 }});
 with_span!(span pub fn foo_pm() {});
 with_span!(span pub static FOO_PM: u32 = 0;);
 with_span!(span pub const FOO2_PM: u32 = 0;);
+
+// issue #12197
+// Undocumented field originated inside of spanned proc-macro attribute
+/// Some dox for struct.
+#[rewrite_struct]
+pub struct Test {
+    /// Dox
+    a: u8,
+}
diff --git a/src/tools/clippy/tests/ui/missing_doc.stderr b/src/tools/clippy/tests/ui/missing_doc.stderr
index 7e66e2097e9..ef0f96a5b71 100644
--- a/src/tools/clippy/tests/ui/missing_doc.stderr
+++ b/src/tools/clippy/tests/ui/missing_doc.stderr
@@ -1,5 +1,5 @@
 error: missing documentation for a type alias
-  --> tests/ui/missing_doc.rs:16:1
+  --> tests/ui/missing_doc.rs:19:1
    |
 LL | type Typedef = String;
    | ^^^^^^^^^^^^^^^^^^^^^^
@@ -8,19 +8,19 @@ LL | type Typedef = String;
    = help: to override `-D warnings` add `#[allow(clippy::missing_docs_in_private_items)]`
 
 error: missing documentation for a module
-  --> tests/ui/missing_doc.rs:19:1
+  --> tests/ui/missing_doc.rs:22:1
    |
 LL | mod module_no_dox {}
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> tests/ui/missing_doc.rs:25:1
+  --> tests/ui/missing_doc.rs:28:1
    |
 LL | fn foo3() {}
    | ^^^^^^^^^^^^
 
 error: missing documentation for an enum
-  --> tests/ui/missing_doc.rs:39:1
+  --> tests/ui/missing_doc.rs:42:1
    |
 LL | / enum Baz {
 LL | |     BazA { a: isize, b: isize },
@@ -29,43 +29,43 @@ LL | | }
    | |_^
 
 error: missing documentation for a variant
-  --> tests/ui/missing_doc.rs:40:5
+  --> tests/ui/missing_doc.rs:43:5
    |
 LL |     BazA { a: isize, b: isize },
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a struct field
-  --> tests/ui/missing_doc.rs:40:12
+  --> tests/ui/missing_doc.rs:43:12
    |
 LL |     BazA { a: isize, b: isize },
    |            ^^^^^^^^
 
 error: missing documentation for a struct field
-  --> tests/ui/missing_doc.rs:40:22
+  --> tests/ui/missing_doc.rs:43:22
    |
 LL |     BazA { a: isize, b: isize },
    |                      ^^^^^^^^
 
 error: missing documentation for a variant
-  --> tests/ui/missing_doc.rs:41:5
+  --> tests/ui/missing_doc.rs:44:5
    |
 LL |     BarB,
    |     ^^^^
 
 error: missing documentation for a constant
-  --> tests/ui/missing_doc.rs:65:1
+  --> tests/ui/missing_doc.rs:68:1
    |
 LL | const FOO: u32 = 0;
    | ^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a static
-  --> tests/ui/missing_doc.rs:74:1
+  --> tests/ui/missing_doc.rs:77:1
    |
 LL | static BAR: u32 = 0;
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a module
-  --> tests/ui/missing_doc.rs:83:1
+  --> tests/ui/missing_doc.rs:86:1
    |
 LL | / mod internal_impl {
 LL | |     /// dox
@@ -77,13 +77,13 @@ LL | | }
    | |_^
 
 error: missing documentation for a function
-  --> tests/ui/missing_doc.rs:88:5
+  --> tests/ui/missing_doc.rs:91:5
    |
 LL |     fn undocumented3() {}
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> tests/ui/missing_doc.rs:94:9
+  --> tests/ui/missing_doc.rs:97:9
    |
 LL |         fn also_undocumented2() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/mixed_attributes_style.rs b/src/tools/clippy/tests/ui/mixed_attributes_style.rs
index ad93e3019fa..4f89aa8a5e5 100644
--- a/src/tools/clippy/tests/ui/mixed_attributes_style.rs
+++ b/src/tools/clippy/tests/ui/mixed_attributes_style.rs
@@ -1,4 +1,5 @@
 #![warn(clippy::mixed_attributes_style)]
+#![allow(clippy::duplicated_attributes)]
 
 #[allow(unused)] //~ ERROR: item has both inner and outer attributes
 fn foo1() {
diff --git a/src/tools/clippy/tests/ui/mixed_attributes_style.stderr b/src/tools/clippy/tests/ui/mixed_attributes_style.stderr
index d1d5cd3f47f..ed798073cb7 100644
--- a/src/tools/clippy/tests/ui/mixed_attributes_style.stderr
+++ b/src/tools/clippy/tests/ui/mixed_attributes_style.stderr
@@ -1,5 +1,5 @@
 error: item has both inner and outer attributes
-  --> tests/ui/mixed_attributes_style.rs:3:1
+  --> tests/ui/mixed_attributes_style.rs:4:1
    |
 LL | / #[allow(unused)]
 LL | | fn foo1() {
@@ -10,7 +10,7 @@ LL | |     #![allow(unused)]
    = help: to override `-D warnings` add `#[allow(clippy::mixed_attributes_style)]`
 
 error: item has both inner and outer attributes
-  --> tests/ui/mixed_attributes_style.rs:17:1
+  --> tests/ui/mixed_attributes_style.rs:18:1
    |
 LL | / /// linux
 LL | |
@@ -19,7 +19,7 @@ LL | |     //! windows
    | |_______________^
 
 error: item has both inner and outer attributes
-  --> tests/ui/mixed_attributes_style.rs:32:1
+  --> tests/ui/mixed_attributes_style.rs:33:1
    |
 LL | / #[allow(unused)]
 LL | | mod bar {
diff --git a/src/tools/clippy/tests/ui/mut_mut.rs b/src/tools/clippy/tests/ui/mut_mut.rs
index 288b003405d..4c45bc98026 100644
--- a/src/tools/clippy/tests/ui/mut_mut.rs
+++ b/src/tools/clippy/tests/ui/mut_mut.rs
@@ -1,5 +1,4 @@
 //@aux-build:proc_macros.rs
-//@compile-flags: -Zdeduplicate-diagnostics=yes
 
 #![warn(clippy::mut_mut)]
 #![allow(unused)]
@@ -82,3 +81,8 @@ mod issue9035 {
 
     fn bar(_: &mut impl Display) {}
 }
+
+fn allow_works() {
+    #[allow(clippy::mut_mut)]
+    let _ = &mut &mut 1;
+}
diff --git a/src/tools/clippy/tests/ui/mut_mut.stderr b/src/tools/clippy/tests/ui/mut_mut.stderr
index 73f2410a252..42853fdc008 100644
--- a/src/tools/clippy/tests/ui/mut_mut.stderr
+++ b/src/tools/clippy/tests/ui/mut_mut.stderr
@@ -1,5 +1,5 @@
 error: generally you want to avoid `&mut &mut _` if possible
-  --> tests/ui/mut_mut.rs:16:11
+  --> tests/ui/mut_mut.rs:15:11
    |
 LL | fn fun(x: &mut &mut u32) -> bool {
    |           ^^^^^^^^^^^^^
@@ -8,13 +8,13 @@ LL | fn fun(x: &mut &mut u32) -> bool {
    = help: to override `-D warnings` add `#[allow(clippy::mut_mut)]`
 
 error: generally you want to avoid `&mut &mut _` if possible
-  --> tests/ui/mut_mut.rs:33:17
+  --> tests/ui/mut_mut.rs:32:17
    |
 LL |     let mut x = &mut &mut 1u32;
    |                 ^^^^^^^^^^^^^^
 
 error: generally you want to avoid `&mut &mut _` if possible
-  --> tests/ui/mut_mut.rs:48:25
+  --> tests/ui/mut_mut.rs:47:25
    |
 LL |     let mut z = inline!(&mut $(&mut 3u32));
    |                         ^
@@ -22,37 +22,37 @@ LL |     let mut z = inline!(&mut $(&mut 3u32));
    = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: this expression mutably borrows a mutable reference. Consider reborrowing
-  --> tests/ui/mut_mut.rs:35:21
+  --> tests/ui/mut_mut.rs:34:21
    |
 LL |         let mut y = &mut x;
    |                     ^^^^^^
 
 error: generally you want to avoid `&mut &mut _` if possible
-  --> tests/ui/mut_mut.rs:39:32
+  --> tests/ui/mut_mut.rs:38:32
    |
 LL |         let y: &mut &mut u32 = &mut &mut 2;
    |                                ^^^^^^^^^^^
 
 error: generally you want to avoid `&mut &mut _` if possible
-  --> tests/ui/mut_mut.rs:39:16
+  --> tests/ui/mut_mut.rs:38:16
    |
 LL |         let y: &mut &mut u32 = &mut &mut 2;
    |                ^^^^^^^^^^^^^
 
 error: generally you want to avoid `&mut &mut _` if possible
-  --> tests/ui/mut_mut.rs:44:37
+  --> tests/ui/mut_mut.rs:43:37
    |
 LL |         let y: &mut &mut &mut u32 = &mut &mut &mut 2;
    |                                     ^^^^^^^^^^^^^^^^
 
 error: generally you want to avoid `&mut &mut _` if possible
-  --> tests/ui/mut_mut.rs:44:16
+  --> tests/ui/mut_mut.rs:43:16
    |
 LL |         let y: &mut &mut &mut u32 = &mut &mut &mut 2;
    |                ^^^^^^^^^^^^^^^^^^
 
 error: generally you want to avoid `&mut &mut _` if possible
-  --> tests/ui/mut_mut.rs:44:21
+  --> tests/ui/mut_mut.rs:43:21
    |
 LL |         let y: &mut &mut &mut u32 = &mut &mut &mut 2;
    |                     ^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed b/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed
index 201f8a4c19d..a8176618c1f 100644
--- a/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed
+++ b/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed
@@ -1,4 +1,5 @@
 #![warn(clippy::needless_bitwise_bool)]
+#![allow(clippy::const_is_empty)]
 
 fn returns_bool() -> bool {
     true
diff --git a/src/tools/clippy/tests/ui/needless_bitwise_bool.rs b/src/tools/clippy/tests/ui/needless_bitwise_bool.rs
index b0e5014b74b..f190eb2b76e 100644
--- a/src/tools/clippy/tests/ui/needless_bitwise_bool.rs
+++ b/src/tools/clippy/tests/ui/needless_bitwise_bool.rs
@@ -1,4 +1,5 @@
 #![warn(clippy::needless_bitwise_bool)]
+#![allow(clippy::const_is_empty)]
 
 fn returns_bool() -> bool {
     true
diff --git a/src/tools/clippy/tests/ui/needless_bitwise_bool.stderr b/src/tools/clippy/tests/ui/needless_bitwise_bool.stderr
index f29d4492540..9f14646c3e5 100644
--- a/src/tools/clippy/tests/ui/needless_bitwise_bool.stderr
+++ b/src/tools/clippy/tests/ui/needless_bitwise_bool.stderr
@@ -1,5 +1,5 @@
 error: use of bitwise operator instead of lazy operator between booleans
-  --> tests/ui/needless_bitwise_bool.rs:22:8
+  --> tests/ui/needless_bitwise_bool.rs:23:8
    |
 LL |     if y & !x {
    |        ^^^^^^ help: try: `y && !x`
diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed
index f9eb39d4938..2575f2449e1 100644
--- a/src/tools/clippy/tests/ui/needless_return.fixed
+++ b/src/tools/clippy/tests/ui/needless_return.fixed
@@ -316,4 +316,11 @@ fn test_match_as_stmt() {
     };
 }
 
+fn allow_works() -> i32 {
+    #[allow(clippy::needless_return, clippy::match_single_binding)]
+    match () {
+        () => return 42,
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs
index 4dd2e22ea9f..04f21834d88 100644
--- a/src/tools/clippy/tests/ui/needless_return.rs
+++ b/src/tools/clippy/tests/ui/needless_return.rs
@@ -326,4 +326,11 @@ fn test_match_as_stmt() {
     };
 }
 
+fn allow_works() -> i32 {
+    #[allow(clippy::needless_return, clippy::match_single_binding)]
+    match () {
+        () => return 42,
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/no_effect_replace.rs b/src/tools/clippy/tests/ui/no_effect_replace.rs
index 2a940d87fb9..e4fd5caae2a 100644
--- a/src/tools/clippy/tests/ui/no_effect_replace.rs
+++ b/src/tools/clippy/tests/ui/no_effect_replace.rs
@@ -1,5 +1,3 @@
-//@compile-flags: -Zdeduplicate-diagnostics=yes
-
 #![warn(clippy::no_effect_replace)]
 
 fn main() {
diff --git a/src/tools/clippy/tests/ui/no_effect_replace.stderr b/src/tools/clippy/tests/ui/no_effect_replace.stderr
index ad2dcd2cc9b..ded86c5c5b8 100644
--- a/src/tools/clippy/tests/ui/no_effect_replace.stderr
+++ b/src/tools/clippy/tests/ui/no_effect_replace.stderr
@@ -1,5 +1,5 @@
 error: replacing text with itself
-  --> tests/ui/no_effect_replace.rs:6:13
+  --> tests/ui/no_effect_replace.rs:4:13
    |
 LL |     let _ = "12345".replace('1', "1");
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -8,43 +8,43 @@ LL |     let _ = "12345".replace('1', "1");
    = help: to override `-D warnings` add `#[allow(clippy::no_effect_replace)]`
 
 error: replacing text with itself
-  --> tests/ui/no_effect_replace.rs:9:13
+  --> tests/ui/no_effect_replace.rs:7:13
    |
 LL |     let _ = "12345".replace("12", "12");
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: replacing text with itself
-  --> tests/ui/no_effect_replace.rs:11:13
+  --> tests/ui/no_effect_replace.rs:9:13
    |
 LL |     let _ = String::new().replace("12", "12");
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: replacing text with itself
-  --> tests/ui/no_effect_replace.rs:14:13
+  --> tests/ui/no_effect_replace.rs:12:13
    |
 LL |     let _ = "12345".replacen('1', "1", 1);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: replacing text with itself
-  --> tests/ui/no_effect_replace.rs:16:13
+  --> tests/ui/no_effect_replace.rs:14:13
    |
 LL |     let _ = "12345".replacen("12", "12", 1);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: replacing text with itself
-  --> tests/ui/no_effect_replace.rs:18:13
+  --> tests/ui/no_effect_replace.rs:16:13
    |
 LL |     let _ = String::new().replacen("12", "12", 1);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: replacing text with itself
-  --> tests/ui/no_effect_replace.rs:25:13
+  --> tests/ui/no_effect_replace.rs:23:13
    |
 LL |     let _ = "hello".replace(&x.f(), &x.f());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: replacing text with itself
-  --> tests/ui/no_effect_replace.rs:29:13
+  --> tests/ui/no_effect_replace.rs:27:13
    |
 LL |     let _ = "hello".replace(&y(), &y());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.fixed b/src/tools/clippy/tests/ui/option_if_let_else.fixed
index d443334bb05..eeab801b7da 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.fixed
+++ b/src/tools/clippy/tests/ui/option_if_let_else.fixed
@@ -3,7 +3,8 @@
     clippy::ref_option_ref,
     clippy::equatable_if_let,
     clippy::let_unit_value,
-    clippy::redundant_locals
+    clippy::redundant_locals,
+    clippy::manual_unwrap_or_default
 )]
 
 fn bad1(string: Option<&str>) -> (bool, &str) {
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.rs b/src/tools/clippy/tests/ui/option_if_let_else.rs
index 317c35bf842..3e5b96d7c31 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.rs
+++ b/src/tools/clippy/tests/ui/option_if_let_else.rs
@@ -3,7 +3,8 @@
     clippy::ref_option_ref,
     clippy::equatable_if_let,
     clippy::let_unit_value,
-    clippy::redundant_locals
+    clippy::redundant_locals,
+    clippy::manual_unwrap_or_default
 )]
 
 fn bad1(string: Option<&str>) -> (bool, &str) {
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.stderr b/src/tools/clippy/tests/ui/option_if_let_else.stderr
index a794dca762f..f5359a0c34f 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.stderr
+++ b/src/tools/clippy/tests/ui/option_if_let_else.stderr
@@ -1,5 +1,5 @@
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:10:5
+  --> tests/ui/option_if_let_else.rs:11:5
    |
 LL | /     if let Some(x) = string {
 LL | |         (true, x)
@@ -12,19 +12,19 @@ LL | |     }
    = help: to override `-D warnings` add `#[allow(clippy::option_if_let_else)]`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:28:13
+  --> tests/ui/option_if_let_else.rs:29:13
    |
 LL |     let _ = if let Some(s) = *string { s.len() } else { 0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:29:13
+  --> tests/ui/option_if_let_else.rs:30:13
    |
 LL |     let _ = if let Some(s) = &num { s } else { &0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:30:13
+  --> tests/ui/option_if_let_else.rs:31:13
    |
 LL |       let _ = if let Some(s) = &mut num {
    |  _____________^
@@ -44,13 +44,13 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:36:13
+  --> tests/ui/option_if_let_else.rs:37:13
    |
 LL |     let _ = if let Some(ref s) = num { s } else { &0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:37:13
+  --> tests/ui/option_if_let_else.rs:38:13
    |
 LL |       let _ = if let Some(mut s) = num {
    |  _____________^
@@ -70,7 +70,7 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:43:13
+  --> tests/ui/option_if_let_else.rs:44:13
    |
 LL |       let _ = if let Some(ref mut s) = num {
    |  _____________^
@@ -90,7 +90,7 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:52:5
+  --> tests/ui/option_if_let_else.rs:53:5
    |
 LL | /     if let Some(x) = arg {
 LL | |         let y = x * x;
@@ -109,7 +109,7 @@ LL +     })
    |
 
 error: use Option::map_or_else instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:65:13
+  --> tests/ui/option_if_let_else.rs:66:13
    |
 LL |       let _ = if let Some(x) = arg {
    |  _____________^
@@ -121,7 +121,7 @@ LL | |     };
    | |_____^ help: try: `arg.map_or_else(side_effect, |x| x)`
 
 error: use Option::map_or_else instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:74:13
+  --> tests/ui/option_if_let_else.rs:75:13
    |
 LL |       let _ = if let Some(x) = arg {
    |  _____________^
@@ -144,7 +144,7 @@ LL ~     }, |x| x * x * x * x);
    |
 
 error: use Option::map_or_else instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:107:13
+  --> tests/ui/option_if_let_else.rs:108:13
    |
 LL | /             if let Some(idx) = s.find('.') {
 LL | |                 vec![s[..idx].to_string(), s[idx..].to_string()]
@@ -154,7 +154,7 @@ LL | |             }
    | |_____________^ help: try: `s.find('.').map_or_else(|| vec![s.to_string()], |idx| vec![s[..idx].to_string(), s[idx..].to_string()])`
 
 error: use Option::map_or_else instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:118:5
+  --> tests/ui/option_if_let_else.rs:119:5
    |
 LL | /     if let Ok(binding) = variable {
 LL | |         println!("Ok {binding}");
@@ -177,13 +177,13 @@ LL +     })
    |
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:142:13
+  --> tests/ui/option_if_let_else.rs:143:13
    |
 LL |     let _ = if let Some(x) = optional { x + 2 } else { 5 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:152:13
+  --> tests/ui/option_if_let_else.rs:153:13
    |
 LL |       let _ = if let Some(x) = Some(0) {
    |  _____________^
@@ -205,13 +205,13 @@ LL ~         });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:180:13
+  --> tests/ui/option_if_let_else.rs:181:13
    |
 LL |     let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or(s.len(), |x| s.len() + x)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:184:13
+  --> tests/ui/option_if_let_else.rs:185:13
    |
 LL |       let _ = if let Some(x) = Some(0) {
    |  _____________^
@@ -231,7 +231,7 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:223:13
+  --> tests/ui/option_if_let_else.rs:224:13
    |
 LL |       let _ = match s {
    |  _____________^
@@ -241,7 +241,7 @@ LL | |     };
    | |_____^ help: try: `s.map_or(1, |string| string.len())`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:227:13
+  --> tests/ui/option_if_let_else.rs:228:13
    |
 LL |       let _ = match Some(10) {
    |  _____________^
@@ -251,7 +251,7 @@ LL | |     };
    | |_____^ help: try: `Some(10).map_or(5, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:233:13
+  --> tests/ui/option_if_let_else.rs:234:13
    |
 LL |       let _ = match res {
    |  _____________^
@@ -261,7 +261,7 @@ LL | |     };
    | |_____^ help: try: `res.map_or(1, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:237:13
+  --> tests/ui/option_if_let_else.rs:238:13
    |
 LL |       let _ = match res {
    |  _____________^
@@ -271,13 +271,13 @@ LL | |     };
    | |_____^ help: try: `res.map_or(1, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:241:13
+  --> tests/ui/option_if_let_else.rs:242:13
    |
 LL |     let _ = if let Ok(a) = res { a + 1 } else { 5 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or(5, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:258:17
+  --> tests/ui/option_if_let_else.rs:259:17
    |
 LL |           let _ = match initial {
    |  _________________^
@@ -287,7 +287,7 @@ LL | |         };
    | |_________^ help: try: `initial.as_ref().map_or(42, |value| do_something(value))`
 
 error: use Option::map_or instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:265:17
+  --> tests/ui/option_if_let_else.rs:266:17
    |
 LL |           let _ = match initial {
    |  _________________^
@@ -297,7 +297,7 @@ LL | |         };
    | |_________^ help: try: `initial.as_mut().map_or(42, |value| do_something2(value))`
 
 error: use Option::map_or_else instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:288:24
+  --> tests/ui/option_if_let_else.rs:289:24
    |
 LL |       let mut _hashmap = if let Some(hm) = &opt {
    |  ________________________^
@@ -308,7 +308,7 @@ LL | |     };
    | |_____^ help: try: `opt.as_ref().map_or_else(HashMap::new, |hm| hm.clone())`
 
 error: use Option::map_or_else instead of an if let/else
-  --> tests/ui/option_if_let_else.rs:294:19
+  --> tests/ui/option_if_let_else.rs:295:19
    |
 LL |     let mut _hm = if let Some(hm) = &opt { hm.clone() } else { new_map!() };
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.as_ref().map_or_else(|| new_map!(), |hm| hm.clone())`
diff --git a/src/tools/clippy/tests/ui/option_option.rs b/src/tools/clippy/tests/ui/option_option.rs
index 2f6e4d76145..42f03aae7bb 100644
--- a/src/tools/clippy/tests/ui/option_option.rs
+++ b/src/tools/clippy/tests/ui/option_option.rs
@@ -1,7 +1,5 @@
-//@compile-flags: -Zdeduplicate-diagnostics=yes
-
 #![deny(clippy::option_option)]
-#![allow(clippy::unnecessary_wraps)]
+#![allow(clippy::unnecessary_wraps, clippy::manual_unwrap_or_default)]
 
 const C: Option<Option<i32>> = None;
 //~^ ERROR: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if
diff --git a/src/tools/clippy/tests/ui/option_option.stderr b/src/tools/clippy/tests/ui/option_option.stderr
index 76cb9ae944c..0cd048e400e 100644
--- a/src/tools/clippy/tests/ui/option_option.stderr
+++ b/src/tools/clippy/tests/ui/option_option.stderr
@@ -1,77 +1,77 @@
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
-  --> tests/ui/option_option.rs:6:10
+  --> tests/ui/option_option.rs:4:10
    |
 LL | const C: Option<Option<i32>> = None;
    |          ^^^^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> tests/ui/option_option.rs:3:9
+  --> tests/ui/option_option.rs:1:9
    |
 LL | #![deny(clippy::option_option)]
    |         ^^^^^^^^^^^^^^^^^^^^^
 
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
-  --> tests/ui/option_option.rs:8:11
+  --> tests/ui/option_option.rs:6:11
    |
 LL | static S: Option<Option<i32>> = None;
    |           ^^^^^^^^^^^^^^^^^^^
 
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
-  --> tests/ui/option_option.rs:11:13
+  --> tests/ui/option_option.rs:9:13
    |
 LL | fn input(_: Option<Option<u8>>) {}
    |             ^^^^^^^^^^^^^^^^^^
 
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
-  --> tests/ui/option_option.rs:14:16
+  --> tests/ui/option_option.rs:12:16
    |
 LL | fn output() -> Option<Option<u8>> {
    |                ^^^^^^^^^^^^^^^^^^
 
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
-  --> tests/ui/option_option.rs:19:27
+  --> tests/ui/option_option.rs:17:27
    |
 LL | fn output_nested() -> Vec<Option<Option<u8>>> {
    |                           ^^^^^^^^^^^^^^^^^^
 
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
-  --> tests/ui/option_option.rs:25:30
+  --> tests/ui/option_option.rs:23:30
    |
 LL | fn output_nested_nested() -> Option<Option<Option<u8>>> {
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
-  --> tests/ui/option_option.rs:31:8
+  --> tests/ui/option_option.rs:29:8
    |
 LL |     x: Option<Option<u8>>,
    |        ^^^^^^^^^^^^^^^^^^
 
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
-  --> tests/ui/option_option.rs:36:23
+  --> tests/ui/option_option.rs:34:23
    |
 LL |     fn struct_fn() -> Option<Option<u8>> {
    |                       ^^^^^^^^^^^^^^^^^^
 
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
-  --> tests/ui/option_option.rs:43:22
+  --> tests/ui/option_option.rs:41:22
    |
 LL |     fn trait_fn() -> Option<Option<u8>>;
    |                      ^^^^^^^^^^^^^^^^^^
 
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
-  --> tests/ui/option_option.rs:48:11
+  --> tests/ui/option_option.rs:46:11
    |
 LL |     Tuple(Option<Option<u8>>),
    |           ^^^^^^^^^^^^^^^^^^
 
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
-  --> tests/ui/option_option.rs:50:17
+  --> tests/ui/option_option.rs:48:17
    |
 LL |     Struct { x: Option<Option<u8>> },
    |                 ^^^^^^^^^^^^^^^^^^
 
 error: consider using `Option<T>` instead of `Option<Option<T>>` or a custom enum if you need to distinguish all 3 cases
-  --> tests/ui/option_option.rs:92:14
+  --> tests/ui/option_option.rs:90:14
    |
 LL |         foo: Option<Option<Cow<'a, str>>>,
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/read_zero_byte_vec.rs b/src/tools/clippy/tests/ui/read_zero_byte_vec.rs
index fd5a88a37a6..68acf433469 100644
--- a/src/tools/clippy/tests/ui/read_zero_byte_vec.rs
+++ b/src/tools/clippy/tests/ui/read_zero_byte_vec.rs
@@ -112,4 +112,10 @@ async fn test_tokio<R: TokioAsyncRead + Unpin>(r: &mut R) {
     //~^ ERROR: reading zero byte data to `Vec`
 }
 
+fn allow_works<F: std::io::Read>(mut f: F) {
+    let mut data = Vec::with_capacity(100);
+    #[allow(clippy::read_zero_byte_vec)]
+    f.read(&mut data).unwrap();
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/redundant_as_str.fixed b/src/tools/clippy/tests/ui/redundant_as_str.fixed
index 4185b402226..708a1cc9150 100644
--- a/src/tools/clippy/tests/ui/redundant_as_str.fixed
+++ b/src/tools/clippy/tests/ui/redundant_as_str.fixed
@@ -1,4 +1,5 @@
 #![warn(clippy::redundant_as_str)]
+#![allow(clippy::const_is_empty)]
 
 fn main() {
     let string = "Hello, world!".to_owned();
diff --git a/src/tools/clippy/tests/ui/redundant_as_str.rs b/src/tools/clippy/tests/ui/redundant_as_str.rs
index 7a74d8a55de..257af591cef 100644
--- a/src/tools/clippy/tests/ui/redundant_as_str.rs
+++ b/src/tools/clippy/tests/ui/redundant_as_str.rs
@@ -1,4 +1,5 @@
 #![warn(clippy::redundant_as_str)]
+#![allow(clippy::const_is_empty)]
 
 fn main() {
     let string = "Hello, world!".to_owned();
diff --git a/src/tools/clippy/tests/ui/redundant_as_str.stderr b/src/tools/clippy/tests/ui/redundant_as_str.stderr
index f086de5fede..f5379d701db 100644
--- a/src/tools/clippy/tests/ui/redundant_as_str.stderr
+++ b/src/tools/clippy/tests/ui/redundant_as_str.stderr
@@ -1,5 +1,5 @@
 error: this `as_str` is redundant and can be removed as the method immediately following exists on `String` too
-  --> tests/ui/redundant_as_str.rs:7:29
+  --> tests/ui/redundant_as_str.rs:8:29
    |
 LL |     let _redundant = string.as_str().as_bytes();
    |                             ^^^^^^^^^^^^^^^^^ help: try: `as_bytes`
@@ -8,7 +8,7 @@ LL |     let _redundant = string.as_str().as_bytes();
    = help: to override `-D warnings` add `#[allow(clippy::redundant_as_str)]`
 
 error: this `as_str` is redundant and can be removed as the method immediately following exists on `String` too
-  --> tests/ui/redundant_as_str.rs:8:29
+  --> tests/ui/redundant_as_str.rs:9:29
    |
 LL |     let _redundant = string.as_str().is_empty();
    |                             ^^^^^^^^^^^^^^^^^ help: try: `is_empty`
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index f4ff0f0b88b..24d0f797542 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -2,6 +2,7 @@
 // Use that command to update this file and do not edit by hand.
 // Manual edits will be overwritten.
 
+#![allow(clippy::duplicated_attributes)]
 #![allow(clippy::almost_complete_range)]
 #![allow(clippy::disallowed_names)]
 #![allow(clippy::blocks_in_conditions)]
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index 0df1098f5fb..be8da2fa1a3 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -2,6 +2,7 @@
 // Use that command to update this file and do not edit by hand.
 // Manual edits will be overwritten.
 
+#![allow(clippy::duplicated_attributes)]
 #![allow(clippy::almost_complete_range)]
 #![allow(clippy::disallowed_names)]
 #![allow(clippy::blocks_in_conditions)]
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index e6659b109e5..777ac20153d 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -1,5 +1,5 @@
 error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
-  --> tests/ui/rename.rs:55:9
+  --> tests/ui/rename.rs:56:9
    |
 LL | #![warn(clippy::almost_complete_letter_range)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
@@ -8,343 +8,343 @@ LL | #![warn(clippy::almost_complete_letter_range)]
    = 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:56:9
+  --> tests/ui/rename.rs:57:9
    |
 LL | #![warn(clippy::blacklisted_name)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
 
 error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_conditions`
-  --> tests/ui/rename.rs:57:9
+  --> tests/ui/rename.rs:58:9
    |
 LL | #![warn(clippy::block_in_if_condition_expr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions`
 
 error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_conditions`
-  --> tests/ui/rename.rs:58:9
+  --> tests/ui/rename.rs:59:9
    |
 LL | #![warn(clippy::block_in_if_condition_stmt)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions`
 
 error: lint `clippy::blocks_in_if_conditions` has been renamed to `clippy::blocks_in_conditions`
-  --> tests/ui/rename.rs:59:9
+  --> tests/ui/rename.rs:60:9
    |
 LL | #![warn(clippy::blocks_in_if_conditions)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions`
 
 error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
-  --> tests/ui/rename.rs:60:9
+  --> tests/ui/rename.rs:61:9
    |
 LL | #![warn(clippy::box_vec)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
 
 error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
-  --> tests/ui/rename.rs:61:9
+  --> tests/ui/rename.rs:62:9
    |
 LL | #![warn(clippy::const_static_lifetime)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
 
 error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
-  --> tests/ui/rename.rs:62:9
+  --> tests/ui/rename.rs:63:9
    |
 LL | #![warn(clippy::cyclomatic_complexity)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
 
 error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq`
-  --> tests/ui/rename.rs:63:9
+  --> tests/ui/rename.rs:64:9
    |
 LL | #![warn(clippy::derive_hash_xor_eq)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq`
 
 error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
-  --> tests/ui/rename.rs:64:9
+  --> tests/ui/rename.rs:65:9
    |
 LL | #![warn(clippy::disallowed_method)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
 
 error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
-  --> tests/ui/rename.rs:65:9
+  --> tests/ui/rename.rs:66:9
    |
 LL | #![warn(clippy::disallowed_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
 
 error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
-  --> tests/ui/rename.rs:66:9
+  --> tests/ui/rename.rs:67:9
    |
 LL | #![warn(clippy::eval_order_dependence)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
 
 error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
-  --> tests/ui/rename.rs:67:9
+  --> tests/ui/rename.rs:68:9
    |
 LL | #![warn(clippy::identity_conversion)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
 
 error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
-  --> tests/ui/rename.rs:68:9
+  --> tests/ui/rename.rs:69:9
    |
 LL | #![warn(clippy::if_let_some_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
 
 error: lint `clippy::incorrect_clone_impl_on_copy_type` has been renamed to `clippy::non_canonical_clone_impl`
-  --> tests/ui/rename.rs:69:9
+  --> tests/ui/rename.rs:70:9
    |
 LL | #![warn(clippy::incorrect_clone_impl_on_copy_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_clone_impl`
 
 error: lint `clippy::incorrect_partial_ord_impl_on_ord_type` has been renamed to `clippy::non_canonical_partial_ord_impl`
-  --> tests/ui/rename.rs:70:9
+  --> tests/ui/rename.rs:71:9
    |
 LL | #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_partial_ord_impl`
 
 error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects`
-  --> tests/ui/rename.rs:71:9
+  --> tests/ui/rename.rs:72:9
    |
 LL | #![warn(clippy::integer_arithmetic)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects`
 
 error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
-  --> tests/ui/rename.rs:72:9
+  --> tests/ui/rename.rs:73:9
    |
 LL | #![warn(clippy::logic_bug)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
 
 error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
-  --> tests/ui/rename.rs:73:9
+  --> tests/ui/rename.rs:74:9
    |
 LL | #![warn(clippy::new_without_default_derive)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
 
 error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
-  --> tests/ui/rename.rs:74:9
+  --> tests/ui/rename.rs:75:9
    |
 LL | #![warn(clippy::option_and_then_some)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
 
 error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
-  --> tests/ui/rename.rs:75:9
+  --> tests/ui/rename.rs:76:9
    |
 LL | #![warn(clippy::option_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
-  --> tests/ui/rename.rs:76:9
+  --> tests/ui/rename.rs:77:9
    |
 LL | #![warn(clippy::option_map_unwrap_or)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> tests/ui/rename.rs:77:9
+  --> tests/ui/rename.rs:78:9
    |
 LL | #![warn(clippy::option_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> tests/ui/rename.rs:78:9
+  --> tests/ui/rename.rs:79:9
    |
 LL | #![warn(clippy::option_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
-  --> tests/ui/rename.rs:79:9
+  --> tests/ui/rename.rs:80:9
    |
 LL | #![warn(clippy::ref_in_deref)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
 
 error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
-  --> tests/ui/rename.rs:80:9
+  --> tests/ui/rename.rs:81:9
    |
 LL | #![warn(clippy::result_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> tests/ui/rename.rs:81:9
+  --> tests/ui/rename.rs:82:9
    |
 LL | #![warn(clippy::result_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> tests/ui/rename.rs:82:9
+  --> tests/ui/rename.rs:83:9
    |
 LL | #![warn(clippy::result_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
-  --> tests/ui/rename.rs:83:9
+  --> tests/ui/rename.rs:84:9
    |
 LL | #![warn(clippy::single_char_push_str)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
 
 error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
-  --> tests/ui/rename.rs:84:9
+  --> tests/ui/rename.rs:85:9
    |
 LL | #![warn(clippy::stutter)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
 
 error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
-  --> tests/ui/rename.rs:85:9
+  --> tests/ui/rename.rs:86:9
    |
 LL | #![warn(clippy::to_string_in_display)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
 
 error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default`
-  --> tests/ui/rename.rs:86:9
+  --> tests/ui/rename.rs:87:9
    |
 LL | #![warn(clippy::unwrap_or_else_default)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default`
 
 error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
-  --> tests/ui/rename.rs:87:9
+  --> tests/ui/rename.rs:88:9
    |
 LL | #![warn(clippy::zero_width_space)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
 
 error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting`
-  --> tests/ui/rename.rs:88:9
+  --> tests/ui/rename.rs:89:9
    |
 LL | #![warn(clippy::cast_ref_to_mut)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting`
 
 error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op`
-  --> tests/ui/rename.rs:89:9
+  --> tests/ui/rename.rs:90:9
    |
 LL | #![warn(clippy::clone_double_ref)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op`
 
 error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons`
-  --> tests/ui/rename.rs:90:9
+  --> tests/ui/rename.rs:91:9
    |
 LL | #![warn(clippy::cmp_nan)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons`
 
 error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
-  --> tests/ui/rename.rs:91:9
+  --> tests/ui/rename.rs:92:9
    |
 LL | #![warn(clippy::drop_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
 error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types`
-  --> tests/ui/rename.rs:92:9
+  --> tests/ui/rename.rs:93:9
    |
 LL | #![warn(clippy::drop_copy)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types`
 
 error: lint `clippy::drop_ref` has been renamed to `dropping_references`
-  --> tests/ui/rename.rs:93:9
+  --> tests/ui/rename.rs:94:9
    |
 LL | #![warn(clippy::drop_ref)]
    |         ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references`
 
 error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks`
-  --> tests/ui/rename.rs:94:9
+  --> tests/ui/rename.rs:95:9
    |
 LL | #![warn(clippy::fn_null_check)]
    |         ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks`
 
 error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
-  --> tests/ui/rename.rs:95:9
+  --> tests/ui/rename.rs:96:9
    |
 LL | #![warn(clippy::for_loop_over_option)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
-  --> tests/ui/rename.rs:96:9
+  --> tests/ui/rename.rs:97:9
    |
 LL | #![warn(clippy::for_loop_over_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
-  --> tests/ui/rename.rs:97:9
+  --> tests/ui/rename.rs:98:9
    |
 LL | #![warn(clippy::for_loops_over_fallibles)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types`
-  --> tests/ui/rename.rs:98:9
+  --> tests/ui/rename.rs:99:9
    |
 LL | #![warn(clippy::forget_copy)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types`
 
 error: lint `clippy::forget_ref` has been renamed to `forgetting_references`
-  --> tests/ui/rename.rs:99:9
+  --> tests/ui/rename.rs:100:9
    |
 LL | #![warn(clippy::forget_ref)]
    |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references`
 
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> tests/ui/rename.rs:100:9
+  --> tests/ui/rename.rs:101:9
    |
 LL | #![warn(clippy::into_iter_on_array)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
 
 error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
-  --> tests/ui/rename.rs:101:9
+  --> tests/ui/rename.rs:102:9
    |
 LL | #![warn(clippy::invalid_atomic_ordering)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
 
 error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
-  --> tests/ui/rename.rs:102:9
+  --> tests/ui/rename.rs:103:9
    |
 LL | #![warn(clippy::invalid_ref)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
 error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked`
-  --> tests/ui/rename.rs:103:9
+  --> tests/ui/rename.rs:104:9
    |
 LL | #![warn(clippy::invalid_utf8_in_unchecked)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked`
 
 error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
-  --> tests/ui/rename.rs:104:9
+  --> tests/ui/rename.rs:105:9
    |
 LL | #![warn(clippy::let_underscore_drop)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
 
 error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> tests/ui/rename.rs:105:9
+  --> tests/ui/rename.rs:106:9
    |
 LL | #![warn(clippy::mem_discriminant_non_enum)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
 error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
-  --> tests/ui/rename.rs:106:9
+  --> tests/ui/rename.rs:107:9
    |
 LL | #![warn(clippy::panic_params)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
 error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
-  --> tests/ui/rename.rs:107:9
+  --> tests/ui/rename.rs:108:9
    |
 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`
-  --> tests/ui/rename.rs:108:9
+  --> tests/ui/rename.rs:109:9
    |
 LL | #![warn(clippy::temporary_cstring_as_ptr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
 
 error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops`
-  --> tests/ui/rename.rs:109:9
+  --> tests/ui/rename.rs:110:9
    |
 LL | #![warn(clippy::undropped_manually_drops)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops`
 
 error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-  --> tests/ui/rename.rs:110:9
+  --> tests/ui/rename.rs:111:9
    |
 LL | #![warn(clippy::unknown_clippy_lints)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
 
 error: lint `clippy::unused_label` has been renamed to `unused_labels`
-  --> tests/ui/rename.rs:111:9
+  --> tests/ui/rename.rs:112:9
    |
 LL | #![warn(clippy::unused_label)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
 
 error: lint `clippy::vtable_address_comparisons` has been renamed to `ambiguous_wide_pointer_comparisons`
-  --> tests/ui/rename.rs:112:9
+  --> tests/ui/rename.rs:113:9
    |
 LL | #![warn(clippy::vtable_address_comparisons)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons`
diff --git a/src/tools/clippy/tests/ui/single_match.fixed b/src/tools/clippy/tests/ui/single_match.fixed
index 6df64eb4053..acd70416d8b 100644
--- a/src/tools/clippy/tests/ui/single_match.fixed
+++ b/src/tools/clippy/tests/ui/single_match.fixed
@@ -1,12 +1,11 @@
-//@compile-flags: -Zdeduplicate-diagnostics=yes
-
 #![warn(clippy::single_match)]
 #![allow(
     unused,
     clippy::uninlined_format_args,
     clippy::needless_if,
     clippy::redundant_guards,
-    clippy::redundant_pattern_matching
+    clippy::redundant_pattern_matching,
+    clippy::manual_unwrap_or_default
 )]
 fn dummy() {}
 
diff --git a/src/tools/clippy/tests/ui/single_match.rs b/src/tools/clippy/tests/ui/single_match.rs
index 4f005f4e04f..bde78199810 100644
--- a/src/tools/clippy/tests/ui/single_match.rs
+++ b/src/tools/clippy/tests/ui/single_match.rs
@@ -1,12 +1,11 @@
-//@compile-flags: -Zdeduplicate-diagnostics=yes
-
 #![warn(clippy::single_match)]
 #![allow(
     unused,
     clippy::uninlined_format_args,
     clippy::needless_if,
     clippy::redundant_guards,
-    clippy::redundant_pattern_matching
+    clippy::redundant_pattern_matching,
+    clippy::manual_unwrap_or_default
 )]
 fn dummy() {}
 
diff --git a/src/tools/clippy/tests/ui/single_match.stderr b/src/tools/clippy/tests/ui/single_match.stderr
index 651d0b4911d..a249c120ee4 100644
--- a/src/tools/clippy/tests/ui/single_match.stderr
+++ b/src/tools/clippy/tests/ui/single_match.stderr
@@ -1,5 +1,5 @@
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> tests/ui/single_match.rs:16:5
+  --> tests/ui/single_match.rs:15:5
    |
 LL | /     match x {
 LL | |         Some(y) => {
@@ -19,7 +19,7 @@ LL ~     };
    |
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> tests/ui/single_match.rs:24:5
+  --> tests/ui/single_match.rs:23:5
    |
 LL | /     match x {
 LL | |         // Note the missing block braces.
@@ -31,7 +31,7 @@ LL | |     }
    | |_____^ help: try: `if let Some(y) = x { println!("{:?}", y) }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> tests/ui/single_match.rs:33:5
+  --> tests/ui/single_match.rs:32:5
    |
 LL | /     match z {
 LL | |         (2..=3, 7..=9) => dummy(),
@@ -40,7 +40,7 @@ LL | |     };
    | |_____^ help: try: `if let (2..=3, 7..=9) = z { dummy() }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> tests/ui/single_match.rs:62:5
+  --> tests/ui/single_match.rs:61:5
    |
 LL | /     match x {
 LL | |         Some(y) => dummy(),
@@ -49,7 +49,7 @@ LL | |     };
    | |_____^ help: try: `if let Some(y) = x { dummy() }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> tests/ui/single_match.rs:67:5
+  --> tests/ui/single_match.rs:66:5
    |
 LL | /     match y {
 LL | |         Ok(y) => dummy(),
@@ -58,7 +58,7 @@ LL | |     };
    | |_____^ help: try: `if let Ok(y) = y { dummy() }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> tests/ui/single_match.rs:74:5
+  --> tests/ui/single_match.rs:73:5
    |
 LL | /     match c {
 LL | |         Cow::Borrowed(..) => dummy(),
@@ -67,7 +67,7 @@ LL | |     };
    | |_____^ help: try: `if let Cow::Borrowed(..) = c { dummy() }`
 
 error: you seem to be trying to use `match` for an equality check. Consider using `if`
-  --> tests/ui/single_match.rs:95:5
+  --> tests/ui/single_match.rs:94:5
    |
 LL | /     match x {
 LL | |         "test" => println!(),
@@ -76,7 +76,7 @@ LL | |     }
    | |_____^ help: try: `if x == "test" { println!() }`
 
 error: you seem to be trying to use `match` for an equality check. Consider using `if`
-  --> tests/ui/single_match.rs:108:5
+  --> tests/ui/single_match.rs:107:5
    |
 LL | /     match x {
 LL | |         Foo::A => println!(),
@@ -85,7 +85,7 @@ LL | |     }
    | |_____^ help: try: `if x == Foo::A { println!() }`
 
 error: you seem to be trying to use `match` for an equality check. Consider using `if`
-  --> tests/ui/single_match.rs:114:5
+  --> tests/ui/single_match.rs:113:5
    |
 LL | /     match x {
 LL | |         FOO_C => println!(),
@@ -94,7 +94,7 @@ LL | |     }
    | |_____^ help: try: `if x == FOO_C { println!() }`
 
 error: you seem to be trying to use `match` for an equality check. Consider using `if`
-  --> tests/ui/single_match.rs:119:5
+  --> tests/ui/single_match.rs:118:5
    |
 LL | /     match &&x {
 LL | |         Foo::A => println!(),
@@ -103,7 +103,7 @@ LL | |     }
    | |_____^ help: try: `if x == Foo::A { println!() }`
 
 error: you seem to be trying to use `match` for an equality check. Consider using `if`
-  --> tests/ui/single_match.rs:125:5
+  --> tests/ui/single_match.rs:124:5
    |
 LL | /     match &x {
 LL | |         Foo::A => println!(),
@@ -112,7 +112,7 @@ LL | |     }
    | |_____^ help: try: `if x == &Foo::A { println!() }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> tests/ui/single_match.rs:142:5
+  --> tests/ui/single_match.rs:141:5
    |
 LL | /     match x {
 LL | |         Bar::A => println!(),
@@ -121,7 +121,7 @@ LL | |     }
    | |_____^ help: try: `if let Bar::A = x { println!() }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> tests/ui/single_match.rs:150:5
+  --> tests/ui/single_match.rs:149:5
    |
 LL | /     match x {
 LL | |         None => println!(),
@@ -130,7 +130,7 @@ LL | |     };
    | |_____^ help: try: `if let None = x { println!() }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> tests/ui/single_match.rs:172:5
+  --> tests/ui/single_match.rs:171:5
    |
 LL | /     match x {
 LL | |         (Some(_), _) => {},
@@ -139,7 +139,7 @@ LL | |     }
    | |_____^ help: try: `if let (Some(_), _) = x {}`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> tests/ui/single_match.rs:178:5
+  --> tests/ui/single_match.rs:177:5
    |
 LL | /     match x {
 LL | |         (Some(E::V), _) => todo!(),
@@ -148,7 +148,7 @@ LL | |     }
    | |_____^ help: try: `if let (Some(E::V), _) = x { todo!() }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> tests/ui/single_match.rs:184:5
+  --> tests/ui/single_match.rs:183:5
    |
 LL | /     match (Some(42), Some(E::V), Some(42)) {
 LL | |         (.., Some(E::V), _) => {},
@@ -157,7 +157,7 @@ LL | |     }
    | |_____^ help: try: `if let (.., Some(E::V), _) = (Some(42), Some(E::V), Some(42)) {}`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> tests/ui/single_match.rs:256:5
+  --> tests/ui/single_match.rs:255:5
    |
 LL | /     match bar {
 LL | |         Some(v) => unsafe {
@@ -177,7 +177,7 @@ LL +     } }
    |
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> tests/ui/single_match.rs:264:5
+  --> tests/ui/single_match.rs:263:5
    |
 LL | /     match bar {
 LL | |         #[rustfmt::skip]
diff --git a/src/tools/clippy/tests/ui/single_match_else.fixed b/src/tools/clippy/tests/ui/single_match_else.fixed
index 2970f5485fa..e840adf0fa3 100644
--- a/src/tools/clippy/tests/ui/single_match_else.fixed
+++ b/src/tools/clippy/tests/ui/single_match_else.fixed
@@ -1,5 +1,4 @@
 //@aux-build: proc_macros.rs
-//@compile-flags: -Zdeduplicate-diagnostics=yes
 
 #![warn(clippy::single_match_else)]
 #![allow(unused, clippy::needless_return, clippy::no_effect, clippy::uninlined_format_args)]
diff --git a/src/tools/clippy/tests/ui/single_match_else.rs b/src/tools/clippy/tests/ui/single_match_else.rs
index 26974b2a48a..430c4da20f1 100644
--- a/src/tools/clippy/tests/ui/single_match_else.rs
+++ b/src/tools/clippy/tests/ui/single_match_else.rs
@@ -1,5 +1,4 @@
 //@aux-build: proc_macros.rs
-//@compile-flags: -Zdeduplicate-diagnostics=yes
 
 #![warn(clippy::single_match_else)]
 #![allow(unused, clippy::needless_return, clippy::no_effect, clippy::uninlined_format_args)]
diff --git a/src/tools/clippy/tests/ui/single_match_else.stderr b/src/tools/clippy/tests/ui/single_match_else.stderr
index 48c74c0caea..f8f88379d6d 100644
--- a/src/tools/clippy/tests/ui/single_match_else.stderr
+++ b/src/tools/clippy/tests/ui/single_match_else.stderr
@@ -1,5 +1,5 @@
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> tests/ui/single_match_else.rs:18:13
+  --> tests/ui/single_match_else.rs:17:13
    |
 LL |       let _ = match ExprNode::Butterflies {
    |  _____________^
@@ -22,7 +22,7 @@ LL ~     };
    |
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> tests/ui/single_match_else.rs:83:5
+  --> tests/ui/single_match_else.rs:82:5
    |
 LL | /     match Some(1) {
 LL | |         Some(a) => println!("${:?}", a),
@@ -42,7 +42,7 @@ LL +     }
    |
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> tests/ui/single_match_else.rs:92:5
+  --> tests/ui/single_match_else.rs:91:5
    |
 LL | /     match Some(1) {
 LL | |         Some(a) => println!("${:?}", a),
@@ -62,7 +62,7 @@ LL +     }
    |
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> tests/ui/single_match_else.rs:102:5
+  --> tests/ui/single_match_else.rs:101:5
    |
 LL | /     match Result::<i32, Infallible>::Ok(1) {
 LL | |         Ok(a) => println!("${:?}", a),
@@ -82,7 +82,7 @@ LL +     }
    |
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> tests/ui/single_match_else.rs:111:5
+  --> tests/ui/single_match_else.rs:110:5
    |
 LL | /     match Cow::from("moo") {
 LL | |         Cow::Owned(a) => println!("${:?}", a),
@@ -102,7 +102,7 @@ LL +     }
    |
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> tests/ui/single_match_else.rs:121:5
+  --> tests/ui/single_match_else.rs:120:5
    |
 LL | /     match bar {
 LL | |         Some(v) => unsafe {
@@ -125,7 +125,7 @@ LL +     }
    |
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> tests/ui/single_match_else.rs:132:5
+  --> tests/ui/single_match_else.rs:131:5
    |
 LL | /     match bar {
 LL | |         Some(v) => {
@@ -149,7 +149,7 @@ LL +     } }
    |
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> tests/ui/single_match_else.rs:144:5
+  --> tests/ui/single_match_else.rs:143:5
    |
 LL | /     match bar {
 LL | |         Some(v) => unsafe {
@@ -173,7 +173,7 @@ LL +     } }
    |
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> tests/ui/single_match_else.rs:156:5
+  --> tests/ui/single_match_else.rs:155:5
    |
 LL | /     match bar {
 LL | |         #[rustfmt::skip]
diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.fixed b/src/tools/clippy/tests/ui/std_instead_of_core.fixed
index 0a734a65d29..ec4ae2ea13c 100644
--- a/src/tools/clippy/tests/ui/std_instead_of_core.fixed
+++ b/src/tools/clippy/tests/ui/std_instead_of_core.fixed
@@ -17,7 +17,7 @@ fn std_instead_of_core() {
     use ::core::hash::Hash;
     //~^ ERROR: used import from `std` instead of `core`
     // Don't lint on `env` macro
-    use core::env;
+    use std::env;
 
     // Multiple imports
     use core::fmt::{Debug, Result};
diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.stderr b/src/tools/clippy/tests/ui/std_instead_of_core.stderr
index ee42b474a32..8f920511cc5 100644
--- a/src/tools/clippy/tests/ui/std_instead_of_core.stderr
+++ b/src/tools/clippy/tests/ui/std_instead_of_core.stderr
@@ -14,12 +14,6 @@ LL |     use ::std::hash::Hash;
    |           ^^^ help: consider importing the item from `core`: `core`
 
 error: used import from `std` instead of `core`
-  --> tests/ui/std_instead_of_core.rs:20:9
-   |
-LL |     use std::env;
-   |         ^^^ help: consider importing the item from `core`: `core`
-
-error: used import from `std` instead of `core`
   --> tests/ui/std_instead_of_core.rs:23:9
    |
 LL |     use std::fmt::{Debug, Result};
@@ -85,5 +79,5 @@ LL |     use alloc::slice::from_ref;
    = note: `-D clippy::alloc-instead-of-core` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::alloc_instead_of_core)]`
 
-error: aborting due to 13 previous errors
+error: aborting due to 12 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unconditional_recursion.rs b/src/tools/clippy/tests/ui/unconditional_recursion.rs
index 35275e81ded..70b390b00e2 100644
--- a/src/tools/clippy/tests/ui/unconditional_recursion.rs
+++ b/src/tools/clippy/tests/ui/unconditional_recursion.rs
@@ -1,7 +1,11 @@
 //@no-rustfix
 
 #![warn(clippy::unconditional_recursion)]
-#![allow(clippy::partialeq_ne_impl, clippy::default_constructed_unit_structs)]
+#![allow(
+    clippy::partialeq_ne_impl,
+    clippy::default_constructed_unit_structs,
+    clippy::only_used_in_recursion
+)]
 
 enum Foo {
     A,
@@ -350,4 +354,48 @@ mod issue12154 {
     }
 }
 
+// From::from -> Into::into -> From::from
+struct BadFromTy1<'a>(&'a ());
+struct BadIntoTy1<'b>(&'b ());
+impl<'a> From<BadFromTy1<'a>> for BadIntoTy1<'static> {
+    fn from(f: BadFromTy1<'a>) -> Self {
+        f.into()
+    }
+}
+
+// Using UFCS syntax
+struct BadFromTy2<'a>(&'a ());
+struct BadIntoTy2<'b>(&'b ());
+impl<'a> From<BadFromTy2<'a>> for BadIntoTy2<'static> {
+    fn from(f: BadFromTy2<'a>) -> Self {
+        Into::into(f)
+    }
+}
+
+// Different Into impl (<i16 as Into<i32>>), so no infinite recursion
+struct BadFromTy3;
+impl From<BadFromTy3> for i32 {
+    fn from(f: BadFromTy3) -> Self {
+        Into::into(1i16)
+    }
+}
+
+// A conditional return that ends the recursion
+struct BadFromTy4;
+impl From<BadFromTy4> for i32 {
+    fn from(f: BadFromTy4) -> Self {
+        if true {
+            return 42;
+        }
+        f.into()
+    }
+}
+
+// Types differ in refs, don't lint
+impl From<&BadFromTy4> for i32 {
+    fn from(f: &BadFromTy4) -> Self {
+        BadFromTy4.into()
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/unconditional_recursion.stderr b/src/tools/clippy/tests/ui/unconditional_recursion.stderr
index 3fd6c91000e..03c27bd8ed8 100644
--- a/src/tools/clippy/tests/ui/unconditional_recursion.stderr
+++ b/src/tools/clippy/tests/ui/unconditional_recursion.stderr
@@ -1,5 +1,5 @@
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:42:5
+  --> tests/ui/unconditional_recursion.rs:46:5
    |
 LL |     fn ne(&self, other: &Self) -> bool {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
@@ -12,7 +12,7 @@ LL |         self.ne(other)
    = help: to override `-D warnings` add `#[allow(unconditional_recursion)]`
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:46:5
+  --> tests/ui/unconditional_recursion.rs:50:5
    |
 LL |     fn eq(&self, other: &Self) -> bool {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
@@ -23,7 +23,7 @@ LL |         self.eq(other)
    = help: a `loop` may express intention better if this is on purpose
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:211:5
+  --> tests/ui/unconditional_recursion.rs:215:5
    |
 LL |     fn to_string(&self) -> String {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
@@ -34,7 +34,7 @@ LL |         self.to_string()
    = help: a `loop` may express intention better if this is on purpose
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:221:5
+  --> tests/ui/unconditional_recursion.rs:225:5
    |
 LL |     fn to_string(&self) -> String {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
@@ -45,7 +45,7 @@ LL |         x.to_string()
    = help: a `loop` may express intention better if this is on purpose
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:232:5
+  --> tests/ui/unconditional_recursion.rs:236:5
    |
 LL |     fn to_string(&self) -> String {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
@@ -56,7 +56,7 @@ LL |         (self as &Self).to_string()
    = help: a `loop` may express intention better if this is on purpose
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:12:5
+  --> tests/ui/unconditional_recursion.rs:16:5
    |
 LL | /     fn ne(&self, other: &Self) -> bool {
 LL | |
@@ -65,7 +65,7 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:14:9
+  --> tests/ui/unconditional_recursion.rs:18:9
    |
 LL |         self != other
    |         ^^^^^^^^^^^^^
@@ -73,7 +73,7 @@ LL |         self != other
    = help: to override `-D warnings` add `#[allow(clippy::unconditional_recursion)]`
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:16:5
+  --> tests/ui/unconditional_recursion.rs:20:5
    |
 LL | /     fn eq(&self, other: &Self) -> bool {
 LL | |
@@ -82,13 +82,13 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:18:9
+  --> tests/ui/unconditional_recursion.rs:22:9
    |
 LL |         self == other
    |         ^^^^^^^^^^^^^
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:28:5
+  --> tests/ui/unconditional_recursion.rs:32:5
    |
 LL | /     fn ne(&self, other: &Self) -> bool {
 LL | |         self != &Foo2::B // no error here
@@ -96,13 +96,13 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:29:9
+  --> tests/ui/unconditional_recursion.rs:33:9
    |
 LL |         self != &Foo2::B // no error here
    |         ^^^^^^^^^^^^^^^^
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:31:5
+  --> tests/ui/unconditional_recursion.rs:35:5
    |
 LL | /     fn eq(&self, other: &Self) -> bool {
 LL | |         self == &Foo2::B // no error here
@@ -110,13 +110,13 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:32:9
+  --> tests/ui/unconditional_recursion.rs:36:9
    |
 LL |         self == &Foo2::B // no error here
    |         ^^^^^^^^^^^^^^^^
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:42:5
+  --> tests/ui/unconditional_recursion.rs:46:5
    |
 LL | /     fn ne(&self, other: &Self) -> bool {
 LL | |
@@ -125,27 +125,13 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:44:9
+  --> tests/ui/unconditional_recursion.rs:48:9
    |
 LL |         self.ne(other)
    |         ^^^^^^^^^^^^^^
 
-error: parameter is only used in recursion
-  --> tests/ui/unconditional_recursion.rs:42:18
-   |
-LL |     fn ne(&self, other: &Self) -> bool {
-   |                  ^^^^^ help: if this is intentional, prefix it with an underscore: `_other`
-   |
-note: parameter used here
-  --> tests/ui/unconditional_recursion.rs:44:17
-   |
-LL |         self.ne(other)
-   |                 ^^^^^
-   = note: `-D clippy::only-used-in-recursion` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::only_used_in_recursion)]`
-
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:46:5
+  --> tests/ui/unconditional_recursion.rs:50:5
    |
 LL | /     fn eq(&self, other: &Self) -> bool {
 LL | |
@@ -154,25 +140,13 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:48:9
+  --> tests/ui/unconditional_recursion.rs:52:9
    |
 LL |         self.eq(other)
    |         ^^^^^^^^^^^^^^
 
-error: parameter is only used in recursion
-  --> tests/ui/unconditional_recursion.rs:46:18
-   |
-LL |     fn eq(&self, other: &Self) -> bool {
-   |                  ^^^^^ help: if this is intentional, prefix it with an underscore: `_other`
-   |
-note: parameter used here
-  --> tests/ui/unconditional_recursion.rs:48:17
-   |
-LL |         self.eq(other)
-   |                 ^^^^^
-
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:90:5
+  --> tests/ui/unconditional_recursion.rs:94:5
    |
 LL | /     fn ne(&self, other: &Self) -> bool {
 LL | |
@@ -181,13 +155,13 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:92:9
+  --> tests/ui/unconditional_recursion.rs:96:9
    |
 LL |         other != self
    |         ^^^^^^^^^^^^^
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:94:5
+  --> tests/ui/unconditional_recursion.rs:98:5
    |
 LL | /     fn eq(&self, other: &Self) -> bool {
 LL | |
@@ -196,13 +170,13 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:96:9
+  --> tests/ui/unconditional_recursion.rs:100:9
    |
 LL |         other == self
    |         ^^^^^^^^^^^^^
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:104:5
+  --> tests/ui/unconditional_recursion.rs:108:5
    |
 LL | /     fn ne(&self, other: &Self) -> bool {
 LL | |
@@ -211,13 +185,13 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:106:9
+  --> tests/ui/unconditional_recursion.rs:110:9
    |
 LL |         other != other
    |         ^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `!=`
-  --> tests/ui/unconditional_recursion.rs:106:9
+  --> tests/ui/unconditional_recursion.rs:110:9
    |
 LL |         other != other
    |         ^^^^^^^^^^^^^^
@@ -225,7 +199,7 @@ LL |         other != other
    = note: `#[deny(clippy::eq_op)]` on by default
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:108:5
+  --> tests/ui/unconditional_recursion.rs:112:5
    |
 LL | /     fn eq(&self, other: &Self) -> bool {
 LL | |
@@ -234,19 +208,19 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:110:9
+  --> tests/ui/unconditional_recursion.rs:114:9
    |
 LL |         other == other
    |         ^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `==`
-  --> tests/ui/unconditional_recursion.rs:110:9
+  --> tests/ui/unconditional_recursion.rs:114:9
    |
 LL |         other == other
    |         ^^^^^^^^^^^^^^
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:117:5
+  --> tests/ui/unconditional_recursion.rs:121:5
    |
 LL | /     fn ne(&self, _other: &Self) -> bool {
 LL | |
@@ -255,19 +229,19 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:119:9
+  --> tests/ui/unconditional_recursion.rs:123:9
    |
 LL |         self != self
    |         ^^^^^^^^^^^^
 
 error: equal expressions as operands to `!=`
-  --> tests/ui/unconditional_recursion.rs:119:9
+  --> tests/ui/unconditional_recursion.rs:123:9
    |
 LL |         self != self
    |         ^^^^^^^^^^^^
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:121:5
+  --> tests/ui/unconditional_recursion.rs:125:5
    |
 LL | /     fn eq(&self, _other: &Self) -> bool {
 LL | |
@@ -276,19 +250,19 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:123:9
+  --> tests/ui/unconditional_recursion.rs:127:9
    |
 LL |         self == self
    |         ^^^^^^^^^^^^
 
 error: equal expressions as operands to `==`
-  --> tests/ui/unconditional_recursion.rs:123:9
+  --> tests/ui/unconditional_recursion.rs:127:9
    |
 LL |         self == self
    |         ^^^^^^^^^^^^
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:149:13
+  --> tests/ui/unconditional_recursion.rs:153:13
    |
 LL | /             fn eq(&self, other: &Self) -> bool {
 LL | |
@@ -300,7 +274,7 @@ LL |   impl_partial_eq!(S5);
    |   -------------------- in this macro invocation
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:151:17
+  --> tests/ui/unconditional_recursion.rs:155:17
    |
 LL |                 self == other
    |                 ^^^^^^^^^^^^^
@@ -310,7 +284,7 @@ LL | impl_partial_eq!(S5);
    = note: this error originates in the macro `impl_partial_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:178:5
+  --> tests/ui/unconditional_recursion.rs:182:5
    |
 LL | /     fn eq(&self, other: &Self) -> bool {
 LL | |
@@ -321,13 +295,13 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:182:9
+  --> tests/ui/unconditional_recursion.rs:186:9
    |
 LL |         mine == theirs
    |         ^^^^^^^^^^^^^^
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:247:5
+  --> tests/ui/unconditional_recursion.rs:251:5
    |
 LL | /     fn new() -> Self {
 LL | |
@@ -336,13 +310,13 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:249:9
+  --> tests/ui/unconditional_recursion.rs:253:9
    |
 LL |         Self::default()
    |         ^^^^^^^^^^^^^^^
 
 error: function cannot return without recursing
-  --> tests/ui/unconditional_recursion.rs:286:5
+  --> tests/ui/unconditional_recursion.rs:290:5
    |
 LL | /     fn eq(&self, other: &Self) -> bool {
 LL | |
@@ -353,10 +327,38 @@ LL | |     }
    | |_____^
    |
 note: recursive call site
-  --> tests/ui/unconditional_recursion.rs:290:9
+  --> tests/ui/unconditional_recursion.rs:294:9
    |
 LL |         mine.eq(theirs)
    |         ^^^^^^^^^^^^^^^
 
+error: function cannot return without recursing
+  --> tests/ui/unconditional_recursion.rs:361:5
+   |
+LL | /     fn from(f: BadFromTy1<'a>) -> Self {
+LL | |         f.into()
+LL | |     }
+   | |_____^
+   |
+note: recursive call site
+  --> tests/ui/unconditional_recursion.rs:362:9
+   |
+LL |         f.into()
+   |         ^^^^^^^^
+
+error: function cannot return without recursing
+  --> tests/ui/unconditional_recursion.rs:370:5
+   |
+LL | /     fn from(f: BadFromTy2<'a>) -> Self {
+LL | |         Into::into(f)
+LL | |     }
+   | |_____^
+   |
+note: recursive call site
+  --> tests/ui/unconditional_recursion.rs:371:9
+   |
+LL |         Into::into(f)
+   |         ^^^^^^^^^^^^^
+
 error: aborting due to 27 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unused_enumerate_index.fixed b/src/tools/clippy/tests/ui/unused_enumerate_index.fixed
index d079807ab58..cffd02b0acc 100644
--- a/src/tools/clippy/tests/ui/unused_enumerate_index.fixed
+++ b/src/tools/clippy/tests/ui/unused_enumerate_index.fixed
@@ -1,8 +1,12 @@
-#![allow(unused)]
+#![allow(unused, clippy::map_identity)]
 #![warn(clippy::unused_enumerate_index)]
 
 use std::iter::Enumerate;
 
+fn get_enumerate() -> Enumerate<std::vec::IntoIter<i32>> {
+    vec![1].into_iter().enumerate()
+}
+
 fn main() {
     let v = [1, 2, 3];
     for x in v.iter() {
@@ -55,4 +59,48 @@ fn main() {
     for x in dummy {
         println!("{x}");
     }
+
+    let _ = vec![1, 2, 3].into_iter().map(|x| println!("{x}"));
+
+    let p = vec![1, 2, 3].into_iter();
+    p.map(|x| println!("{x}"));
+
+    // This shouldn't trigger the lint. `get_enumerate` may come from an external library on which we
+    // have no control.
+    let p = get_enumerate();
+    p.map(|(_, x)| println!("{x}"));
+
+    // This shouldn't trigger the lint. The `enumerate` call is in a different context.
+    macro_rules! mac {
+        () => {
+            [1].iter().enumerate()
+        };
+    }
+    _ = mac!().map(|(_, v)| v);
+
+    macro_rules! mac2 {
+        () => {
+            [1].iter()
+        };
+    }
+    _ = mac2!().map(|_v| {});
+
+    // This shouldn't trigger the lint because of the `allow`.
+    #[allow(clippy::unused_enumerate_index)]
+    let v = [1].iter().enumerate();
+    v.map(|(_, _x)| {});
+
+    // This should keep the explicit type of `x`.
+    let v = [1, 2, 3].iter().copied();
+    let x = v.map(|x: i32| x).sum::<i32>();
+    assert_eq!(x, 6);
+
+    // This should keep the explicit type of `x`.
+    let v = [1, 2, 3].iter().copied();
+    let x = v.map(|x: i32| x).sum::<i32>();
+    assert_eq!(x, 6);
+
+    let v = [1, 2, 3].iter().copied();
+    let x = v.map(|x| x).sum::<i32>();
+    assert_eq!(x, 6);
 }
diff --git a/src/tools/clippy/tests/ui/unused_enumerate_index.rs b/src/tools/clippy/tests/ui/unused_enumerate_index.rs
index 2d524da7632..f2b5f8b9124 100644
--- a/src/tools/clippy/tests/ui/unused_enumerate_index.rs
+++ b/src/tools/clippy/tests/ui/unused_enumerate_index.rs
@@ -1,8 +1,12 @@
-#![allow(unused)]
+#![allow(unused, clippy::map_identity)]
 #![warn(clippy::unused_enumerate_index)]
 
 use std::iter::Enumerate;
 
+fn get_enumerate() -> Enumerate<std::vec::IntoIter<i32>> {
+    vec![1].into_iter().enumerate()
+}
+
 fn main() {
     let v = [1, 2, 3];
     for (_, x) in v.iter().enumerate() {
@@ -55,4 +59,48 @@ fn main() {
     for (_, x) in dummy.enumerate() {
         println!("{x}");
     }
+
+    let _ = vec![1, 2, 3].into_iter().enumerate().map(|(_, x)| println!("{x}"));
+
+    let p = vec![1, 2, 3].into_iter().enumerate();
+    p.map(|(_, x)| println!("{x}"));
+
+    // This shouldn't trigger the lint. `get_enumerate` may come from an external library on which we
+    // have no control.
+    let p = get_enumerate();
+    p.map(|(_, x)| println!("{x}"));
+
+    // This shouldn't trigger the lint. The `enumerate` call is in a different context.
+    macro_rules! mac {
+        () => {
+            [1].iter().enumerate()
+        };
+    }
+    _ = mac!().map(|(_, v)| v);
+
+    macro_rules! mac2 {
+        () => {
+            [1].iter()
+        };
+    }
+    _ = mac2!().enumerate().map(|(_, _v)| {});
+
+    // This shouldn't trigger the lint because of the `allow`.
+    #[allow(clippy::unused_enumerate_index)]
+    let v = [1].iter().enumerate();
+    v.map(|(_, _x)| {});
+
+    // This should keep the explicit type of `x`.
+    let v = [1, 2, 3].iter().copied().enumerate();
+    let x = v.map(|(_, x): (usize, i32)| x).sum::<i32>();
+    assert_eq!(x, 6);
+
+    // This should keep the explicit type of `x`.
+    let v = [1, 2, 3].iter().copied().enumerate();
+    let x = v.map(|(_, x): (_, i32)| x).sum::<i32>();
+    assert_eq!(x, 6);
+
+    let v = [1, 2, 3].iter().copied().enumerate();
+    let x = v.map(|(_, x)| x).sum::<i32>();
+    assert_eq!(x, 6);
 }
diff --git a/src/tools/clippy/tests/ui/unused_enumerate_index.stderr b/src/tools/clippy/tests/ui/unused_enumerate_index.stderr
index 7bd7d29117e..6ec07dcbff0 100644
--- a/src/tools/clippy/tests/ui/unused_enumerate_index.stderr
+++ b/src/tools/clippy/tests/ui/unused_enumerate_index.stderr
@@ -1,5 +1,5 @@
 error: you seem to use `.enumerate()` and immediately discard the index
-  --> tests/ui/unused_enumerate_index.rs:8:19
+  --> tests/ui/unused_enumerate_index.rs:12:19
    |
 LL |     for (_, x) in v.iter().enumerate() {
    |                   ^^^^^^^^^^^^^^^^^^^^
@@ -12,7 +12,7 @@ LL |     for x in v.iter() {
    |         ~    ~~~~~~~~
 
 error: you seem to use `.enumerate()` and immediately discard the index
-  --> tests/ui/unused_enumerate_index.rs:55:19
+  --> tests/ui/unused_enumerate_index.rs:59:19
    |
 LL |     for (_, x) in dummy.enumerate() {
    |                   ^^^^^^^^^^^^^^^^^
@@ -22,5 +22,77 @@ help: remove the `.enumerate()` call
 LL |     for x in dummy {
    |         ~    ~~~~~
 
-error: aborting due to 2 previous errors
+error: you seem to use `.enumerate()` and immediately discard the index
+  --> tests/ui/unused_enumerate_index.rs:63:39
+   |
+LL |     let _ = vec![1, 2, 3].into_iter().enumerate().map(|(_, x)| println!("{x}"));
+   |                                       ^^^^^^^^^^^
+   |
+help: remove the `.enumerate()` call
+   |
+LL -     let _ = vec![1, 2, 3].into_iter().enumerate().map(|(_, x)| println!("{x}"));
+LL +     let _ = vec![1, 2, 3].into_iter().map(|x| println!("{x}"));
+   |
+
+error: you seem to use `.enumerate()` and immediately discard the index
+  --> tests/ui/unused_enumerate_index.rs:65:39
+   |
+LL |     let p = vec![1, 2, 3].into_iter().enumerate();
+   |                                       ^^^^^^^^^^^
+   |
+help: remove the `.enumerate()` call
+   |
+LL ~     let p = vec![1, 2, 3].into_iter();
+LL ~     p.map(|x| println!("{x}"));
+   |
+
+error: you seem to use `.enumerate()` and immediately discard the index
+  --> tests/ui/unused_enumerate_index.rs:86:17
+   |
+LL |     _ = mac2!().enumerate().map(|(_, _v)| {});
+   |                 ^^^^^^^^^^^
+   |
+help: remove the `.enumerate()` call
+   |
+LL -     _ = mac2!().enumerate().map(|(_, _v)| {});
+LL +     _ = mac2!().map(|_v| {});
+   |
+
+error: you seem to use `.enumerate()` and immediately discard the index
+  --> tests/ui/unused_enumerate_index.rs:94:39
+   |
+LL |     let v = [1, 2, 3].iter().copied().enumerate();
+   |                                       ^^^^^^^^^^^
+   |
+help: remove the `.enumerate()` call
+   |
+LL ~     let v = [1, 2, 3].iter().copied();
+LL ~     let x = v.map(|x: i32| x).sum::<i32>();
+   |
+
+error: you seem to use `.enumerate()` and immediately discard the index
+  --> tests/ui/unused_enumerate_index.rs:99:39
+   |
+LL |     let v = [1, 2, 3].iter().copied().enumerate();
+   |                                       ^^^^^^^^^^^
+   |
+help: remove the `.enumerate()` call
+   |
+LL ~     let v = [1, 2, 3].iter().copied();
+LL ~     let x = v.map(|x: i32| x).sum::<i32>();
+   |
+
+error: you seem to use `.enumerate()` and immediately discard the index
+  --> tests/ui/unused_enumerate_index.rs:103:39
+   |
+LL |     let v = [1, 2, 3].iter().copied().enumerate();
+   |                                       ^^^^^^^^^^^
+   |
+help: remove the `.enumerate()` call
+   |
+LL ~     let v = [1, 2, 3].iter().copied();
+LL ~     let x = v.map(|x| x).sum::<i32>();
+   |
+
+error: aborting due to 8 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unused_io_amount.rs b/src/tools/clippy/tests/ui/unused_io_amount.rs
index 7e5a10c911b..f5b200d5ffe 100644
--- a/src/tools/clippy/tests/ui/unused_io_amount.rs
+++ b/src/tools/clippy/tests/ui/unused_io_amount.rs
@@ -271,5 +271,10 @@ pub fn wildcards(rdr: &mut dyn std::io::Read) {
         }
     }
 }
+fn allow_works<F: std::io::Read>(mut f: F) {
+    let mut data = Vec::with_capacity(100);
+    #[allow(clippy::unused_io_amount)]
+    f.read(&mut data).unwrap();
+}
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/unused_peekable.rs b/src/tools/clippy/tests/ui/unused_peekable.rs
index 131b51e01b6..5865bba4350 100644
--- a/src/tools/clippy/tests/ui/unused_peekable.rs
+++ b/src/tools/clippy/tests/ui/unused_peekable.rs
@@ -174,3 +174,9 @@ fn valid() {
     let mut peekable = std::iter::empty::<u32>().peekable();
     takes_dyn(&mut peekable);
 }
+
+fn allow_works() {
+    #[allow(clippy::unused_peekable)]
+    let iter = [1, 2, 3].iter().peekable();
+    iter;
+}
diff --git a/src/tools/clippy/tests/ui/use_self.fixed b/src/tools/clippy/tests/ui/use_self.fixed
index 787dd3ec7e6..6ea7857a238 100644
--- a/src/tools/clippy/tests/ui/use_self.fixed
+++ b/src/tools/clippy/tests/ui/use_self.fixed
@@ -6,7 +6,8 @@
     clippy::should_implement_trait,
     clippy::upper_case_acronyms,
     clippy::from_over_into,
-    clippy::self_named_constructors
+    clippy::self_named_constructors,
+    clippy::needless_lifetimes
 )]
 
 #[macro_use]
@@ -53,6 +54,7 @@ mod better {
 }
 
 mod lifetimes {
+    #[derive(Clone, Copy)]
     struct Foo<'a> {
         foo_str: &'a str,
     }
@@ -68,11 +70,19 @@ mod lifetimes {
             Foo { foo_str: "foo" }
         }
 
-        // FIXME: the lint does not handle lifetimed struct
-        // `Self` should be applicable here
-        fn clone(&self) -> Foo<'a> {
+        fn clone(&self) -> Self {
             Foo { foo_str: self.foo_str }
         }
+
+        // Cannot replace with `Self` because the lifetime is not `'a`.
+        fn eq<'b>(&self, other: Foo<'b>) -> bool {
+            let x: Foo<'_> = other;
+            self.foo_str == other.foo_str
+        }
+
+        fn f(&self) -> Foo<'_> {
+            *self
+        }
     }
 }
 
diff --git a/src/tools/clippy/tests/ui/use_self.rs b/src/tools/clippy/tests/ui/use_self.rs
index 39e182faea6..338cc00e45a 100644
--- a/src/tools/clippy/tests/ui/use_self.rs
+++ b/src/tools/clippy/tests/ui/use_self.rs
@@ -6,7 +6,8 @@
     clippy::should_implement_trait,
     clippy::upper_case_acronyms,
     clippy::from_over_into,
-    clippy::self_named_constructors
+    clippy::self_named_constructors,
+    clippy::needless_lifetimes
 )]
 
 #[macro_use]
@@ -53,6 +54,7 @@ mod better {
 }
 
 mod lifetimes {
+    #[derive(Clone, Copy)]
     struct Foo<'a> {
         foo_str: &'a str,
     }
@@ -68,11 +70,19 @@ mod lifetimes {
             Foo { foo_str: "foo" }
         }
 
-        // FIXME: the lint does not handle lifetimed struct
-        // `Self` should be applicable here
         fn clone(&self) -> Foo<'a> {
             Foo { foo_str: self.foo_str }
         }
+
+        // Cannot replace with `Self` because the lifetime is not `'a`.
+        fn eq<'b>(&self, other: Foo<'b>) -> bool {
+            let x: Foo<'_> = other;
+            self.foo_str == other.foo_str
+        }
+
+        fn f(&self) -> Foo<'_> {
+            *self
+        }
     }
 }
 
diff --git a/src/tools/clippy/tests/ui/use_self.stderr b/src/tools/clippy/tests/ui/use_self.stderr
index 8d045f05ed2..d7aa8410a47 100644
--- a/src/tools/clippy/tests/ui/use_self.stderr
+++ b/src/tools/clippy/tests/ui/use_self.stderr
@@ -1,5 +1,5 @@
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:21:21
+  --> tests/ui/use_self.rs:22:21
    |
 LL |         fn new() -> Foo {
    |                     ^^^ help: use the applicable keyword: `Self`
@@ -8,250 +8,256 @@ LL |         fn new() -> Foo {
    = help: to override `-D warnings` add `#[allow(clippy::use_self)]`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:22:13
+  --> tests/ui/use_self.rs:23:13
    |
 LL |             Foo {}
    |             ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:24:22
+  --> tests/ui/use_self.rs:25:22
    |
 LL |         fn test() -> Foo {
    |                      ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:25:13
+  --> tests/ui/use_self.rs:26:13
    |
 LL |             Foo::new()
    |             ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:30:25
+  --> tests/ui/use_self.rs:31:25
    |
 LL |         fn default() -> Foo {
    |                         ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:31:13
+  --> tests/ui/use_self.rs:32:13
    |
 LL |             Foo::new()
    |             ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:96:24
+  --> tests/ui/use_self.rs:73:28
+   |
+LL |         fn clone(&self) -> Foo<'a> {
+   |                            ^^^^^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> tests/ui/use_self.rs:106:24
    |
 LL |         fn bad(foos: &[Foo]) -> impl Iterator<Item = &Foo> {
    |                        ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:96:55
+  --> tests/ui/use_self.rs:106:55
    |
 LL |         fn bad(foos: &[Foo]) -> impl Iterator<Item = &Foo> {
    |                                                       ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:111:13
+  --> tests/ui/use_self.rs:121:13
    |
 LL |             TS(0)
    |             ^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:146:29
+  --> tests/ui/use_self.rs:156:29
    |
 LL |                 fn bar() -> Bar {
    |                             ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:147:21
+  --> tests/ui/use_self.rs:157:21
    |
 LL |                     Bar { foo: Foo {} }
    |                     ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:158:21
+  --> tests/ui/use_self.rs:168:21
    |
 LL |         fn baz() -> Foo {
    |                     ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:159:13
+  --> tests/ui/use_self.rs:169:13
    |
 LL |             Foo {}
    |             ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:176:21
+  --> tests/ui/use_self.rs:186:21
    |
 LL |             let _ = Enum::B(42);
    |                     ^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:177:21
+  --> tests/ui/use_self.rs:187:21
    |
 LL |             let _ = Enum::C { field: true };
    |                     ^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:178:21
+  --> tests/ui/use_self.rs:188:21
    |
 LL |             let _ = Enum::A;
    |                     ^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:220:13
+  --> tests/ui/use_self.rs:230:13
    |
 LL |             nested::A::fun_1();
    |             ^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:221:13
+  --> tests/ui/use_self.rs:231:13
    |
 LL |             nested::A::A;
    |             ^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:223:13
+  --> tests/ui/use_self.rs:233:13
    |
 LL |             nested::A {};
    |             ^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:242:13
+  --> tests/ui/use_self.rs:252:13
    |
 LL |             TestStruct::from_something()
    |             ^^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:256:25
+  --> tests/ui/use_self.rs:266:25
    |
 LL |         async fn g() -> S {
    |                         ^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:257:13
+  --> tests/ui/use_self.rs:267:13
    |
 LL |             S {}
    |             ^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:261:16
+  --> tests/ui/use_self.rs:271:16
    |
 LL |             &p[S::A..S::B]
    |                ^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:261:22
+  --> tests/ui/use_self.rs:271:22
    |
 LL |             &p[S::A..S::B]
    |                      ^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:284:29
+  --> tests/ui/use_self.rs:294:29
    |
 LL |         fn foo(value: T) -> Foo<T> {
    |                             ^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:285:13
+  --> tests/ui/use_self.rs:295:13
    |
 LL |             Foo::<T> { value }
    |             ^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:457:13
+  --> tests/ui/use_self.rs:467:13
    |
 LL |             A::new::<submod::B>(submod::B {})
    |             ^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:494:13
+  --> tests/ui/use_self.rs:504:13
    |
 LL |             S2::new()
    |             ^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:531:17
+  --> tests/ui/use_self.rs:541:17
    |
 LL |                 Foo::Bar => unimplemented!(),
    |                 ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:532:17
+  --> tests/ui/use_self.rs:542:17
    |
 LL |                 Foo::Baz => unimplemented!(),
    |                 ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:538:20
+  --> tests/ui/use_self.rs:548:20
    |
 LL |             if let Foo::Bar = self {
    |                    ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:562:17
+  --> tests/ui/use_self.rs:572:17
    |
 LL |                 Something::Num(n) => *n,
    |                 ^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:563:17
+  --> tests/ui/use_self.rs:573:17
    |
 LL |                 Something::TupleNums(n, _m) => *n,
    |                 ^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:564:17
+  --> tests/ui/use_self.rs:574:17
    |
 LL |                 Something::StructNums { one, two: _ } => *one,
    |                 ^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:570:17
+  --> tests/ui/use_self.rs:580:17
    |
 LL |                 crate::issue8845::Something::Num(n) => *n,
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:571:17
+  --> tests/ui/use_self.rs:581:17
    |
 LL |                 crate::issue8845::Something::TupleNums(n, _m) => *n,
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:572:17
+  --> tests/ui/use_self.rs:582:17
    |
 LL |                 crate::issue8845::Something::StructNums { one, two: _ } => *one,
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:588:17
+  --> tests/ui/use_self.rs:598:17
    |
 LL |             let Foo(x) = self;
    |                 ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:593:17
+  --> tests/ui/use_self.rs:603:17
    |
 LL |             let crate::issue8845::Foo(x) = self;
    |                 ^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:600:17
+  --> tests/ui/use_self.rs:610:17
    |
 LL |             let Bar { x, .. } = self;
    |                 ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:605:17
+  --> tests/ui/use_self.rs:615:17
    |
 LL |             let crate::issue8845::Bar { x, .. } = self;
    |                 ^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> tests/ui/use_self.rs:644:17
+  --> tests/ui/use_self.rs:654:17
    |
 LL |                 E::A => {},
    |                 ^ help: use the applicable keyword: `Self`
 
-error: aborting due to 42 previous errors
+error: aborting due to 43 previous errors
 
diff --git a/src/tools/clippy/tests/ui/zero_repeat_side_effects.fixed b/src/tools/clippy/tests/ui/zero_repeat_side_effects.fixed
new file mode 100644
index 00000000000..6f132521926
--- /dev/null
+++ b/src/tools/clippy/tests/ui/zero_repeat_side_effects.fixed
@@ -0,0 +1,60 @@
+#![warn(clippy::zero_repeat_side_effects)]
+#![allow(clippy::unnecessary_operation)]
+#![allow(clippy::useless_vec)]
+#![allow(clippy::needless_late_init)]
+
+fn f() -> i32 {
+    println!("side effect");
+    10
+}
+
+fn main() {
+    const N: usize = 0;
+    const M: usize = 1;
+
+    // should trigger
+
+    // on arrays
+    f(); let a: [i32; 0] = [];
+    f(); let a: [i32; 0] = [];
+    let mut b;
+    f(); b = [] as [i32; 0];
+    f(); b = [] as [i32; 0];
+
+    // on vecs
+    // vecs dont support infering value of consts
+    f(); let c: std::vec::Vec<i32> = vec![];
+    let d;
+    f(); d = vec![] as std::vec::Vec<i32>;
+
+    // for macros
+    println!("side effect"); let e: [(); 0] = [];
+
+    // for nested calls
+    { f() }; let g: [i32; 0] = [];
+
+    // as function param
+    drop({ f(); vec![] as std::vec::Vec<i32> });
+
+    // when singled out/not part of assignment/local
+    { f(); vec![] as std::vec::Vec<i32> };
+    { f(); [] as [i32; 0] };
+    { f(); [] as [i32; 0] };
+
+    // should not trigger
+
+    // on arrays with > 0 repeat
+    let a = [f(); 1];
+    let a = [f(); M];
+    let mut b;
+    b = [f(); 1];
+    b = [f(); M];
+
+    // on vecs with > 0 repeat
+    let c = vec![f(); 1];
+    let d;
+    d = vec![f(); 1];
+
+    // as function param
+    drop(vec![f(); 1]);
+}
diff --git a/src/tools/clippy/tests/ui/zero_repeat_side_effects.rs b/src/tools/clippy/tests/ui/zero_repeat_side_effects.rs
new file mode 100644
index 00000000000..9d9c367375a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/zero_repeat_side_effects.rs
@@ -0,0 +1,60 @@
+#![warn(clippy::zero_repeat_side_effects)]
+#![allow(clippy::unnecessary_operation)]
+#![allow(clippy::useless_vec)]
+#![allow(clippy::needless_late_init)]
+
+fn f() -> i32 {
+    println!("side effect");
+    10
+}
+
+fn main() {
+    const N: usize = 0;
+    const M: usize = 1;
+
+    // should trigger
+
+    // on arrays
+    let a = [f(); 0];
+    let a = [f(); N];
+    let mut b;
+    b = [f(); 0];
+    b = [f(); N];
+
+    // on vecs
+    // vecs dont support infering value of consts
+    let c = vec![f(); 0];
+    let d;
+    d = vec![f(); 0];
+
+    // for macros
+    let e = [println!("side effect"); 0];
+
+    // for nested calls
+    let g = [{ f() }; 0];
+
+    // as function param
+    drop(vec![f(); 0]);
+
+    // when singled out/not part of assignment/local
+    vec![f(); 0];
+    [f(); 0];
+    [f(); N];
+
+    // should not trigger
+
+    // on arrays with > 0 repeat
+    let a = [f(); 1];
+    let a = [f(); M];
+    let mut b;
+    b = [f(); 1];
+    b = [f(); M];
+
+    // on vecs with > 0 repeat
+    let c = vec![f(); 1];
+    let d;
+    d = vec![f(); 1];
+
+    // as function param
+    drop(vec![f(); 1]);
+}
diff --git a/src/tools/clippy/tests/ui/zero_repeat_side_effects.stderr b/src/tools/clippy/tests/ui/zero_repeat_side_effects.stderr
new file mode 100644
index 00000000000..afdc6054253
--- /dev/null
+++ b/src/tools/clippy/tests/ui/zero_repeat_side_effects.stderr
@@ -0,0 +1,77 @@
+error: function or method calls as the initial value in zero-sized array initializers may cause side effects
+  --> tests/ui/zero_repeat_side_effects.rs:18:5
+   |
+LL |     let a = [f(); 0];
+   |     ^^^^^^^^^^^^^^^^^ help: consider using: `f(); let a: [i32; 0] = [];`
+   |
+   = note: `-D clippy::zero-repeat-side-effects` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::zero_repeat_side_effects)]`
+
+error: function or method calls as the initial value in zero-sized array initializers may cause side effects
+  --> tests/ui/zero_repeat_side_effects.rs:19:5
+   |
+LL |     let a = [f(); N];
+   |     ^^^^^^^^^^^^^^^^^ help: consider using: `f(); let a: [i32; 0] = [];`
+
+error: function or method calls as the initial value in zero-sized array initializers may cause side effects
+  --> tests/ui/zero_repeat_side_effects.rs:21:5
+   |
+LL |     b = [f(); 0];
+   |     ^^^^^^^^^^^^ help: consider using: `f(); b = [] as [i32; 0]`
+
+error: function or method calls as the initial value in zero-sized array initializers may cause side effects
+  --> tests/ui/zero_repeat_side_effects.rs:22:5
+   |
+LL |     b = [f(); N];
+   |     ^^^^^^^^^^^^ help: consider using: `f(); b = [] as [i32; 0]`
+
+error: function or method calls as the initial value in zero-sized array initializers may cause side effects
+  --> tests/ui/zero_repeat_side_effects.rs:26:5
+   |
+LL |     let c = vec![f(); 0];
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f(); let c: std::vec::Vec<i32> = vec![];`
+
+error: function or method calls as the initial value in zero-sized array initializers may cause side effects
+  --> tests/ui/zero_repeat_side_effects.rs:28:5
+   |
+LL |     d = vec![f(); 0];
+   |     ^^^^^^^^^^^^^^^^ help: consider using: `f(); d = vec![] as std::vec::Vec<i32>`
+
+error: function or method calls as the initial value in zero-sized array initializers may cause side effects
+  --> tests/ui/zero_repeat_side_effects.rs:31:5
+   |
+LL |     let e = [println!("side effect"); 0];
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `println!("side effect"); let e: [(); 0] = [];`
+
+error: function or method calls as the initial value in zero-sized array initializers may cause side effects
+  --> tests/ui/zero_repeat_side_effects.rs:34:5
+   |
+LL |     let g = [{ f() }; 0];
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `{ f() }; let g: [i32; 0] = [];`
+
+error: function or method calls as the initial value in zero-sized array initializers may cause side effects
+  --> tests/ui/zero_repeat_side_effects.rs:37:10
+   |
+LL |     drop(vec![f(); 0]);
+   |          ^^^^^^^^^^^^ help: consider using: `{ f(); vec![] as std::vec::Vec<i32> }`
+
+error: function or method calls as the initial value in zero-sized array initializers may cause side effects
+  --> tests/ui/zero_repeat_side_effects.rs:40:5
+   |
+LL |     vec![f(); 0];
+   |     ^^^^^^^^^^^^ help: consider using: `{ f(); vec![] as std::vec::Vec<i32> }`
+
+error: function or method calls as the initial value in zero-sized array initializers may cause side effects
+  --> tests/ui/zero_repeat_side_effects.rs:41:5
+   |
+LL |     [f(); 0];
+   |     ^^^^^^^^ help: consider using: `{ f(); [] as [i32; 0] }`
+
+error: function or method calls as the initial value in zero-sized array initializers may cause side effects
+  --> tests/ui/zero_repeat_side_effects.rs:42:5
+   |
+LL |     [f(); N];
+   |     ^^^^^^^^ help: consider using: `{ f(); [] as [i32; 0] }`
+
+error: aborting due to 12 previous errors
+
diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml
index 1a81394af10..d455d967e30 100644
--- a/src/tools/clippy/triagebot.toml
+++ b/src/tools/clippy/triagebot.toml
@@ -19,7 +19,7 @@ new_pr = true
 
 [assign]
 contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md"
-users_on_vacation = ["xFrednet"]
+users_on_vacation = []
 
 [assign.owners]
 "/.github" = ["@flip1995"]
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 0c590b0fda6..bd2f65925bb 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -198,6 +198,11 @@ pub fn compute_stamp_hash(config: &Config) -> String {
     format!("{:x}", hash.finish())
 }
 
+fn remove_and_create_dir_all(path: &Path) {
+    let _ = fs::remove_dir_all(path);
+    fs::create_dir_all(path).unwrap();
+}
+
 #[derive(Copy, Clone)]
 struct TestCx<'test> {
     config: &'test Config,
@@ -998,8 +1003,7 @@ impl<'test> TestCx<'test> {
         let mut rustc = Command::new(&self.config.rustc_path);
 
         let out_dir = self.output_base_name().with_extension("pretty-out");
-        let _ = fs::remove_dir_all(&out_dir);
-        create_dir_all(&out_dir).unwrap();
+        remove_and_create_dir_all(&out_dir);
 
         let target = if self.props.force_host { &*self.config.host } else { &*self.config.target };
 
@@ -2094,14 +2098,12 @@ impl<'test> TestCx<'test> {
         let aux_dir = self.aux_output_dir_name();
 
         if !self.props.aux_builds.is_empty() {
-            let _ = fs::remove_dir_all(&aux_dir);
-            create_dir_all(&aux_dir).unwrap();
+            remove_and_create_dir_all(&aux_dir);
         }
 
         if !self.props.aux_bins.is_empty() {
             let aux_bin_dir = self.aux_bin_output_dir_name();
-            let _ = fs::remove_dir_all(&aux_bin_dir);
-            create_dir_all(&aux_bin_dir).unwrap();
+            remove_and_create_dir_all(&aux_bin_dir);
         }
 
         aux_dir
@@ -2469,8 +2471,7 @@ impl<'test> TestCx<'test> {
                 }
 
                 let mir_dump_dir = self.get_mir_dump_dir();
-                let _ = fs::remove_dir_all(&mir_dump_dir);
-                create_dir_all(mir_dump_dir.as_path()).unwrap();
+                remove_and_create_dir_all(&mir_dump_dir);
                 let mut dir_opt = "-Zdump-mir-dir=".to_string();
                 dir_opt.push_str(mir_dump_dir.to_str().unwrap());
                 debug!("dir_opt: {:?}", dir_opt);
@@ -2951,8 +2952,7 @@ impl<'test> TestCx<'test> {
         assert!(self.revision.is_none(), "revisions not relevant here");
 
         let out_dir = self.output_base_dir();
-        let _ = fs::remove_dir_all(&out_dir);
-        create_dir_all(&out_dir).unwrap();
+        remove_and_create_dir_all(&out_dir);
 
         let proc_res = self.document(&out_dir);
         if !proc_res.status.success() {
@@ -2986,9 +2986,7 @@ impl<'test> TestCx<'test> {
         let suffix =
             self.safe_revision().map_or("nightly".into(), |path| path.to_owned() + "-nightly");
         let compare_dir = output_base_dir(self.config, self.testpaths, Some(&suffix));
-        // Don't give an error if the directory didn't already exist
-        let _ = fs::remove_dir_all(&compare_dir);
-        create_dir_all(&compare_dir).unwrap();
+        remove_and_create_dir_all(&compare_dir);
 
         // We need to create a new struct for the lifetimes on `config` to work.
         let new_rustdoc = TestCx {
@@ -3137,8 +3135,7 @@ impl<'test> TestCx<'test> {
         assert!(self.revision.is_none(), "revisions not relevant here");
 
         let out_dir = self.output_base_dir();
-        let _ = fs::remove_dir_all(&out_dir);
-        create_dir_all(&out_dir).unwrap();
+        remove_and_create_dir_all(&out_dir);
 
         let proc_res = self.document(&out_dir);
         if !proc_res.status.success() {
diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml
index c70005c2c58..1097fc6db72 100644
--- a/src/tools/miri/.github/workflows/ci.yml
+++ b/src/tools/miri/.github/workflows/ci.yml
@@ -206,7 +206,7 @@ jobs:
         run: |
           PR=$(gh pr create -B master --title 'Automatic Rustup' --body '')
           ~/.local/bin/zulip-send --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com \
-            --stream miri --subject "Cron Job Failure (miri, $(date -u +%Y-%m))" \
+            --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."
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/src/tools/miri/bench-cargo-miri/invalidate/Cargo.lock b/src/tools/miri/bench-cargo-miri/range-iteration/Cargo.lock
index 7bf23225ea5..2a5f8f32254 100644
--- a/src/tools/miri/bench-cargo-miri/invalidate/Cargo.lock
+++ b/src/tools/miri/bench-cargo-miri/range-iteration/Cargo.lock
@@ -3,5 +3,5 @@
 version = 3
 
 [[package]]
-name = "invalidate"
+name = "range-iteration"
 version = "0.1.0"
diff --git a/src/tools/miri/bench-cargo-miri/invalidate/Cargo.toml b/src/tools/miri/bench-cargo-miri/range-iteration/Cargo.toml
index 14cf0882f0b..3f0146f6259 100644
--- a/src/tools/miri/bench-cargo-miri/invalidate/Cargo.toml
+++ b/src/tools/miri/bench-cargo-miri/range-iteration/Cargo.toml
@@ -1,5 +1,5 @@
 [package]
-name = "invalidate"
+name = "range-iteration"
 version = "0.1.0"
 edition = "2021"
 
diff --git a/src/tools/miri/bench-cargo-miri/invalidate/src/main.rs b/src/tools/miri/bench-cargo-miri/range-iteration/src/main.rs
index fa8deb851c3..1ef35ee6b3c 100644
--- a/src/tools/miri/bench-cargo-miri/invalidate/src/main.rs
+++ b/src/tools/miri/bench-cargo-miri/range-iteration/src/main.rs
@@ -1,4 +1,5 @@
+//! This generates a lot of work for the AllocId part of the GC.
 fn main() {
     // The end of the range is just chosen to make the benchmark run for a few seconds.
-    for _ in 0..200_000 {}
+    for _ in 0..50_000 {}
 }
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index e32968d8178..9b89f016a77 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-ee03c286cfdca26fa5b2a4ee40957625d2c826ff
+c3b05c6e5b5b59613350b8c2875b0add67ed74df
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 6955e649b4d..c12382527e7 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -179,6 +179,26 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls {
             });
         }
     }
+
+    fn after_analysis<'tcx>(
+        &mut self,
+        _: &rustc_interface::interface::Compiler,
+        queries: &'tcx rustc_interface::Queries<'tcx>,
+    ) -> Compilation {
+        queries.global_ctxt().unwrap().enter(|tcx| {
+            if self.target_crate {
+                // cargo-miri has patched the compiler flags to make these into check-only builds,
+                // but we are still emulating regular rustc builds, which would perform post-mono
+                // const-eval during collection. So let's also do that here, even if we might be
+                // running with `--emit=metadata`. In particular this is needed to make
+                // `compile_fail` doc tests trigger post-mono errors.
+                // In general `collect_and_partition_mono_items` is not safe to call in check-only
+                // builds, but we are setting `-Zalways-encode-mir` which avoids those issues.
+                let _ = tcx.collect_and_partition_mono_items(());
+            }
+        });
+        Compilation::Continue
+    }
 }
 
 fn show_error(msg: &impl std::fmt::Display) -> ! {
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
index 7a6a85a2f79..96ff298402d 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
@@ -18,6 +18,7 @@ use crate::borrow_tracker::{
     stacked_borrows::diagnostics::{AllocHistory, DiagnosticCx, DiagnosticCxBuilder},
     GlobalStateInner, ProtectorKind,
 };
+use crate::concurrency::data_race::{NaReadType, NaWriteType};
 use crate::*;
 
 use diagnostics::{RetagCause, RetagInfo};
@@ -90,7 +91,7 @@ impl NewPermission {
                     }
                 }
             }
-            ty::RawPtr(ty::TypeAndMut { mutbl: Mutability::Mut, .. }) => {
+            ty::RawPtr(_, Mutability::Mut) => {
                 assert!(protector.is_none()); // RetagKind can't be both FnEntry and Raw.
                 // Mutable raw pointer. No access, not protected.
                 NewPermission::Uniform {
@@ -114,7 +115,7 @@ impl NewPermission {
                     // This fixes https://github.com/rust-lang/rust/issues/55005.
                 }
             }
-            ty::RawPtr(ty::TypeAndMut { mutbl: Mutability::Not, .. }) => {
+            ty::RawPtr(_, Mutability::Not) => {
                 assert!(protector.is_none()); // RetagKind can't be both FnEntry and Raw.
                 // `*const T`, when freshly created, are read-only in the frozen part.
                 NewPermission::FreezeSensitive {
@@ -751,7 +752,13 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
                     assert_eq!(access, AccessKind::Write);
                     // Make sure the data race model also knows about this.
                     if let Some(data_race) = alloc_extra.data_race.as_mut() {
-                        data_race.write(alloc_id, range, machine)?;
+                        data_race.write(
+                            alloc_id,
+                            range,
+                            NaWriteType::Retag,
+                            Some(place.layout.ty),
+                            machine,
+                        )?;
                     }
                 }
             }
@@ -794,7 +801,13 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
                         assert_eq!(access, AccessKind::Read);
                         // Make sure the data race model also knows about this.
                         if let Some(data_race) = alloc_extra.data_race.as_ref() {
-                            data_race.read(alloc_id, range, &this.machine)?;
+                            data_race.read(
+                                alloc_id,
+                                range,
+                                NaReadType::Retag,
+                                Some(place.layout.ty),
+                                &this.machine,
+                            )?;
                         }
                     }
                     Ok(())
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
index 80bdcbb7559..a3d49756e4c 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
@@ -9,8 +9,11 @@ use rustc_middle::{
 use rustc_span::def_id::DefId;
 use rustc_target::abi::{Abi, Size};
 
-use crate::borrow_tracker::{GlobalState, GlobalStateInner, ProtectorKind};
 use crate::*;
+use crate::{
+    borrow_tracker::{GlobalState, GlobalStateInner, ProtectorKind},
+    concurrency::data_race::NaReadType,
+};
 
 pub mod diagnostics;
 mod perms;
@@ -312,7 +315,13 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
         // Also inform the data race model (but only if any bytes are actually affected).
         if range.size.bytes() > 0 {
             if let Some(data_race) = alloc_extra.data_race.as_ref() {
-                data_race.read(alloc_id, range, &this.machine)?;
+                data_race.read(
+                    alloc_id,
+                    range,
+                    NaReadType::Retag,
+                    Some(place.layout.ty),
+                    &this.machine,
+                )?;
             }
         }
 
@@ -475,7 +484,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                             NewPermission::from_ref_ty(pointee, mutability, self.kind, self.ecx);
                         self.retag_ptr_inplace(place, new_perm)?;
                     }
-                    ty::RawPtr(_) => {
+                    ty::RawPtr(_, _) => {
                         // We definitely do *not* want to recurse into raw pointers -- wide raw
                         // pointers have fields, and for dyn Trait pointees those can have reference
                         // type!
diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs
index 127d97bd5af..d51160b2831 100644
--- a/src/tools/miri/src/concurrency/data_race.rs
+++ b/src/tools/miri/src/concurrency/data_race.rs
@@ -49,7 +49,7 @@ use std::{
 use rustc_ast::Mutability;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_index::{Idx, IndexVec};
-use rustc_middle::mir;
+use rustc_middle::{mir, ty::Ty};
 use rustc_span::Span;
 use rustc_target::abi::{Align, HasDataLayout, Size};
 
@@ -200,18 +200,38 @@ enum AtomicAccessType {
     Rmw,
 }
 
-/// Type of write operation: allocating memory
-/// non-atomic writes and deallocating memory
-/// are all treated as writes for the purpose
-/// of the data-race detector.
+/// Type of a non-atomic read operation.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
-enum NaWriteType {
+pub enum NaReadType {
+    /// Standard unsynchronized write.
+    Read,
+
+    // An implicit read generated by a retag.
+    Retag,
+}
+
+impl NaReadType {
+    fn description(self) -> &'static str {
+        match self {
+            NaReadType::Read => "non-atomic read",
+            NaReadType::Retag => "retag read",
+        }
+    }
+}
+
+/// Type of a non-atomic write operation: allocating memory, non-atomic writes, and
+/// deallocating memory are all treated as writes for the purpose of the data-race detector.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum NaWriteType {
     /// Allocate memory.
     Allocate,
 
     /// Standard unsynchronized write.
     Write,
 
+    // An implicit write generated by a retag.
+    Retag,
+
     /// Deallocate memory.
     /// Note that when memory is deallocated first, later non-atomic accesses
     /// will be reported as use-after-free, not as data races.
@@ -224,6 +244,7 @@ impl NaWriteType {
         match self {
             NaWriteType::Allocate => "creating a new allocation",
             NaWriteType::Write => "non-atomic write",
+            NaWriteType::Retag => "retag write",
             NaWriteType::Deallocate => "deallocation",
         }
     }
@@ -231,7 +252,7 @@ impl NaWriteType {
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 enum AccessType {
-    NaRead,
+    NaRead(NaReadType),
     NaWrite(NaWriteType),
     AtomicLoad,
     AtomicStore,
@@ -239,29 +260,48 @@ enum AccessType {
 }
 
 impl AccessType {
-    fn description(self) -> &'static str {
-        match self {
-            AccessType::NaRead => "non-atomic read",
+    fn description(self, ty: Option<Ty<'_>>, size: Option<Size>) -> String {
+        let mut msg = String::new();
+
+        if let Some(size) = size {
+            msg.push_str(&format!("{}-byte {}", size.bytes(), msg))
+        }
+
+        msg.push_str(match self {
+            AccessType::NaRead(w) => w.description(),
             AccessType::NaWrite(w) => w.description(),
             AccessType::AtomicLoad => "atomic load",
             AccessType::AtomicStore => "atomic store",
             AccessType::AtomicRmw => "atomic read-modify-write",
+        });
+
+        if let Some(ty) = ty {
+            msg.push_str(&format!(" of type `{}`", ty));
         }
+
+        msg
     }
 
     fn is_atomic(self) -> bool {
         match self {
             AccessType::AtomicLoad | AccessType::AtomicStore | AccessType::AtomicRmw => true,
-            AccessType::NaRead | AccessType::NaWrite(_) => false,
+            AccessType::NaRead(_) | AccessType::NaWrite(_) => false,
         }
     }
 
     fn is_read(self) -> bool {
         match self {
-            AccessType::AtomicLoad | AccessType::NaRead => true,
+            AccessType::AtomicLoad | AccessType::NaRead(_) => true,
             AccessType::NaWrite(_) | AccessType::AtomicStore | AccessType::AtomicRmw => false,
         }
     }
+
+    fn is_retag(self) -> bool {
+        matches!(
+            self,
+            AccessType::NaRead(NaReadType::Retag) | AccessType::NaWrite(NaWriteType::Retag)
+        )
+    }
 }
 
 /// Memory Cell vector clock metadata
@@ -502,12 +542,14 @@ impl MemoryCellClocks {
         &mut self,
         thread_clocks: &mut ThreadClockSet,
         index: VectorIdx,
+        read_type: NaReadType,
         current_span: Span,
     ) -> Result<(), DataRace> {
         trace!("Unsynchronized read with vectors: {:#?} :: {:#?}", self, thread_clocks);
         if !current_span.is_dummy() {
             thread_clocks.clock[index].span = current_span;
         }
+        thread_clocks.clock[index].set_read_type(read_type);
         if self.write_was_before(&thread_clocks.clock) {
             let race_free = if let Some(atomic) = self.atomic() {
                 // We must be ordered-after all atomic accesses, reads and writes.
@@ -875,7 +917,8 @@ impl VClockAlloc {
     /// This finds the two racing threads and the type
     /// of data-race that occurred. This will also
     /// return info about the memory location the data-race
-    /// occurred in.
+    /// occurred in. The `ty` parameter is used for diagnostics, letting
+    /// the user know which type was involved in the access.
     #[cold]
     #[inline(never)]
     fn report_data_race<'tcx>(
@@ -885,6 +928,7 @@ impl VClockAlloc {
         access: AccessType,
         access_size: Size,
         ptr_dbg: Pointer<AllocId>,
+        ty: Option<Ty<'_>>,
     ) -> InterpResult<'tcx> {
         let (current_index, current_clocks) = global.current_thread_state(thread_mgr);
         let mut other_size = None; // if `Some`, this was a size-mismatch race
@@ -908,7 +952,7 @@ impl VClockAlloc {
                 write_clock = mem_clocks.write();
                 (AccessType::NaWrite(mem_clocks.write_type), mem_clocks.write.0, &write_clock)
             } else if let Some(idx) = Self::find_gt_index(&mem_clocks.read, &current_clocks.clock) {
-                (AccessType::NaRead, idx, &mem_clocks.read)
+                (AccessType::NaRead(mem_clocks.read[idx].read_type()), idx, &mem_clocks.read)
             // Finally, mixed-size races.
             } else if access.is_atomic() && let Some(atomic) = mem_clocks.atomic() && atomic.size != access_size {
                 // This is only a race if we are not synchronized with all atomic accesses, so find
@@ -950,37 +994,33 @@ impl VClockAlloc {
         Err(err_machine_stop!(TerminationInfo::DataRace {
             involves_non_atomic,
             extra,
+            retag_explain: access.is_retag() || other_access.is_retag(),
             ptr: ptr_dbg,
             op1: RacingOp {
-                action: if let Some(other_size) = other_size {
-                    format!("{}-byte {}", other_size.bytes(), other_access.description())
-                } else {
-                    other_access.description().to_owned()
-                },
+                action: other_access.description(None, other_size),
                 thread_info: other_thread_info,
                 span: other_clock.as_slice()[other_thread.index()].span_data(),
             },
             op2: RacingOp {
-                action: if other_size.is_some() {
-                    format!("{}-byte {}", access_size.bytes(), access.description())
-                } else {
-                    access.description().to_owned()
-                },
+                action: access.description(ty, other_size.map(|_| access_size)),
                 thread_info: current_thread_info,
                 span: current_clocks.clock.as_slice()[current_index.index()].span_data(),
             },
         }))?
     }
 
-    /// Detect data-races for an unsynchronized read operation, will not perform
+    /// Detect data-races for an unsynchronized read operation. It will not perform
     /// data-race detection if `race_detecting()` is false, either due to no threads
     /// being created or if it is temporarily disabled during a racy read or write
     /// operation for which data-race detection is handled separately, for example
-    /// atomic read operations.
+    /// atomic read operations. The `ty` parameter is used for diagnostics, letting
+    /// the user know which type was read.
     pub fn read<'tcx>(
         &self,
         alloc_id: AllocId,
         access_range: AllocRange,
+        read_type: NaReadType,
+        ty: Option<Ty<'_>>,
         machine: &MiriMachine<'_, '_>,
     ) -> InterpResult<'tcx> {
         let current_span = machine.current_span();
@@ -992,7 +1032,7 @@ impl VClockAlloc {
                 alloc_ranges.iter_mut(access_range.start, access_range.size)
             {
                 if let Err(DataRace) =
-                    mem_clocks.read_race_detect(&mut thread_clocks, index, current_span)
+                    mem_clocks.read_race_detect(&mut thread_clocks, index, read_type, current_span)
                 {
                     drop(thread_clocks);
                     // Report data-race.
@@ -1000,9 +1040,10 @@ impl VClockAlloc {
                         global,
                         &machine.threads,
                         mem_clocks,
-                        AccessType::NaRead,
+                        AccessType::NaRead(read_type),
                         access_range.size,
                         Pointer::new(alloc_id, Size::from_bytes(mem_clocks_range.start)),
+                        ty,
                     );
                 }
             }
@@ -1012,12 +1053,17 @@ impl VClockAlloc {
         }
     }
 
-    // Shared code for detecting data-races on unique access to a section of memory
-    fn unique_access<'tcx>(
+    /// Detect data-races for an unsynchronized write operation. It will not perform
+    /// data-race detection if `race_detecting()` is false, either due to no threads
+    /// being created or if it is temporarily disabled during a racy read or write
+    /// operation. The `ty` parameter is used for diagnostics, letting
+    /// the user know which type was written.
+    pub fn write<'tcx>(
         &mut self,
         alloc_id: AllocId,
         access_range: AllocRange,
         write_type: NaWriteType,
+        ty: Option<Ty<'_>>,
         machine: &mut MiriMachine<'_, '_>,
     ) -> InterpResult<'tcx> {
         let current_span = machine.current_span();
@@ -1042,6 +1088,7 @@ impl VClockAlloc {
                         AccessType::NaWrite(write_type),
                         access_range.size,
                         Pointer::new(alloc_id, Size::from_bytes(mem_clocks_range.start)),
+                        ty,
                     );
                 }
             }
@@ -1050,37 +1097,6 @@ impl VClockAlloc {
             Ok(())
         }
     }
-
-    /// Detect data-races for an unsynchronized write operation, will not perform
-    /// data-race threads if `race_detecting()` is false, either due to no threads
-    /// being created or if it is temporarily disabled during a racy read or write
-    /// operation
-    pub fn write<'tcx>(
-        &mut self,
-        alloc_id: AllocId,
-        range: AllocRange,
-        machine: &mut MiriMachine<'_, '_>,
-    ) -> InterpResult<'tcx> {
-        self.unique_access(alloc_id, range, NaWriteType::Write, machine)
-    }
-
-    /// Detect data-races for an unsynchronized deallocate operation, will not perform
-    /// data-race threads if `race_detecting()` is false, either due to no threads
-    /// being created or if it is temporarily disabled during a racy read or write
-    /// operation
-    pub fn deallocate<'tcx>(
-        &mut self,
-        alloc_id: AllocId,
-        size: Size,
-        machine: &mut MiriMachine<'_, '_>,
-    ) -> InterpResult<'tcx> {
-        self.unique_access(
-            alloc_id,
-            alloc_range(Size::ZERO, size),
-            NaWriteType::Deallocate,
-            machine,
-        )
-    }
 }
 
 impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for MiriInterpCx<'mir, 'tcx> {}
@@ -1279,7 +1295,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
                 let alloc_meta = this.get_alloc_extra(alloc_id)?.data_race.as_ref().unwrap();
                 trace!(
                     "Atomic op({}) with ordering {:?} on {:?} (size={})",
-                    access.description(),
+                    access.description(None, None),
                     &atomic,
                     place.ptr(),
                     size.bytes()
@@ -1307,6 +1323,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
                                         alloc_id,
                                         Size::from_bytes(mem_clocks_range.start),
                                     ),
+                                    None,
                                 )
                                 .map(|_| true);
                             }
diff --git a/src/tools/miri/src/concurrency/vector_clock.rs b/src/tools/miri/src/concurrency/vector_clock.rs
index fa93c9e00b1..fe719943dcb 100644
--- a/src/tools/miri/src/concurrency/vector_clock.rs
+++ b/src/tools/miri/src/concurrency/vector_clock.rs
@@ -4,9 +4,11 @@ use smallvec::SmallVec;
 use std::{
     cmp::Ordering,
     fmt::Debug,
-    ops::{Index, IndexMut},
+    ops::{Index, IndexMut, Shr},
 };
 
+use super::data_race::NaReadType;
+
 /// A vector clock index, this is associated with a thread id
 /// but in some cases one vector index may be shared with
 /// multiple thread ids if it's safe to do so.
@@ -50,13 +52,51 @@ const SMALL_VECTOR: usize = 4;
 /// so that diagnostics can report what code was responsible for an operation.
 #[derive(Clone, Copy, Debug)]
 pub struct VTimestamp {
-    time: u32,
+    /// The lowest bit indicates read type, the rest is the time.
+    /// `1` indicates a retag read, `0` a regular read.
+    time_and_read_type: u32,
     pub span: Span,
 }
 
 impl VTimestamp {
-    pub const ZERO: VTimestamp = VTimestamp { time: 0, span: DUMMY_SP };
+    pub const ZERO: VTimestamp = VTimestamp::new(0, NaReadType::Read, DUMMY_SP);
+
+    #[inline]
+    const fn encode_time_and_read_type(time: u32, read_type: NaReadType) -> u32 {
+        let read_type_bit = match read_type {
+            NaReadType::Read => 0,
+            NaReadType::Retag => 1,
+        };
+        // Put the `read_type` in the lowest bit and `time` in the rest
+        read_type_bit | time.checked_mul(2).expect("Vector clock overflow")
+    }
+
+    #[inline]
+    const fn new(time: u32, read_type: NaReadType, span: Span) -> Self {
+        Self { time_and_read_type: Self::encode_time_and_read_type(time, read_type), span }
+    }
+
+    #[inline]
+    fn time(&self) -> u32 {
+        self.time_and_read_type.shr(1)
+    }
 
+    #[inline]
+    fn set_time(&mut self, time: u32) {
+        self.time_and_read_type = Self::encode_time_and_read_type(time, self.read_type());
+    }
+
+    #[inline]
+    pub fn read_type(&self) -> NaReadType {
+        if self.time_and_read_type & 1 == 0 { NaReadType::Read } else { NaReadType::Retag }
+    }
+
+    #[inline]
+    pub fn set_read_type(&mut self, read_type: NaReadType) {
+        self.time_and_read_type = Self::encode_time_and_read_type(self.time(), read_type);
+    }
+
+    #[inline]
     pub fn span_data(&self) -> SpanData {
         self.span.data()
     }
@@ -64,7 +104,7 @@ impl VTimestamp {
 
 impl PartialEq for VTimestamp {
     fn eq(&self, other: &Self) -> bool {
-        self.time == other.time
+        self.time() == other.time()
     }
 }
 
@@ -78,7 +118,7 @@ impl PartialOrd for VTimestamp {
 
 impl Ord for VTimestamp {
     fn cmp(&self, other: &Self) -> Ordering {
-        self.time.cmp(&other.time)
+        self.time().cmp(&other.time())
     }
 }
 
@@ -130,7 +170,7 @@ impl VClock {
         let idx = idx.index();
         let mut_slice = self.get_mut_with_min_len(idx + 1);
         let idx_ref = &mut mut_slice[idx];
-        idx_ref.time = idx_ref.time.checked_add(1).expect("Vector clock overflow");
+        idx_ref.set_time(idx_ref.time().checked_add(1).expect("Vector clock overflow"));
         if !current_span.is_dummy() {
             idx_ref.span = current_span;
         }
@@ -379,8 +419,8 @@ impl IndexMut<VectorIdx> for VClock {
 ///  test suite
 #[cfg(test)]
 mod tests {
-
     use super::{VClock, VTimestamp, VectorIdx};
+    use crate::concurrency::data_race::NaReadType;
     use rustc_span::DUMMY_SP;
     use std::cmp::Ordering;
 
@@ -448,7 +488,13 @@ mod tests {
         while let Some(0) = slice.last() {
             slice = &slice[..slice.len() - 1]
         }
-        VClock(slice.iter().copied().map(|time| VTimestamp { time, span: DUMMY_SP }).collect())
+        VClock(
+            slice
+                .iter()
+                .copied()
+                .map(|time| VTimestamp::new(time, NaReadType::Read, DUMMY_SP))
+                .collect(),
+        )
     }
 
     fn assert_order(l: &[u32], r: &[u32], o: Option<Ordering>) {
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index 03428b081c5..99d37065bac 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -46,6 +46,7 @@ pub enum TerminationInfo {
         op1: RacingOp,
         op2: RacingOp,
         extra: Option<&'static str>,
+        retag_explain: bool,
     },
 }
 
@@ -263,12 +264,17 @@ pub fn report_error<'tcx, 'mir>(
                 vec![(Some(*span), format!("the `{link_name}` symbol is defined here"))],
             Int2PtrWithStrictProvenance =>
                 vec![(None, format!("use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead"))],
-            DataRace { op1, extra, .. } => {
+            DataRace { op1, extra, retag_explain, .. } => {
                 let mut helps = vec![(Some(op1.span), format!("and (1) occurred earlier here"))];
                 if let Some(extra) = extra {
                     helps.push((None, format!("{extra}")));
                     helps.push((None, format!("see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model")));
                 }
+                if *retag_explain {
+                    helps.push((None, "retags occur on all (re)borrows and as well as when references are copied or moved".to_owned()));
+                    helps.push((None, "retags permit optimizations that insert speculative reads or writes".to_owned()));
+                    helps.push((None, "therefore from the perspective of data races, a retag has the same implications as a read or write".to_owned()));
+                }
                 helps.push((None, format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior")));
                 helps.push((None, format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information")));
                 helps
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 416d0cda8f1..7821aa9efd4 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -1,5 +1,6 @@
 #![feature(rustc_private)]
 #![feature(cell_update)]
+#![feature(const_option)]
 #![feature(float_gamma)]
 #![feature(generic_nonzero)]
 #![feature(map_try_insert)]
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 3a4ab32e4ab..2137de6a29b 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -12,7 +12,6 @@ use rand::rngs::StdRng;
 use rand::Rng;
 use rand::SeedableRng;
 
-use rustc_ast::ast::Mutability;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 #[allow(unused)]
 use rustc_data_structures::static_assert_size;
@@ -22,7 +21,7 @@ use rustc_middle::{
     ty::{
         self,
         layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout},
-        Instance, Ty, TyCtxt, TypeAndMut,
+        Instance, Ty, TyCtxt,
     },
 };
 use rustc_span::def_id::{CrateNum, DefId};
@@ -36,6 +35,9 @@ use crate::{
     *,
 };
 
+use self::concurrency::data_race::NaReadType;
+use self::concurrency::data_race::NaWriteType;
+
 /// First real-time signal.
 /// `signal(7)` says this must be between 32 and 64 and specifies 34 or 35
 /// as typical values.
@@ -373,10 +375,8 @@ pub struct PrimitiveLayouts<'tcx> {
 impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> {
     fn new(layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result<Self, &'tcx LayoutError<'tcx>> {
         let tcx = layout_cx.tcx;
-        let mut_raw_ptr =
-            Ty::new_ptr(tcx, TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Mut });
-        let const_raw_ptr =
-            Ty::new_ptr(tcx, TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Not });
+        let mut_raw_ptr = Ty::new_mut_ptr(tcx, tcx.types.unit);
+        let const_raw_ptr = Ty::new_imm_ptr(tcx, tcx.types.unit);
         Ok(Self {
             unit: layout_cx.layout_of(Ty::new_unit(tcx))?,
             i8: layout_cx.layout_of(tcx.types.i8)?,
@@ -1241,7 +1241,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
                 .emit_diagnostic(NonHaltingDiagnostic::AccessedAlloc(alloc_id, AccessKind::Read));
         }
         if let Some(data_race) = &alloc_extra.data_race {
-            data_race.read(alloc_id, range, machine)?;
+            data_race.read(alloc_id, range, NaReadType::Read, None, machine)?;
         }
         if let Some(borrow_tracker) = &alloc_extra.borrow_tracker {
             borrow_tracker.before_memory_read(alloc_id, prov_extra, range, machine)?;
@@ -1265,7 +1265,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
                 .emit_diagnostic(NonHaltingDiagnostic::AccessedAlloc(alloc_id, AccessKind::Write));
         }
         if let Some(data_race) = &mut alloc_extra.data_race {
-            data_race.write(alloc_id, range, machine)?;
+            data_race.write(alloc_id, range, NaWriteType::Write, None, machine)?;
         }
         if let Some(borrow_tracker) = &mut alloc_extra.borrow_tracker {
             borrow_tracker.before_memory_write(alloc_id, prov_extra, range, machine)?;
@@ -1289,7 +1289,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
             machine.emit_diagnostic(NonHaltingDiagnostic::FreedAlloc(alloc_id));
         }
         if let Some(data_race) = &mut alloc_extra.data_race {
-            data_race.deallocate(alloc_id, size, machine)?;
+            data_race.write(
+                alloc_id,
+                alloc_range(Size::ZERO, size),
+                NaWriteType::Deallocate,
+                None,
+                machine,
+            )?;
         }
         if let Some(borrow_tracker) = &mut alloc_extra.borrow_tracker {
             borrow_tracker.before_memory_deallocation(alloc_id, prove_extra, size, machine)?;
diff --git a/src/tools/miri/src/shims/intrinsics/simd.rs b/src/tools/miri/src/shims/intrinsics/simd.rs
index c97a052f517..6973c0e9c35 100644
--- a/src/tools/miri/src/shims/intrinsics/simd.rs
+++ b/src/tools/miri/src/shims/intrinsics/simd.rs
@@ -33,6 +33,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             | "round"
             | "trunc"
             | "fsqrt"
+            | "fsin"
+            | "fcos"
+            | "fexp"
+            | "fexp2"
+            | "flog"
+            | "flog2"
+            | "flog10"
             | "ctlz"
             | "cttz"
             | "bswap"
@@ -45,17 +52,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 assert_eq!(dest_len, op_len);
 
                 #[derive(Copy, Clone)]
-                enum Op {
+                enum Op<'a> {
                     MirOp(mir::UnOp),
                     Abs,
-                    Sqrt,
                     Round(rustc_apfloat::Round),
                     Numeric(Symbol),
+                    HostOp(&'a str),
                 }
                 let which = match intrinsic_name {
                     "neg" => Op::MirOp(mir::UnOp::Neg),
                     "fabs" => Op::Abs,
-                    "fsqrt" => Op::Sqrt,
                     "ceil" => Op::Round(rustc_apfloat::Round::TowardPositive),
                     "floor" => Op::Round(rustc_apfloat::Round::TowardNegative),
                     "round" => Op::Round(rustc_apfloat::Round::NearestTiesToAway),
@@ -64,7 +70,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     "cttz" => Op::Numeric(sym::cttz),
                     "bswap" => Op::Numeric(sym::bswap),
                     "bitreverse" => Op::Numeric(sym::bitreverse),
-                    _ => unreachable!(),
+                    _ => Op::HostOp(intrinsic_name),
                 };
 
                 for i in 0..dest_len {
@@ -89,7 +95,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                                 FloatTy::F128 => unimplemented!("f16_f128"),
                             }
                         }
-                        Op::Sqrt => {
+                        Op::HostOp(host_op) => {
                             let ty::Float(float_ty) = op.layout.ty.kind() else {
                                 span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name)
                             };
@@ -98,13 +104,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                                 FloatTy::F16 => unimplemented!("f16_f128"),
                                 FloatTy::F32 => {
                                     let f = op.to_scalar().to_f32()?;
-                                    let res = f.to_host().sqrt().to_soft();
+                                    let f_host = f.to_host();
+                                    let res = match host_op {
+                                        "fsqrt" => f_host.sqrt(),
+                                        "fsin" => f_host.sin(),
+                                        "fcos" => f_host.cos(),
+                                        "fexp" => f_host.exp(),
+                                        "fexp2" => f_host.exp2(),
+                                        "flog" => f_host.ln(),
+                                        "flog2" => f_host.log2(),
+                                        "flog10" => f_host.log10(),
+                                        _ => bug!(),
+                                    };
+                                    let res = res.to_soft();
                                     let res = this.adjust_nan(res, &[f]);
                                     Scalar::from(res)
                                 }
                                 FloatTy::F64 => {
                                     let f = op.to_scalar().to_f64()?;
-                                    let res = f.to_host().sqrt().to_soft();
+                                    let f_host = f.to_host();
+                                    let res = match host_op {
+                                        "fsqrt" => f_host.sqrt(),
+                                        "fsin" => f_host.sin(),
+                                        "fcos" => f_host.cos(),
+                                        "fexp" => f_host.exp(),
+                                        "fexp2" => f_host.exp2(),
+                                        "flog" => f_host.ln(),
+                                        "flog2" => f_host.log2(),
+                                        "flog10" => f_host.log10(),
+                                        _ => bug!(),
+                                    };
+                                    let res = res.to_soft();
                                     let res = this.adjust_nan(res, &[f]);
                                     Scalar::from(res)
                                 }
@@ -427,7 +457,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 let bitmask_len = u32::try_from(bitmask_len).unwrap();
 
                 // To read the mask, we transmute it to an integer.
-                // That does the right thing wrt endianess.
+                // That does the right thing wrt endianness.
                 let mask_ty = this.machine.layouts.uint(mask.layout.size).unwrap();
                 let mask = mask.transmute(mask_ty, this)?;
                 let mask: u64 = this.read_scalar(&mask)?.to_bits(mask_ty.size)?.try_into().unwrap();
@@ -479,7 +509,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     }
                 }
                 // We have to change the type of the place to be able to write `res` into it. This
-                // transmutes the integer to an array, which does the right thing wrt endianess.
+                // transmutes the integer to an array, which does the right thing wrt endianness.
                 let dest =
                     dest.transmute(this.machine.layouts.uint(dest.layout.size).unwrap(), this)?;
                 this.write_int(res, &dest)?;
diff --git a/src/tools/miri/src/shims/unix/linux/fd/epoll.rs b/src/tools/miri/src/shims/unix/linux/fd/epoll.rs
index a429caaf8f4..8c5aed6def6 100644
--- a/src/tools/miri/src/shims/unix/linux/fd/epoll.rs
+++ b/src/tools/miri/src/shims/unix/linux/fd/epoll.rs
@@ -21,9 +21,11 @@ pub struct Epoll {
 /// <https://man7.org/linux/man-pages/man2/epoll_ctl.2.html>
 #[derive(Clone, Debug)]
 pub struct EpollEvent {
+    #[allow(dead_code)]
     pub events: u32,
     /// `Scalar<Provenance>` is used to represent the
     /// `epoll_data` type union.
+    #[allow(dead_code)]
     pub data: Scalar<Provenance>,
 }
 
diff --git a/src/tools/miri/src/shims/unix/linux/fd/event.rs b/src/tools/miri/src/shims/unix/linux/fd/event.rs
index 1f17ffb88c8..49408fda3ae 100644
--- a/src/tools/miri/src/shims/unix/linux/fd/event.rs
+++ b/src/tools/miri/src/shims/unix/linux/fd/event.rs
@@ -38,7 +38,7 @@ impl FileDescriptor for Event {
     }
 
     /// A write call adds the 8-byte integer value supplied in
-    /// its buffer (in native endianess) to the counter.  The maximum value that may be
+    /// its buffer (in native endianness) to the counter.  The maximum value that may be
     /// stored in the counter is the largest unsigned 64-bit value
     /// minus 1 (i.e., 0xfffffffffffffffe).  If the addition would
     /// cause the counter's value to exceed the maximum, then the
@@ -57,7 +57,7 @@ impl FileDescriptor for Event {
     ) -> InterpResult<'tcx, io::Result<usize>> {
         let v1 = self.val.get();
         let bytes: [u8; 8] = bytes.try_into().unwrap(); // FIXME fail gracefully when this has the wrong size
-        // Convert from target endianess to host endianess.
+        // Convert from target endianness to host endianness.
         let num = match tcx.sess.target.endian {
             Endian::Little => u64::from_le_bytes(bytes),
             Endian::Big => u64::from_be_bytes(bytes),
diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs
index 7cd397625dc..7b7921219e6 100644
--- a/src/tools/miri/src/shims/x86/mod.rs
+++ b/src/tools/miri/src/shims/x86/mod.rs
@@ -88,6 +88,19 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
                 this.write_immediate(*sub, &this.project_field(dest, 1)?)?;
             }
 
+            // Used to implement the `_mm_pause` function.
+            // The intrinsic is used to hint the processor that the code is in a spin-loop.
+            // It is compiled down to a `pause` instruction. When SSE2 is not available,
+            // the instruction behaves like a no-op, so it is always safe to call the
+            // intrinsic.
+            "sse2.pause" => {
+                let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                // Only exhibit the spin-loop hint behavior when SSE2 is enabled.
+                if this.tcx.sess.unstable_target_features.contains(&Symbol::intern("sse2")) {
+                    this.yield_active_thread();
+                }
+            }
+
             name if name.starts_with("sse.") => {
                 return sse::EvalContextExt::emulate_x86_sse_intrinsic(
                     this, link_name, abi, args, dest,
diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs
index 18ff5d809e3..eb2cc9d37c8 100644
--- a/src/tools/miri/src/shims/x86/sse2.rs
+++ b/src/tools/miri/src/shims/x86/sse2.rs
@@ -580,12 +580,6 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
                     this.copy_op(&this.project_index(&left, i)?, &this.project_index(&dest, i)?)?;
                 }
             }
-            // Used to implement the `_mm_pause` function.
-            // The intrinsic is used to hint the processor that the code is in a spin-loop.
-            "pause" => {
-                let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                this.yield_active_thread();
-            }
             _ => return Ok(EmulateForeignItemResult::NotSupported),
         }
         Ok(EmulateForeignItemResult::NeedsJumping)
diff --git a/src/tools/miri/test-cargo-miri/src/lib.rs b/src/tools/miri/test-cargo-miri/src/lib.rs
index 66c8aa2eac5..e6b8c4ef65b 100644
--- a/src/tools/miri/test-cargo-miri/src/lib.rs
+++ b/src/tools/miri/test-cargo-miri/src/lib.rs
@@ -1,13 +1,31 @@
 /// Doc-test test
+///
 /// ```rust
 /// assert!(cargo_miri_test::make_true());
 /// ```
+///
+/// `no_run` test:
+///
 /// ```rust,no_run
 /// assert!(!cargo_miri_test::make_true());
 /// ```
+///
+/// `compile_fail` test:
+///
 /// ```rust,compile_fail
 /// assert!(cargo_miri_test::make_true() == 5);
 /// ```
+///
+/// Post-monomorphization error in `compile_fail` test:
+///
+/// ```rust,compile_fail
+/// struct Fail<T>(T);
+/// impl<T> Fail<T> {
+///     const C: () = panic!();
+/// }
+///
+/// let _val = Fail::<i32>::C;
+/// ```
 #[no_mangle]
 pub fn make_true() -> bool {
     issue_1567::use_the_dependency();
diff --git a/src/tools/miri/test-cargo-miri/test.default.stdout.ref b/src/tools/miri/test-cargo-miri/test.default.stdout.ref
index 9a17f3d61b6..922d2120bed 100644
--- a/src/tools/miri/test-cargo-miri/test.default.stdout.ref
+++ b/src/tools/miri/test-cargo-miri/test.default.stdout.ref
@@ -10,7 +10,7 @@ running 6 tests
 test result: ok. 5 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out
 
 
-running 4 tests
-....
-test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+running 5 tests
+.....
+test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
diff --git a/src/tools/miri/test-cargo-miri/test.filter.stdout.ref b/src/tools/miri/test-cargo-miri/test.filter.stdout.ref
index c618956656a..5c819dd5323 100644
--- a/src/tools/miri/test-cargo-miri/test.filter.stdout.ref
+++ b/src/tools/miri/test-cargo-miri/test.filter.stdout.ref
@@ -13,5 +13,5 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 5 filtered out
 
 running 0 tests
 
-test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 4 filtered out; finished in $TIME
+test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 5 filtered out; finished in $TIME
 
diff --git a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs
index eb1fe56df07..3edaf10f3dc 100644
--- a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs
+++ b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs
@@ -17,7 +17,7 @@ fn thread_1(p: SendPtr) {
 fn thread_2(p: SendPtr) {
     let p = p.0;
     unsafe {
-        *p = 5; //~ ERROR: /Data race detected between \(1\) non-atomic (read|write) on thread `unnamed-[0-9]+` and \(2\) non-atomic write on thread `unnamed-[0-9]+`/
+        *p = 5; //~ ERROR: /Data race detected between \(1\) retag (read|write) on thread `unnamed-[0-9]+` and \(2\) non-atomic write on thread `unnamed-[0-9]+`/
     }
 }
 
diff --git a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr
index c5b65e6f747..6f4b52fb887 100644
--- a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr
+++ b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.stack.stderr
@@ -1,14 +1,17 @@
-error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here
+error: Undefined Behavior: Data race detected between (1) retag write on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here
   --> $DIR/retag_data_race_write.rs:LL:CC
    |
 LL |         *p = 5;
-   |         ^^^^^^ Data race detected between (1) non-atomic write on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here
+   |         ^^^^^^ Data race detected between (1) retag write on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here
    |
 help: and (1) occurred earlier here
   --> $DIR/retag_data_race_write.rs:LL:CC
    |
 LL |         let _r = &mut *p;
    |                  ^^^^^^^
+   = help: retags occur on all (re)borrows and as well as when references are copied or moved
+   = help: retags permit optimizations that insert speculative reads or writes
+   = help: therefore from the perspective of data races, a retag has the same implications as a read or write
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE (of the first span) on thread `unnamed-ID`:
diff --git a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr
index 62f139f6f08..fa0012f9b26 100644
--- a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr
+++ b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.tree.stderr
@@ -1,14 +1,17 @@
-error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here
+error: Undefined Behavior: Data race detected between (1) retag read on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here
   --> $DIR/retag_data_race_write.rs:LL:CC
    |
 LL |         *p = 5;
-   |         ^^^^^^ Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here
+   |         ^^^^^^ Data race detected between (1) retag read on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here
    |
 help: and (1) occurred earlier here
   --> $DIR/retag_data_race_write.rs:LL:CC
    |
 LL |         let _r = &mut *p;
    |                  ^^^^^^^
+   = help: retags occur on all (re)borrows and as well as when references are copied or moved
+   = help: retags permit optimizations that insert speculative reads or writes
+   = help: therefore from the perspective of data races, a retag has the same implications as a read or write
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE (of the first span) on thread `unnamed-ID`:
diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.rs b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.rs
new file mode 100644
index 00000000000..89fdd2a01eb
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.rs
@@ -0,0 +1,19 @@
+#![feature(core_intrinsics)]
+#![feature(rustc_attrs)]
+
+use std::intrinsics::typed_swap;
+use std::ptr::addr_of_mut;
+
+fn invalid_array() {
+    let mut a = [1_u8; 100];
+    let mut b = [2_u8; 100];
+    unsafe {
+        let a = addr_of_mut!(a).cast::<[bool; 100]>();
+        let b = addr_of_mut!(b).cast::<[bool; 100]>();
+        typed_swap(a, b); //~ERROR: constructing invalid value
+    }
+}
+
+fn main() {
+    invalid_array();
+}
diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr
new file mode 100644
index 00000000000..15f01c1c095
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-array.stderr
@@ -0,0 +1,20 @@
+error: Undefined Behavior: constructing invalid value at [0]: encountered 0x02, but expected a boolean
+  --> $DIR/typed-swap-invalid-array.rs:LL:CC
+   |
+LL |         typed_swap(a, b);
+   |         ^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered 0x02, but expected a boolean
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `invalid_array` at $DIR/typed-swap-invalid-array.rs:LL:CC
+note: inside `main`
+  --> $DIR/typed-swap-invalid-array.rs:LL:CC
+   |
+LL |     invalid_array();
+   |     ^^^^^^^^^^^^^^^
+
+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/intrinsics/typed-swap-invalid-scalar.rs b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.rs
new file mode 100644
index 00000000000..9d014a523f8
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.rs
@@ -0,0 +1,19 @@
+#![feature(core_intrinsics)]
+#![feature(rustc_attrs)]
+
+use std::intrinsics::typed_swap;
+use std::ptr::addr_of_mut;
+
+fn invalid_scalar() {
+    let mut a = 1_u8;
+    let mut b = 2_u8;
+    unsafe {
+        let a = addr_of_mut!(a).cast::<bool>();
+        let b = addr_of_mut!(b).cast::<bool>();
+        typed_swap(a, b); //~ERROR: constructing invalid value
+    }
+}
+
+fn main() {
+    invalid_scalar();
+}
diff --git a/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.stderr b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.stderr
new file mode 100644
index 00000000000..262ca202f9f
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/typed-swap-invalid-scalar.stderr
@@ -0,0 +1,20 @@
+error: Undefined Behavior: constructing invalid value: encountered 0x02, but expected a boolean
+  --> $DIR/typed-swap-invalid-scalar.rs:LL:CC
+   |
+LL |         typed_swap(a, b);
+   |         ^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x02, but expected a boolean
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `invalid_scalar` at $DIR/typed-swap-invalid-scalar.rs:LL:CC
+note: inside `main`
+  --> $DIR/typed-swap-invalid-scalar.rs:LL:CC
+   |
+LL |     invalid_scalar();
+   |     ^^^^^^^^^^^^^^^^
+
+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/stacked_borrows/retag_data_race_protected_read.rs b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.rs
index 5db89c89b77..3de517055ec 100644
--- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.rs
+++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.rs
@@ -13,7 +13,7 @@ fn main() {
         let ptr = ptr;
         // We do a protected mutable retag (but no write!) in this thread.
         fn retag(_x: &mut i32) {}
-        retag(unsafe { &mut *ptr.0 }); //~ERROR: Data race detected between (1) non-atomic read on thread `main` and (2) non-atomic write on thread `unnamed-1`
+        retag(unsafe { &mut *ptr.0 }); //~ERROR: Data race detected between (1) non-atomic read on thread `main` and (2) retag write of type `i32` on thread `unnamed-1`
     });
 
     // We do a read in the main thread.
diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr
index 2ce757013d5..47ae4b5d46d 100644
--- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr
+++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.stderr
@@ -1,14 +1,17 @@
-error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `main` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here
+error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `main` and (2) retag write of type `i32` on thread `unnamed-ID` at ALLOC. (2) just happened here
   --> $DIR/retag_data_race_protected_read.rs:LL:CC
    |
 LL |         retag(unsafe { &mut *ptr.0 });
-   |                        ^^^^^^^^^^^ Data race detected between (1) non-atomic read on thread `main` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here
+   |                        ^^^^^^^^^^^ Data race detected between (1) non-atomic read on thread `main` and (2) retag write of type `i32` on thread `unnamed-ID` at ALLOC. (2) just happened here
    |
 help: and (1) occurred earlier here
   --> $DIR/retag_data_race_protected_read.rs:LL:CC
    |
 LL |     unsafe { ptr.0.read() };
    |              ^^^^^^^^^^^^
+   = help: retags occur on all (re)borrows and as well as when references are copied or moved
+   = help: retags permit optimizations that insert speculative reads or writes
+   = help: therefore from the perspective of data races, a retag has the same implications as a read or write
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE (of the first span) on thread `unnamed-ID`:
diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs
index 01a2e9ac474..25c92ddf6ca 100644
--- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs
+++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs
@@ -15,7 +15,7 @@ fn thread_1(p: SendPtr) {
 fn thread_2(p: SendPtr) {
     let p = p.0;
     unsafe {
-        *p = 5; //~ ERROR: Data race detected between (1) non-atomic read on thread `unnamed-1` and (2) non-atomic write on thread `unnamed-2`
+        *p = 5; //~ ERROR: Data race detected between (1) retag read on thread `unnamed-1` and (2) non-atomic write on thread `unnamed-2`
     }
 }
 
diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr
index d3c8d14e2a1..9fe9fbeda44 100644
--- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr
+++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.stderr
@@ -1,14 +1,17 @@
-error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here
+error: Undefined Behavior: Data race detected between (1) retag read on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here
   --> $DIR/retag_data_race_read.rs:LL:CC
    |
 LL |         *p = 5;
-   |         ^^^^^^ Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here
+   |         ^^^^^^ Data race detected between (1) retag read on thread `unnamed-ID` and (2) non-atomic write on thread `unnamed-ID` at ALLOC. (2) just happened here
    |
 help: and (1) occurred earlier here
   --> $DIR/retag_data_race_read.rs:LL:CC
    |
 LL |         let _r = &*p;
    |                  ^^^
+   = help: retags occur on all (re)borrows and as well as when references are copied or moved
+   = help: retags permit optimizations that insert speculative reads or writes
+   = help: therefore from the perspective of data races, a retag has the same implications as a read or write
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE (of the first span) on thread `unnamed-ID`:
diff --git a/src/tools/miri/tests/pass/intptrcast.rs b/src/tools/miri/tests/pass/intptrcast.rs
index 370b09f512c..4e9fa12c181 100644
--- a/src/tools/miri/tests/pass/intptrcast.rs
+++ b/src/tools/miri/tests/pass/intptrcast.rs
@@ -149,6 +149,31 @@ fn functions() {
     }
 }
 
+/// Example that should be UB but due to wildcard pointers being too permissive
+/// we don't notice.
+fn should_be_ub() {
+    let alloc1 = 1u8;
+    let alloc2 = 2u8;
+    // Expose both allocations
+    let addr1: usize = &alloc1 as *const u8 as usize;
+    let addr2: usize = &alloc2 as *const u8 as usize;
+
+    // Cast addr1 back to a pointer. In Miri, this gives it Wildcard provenance.
+    let wildcard = addr1 as *const u8;
+    unsafe {
+        // Read through the wildcard
+        assert_eq!(*wildcard, 1);
+        // Offset the pointer to another allocation.
+        // Note that we are doing this arithmetic that does not require we stay within bounds of the allocation.
+        let wildcard = wildcard.wrapping_offset(addr2 as isize - addr1 as isize);
+        // This should report UB:
+        assert_eq!(*wildcard, 2);
+        // ... but it doesn't. A pointer's provenance specifies a single allocation that it is allowed to read from.
+        // And wrapping_offset only modifies the address, not the provenance.
+        // So which allocation is wildcard allowed to access? It cannot be both.
+    }
+}
+
 fn main() {
     cast();
     cast_dangling();
@@ -162,4 +187,5 @@ fn main() {
     ptr_eq_integer();
     zst_deref_of_dangling();
     functions();
+    should_be_ub();
 }
diff --git a/src/tools/miri/tests/pass/intrinsics-x86-pause-without-sse2.rs b/src/tools/miri/tests/pass/intrinsics-x86-pause-without-sse2.rs
new file mode 100644
index 00000000000..c8b92fd5458
--- /dev/null
+++ b/src/tools/miri/tests/pass/intrinsics-x86-pause-without-sse2.rs
@@ -0,0 +1,25 @@
+// Ignore everything except x86 and x86_64
+// Any new targets that are added to CI should be ignored here.
+// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.)
+//@ignore-target-aarch64
+//@ignore-target-arm
+//@ignore-target-avr
+//@ignore-target-s390x
+//@ignore-target-thumbv7em
+//@ignore-target-wasm32
+//@compile-flags: -C target-feature=-sse2
+
+#[cfg(target_arch = "x86")]
+use std::arch::x86::*;
+#[cfg(target_arch = "x86_64")]
+use std::arch::x86_64::*;
+
+fn main() {
+    assert!(!is_x86_feature_detected!("sse2"));
+
+    unsafe {
+        // This is a SSE2 intrinsic, but it behaves as a no-op when SSE2
+        // is not available, so it is always safe to call.
+        _mm_pause();
+    }
+}
diff --git a/src/tools/miri/tests/pass/intrinsics-x86-sse2.rs b/src/tools/miri/tests/pass/intrinsics-x86-sse2.rs
index e636d6c8aaf..e0088b9eb24 100644
--- a/src/tools/miri/tests/pass/intrinsics-x86-sse2.rs
+++ b/src/tools/miri/tests/pass/intrinsics-x86-sse2.rs
@@ -54,6 +54,11 @@ mod tests {
             }
         }
 
+        fn test_mm_pause() {
+            unsafe { _mm_pause() }
+        }
+        test_mm_pause();
+
         #[target_feature(enable = "sse2")]
         unsafe fn test_mm_avg_epu8() {
             let (a, b) = (_mm_set1_epi8(3), _mm_set1_epi8(9));
diff --git a/src/tools/miri/tests/pass/main_fn.rs b/src/tools/miri/tests/pass/main_fn.rs
deleted file mode 100644
index 4cdd034f30e..00000000000
--- a/src/tools/miri/tests/pass/main_fn.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-mod foo {
-    pub(crate) fn bar() {}
-}
-
-use foo::bar as main;
diff --git a/src/tools/miri/tests/pass/portable-simd.rs b/src/tools/miri/tests/pass/portable-simd.rs
index 399913a757b..cdb441b450b 100644
--- a/src/tools/miri/tests/pass/portable-simd.rs
+++ b/src/tools/miri/tests/pass/portable-simd.rs
@@ -526,6 +526,23 @@ fn simd_intrinsics() {
     }
 }
 
+fn simd_float_intrinsics() {
+    use intrinsics::*;
+
+    // These are just smoke tests to ensure the intrinsics can be called.
+    unsafe {
+        let a = f32x4::splat(10.0);
+        simd_fsqrt(a);
+        simd_fsin(a);
+        simd_fcos(a);
+        simd_fexp(a);
+        simd_fexp2(a);
+        simd_flog(a);
+        simd_flog2(a);
+        simd_flog10(a);
+    }
+}
+
 fn simd_masked_loadstore() {
     // The buffer is deliberarely too short, so reading the last element would be UB.
     let buf = [3i32; 3];
@@ -559,5 +576,6 @@ fn main() {
     simd_gather_scatter();
     simd_round();
     simd_intrinsics();
+    simd_float_intrinsics();
     simd_masked_loadstore();
 }
diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml
index 958aef69572..d8bb8c643d1 100644
--- a/src/tools/run-make-support/Cargo.toml
+++ b/src/tools/run-make-support/Cargo.toml
@@ -4,4 +4,5 @@ version = "0.0.0"
 edition = "2021"
 
 [dependencies]
+object = "0.34.0"
 wasmparser = "0.118.2"
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index 674860f8413..419b04231b5 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -2,14 +2,15 @@ use std::env;
 use std::path::{Path, PathBuf};
 use std::process::{Command, Output};
 
+pub use object;
 pub use wasmparser;
 
 pub fn out_dir() -> PathBuf {
     env::var_os("TMPDIR").unwrap().into()
 }
 
-fn setup_common_build_cmd() -> Command {
-    let rustc = env::var("RUSTC").unwrap();
+fn setup_common_build_cmd(command: &str) -> Command {
+    let rustc = env::var(command).unwrap();
     let mut cmd = Command::new(rustc);
     cmd.arg("--out-dir").arg(out_dir()).arg("-L").arg(out_dir());
     cmd
@@ -32,6 +33,10 @@ pub fn aux_build() -> AuxBuildInvocationBuilder {
     AuxBuildInvocationBuilder::new()
 }
 
+pub fn rustdoc() -> Rustdoc {
+    Rustdoc::new()
+}
+
 #[derive(Debug)]
 pub struct RustcInvocationBuilder {
     cmd: Command,
@@ -39,7 +44,7 @@ pub struct RustcInvocationBuilder {
 
 impl RustcInvocationBuilder {
     fn new() -> Self {
-        let cmd = setup_common_build_cmd();
+        let cmd = setup_common_build_cmd("RUSTC");
         Self { cmd }
     }
 
@@ -73,7 +78,7 @@ pub struct AuxBuildInvocationBuilder {
 
 impl AuxBuildInvocationBuilder {
     fn new() -> Self {
-        let mut cmd = setup_common_build_cmd();
+        let mut cmd = setup_common_build_cmd("RUSTC");
         cmd.arg("--crate-type=lib");
         Self { cmd }
     }
@@ -96,6 +101,35 @@ impl AuxBuildInvocationBuilder {
     }
 }
 
+#[derive(Debug)]
+pub struct Rustdoc {
+    cmd: Command,
+}
+
+impl Rustdoc {
+    fn new() -> Self {
+        let cmd = setup_common_build_cmd("RUSTDOC");
+        Self { cmd }
+    }
+
+    pub fn arg(&mut self, arg: &str) -> &mut Self {
+        self.cmd.arg(arg);
+        self
+    }
+
+    #[track_caller]
+    pub fn run(&mut self) -> Output {
+        let caller_location = std::panic::Location::caller();
+        let caller_line_number = caller_location.line();
+
+        let output = self.cmd.output().unwrap();
+        if !output.status.success() {
+            handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number);
+        }
+        output
+    }
+}
+
 fn run_common(bin_name: &str) -> (Command, Output) {
     let target = env::var("TARGET").unwrap();
 
diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs
index c500b30b998..053afcc52d4 100644
--- a/src/tools/rustfmt/src/expr.rs
+++ b/src/tools/rustfmt/src/expr.rs
@@ -3,7 +3,7 @@ use std::cmp::min;
 
 use itertools::Itertools;
 use rustc_ast::token::{Delimiter, Lit, LitKind};
-use rustc_ast::{ast, ptr, token, ForLoopKind};
+use rustc_ast::{ast, ptr, token, ForLoopKind, MatchKind};
 use rustc_span::{BytePos, Span};
 
 use crate::chains::rewrite_chain;
@@ -170,8 +170,8 @@ pub(crate) fn format_expr(
                 }
             }
         }
-        ast::ExprKind::Match(ref cond, ref arms) => {
-            rewrite_match(context, cond, arms, shape, expr.span, &expr.attrs)
+        ast::ExprKind::Match(ref cond, ref arms, kind) => {
+            rewrite_match(context, cond, arms, shape, expr.span, &expr.attrs, kind)
         }
         ast::ExprKind::Path(ref qself, ref path) => {
             rewrite_path(context, PathContext::Expr, qself, path, shape)
@@ -625,7 +625,7 @@ pub(crate) fn rewrite_cond(
     shape: Shape,
 ) -> Option<String> {
     match expr.kind {
-        ast::ExprKind::Match(ref cond, _) => {
+        ast::ExprKind::Match(ref cond, _, MatchKind::Prefix) => {
             // `match `cond` {`
             let cond_shape = match context.config.indent_style() {
                 IndentStyle::Visual => shape.shrink_left(6).and_then(|s| s.sub_width(2))?,
diff --git a/src/tools/rustfmt/src/matches.rs b/src/tools/rustfmt/src/matches.rs
index 5a00984d4c0..e68903c8715 100644
--- a/src/tools/rustfmt/src/matches.rs
+++ b/src/tools/rustfmt/src/matches.rs
@@ -2,7 +2,7 @@
 
 use std::iter::repeat;
 
-use rustc_ast::{ast, ptr};
+use rustc_ast::{ast, ptr, MatchKind};
 use rustc_span::{BytePos, Span};
 
 use crate::comment::{combine_strs_with_missing_comments, rewrite_comment};
@@ -72,6 +72,7 @@ pub(crate) fn rewrite_match(
     shape: Shape,
     span: Span,
     attrs: &[ast::Attribute],
+    match_kind: MatchKind,
 ) -> Option<String> {
     // Do not take the rhs overhead from the upper expressions into account
     // when rewriting match condition.
@@ -131,15 +132,27 @@ pub(crate) fn rewrite_match(
         }
     } else {
         let span_after_cond = mk_sp(cond.span.hi(), span.hi());
-        Some(format!(
-            "match {}{}{{\n{}{}{}\n{}}}",
-            cond_str,
-            block_sep,
-            inner_attrs_str,
-            nested_indent_str,
-            rewrite_match_arms(context, arms, shape, span_after_cond, open_brace_pos)?,
-            shape.indent.to_string(context.config),
-        ))
+
+        match match_kind {
+            MatchKind::Prefix => Some(format!(
+                "match {}{}{{\n{}{}{}\n{}}}",
+                cond_str,
+                block_sep,
+                inner_attrs_str,
+                nested_indent_str,
+                rewrite_match_arms(context, arms, shape, span_after_cond, open_brace_pos)?,
+                shape.indent.to_string(context.config),
+            )),
+            MatchKind::Postfix => Some(format!(
+                "{}.match{}{{\n{}{}{}\n{}}}",
+                cond_str,
+                block_sep,
+                inner_attrs_str,
+                nested_indent_str,
+                rewrite_match_arms(context, arms, shape, span_after_cond, open_brace_pos)?,
+                shape.indent.to_string(context.config),
+            )),
+        }
     }
 }
 
diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs
index 7f576279432..47b48468a24 100644
--- a/src/tools/rustfmt/src/patterns.rs
+++ b/src/tools/rustfmt/src/patterns.rs
@@ -55,9 +55,10 @@ fn is_short_pattern_inner(pat: &ast::Pat) -> bool {
         ast::PatKind::TupleStruct(_, ref path, ref subpats) => {
             path.segments.len() <= 1 && subpats.len() <= 1
         }
-        ast::PatKind::Box(ref p) | ast::PatKind::Ref(ref p, _) | ast::PatKind::Paren(ref p) => {
-            is_short_pattern_inner(&*p)
-        }
+        ast::PatKind::Box(ref p)
+        | PatKind::Deref(ref p)
+        | ast::PatKind::Ref(ref p, _)
+        | ast::PatKind::Paren(ref p) => is_short_pattern_inner(&*p),
         PatKind::Or(ref pats) => pats.iter().all(|p| is_short_pattern_inner(p)),
     }
 }
@@ -277,6 +278,7 @@ impl Rewrite for Pat {
                 .rewrite(context, shape.offset_left(1)?.sub_width(1)?)
                 .map(|inner_pat| format!("({})", inner_pat)),
             PatKind::Err(_) => None,
+            PatKind::Deref(_) => None,
         }
     }
 }
diff --git a/src/tools/rustfmt/tests/source/postfix-match/pf-match.rs b/src/tools/rustfmt/tests/source/postfix-match/pf-match.rs
new file mode 100644
index 00000000000..b2366723631
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/postfix-match/pf-match.rs
@@ -0,0 +1,20 @@
+#![feature(postfix_match)]
+
+fn main() {
+    let val = Some(42);
+
+    val.match {
+        Some(_) => 2,
+        _ => 1
+    };
+
+    Some(2).match {
+        Some(_) => true,
+        None => false
+    }.match {
+        false => "ferris is cute",
+        true => "I turn cats in to petted cats",
+    }.match {
+        _ => (),
+    }
+}
\ No newline at end of file
diff --git a/src/tools/rustfmt/tests/target/postfix-match/pf-match.rs b/src/tools/rustfmt/tests/target/postfix-match/pf-match.rs
new file mode 100644
index 00000000000..f439f272623
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/postfix-match/pf-match.rs
@@ -0,0 +1,20 @@
+#![feature(postfix_match)]
+
+fn main() {
+    let val = Some(42);
+
+    val.match {
+        Some(_) => 2,
+        _ => 1,
+    };
+
+    Some(2).match {
+        Some(_) => true,
+        None => false,
+    }.match {
+        false => "ferris is cute",
+        true => "I turn cats in to petted cats",
+    }.match {
+        _ => (),
+    }
+}
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 22927cffd1b..fa24447f699 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -183,9 +183,10 @@ pub fn check(root_path: &Path, bless: bool, bad: &mut bool) {
         }
     });
 
-    // if an excluded file is renamed, it must be removed from this list
+    // if there are any file names remaining, they were moved on the fs.
+    // our data must remain up to date, so it must be removed from issues.txt
     // do this automatically on bless, otherwise issue a tidy error
-    if bless {
+    if bless && !remaining_issue_names.is_empty() {
         let issues_txt_header = r#"
 /*
 ============================================================
diff --git a/tests/assembly/option-nonzero-eq.rs b/tests/assembly/option-nonzero-eq.rs
deleted file mode 100644
index b04cf63fd78..00000000000
--- a/tests/assembly/option-nonzero-eq.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-//@ revisions: WIN LIN
-//@ [WIN] only-windows
-//@ [LIN] only-linux
-//@ assembly-output: emit-asm
-//@ compile-flags: --crate-type=lib -O -C llvm-args=-x86-asm-syntax=intel
-//@ only-x86_64
-//@ ignore-sgx
-
-use std::cmp::Ordering;
-
-// CHECK-lABEL: ordering_eq:
-#[no_mangle]
-pub fn ordering_eq(l: Option<Ordering>, r: Option<Ordering>) -> bool {
-    // Linux (System V): first two arguments are rdi then rsi
-    // Windows: first two arguments are rcx then rdx
-    // Both use rax for the return value.
-
-    // CHECK-NOT: mov
-    // CHECK-NOT: test
-    // CHECK-NOT: cmp
-
-    // LIN: cmp dil, sil
-    // WIN: cmp cl, dl
-    // CHECK-NEXT: sete al
-    // CHECK-NEXT: ret
-    l == r
-}
diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs
index bda77b5f09b..3563aec6d80 100644
--- a/tests/assembly/targets/targets-elf.rs
+++ b/tests/assembly/targets/targets-elf.rs
@@ -369,6 +369,9 @@
 //@ revisions: riscv32im_unknown_none_elf
 //@ [riscv32im_unknown_none_elf] compile-flags: --target riscv32im-unknown-none-elf
 //@ [riscv32im_unknown_none_elf] needs-llvm-components: riscv
+//@ revisions: riscv32ima_unknown_none_elf
+//@ [riscv32ima_unknown_none_elf] compile-flags: --target riscv32ima-unknown-none-elf
+//@ [riscv32ima_unknown_none_elf] needs-llvm-components: riscv
 //@ revisions: riscv32imac_esp_espidf
 //@ [riscv32imac_esp_espidf] compile-flags: --target riscv32imac-esp-espidf
 //@ [riscv32imac_esp_espidf] needs-llvm-components: riscv
diff --git a/tests/assembly/x86_64-typed-swap.rs b/tests/assembly/x86_64-typed-swap.rs
new file mode 100644
index 00000000000..95e87519e6c
--- /dev/null
+++ b/tests/assembly/x86_64-typed-swap.rs
@@ -0,0 +1,53 @@
+//@ revisions: WIN LIN
+//@ [WIN] only-windows
+//@ [LIN] only-linux
+//@ only-x86_64
+//@ assembly-output: emit-asm
+//@ compile-flags: --crate-type=lib -O
+
+use std::arch::x86_64::__m128;
+use std::mem::swap;
+
+// CHECK-LABEL: swap_i32:
+#[no_mangle]
+pub fn swap_i32(x: &mut i32, y: &mut i32) {
+    // CHECK: movl (%[[ARG1:.+]]), %[[T1:.+]]
+    // CHECK: movl (%[[ARG2:.+]]), %[[T2:.+]]
+    // CHECK: movl %[[T2]], (%[[ARG1]])
+    // CHECK: movl %[[T1]], (%[[ARG2]])
+    // CHECK: retq
+    swap(x, y)
+}
+
+// CHECK-LABEL: swap_pair:
+#[no_mangle]
+pub fn swap_pair(x: &mut (i32, u32), y: &mut (i32, u32)) {
+    // CHECK: movq (%[[ARG1]]), %[[T1:.+]]
+    // CHECK: movq (%[[ARG2]]), %[[T2:.+]]
+    // CHECK: movq %[[T2]], (%[[ARG1]])
+    // CHECK: movq %[[T1]], (%[[ARG2]])
+    // CHECK: retq
+    swap(x, y)
+}
+
+// CHECK-LABEL: swap_str:
+#[no_mangle]
+pub fn swap_str<'a>(x: &mut &'a str, y: &mut &'a str) {
+    // CHECK: movups (%[[ARG1]]), %[[T1:xmm.]]
+    // CHECK: movups (%[[ARG2]]), %[[T2:xmm.]]
+    // CHECK: movups %[[T2]], (%[[ARG1]])
+    // CHECK: movups %[[T1]], (%[[ARG2]])
+    // CHECK: retq
+    swap(x, y)
+}
+
+// CHECK-LABEL: swap_simd:
+#[no_mangle]
+pub fn swap_simd(x: &mut __m128, y: &mut __m128) {
+    // CHECK: movaps (%[[ARG1]]), %[[T1:xmm.]]
+    // CHECK: movaps (%[[ARG2]]), %[[T2:xmm.]]
+    // CHECK: movaps %[[T2]], (%[[ARG1]])
+    // CHECK: movaps %[[T1]], (%[[ARG2]])
+    // CHECK: retq
+    swap(x, y)
+}
diff --git a/tests/codegen/intrinsics/typed_swap.rs b/tests/codegen/intrinsics/typed_swap.rs
new file mode 100644
index 00000000000..b55fb8ee36f
--- /dev/null
+++ b/tests/codegen/intrinsics/typed_swap.rs
@@ -0,0 +1,78 @@
+//@ revisions: OPT0 OPT3
+//@ [OPT0] compile-flags: -Copt-level=0
+//@ [OPT3] compile-flags: -Copt-level=3
+//@ compile-flags: -C no-prepopulate-passes
+//@ only-64bit (so I don't need to worry about usize)
+// ignore-tidy-linelength (the memcpy calls get long)
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::typed_swap;
+
+// CHECK-LABEL: @swap_unit(
+#[no_mangle]
+pub unsafe fn swap_unit(x: &mut (), y: &mut ()) {
+    // CHECK: start
+    // CHECK-NEXT: ret void
+    typed_swap(x, y)
+}
+
+// CHECK-LABEL: @swap_i32(
+#[no_mangle]
+pub unsafe fn swap_i32(x: &mut i32, y: &mut i32) {
+    // CHECK-NOT: alloca
+
+    // CHECK: %[[TEMP:.+]] = load i32, ptr %x, align 4
+    // CHECK-SAME: !noundef
+    // OPT0: %[[TEMP2:.+]] = load i32, ptr %y, align 4
+    // OPT0-SAME: !noundef
+    // OPT0: store i32 %[[TEMP2]], ptr %x, align 4
+    // OPT0-NOT: memcpy
+    // OPT3-NOT: load
+    // OPT3: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x, ptr align 4 %y, i64 4, i1 false)
+    // CHECK: store i32 %[[TEMP]], ptr %y, align 4
+    // CHECK: ret void
+    typed_swap(x, y)
+}
+
+// CHECK-LABEL: @swap_pair(
+#[no_mangle]
+pub unsafe fn swap_pair(x: &mut (i32, u32), y: &mut (i32, u32)) {
+    // CHECK-NOT: alloca
+
+    // CHECK: load i32
+    // CHECK-SAME: !noundef
+    // CHECK: load i32
+    // CHECK-SAME: !noundef
+    // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %x, ptr align 4 %y, i64 8, i1 false)
+    // CHECK: store i32
+    // CHECK: store i32
+    typed_swap(x, y)
+}
+
+// CHECK-LABEL: @swap_str(
+#[no_mangle]
+pub unsafe fn swap_str<'a>(x: &mut &'a str, y: &mut &'a str) {
+    // CHECK-NOT: alloca
+
+    // CHECK: load ptr
+    // CHECK-SAME: !nonnull
+    // CHECK-SAME: !noundef
+    // CHECK: load i64
+    // CHECK-SAME: !noundef
+    // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %x, ptr align 8 %y, i64 16, i1 false)
+    // CHECK: store ptr
+    // CHECK: store i64
+    typed_swap(x, y)
+}
+
+// OPT0-LABEL: @swap_string(
+#[no_mangle]
+pub unsafe fn swap_string(x: &mut String, y: &mut String) {
+    // OPT0: %[[TEMP:.+]] = alloca {{.+}}, align 8
+    // OPT0: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %[[TEMP]], ptr align 8 %x, i64 24, i1 false)
+    // OPT0: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %x, ptr align 8 %y, i64 24, i1 false)
+    // OPT0: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %y, ptr align 8 %[[TEMP]], i64 24, i1 false)
+    typed_swap(x, y)
+}
diff --git a/tests/codegen/option-nonzero-eq.rs b/tests/codegen/option-niche-eq.rs
index f637b1aef97..8b8044e9b75 100644
--- a/tests/codegen/option-nonzero-eq.rs
+++ b/tests/codegen/option-niche-eq.rs
@@ -1,4 +1,5 @@
 //@ compile-flags: -O -Zmerge-functions=disabled
+//@ min-llvm-version: 18
 #![crate_type = "lib"]
 #![feature(generic_nonzero)]
 
@@ -7,9 +8,6 @@ use core::cmp::Ordering;
 use core::ptr::NonNull;
 use core::num::NonZero;
 
-// See also tests/assembly/option-nonzero-eq.rs, for cases with `assume`s in the
-// LLVM and thus don't optimize down clearly here, but do in assembly.
-
 // CHECK-lABEL: @non_zero_eq
 #[no_mangle]
 pub fn non_zero_eq(l: Option<NonZero<u32>>, r: Option<NonZero<u32>>) -> bool {
@@ -36,3 +34,42 @@ pub fn non_null_eq(l: Option<NonNull<u8>>, r: Option<NonNull<u8>>) -> bool {
     // CHECK-NEXT: ret i1
     l == r
 }
+
+// CHECK-lABEL: @ordering_eq
+#[no_mangle]
+pub fn ordering_eq(l: Option<Ordering>, r: Option<Ordering>) -> bool {
+    // CHECK: start:
+    // CHECK-NEXT: icmp eq i8
+    // CHECK-NEXT: ret i1
+    l == r
+}
+
+#[derive(PartialEq)]
+pub enum EnumWithNiche {
+    A,
+    B,
+    C,
+    D,
+    E,
+    F,
+    G,
+}
+
+// CHECK-lABEL: @niche_eq
+#[no_mangle]
+pub fn niche_eq(l: Option<EnumWithNiche>, r: Option<EnumWithNiche>) -> bool {
+    // CHECK: start:
+    // CHECK-NEXT: icmp eq i8
+    // CHECK-NEXT: ret i1
+    l == r
+}
+
+// FIXME: This should work too
+// // FIXME-CHECK-lABEL: @bool_eq
+// #[no_mangle]
+// pub fn bool_eq(l: Option<bool>, r: Option<bool>) -> bool {
+//     // FIXME-CHECK: start:
+//     // FIXME-CHECK-NEXT: icmp eq i8
+//     // FIXME-CHECK-NEXT: ret i1
+//     l == r
+// }
diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs
index c5d8e0f22a2..ca781a99296 100644
--- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs
+++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs
@@ -47,40 +47,42 @@ pub fn foo() where
     let _: Type4 = <Foo>::bar;
 }
 
-pub fn foo1(_: Type1) { }
+// Force arguments to be passed by using a reference. Otherwise, they may end up PassMode::Ignore
+
+pub fn foo1(_: &Type1) { }
 // CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
-pub fn foo2(_: Type1, _: Type1) { }
+pub fn foo2(_: &Type1, _: &Type1) { }
 // CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
-pub fn foo3(_: Type1, _: Type1, _: Type1) { }
+pub fn foo3(_: &Type1, _: &Type1, _: &Type1) { }
 // CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
-pub fn foo4(_: Type2) { }
+pub fn foo4(_: &Type2) { }
 // CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
-pub fn foo5(_: Type2, _: Type2) { }
+pub fn foo5(_: &Type2, _: &Type2) { }
 // CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
-pub fn foo6(_: Type2, _: Type2, _: Type2) { }
+pub fn foo6(_: &Type2, _: &Type2, _: &Type2) { }
 // CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
-pub fn foo7(_: Type3) { }
+pub fn foo7(_: &Type3) { }
 // CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
-pub fn foo8(_: Type3, _: Type3) { }
+pub fn foo8(_: &Type3, _: &Type3) { }
 // CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
-pub fn foo9(_: Type3, _: Type3, _: Type3) { }
+pub fn foo9(_: &Type3, _: &Type3, _: &Type3) { }
 // CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
-pub fn foo10(_: Type4) { }
+pub fn foo10(_: &Type4) { }
 // CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
-pub fn foo11(_: Type4, _: Type4) { }
+pub fn foo11(_: &Type4, _: &Type4) { }
 // CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
-pub fn foo12(_: Type4, _: Type4, _: Type4) { }
+pub fn foo12(_: &Type4, _: &Type4, _: &Type4) { }
 // CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
 
-// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barE"}
-// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barS_E"}
-// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barS_S_E"}
-// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooE"}
-// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooS_E"}
-// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooS_S_E"}
-// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooE"}
-// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooS_E"}
-// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooS_S_E"}
-// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barE"}
-// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barS_E"}
-// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barS_S_E"}
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barEE"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barES0_E"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barES0_S0_E"}
+// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooEE"}
+// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooES0_E"}
+// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooES0_S0_E"}
+// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooEE"}
+// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_E"}
+// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_S0_E"}
+// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barEE"}
+// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barES0_E"}
+// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barES0_S0_E"}
diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs
index 3a1a09150ea..38f507856bd 100644
--- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs
+++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs
@@ -12,9 +12,9 @@ use core::ffi::*;
 pub fn foo1(_: ()) { }
 // CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
 pub fn foo2(_: (), _: c_void) { }
-// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
 pub fn foo3(_: (), _: c_void, _: c_void) { }
-// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
+// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
 pub fn foo4(_: *mut ()) { }
 // CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
 pub fn foo5(_: *mut (), _: *mut c_void) { }
@@ -131,8 +131,6 @@ pub fn foo60(_: &str, _: &str, _: &str) { }
 // CHECK: define{{.*}}5foo60{{.*}}!type ![[TYPE60:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}}
 
 // CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvvE"}
-// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvvvE"}
-// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvvvvE"}
 // CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvPvE"}
 // CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvPvS_E"}
 // CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvPvS_S_E"}
diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs
index 0deda029c4b..6f47f5e3355 100644
--- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs
+++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs
@@ -28,7 +28,7 @@ pub struct Type2<'a> {
     member3: &'a Type2<'a>,
 }
 
-pub struct Bar;
+pub struct Bar(i32);
 
 // repr(transparent) user-defined generic type
 #[repr(transparent)]
diff --git a/tests/codegen/sanitizer/cfi/normalize-integers.rs b/tests/codegen/sanitizer/cfi/normalize-integers.rs
index 210814eb9ae..801ed312be5 100644
--- a/tests/codegen/sanitizer/cfi/normalize-integers.rs
+++ b/tests/codegen/sanitizer/cfi/normalize-integers.rs
@@ -41,6 +41,6 @@ pub fn foo11(_: (), _: usize, _: usize, _: usize) { }
 // CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64|u4i128}}E.normalized"}
 // CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64|u4i128}}S_E.normalized"}
 // CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64|u4i128}}S_S_E.normalized"}
-// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvv{{u3u16|u3u32|u3u64|u4u128}}E.normalized"}
-// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvv{{u3u16|u3u32|u3u64|u4u128}}S_E.normalized"}
-// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvv{{u3u16|u3u32|u3u64|u4u128}}S_S_E.normalized"}
+// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64|u4u128}}E.normalized"}
+// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64|u4u128}}S_E.normalized"}
+// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64|u4u128}}S_S_E.normalized"}
diff --git a/tests/codegen/swap-small-types.rs b/tests/codegen/swap-small-types.rs
index 5fdf4a5804a..4dcfed2a53a 100644
--- a/tests/codegen/swap-small-types.rs
+++ b/tests/codegen/swap-small-types.rs
@@ -70,10 +70,7 @@ pub fn swap_slices<'a>(x: &mut &'a [u32], y: &mut &'a [u32]) {
     // CHECK-NOT: alloca
     // CHECK: load ptr
     // CHECK: load i64
-    // CHECK: load ptr
-    // CHECK: load i64
-    // CHECK: store ptr
-    // CHECK: store i64
+    // CHECK: call void @llvm.memcpy.p0.p0.i64({{.+}}, i64 16, i1 false)
     // CHECK: store ptr
     // CHECK: store i64
     swap(x, y)
diff --git a/tests/coverage/let_else_loop.cov-map b/tests/coverage/let_else_loop.cov-map
new file mode 100644
index 00000000000..b0cee300522
--- /dev/null
+++ b/tests/coverage/let_else_loop.cov-map
@@ -0,0 +1,30 @@
+Function name: let_else_loop::_if (unused)
+Raw bytes (19): 0x[01, 01, 00, 03, 00, 16, 01, 01, 0c, 00, 02, 09, 00, 10, 00, 02, 09, 00, 10]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 3
+- Code(Zero) at (prev + 22, 1) to (start + 1, 12)
+- Code(Zero) at (prev + 2, 9) to (start + 0, 16)
+- Code(Zero) at (prev + 2, 9) to (start + 0, 16)
+
+Function name: let_else_loop::_loop_either_way (unused)
+Raw bytes (19): 0x[01, 01, 00, 03, 00, 0f, 01, 01, 14, 00, 01, 1c, 00, 23, 00, 01, 05, 00, 0c]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 3
+- Code(Zero) at (prev + 15, 1) to (start + 1, 20)
+- Code(Zero) at (prev + 1, 28) to (start + 0, 35)
+- Code(Zero) at (prev + 1, 5) to (start + 0, 12)
+
+Function name: let_else_loop::loopy
+Raw bytes (19): 0x[01, 01, 00, 03, 01, 09, 01, 01, 14, 00, 01, 1c, 00, 23, 05, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 3
+- Code(Counter(0)) at (prev + 9, 1) to (start + 1, 20)
+- Code(Zero) at (prev + 1, 28) to (start + 0, 35)
+- Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2)
+
diff --git a/tests/coverage/let_else_loop.coverage b/tests/coverage/let_else_loop.coverage
new file mode 100644
index 00000000000..d193c8ca1b5
--- /dev/null
+++ b/tests/coverage/let_else_loop.coverage
@@ -0,0 +1,35 @@
+   LL|       |#![feature(coverage_attribute)]
+   LL|       |//@ edition: 2021
+   LL|       |
+   LL|       |// Regression test for <https://github.com/rust-lang/rust/issues/122738>.
+   LL|       |// These code patterns should not trigger an ICE when allocating a physical
+   LL|       |// counter to a node and also one of its in-edges, because that is allowed
+   LL|       |// when the node contains a tight loop to itself.
+   LL|       |
+   LL|      1|fn loopy(cond: bool) {
+   LL|      1|    let true = cond else { loop {} };
+                                         ^0
+   LL|      1|}
+   LL|       |
+   LL|       |// Variant that also has `loop {}` on the success path.
+   LL|       |// This isn't needed to catch the original ICE, but might help detect regressions.
+   LL|      0|fn _loop_either_way(cond: bool) {
+   LL|      0|    let true = cond else { loop {} };
+   LL|      0|    loop {}
+   LL|       |}
+   LL|       |
+   LL|       |// Variant using regular `if` instead of let-else.
+   LL|       |// This doesn't trigger the original ICE, but might help detect regressions.
+   LL|      0|fn _if(cond: bool) {
+   LL|      0|    if cond {
+   LL|      0|        loop {}
+   LL|       |    } else {
+   LL|      0|        loop {}
+   LL|       |    }
+   LL|       |}
+   LL|       |
+   LL|       |#[coverage(off)]
+   LL|       |fn main() {
+   LL|       |    loopy(true);
+   LL|       |}
+
diff --git a/tests/coverage/let_else_loop.rs b/tests/coverage/let_else_loop.rs
new file mode 100644
index 00000000000..12e0aeabcab
--- /dev/null
+++ b/tests/coverage/let_else_loop.rs
@@ -0,0 +1,33 @@
+#![feature(coverage_attribute)]
+//@ edition: 2021
+
+// Regression test for <https://github.com/rust-lang/rust/issues/122738>.
+// These code patterns should not trigger an ICE when allocating a physical
+// counter to a node and also one of its in-edges, because that is allowed
+// when the node contains a tight loop to itself.
+
+fn loopy(cond: bool) {
+    let true = cond else { loop {} };
+}
+
+// Variant that also has `loop {}` on the success path.
+// This isn't needed to catch the original ICE, but might help detect regressions.
+fn _loop_either_way(cond: bool) {
+    let true = cond else { loop {} };
+    loop {}
+}
+
+// Variant using regular `if` instead of let-else.
+// This doesn't trigger the original ICE, but might help detect regressions.
+fn _if(cond: bool) {
+    if cond {
+        loop {}
+    } else {
+        loop {}
+    }
+}
+
+#[coverage(off)]
+fn main() {
+    loopy(true);
+}
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff
index a958e5541fa..21cf745b680 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff
@@ -28,6 +28,10 @@
                               let mut _10: *mut ();
                               let mut _11: *const [bool; 0];
                               scope 13 {
+                                  scope 14 (inlined core::ub_checks::check_language_ub) {
+                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
+                                      }
+                                  }
                               }
                           }
                       }
@@ -60,7 +64,7 @@
           StorageDead(_7);
           StorageLive(_11);
           StorageLive(_8);
-          _8 = UbCheck(LanguageUb);
+          _8 = UbChecks();
           switchInt(move _8) -> [0: bb4, otherwise: bb2];
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff
index b073e27729e..ee58a974480 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff
@@ -28,6 +28,10 @@
                               let mut _10: *mut ();
                               let mut _11: *const [bool; 0];
                               scope 13 {
+                                  scope 14 (inlined core::ub_checks::check_language_ub) {
+                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
+                                      }
+                                  }
                               }
                           }
                       }
@@ -60,7 +64,7 @@
           StorageDead(_7);
           StorageLive(_11);
           StorageLive(_8);
-          _8 = UbCheck(LanguageUb);
+          _8 = UbChecks();
           switchInt(move _8) -> [0: bb5, otherwise: bb3];
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff
index 0a9f339ddba..9fc9c8ed409 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff
@@ -28,6 +28,10 @@
                               let mut _10: *mut ();
                               let mut _11: *const [bool; 0];
                               scope 13 {
+                                  scope 14 (inlined core::ub_checks::check_language_ub) {
+                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
+                                      }
+                                  }
                               }
                           }
                       }
@@ -60,7 +64,7 @@
           StorageDead(_7);
           StorageLive(_11);
           StorageLive(_8);
-          _8 = UbCheck(LanguageUb);
+          _8 = UbChecks();
           switchInt(move _8) -> [0: bb4, otherwise: bb2];
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff
index bbc791148af..30d93347afd 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff
@@ -28,6 +28,10 @@
                               let mut _10: *mut ();
                               let mut _11: *const [bool; 0];
                               scope 13 {
+                                  scope 14 (inlined core::ub_checks::check_language_ub) {
+                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
+                                      }
+                                  }
                               }
                           }
                       }
@@ -60,7 +64,7 @@
           StorageDead(_7);
           StorageLive(_11);
           StorageLive(_8);
-          _8 = UbCheck(LanguageUb);
+          _8 = UbChecks();
           switchInt(move _8) -> [0: bb5, otherwise: bb3];
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff
index 3a11677f6f0..3a46edbc849 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff
@@ -28,6 +28,10 @@
                               let mut _10: *mut ();
                               let mut _11: *const [bool; 0];
                               scope 13 {
+                                  scope 14 (inlined core::ub_checks::check_language_ub) {
+                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
+                                      }
+                                  }
                               }
                           }
                       }
@@ -62,7 +66,7 @@
           StorageDead(_7);
           StorageLive(_11);
           StorageLive(_8);
-          _8 = UbCheck(LanguageUb);
+          _8 = UbChecks();
           switchInt(move _8) -> [0: bb4, otherwise: bb2];
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff
index 9e7e08866b9..3c71214c35f 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff
@@ -28,6 +28,10 @@
                               let mut _10: *mut ();
                               let mut _11: *const [bool; 0];
                               scope 13 {
+                                  scope 14 (inlined core::ub_checks::check_language_ub) {
+                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
+                                      }
+                                  }
                               }
                           }
                       }
@@ -62,7 +66,7 @@
           StorageDead(_7);
           StorageLive(_11);
           StorageLive(_8);
-          _8 = UbCheck(LanguageUb);
+          _8 = UbChecks();
           switchInt(move _8) -> [0: bb5, otherwise: bb3];
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff
index beadfbc07b6..4557e7b26d6 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff
@@ -28,6 +28,10 @@
                               let mut _10: *mut ();
                               let mut _11: *const [bool; 0];
                               scope 13 {
+                                  scope 14 (inlined core::ub_checks::check_language_ub) {
+                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
+                                      }
+                                  }
                               }
                           }
                       }
@@ -62,7 +66,7 @@
           StorageDead(_7);
           StorageLive(_11);
           StorageLive(_8);
-          _8 = UbCheck(LanguageUb);
+          _8 = UbChecks();
           switchInt(move _8) -> [0: bb4, otherwise: bb2];
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff
index 9ea86956b83..5ab2d5e0fdc 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff
@@ -28,6 +28,10 @@
                               let mut _10: *mut ();
                               let mut _11: *const [bool; 0];
                               scope 13 {
+                                  scope 14 (inlined core::ub_checks::check_language_ub) {
+                                      scope 15 (inlined core::ub_checks::check_language_ub::runtime) {
+                                      }
+                                  }
                               }
                           }
                       }
@@ -62,7 +66,7 @@
           StorageDead(_7);
           StorageLive(_11);
           StorageLive(_8);
-          _8 = UbCheck(LanguageUb);
+          _8 = UbChecks();
           switchInt(move _8) -> [0: bb5, otherwise: bb3];
       }
   
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs
index 9986d903501..617501217cf 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs
@@ -1,6 +1,5 @@
 //@ unit-test: DataflowConstProp
 //@ compile-flags: -Zmir-enable-passes=+GVN,+Inline
-//@ ignore-debug assertions change the output MIR
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
diff --git a/tests/mir-opt/funky_arms.rs b/tests/mir-opt/funky_arms.rs
index 189cd7951fb..fc3691049eb 100644
--- a/tests/mir-opt/funky_arms.rs
+++ b/tests/mir-opt/funky_arms.rs
@@ -1,6 +1,5 @@
 // skip-filecheck
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
-//@ compile-flags: --crate-type lib -Cdebug-assertions=no
 
 #![feature(flt2dec)]
 
diff --git a/tests/mir-opt/inline/unchecked_shifts.rs b/tests/mir-opt/inline/unchecked_shifts.rs
index 2fd18f3d5eb..12b00e76a11 100644
--- a/tests/mir-opt/inline/unchecked_shifts.rs
+++ b/tests/mir-opt/inline/unchecked_shifts.rs
@@ -2,7 +2,6 @@
 #![crate_type = "lib"]
 #![feature(unchecked_shifts)]
 
-//@ ignore-debug: the debug assertions prevent the inlining we are testing for
 //@ compile-flags: -Zmir-opt-level=2 -Zinline-mir
 
 // EMIT_MIR unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.diff
diff --git a/tests/mir-opt/inline/unwrap_unchecked.rs b/tests/mir-opt/inline/unwrap_unchecked.rs
index e44e4e23a2c..13c76c5bb53 100644
--- a/tests/mir-opt/inline/unwrap_unchecked.rs
+++ b/tests/mir-opt/inline/unwrap_unchecked.rs
@@ -1,8 +1,7 @@
 #![crate_type = "lib"]
 
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
-//@ ignore-debug: the debug assertions prevent the inlining we are testing for
-//@ compile-flags: -Zmir-opt-level=2 -Zinline-mir -Cdebug-assertions=no
+//@ compile-flags: -Zmir-opt-level=2 -Zinline-mir
 
 // EMIT_MIR unwrap_unchecked.unwrap_unchecked.Inline.diff
 // EMIT_MIR unwrap_unchecked.unwrap_unchecked.PreCodegen.after.mir
diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff
index 6f7853a3e97..028040edc85 100644
--- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff
@@ -17,6 +17,10 @@
 +                 let _5: ();
 +                 scope 5 {
 +                 }
++                 scope 6 (inlined core::ub_checks::check_language_ub) {
++                     scope 7 (inlined core::ub_checks::check_language_ub::runtime) {
++                     }
++                 }
 +             }
 +         }
 +     }
@@ -37,7 +41,7 @@
 + 
 +     bb2: {
 +         StorageLive(_4);
-+         _4 = UbCheck(LanguageUb);
++         _4 = UbChecks();
 +         assume(_4);
 +         _5 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable];
 +     }
diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff
index cac06d4af08..484fd37248c 100644
--- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff
@@ -17,6 +17,10 @@
 +                 let _5: ();
 +                 scope 5 {
 +                 }
++                 scope 6 (inlined core::ub_checks::check_language_ub) {
++                     scope 7 (inlined core::ub_checks::check_language_ub::runtime) {
++                     }
++                 }
 +             }
 +         }
 +     }
@@ -41,7 +45,7 @@
 -         resume;
 +     bb2: {
 +         StorageLive(_4);
-+         _4 = UbCheck(LanguageUb);
++         _4 = UbChecks();
 +         assume(_4);
 +         _5 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable];
 +     }
diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir
index 5c611650154..9cd7053871e 100644
--- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-abort.mir
@@ -15,6 +15,10 @@ fn unwrap_unchecked(_1: Option<T>) -> T {
                 let _4: ();
                 scope 5 {
                 }
+                scope 6 (inlined core::ub_checks::check_language_ub) {
+                    scope 7 (inlined core::ub_checks::check_language_ub::runtime) {
+                    }
+                }
             }
         }
     }
@@ -27,7 +31,7 @@ fn unwrap_unchecked(_1: Option<T>) -> T {
 
     bb1: {
         StorageLive(_3);
-        _3 = UbCheck(LanguageUb);
+        _3 = UbChecks();
         assume(_3);
         _4 = unreachable_unchecked::precondition_check() -> [return: bb3, unwind unreachable];
     }
diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir
index 5c611650154..9cd7053871e 100644
--- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.panic-unwind.mir
@@ -15,6 +15,10 @@ fn unwrap_unchecked(_1: Option<T>) -> T {
                 let _4: ();
                 scope 5 {
                 }
+                scope 6 (inlined core::ub_checks::check_language_ub) {
+                    scope 7 (inlined core::ub_checks::check_language_ub::runtime) {
+                    }
+                }
             }
         }
     }
@@ -27,7 +31,7 @@ fn unwrap_unchecked(_1: Option<T>) -> T {
 
     bb1: {
         StorageLive(_3);
-        _3 = UbCheck(LanguageUb);
+        _3 = UbChecks();
         assume(_3);
         _4 = unreachable_unchecked::precondition_check() -> [return: bb3, unwind unreachable];
     }
diff --git a/tests/mir-opt/inline_coroutine_body.rs b/tests/mir-opt/inline_coroutine_body.rs
new file mode 100644
index 00000000000..be73bc49de5
--- /dev/null
+++ b/tests/mir-opt/inline_coroutine_body.rs
@@ -0,0 +1,28 @@
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+// skip-filecheck
+//@ unit-test: Inline
+//@ edition: 2021
+//@ compile-flags: -Zinline-mir-hint-threshold=10000 -Zinline-mir-threshold=10000 --crate-type=lib
+
+pub async fn run(permit: ActionPermit<'_, ()>, ctx: &mut core::task::Context<'_>) {
+    run2(permit, ctx);
+}
+
+// EMIT_MIR inline_coroutine_body.run2-{closure#0}.Inline.diff
+fn run2<T>(permit: ActionPermit<'_, T>, ctx: &mut core::task::Context) {
+    _ = || {
+        let mut fut = ActionPermit::perform(permit);
+        let fut = unsafe { core::pin::Pin::new_unchecked(&mut fut) };
+        _ = core::future::Future::poll(fut, ctx);
+    };
+}
+
+pub struct ActionPermit<'a, T> {
+    _guard: core::cell::Ref<'a, T>,
+}
+
+impl<'a, T> ActionPermit<'a, T> {
+    async fn perform(self) {
+        core::future::ready(()).await
+    }
+}
diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff
new file mode 100644
index 00000000000..b189b4e73f4
--- /dev/null
+++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff
@@ -0,0 +1,281 @@
+- // MIR for `run2::{closure#0}` before Inline
++ // MIR for `run2::{closure#0}` after Inline
+  
+  fn run2::{closure#0}(_1: {closure@$DIR/inline_coroutine_body.rs:13:9: 13:11}) -> () {
+      debug permit => (_1.0: ActionPermit<'_, T>);
+      debug ctx => (*(_1.1: &mut std::task::Context<'_>));
+      let mut _0: ();
+      let mut _2: {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
+      let mut _3: ActionPermit<'_, T>;
+      let mut _5: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
+      let _6: ();
+      let mut _7: std::task::Poll<()>;
+      let mut _8: std::pin::Pin<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>;
+      let mut _9: &mut std::task::Context<'_>;
+      let mut _10: &mut std::task::Context<'_>;
+      scope 1 {
+          debug fut => _2;
+          let _4: std::pin::Pin<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>;
+          scope 2 {
+              debug fut => _4;
+              scope 4 {
+              }
++             scope 7 (inlined ActionPermit::<'_, T>::perform::{closure#0}) {
++                 debug _task_context => _31;
++                 debug self => ((*(_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6})).0: ActionPermit<'_, T>);
++                 let _11: ActionPermit<'_, T>;
++                 let mut _12: std::future::Ready<()>;
++                 let mut _13: std::future::Ready<()>;
++                 let mut _14: ();
++                 let mut _16: ();
++                 let _17: ();
++                 let mut _18: std::task::Poll<()>;
++                 let mut _19: std::pin::Pin<&mut std::future::Ready<()>>;
++                 let mut _20: &mut std::future::Ready<()>;
++                 let mut _21: &mut std::future::Ready<()>;
++                 let mut _22: &mut std::task::Context<'_>;
++                 let mut _23: &mut std::task::Context<'_>;
++                 let mut _24: &mut std::task::Context<'_>;
++                 let mut _25: isize;
++                 let mut _27: !;
++                 let mut _28: &mut std::task::Context<'_>;
++                 let mut _29: ();
++                 let mut _30: ();
++                 let mut _31: &mut std::task::Context<'_>;
++                 let mut _32: u32;
++                 let mut _33: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _34: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _35: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _36: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _37: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _38: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _39: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _40: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 scope 8 {
++                     debug self => (((*(_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6})) as variant#3).0: ActionPermit<'_, T>);
++                     let mut _15: std::future::Ready<()>;
++                     scope 9 {
++                         debug __awaitee => (((*(_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6})) as variant#3).1: std::future::Ready<()>);
++                         let _26: ();
++                         scope 10 {
++                         }
++                         scope 11 {
++                             debug result => _26;
++                         }
++                     }
++                     scope 12 (inlined ready::<()>) {
++                         debug t => _14;
++                         let mut _41: std::option::Option<()>;
++                     }
++                 }
++             }
+          }
+          scope 3 {
++             scope 6 (inlined Pin::<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>::new_unchecked) {
++                 debug pointer => _5;
++             }
+          }
+      }
++     scope 5 (inlined ActionPermit::<'_, T>::perform) {
++         debug self => _3;
++     }
+  
+      bb0: {
+          StorageLive(_2);
+          StorageLive(_3);
+          _3 = move (_1.0: ActionPermit<'_, T>);
+-         _2 = ActionPermit::<'_, T>::perform(move _3) -> [return: bb1, unwind unreachable];
+-     }
+- 
+-     bb1: {
++         _2 = {coroutine@$DIR/inline_coroutine_body.rs:25:28: 27:6 (#0)} { self: move _3 };
+          StorageDead(_3);
+          StorageLive(_4);
+          StorageLive(_5);
+          _5 = &mut _2;
+-         _4 = Pin::<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>::new_unchecked(move _5) -> [return: bb2, unwind unreachable];
+-     }
+- 
+-     bb2: {
++         _4 = Pin::<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}> { __pointer: _5 };
+          StorageDead(_5);
+          StorageLive(_6);
+          StorageLive(_7);
+          StorageLive(_8);
+          _8 = move _4;
+          StorageLive(_9);
+          _10 = deref_copy (_1.1: &mut std::task::Context<'_>);
+          _9 = &mut (*_10);
+-         _7 = <{async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6} as Future>::poll(move _8, move _9) -> [return: bb3, unwind unreachable];
++         StorageLive(_11);
++         StorageLive(_15);
++         StorageLive(_16);
++         StorageLive(_25);
++         StorageLive(_27);
++         StorageLive(_30);
++         StorageLive(_31);
++         StorageLive(_32);
++         StorageLive(_33);
++         StorageLive(_34);
++         StorageLive(_35);
++         StorageLive(_36);
++         StorageLive(_37);
++         StorageLive(_38);
++         StorageLive(_39);
++         StorageLive(_40);
++         _33 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         _32 = discriminant((*_33));
++         switchInt(move _32) -> [0: bb3, 1: bb13, 3: bb12, otherwise: bb8];
+      }
+  
+-     bb3: {
++     bb1: {
++         StorageDead(_2);
++         return;
++     }
++ 
++     bb2: {
++         StorageDead(_40);
++         StorageDead(_39);
++         StorageDead(_38);
++         StorageDead(_37);
++         StorageDead(_36);
++         StorageDead(_35);
++         StorageDead(_34);
++         StorageDead(_33);
++         StorageDead(_32);
++         StorageDead(_31);
++         StorageDead(_30);
++         StorageDead(_27);
++         StorageDead(_25);
++         StorageDead(_16);
++         StorageDead(_15);
++         StorageDead(_11);
+          StorageDead(_9);
+          StorageDead(_8);
+          StorageDead(_7);
+          _6 = const ();
+          StorageDead(_6);
+          _0 = const ();
+          StorageDead(_4);
+-         drop(_2) -> [return: bb4, unwind unreachable];
++         drop(_2) -> [return: bb1, unwind unreachable];
+      }
+  
++     bb3: {
++         _31 = move _9;
++         _34 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         _35 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         (((*_34) as variant#3).0: ActionPermit<'_, T>) = move ((*_35).0: ActionPermit<'_, T>);
++         StorageLive(_12);
++         StorageLive(_13);
++         StorageLive(_14);
++         _14 = ();
++         StorageLive(_41);
++         _41 = Option::<()>::Some(_14);
++         _13 = std::future::Ready::<()>(move _41);
++         StorageDead(_41);
++         StorageDead(_14);
++         _12 = <std::future::Ready<()> as IntoFuture>::into_future(move _13) -> [return: bb4, unwind unreachable];
++     }
++ 
+      bb4: {
+-         StorageDead(_2);
+-         return;
++         StorageDead(_13);
++         _36 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         (((*_36) as variant#3).1: std::future::Ready<()>) = move _12;
++         goto -> bb5;
++     }
++ 
++     bb5: {
++         StorageLive(_17);
++         StorageLive(_18);
++         StorageLive(_19);
++         StorageLive(_20);
++         StorageLive(_21);
++         _37 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         _21 = &mut (((*_37) as variant#3).1: std::future::Ready<()>);
++         _20 = &mut (*_21);
++         _19 = Pin::<&mut std::future::Ready<()>>::new_unchecked(move _20) -> [return: bb6, unwind unreachable];
++     }
++ 
++     bb6: {
++         StorageDead(_20);
++         StorageLive(_22);
++         StorageLive(_23);
++         StorageLive(_24);
++         _24 = _31;
++         _23 = move _24;
++         _22 = &mut (*_23);
++         StorageDead(_24);
++         _18 = <std::future::Ready<()> as Future>::poll(move _19, move _22) -> [return: bb7, unwind unreachable];
++     }
++ 
++     bb7: {
++         StorageDead(_22);
++         StorageDead(_19);
++         _25 = discriminant(_18);
++         switchInt(move _25) -> [0: bb10, 1: bb9, otherwise: bb8];
++     }
++ 
++     bb8: {
++         unreachable;
++     }
++ 
++     bb9: {
++         _17 = const ();
++         StorageDead(_23);
++         StorageDead(_21);
++         StorageDead(_18);
++         StorageDead(_17);
++         StorageLive(_28);
++         StorageLive(_29);
++         _29 = ();
++         _7 = Poll::<()>::Pending;
++         StorageDead(_12);
++         StorageDead(_28);
++         StorageDead(_29);
++         _38 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         discriminant((*_38)) = 3;
++         goto -> bb2;
++     }
++ 
++     bb10: {
++         StorageLive(_26);
++         _26 = ((_18 as Ready).0: ());
++         _30 = _26;
++         StorageDead(_26);
++         StorageDead(_23);
++         StorageDead(_21);
++         StorageDead(_18);
++         StorageDead(_17);
++         StorageDead(_12);
++         _39 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         drop((((*_39) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb11, unwind unreachable];
++     }
++ 
++     bb11: {
++         _7 = Poll::<()>::Ready(move _30);
++         _40 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         discriminant((*_40)) = 1;
++         goto -> bb2;
++     }
++ 
++     bb12: {
++         StorageLive(_12);
++         StorageLive(_28);
++         StorageLive(_29);
++         _28 = move _9;
++         StorageDead(_29);
++         _31 = move _28;
++         StorageDead(_28);
++         _16 = const ();
++         goto -> bb5;
++     }
++ 
++     bb13: {
++         assert(const false, "`async fn` resumed after completion") -> [success: bb13, unwind unreachable];
+      }
+  }
+  
diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff
new file mode 100644
index 00000000000..ed18c0a3adb
--- /dev/null
+++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff
@@ -0,0 +1,341 @@
+- // MIR for `run2::{closure#0}` before Inline
++ // MIR for `run2::{closure#0}` after Inline
+  
+  fn run2::{closure#0}(_1: {closure@$DIR/inline_coroutine_body.rs:13:9: 13:11}) -> () {
+      debug permit => (_1.0: ActionPermit<'_, T>);
+      debug ctx => (*(_1.1: &mut std::task::Context<'_>));
+      let mut _0: ();
+      let mut _2: {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
+      let mut _3: ActionPermit<'_, T>;
+      let mut _5: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
+      let _6: ();
+      let mut _7: std::task::Poll<()>;
+      let mut _8: std::pin::Pin<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>;
+      let mut _9: &mut std::task::Context<'_>;
+      let mut _10: &mut std::task::Context<'_>;
+      scope 1 {
+          debug fut => _2;
+          let _4: std::pin::Pin<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>;
+          scope 2 {
+              debug fut => _4;
+              scope 4 {
+              }
++             scope 7 (inlined ActionPermit::<'_, T>::perform::{closure#0}) {
++                 debug _task_context => _31;
++                 debug self => ((*(_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6})).0: ActionPermit<'_, T>);
++                 let _11: ActionPermit<'_, T>;
++                 let mut _12: std::future::Ready<()>;
++                 let mut _13: std::future::Ready<()>;
++                 let mut _14: ();
++                 let mut _16: ();
++                 let _17: ();
++                 let mut _18: std::task::Poll<()>;
++                 let mut _19: std::pin::Pin<&mut std::future::Ready<()>>;
++                 let mut _20: &mut std::future::Ready<()>;
++                 let mut _21: &mut std::future::Ready<()>;
++                 let mut _22: &mut std::task::Context<'_>;
++                 let mut _23: &mut std::task::Context<'_>;
++                 let mut _24: &mut std::task::Context<'_>;
++                 let mut _25: isize;
++                 let mut _27: !;
++                 let mut _28: &mut std::task::Context<'_>;
++                 let mut _29: ();
++                 let mut _30: ();
++                 let mut _31: &mut std::task::Context<'_>;
++                 let mut _32: u32;
++                 let mut _33: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _34: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _35: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _36: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _37: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _38: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _39: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _40: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _41: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 let mut _42: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6};
++                 scope 8 {
++                     debug self => (((*(_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6})) as variant#3).0: ActionPermit<'_, T>);
++                     let mut _15: std::future::Ready<()>;
++                     scope 9 {
++                         debug __awaitee => (((*(_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6})) as variant#3).1: std::future::Ready<()>);
++                         let _26: ();
++                         scope 10 {
++                         }
++                         scope 11 {
++                             debug result => _26;
++                         }
++                     }
++                     scope 12 (inlined ready::<()>) {
++                         debug t => _14;
++                         let mut _43: std::option::Option<()>;
++                     }
++                 }
++             }
+          }
+          scope 3 {
++             scope 6 (inlined Pin::<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>::new_unchecked) {
++                 debug pointer => _5;
++             }
+          }
+      }
++     scope 5 (inlined ActionPermit::<'_, T>::perform) {
++         debug self => _3;
++     }
+  
+      bb0: {
+          StorageLive(_2);
+          StorageLive(_3);
+          _3 = move (_1.0: ActionPermit<'_, T>);
+-         _2 = ActionPermit::<'_, T>::perform(move _3) -> [return: bb1, unwind: bb6];
+-     }
+- 
+-     bb1: {
++         _2 = {coroutine@$DIR/inline_coroutine_body.rs:25:28: 27:6 (#0)} { self: move _3 };
+          StorageDead(_3);
+          StorageLive(_4);
+          StorageLive(_5);
+          _5 = &mut _2;
+-         _4 = Pin::<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}>::new_unchecked(move _5) -> [return: bb2, unwind: bb5];
+-     }
+- 
+-     bb2: {
++         _4 = Pin::<&mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6}> { __pointer: _5 };
+          StorageDead(_5);
+          StorageLive(_6);
+          StorageLive(_7);
+          StorageLive(_8);
+          _8 = move _4;
+          StorageLive(_9);
+          _10 = deref_copy (_1.1: &mut std::task::Context<'_>);
+          _9 = &mut (*_10);
+-         _7 = <{async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6} as Future>::poll(move _8, move _9) -> [return: bb3, unwind: bb5];
++         StorageLive(_11);
++         StorageLive(_15);
++         StorageLive(_16);
++         StorageLive(_25);
++         StorageLive(_27);
++         StorageLive(_30);
++         StorageLive(_31);
++         StorageLive(_32);
++         StorageLive(_33);
++         StorageLive(_34);
++         StorageLive(_35);
++         StorageLive(_36);
++         StorageLive(_37);
++         StorageLive(_38);
++         StorageLive(_39);
++         StorageLive(_40);
++         StorageLive(_41);
++         StorageLive(_42);
++         _33 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         _32 = discriminant((*_33));
++         switchInt(move _32) -> [0: bb5, 1: bb22, 2: bb21, 3: bb20, otherwise: bb10];
+      }
+  
+-     bb3: {
++     bb1: {
++         StorageDead(_2);
++         return;
++     }
++ 
++     bb2 (cleanup): {
++         drop(_2) -> [return: bb3, unwind terminate(cleanup)];
++     }
++ 
++     bb3 (cleanup): {
++         resume;
++     }
++ 
++     bb4: {
++         StorageDead(_42);
++         StorageDead(_41);
++         StorageDead(_40);
++         StorageDead(_39);
++         StorageDead(_38);
++         StorageDead(_37);
++         StorageDead(_36);
++         StorageDead(_35);
++         StorageDead(_34);
++         StorageDead(_33);
++         StorageDead(_32);
++         StorageDead(_31);
++         StorageDead(_30);
++         StorageDead(_27);
++         StorageDead(_25);
++         StorageDead(_16);
++         StorageDead(_15);
++         StorageDead(_11);
+          StorageDead(_9);
+          StorageDead(_8);
+          StorageDead(_7);
+          _6 = const ();
+          StorageDead(_6);
+          _0 = const ();
+          StorageDead(_4);
+-         drop(_2) -> [return: bb4, unwind: bb6];
++         drop(_2) -> [return: bb1, unwind: bb3];
+      }
+  
+-     bb4: {
+-         StorageDead(_2);
+-         return;
++     bb5: {
++         _31 = move _9;
++         _34 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         _35 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         (((*_34) as variant#3).0: ActionPermit<'_, T>) = move ((*_35).0: ActionPermit<'_, T>);
++         StorageLive(_12);
++         StorageLive(_13);
++         StorageLive(_14);
++         _14 = ();
++         StorageLive(_43);
++         _43 = Option::<()>::Some(_14);
++         _13 = std::future::Ready::<()>(move _43);
++         StorageDead(_43);
++         StorageDead(_14);
++         _12 = <std::future::Ready<()> as IntoFuture>::into_future(move _13) -> [return: bb6, unwind: bb17];
+      }
+  
+-     bb5 (cleanup): {
+-         drop(_2) -> [return: bb6, unwind terminate(cleanup)];
++     bb6: {
++         StorageDead(_13);
++         _36 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         (((*_36) as variant#3).1: std::future::Ready<()>) = move _12;
++         goto -> bb7;
+      }
+  
+-     bb6 (cleanup): {
+-         resume;
++     bb7: {
++         StorageLive(_17);
++         StorageLive(_18);
++         StorageLive(_19);
++         StorageLive(_20);
++         StorageLive(_21);
++         _37 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         _21 = &mut (((*_37) as variant#3).1: std::future::Ready<()>);
++         _20 = &mut (*_21);
++         _19 = Pin::<&mut std::future::Ready<()>>::new_unchecked(move _20) -> [return: bb8, unwind: bb15];
++     }
++ 
++     bb8: {
++         StorageDead(_20);
++         StorageLive(_22);
++         StorageLive(_23);
++         StorageLive(_24);
++         _24 = _31;
++         _23 = move _24;
++         _22 = &mut (*_23);
++         StorageDead(_24);
++         _18 = <std::future::Ready<()> as Future>::poll(move _19, move _22) -> [return: bb9, unwind: bb14];
++     }
++ 
++     bb9: {
++         StorageDead(_22);
++         StorageDead(_19);
++         _25 = discriminant(_18);
++         switchInt(move _25) -> [0: bb12, 1: bb11, otherwise: bb10];
++     }
++ 
++     bb10: {
++         unreachable;
++     }
++ 
++     bb11: {
++         _17 = const ();
++         StorageDead(_23);
++         StorageDead(_21);
++         StorageDead(_18);
++         StorageDead(_17);
++         StorageLive(_28);
++         StorageLive(_29);
++         _29 = ();
++         _7 = Poll::<()>::Pending;
++         StorageDead(_12);
++         StorageDead(_28);
++         StorageDead(_29);
++         _38 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         discriminant((*_38)) = 3;
++         goto -> bb4;
++     }
++ 
++     bb12: {
++         StorageLive(_26);
++         _26 = ((_18 as Ready).0: ());
++         _30 = _26;
++         StorageDead(_26);
++         StorageDead(_23);
++         StorageDead(_21);
++         StorageDead(_18);
++         StorageDead(_17);
++         StorageDead(_12);
++         _39 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         drop((((*_39) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb13, unwind: bb19];
++     }
++ 
++     bb13: {
++         _7 = Poll::<()>::Ready(move _30);
++         _40 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         discriminant((*_40)) = 1;
++         goto -> bb4;
++     }
++ 
++     bb14 (cleanup): {
++         StorageDead(_22);
++         StorageDead(_19);
++         StorageDead(_23);
++         goto -> bb16;
++     }
++ 
++     bb15 (cleanup): {
++         StorageDead(_20);
++         StorageDead(_19);
++         goto -> bb16;
++     }
++ 
++     bb16 (cleanup): {
++         StorageDead(_21);
++         StorageDead(_18);
++         StorageDead(_17);
++         goto -> bb18;
++     }
++ 
++     bb17 (cleanup): {
++         StorageDead(_13);
++         goto -> bb18;
++     }
++ 
++     bb18 (cleanup): {
++         StorageDead(_12);
++         _41 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         drop((((*_41) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb19, unwind terminate(cleanup)];
++     }
++ 
++     bb19 (cleanup): {
++         _42 = deref_copy (_8.0: &mut {async fn body@$DIR/inline_coroutine_body.rs:25:28: 27:6});
++         discriminant((*_42)) = 2;
++         goto -> bb2;
++     }
++ 
++     bb20: {
++         StorageLive(_12);
++         StorageLive(_28);
++         StorageLive(_29);
++         _28 = move _9;
++         StorageDead(_29);
++         _31 = move _28;
++         StorageDead(_28);
++         _16 = const ();
++         goto -> bb7;
++     }
++ 
++     bb21: {
++         assert(const false, "`async fn` resumed after panicking") -> [success: bb21, unwind: bb2];
++     }
++ 
++     bb22: {
++         assert(const false, "`async fn` resumed after completion") -> [success: bb22, unwind: bb2];
+      }
+  }
+  
diff --git a/tests/mir-opt/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff b/tests/mir-opt/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff
new file mode 100644
index 00000000000..ff65ca77039
--- /dev/null
+++ b/tests/mir-opt/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff
@@ -0,0 +1,56 @@
+- // MIR for `main` before CleanupPostBorrowck
++ // MIR for `main` after CleanupPostBorrowck
+  
+  fn main() -> () {
+      let mut _0: ();
+      let mut _1: bool;
+  
+      coverage branch { true: BlockMarkerId(0), false: BlockMarkerId(1) } => /the/src/instrument_coverage_cleanup.rs:15:8: 15:36 (#0)
+  
+      coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Subtract, rhs: Counter(1) };
+      coverage ExpressionId(1) => Expression { lhs: Counter(1), op: Add, rhs: Expression(0) };
+      coverage Code(Counter(0)) => /the/src/instrument_coverage_cleanup.rs:14:1 - 15:36;
+      coverage Code(Expression(0)) => /the/src/instrument_coverage_cleanup.rs:15:37 - 15:39;
+      coverage Code(Counter(1)) => /the/src/instrument_coverage_cleanup.rs:15:39 - 15:40;
+      coverage Code(Expression(1)) => /the/src/instrument_coverage_cleanup.rs:16:1 - 16:2;
+      coverage Branch { true_term: Expression(0), false_term: Counter(1) } => /the/src/instrument_coverage_cleanup.rs:15:8 - 15:36;
+  
+      bb0: {
+          Coverage::CounterIncrement(0);
+-         Coverage::SpanMarker;
++         nop;
+          StorageLive(_1);
+          _1 = std::hint::black_box::<bool>(const true) -> [return: bb1, unwind: bb5];
+      }
+  
+      bb1: {
+          switchInt(move _1) -> [0: bb3, otherwise: bb2];
+      }
+  
+      bb2: {
+          Coverage::CounterIncrement(1);
+-         Coverage::BlockMarker(1);
++         nop;
+          _0 = const ();
+          goto -> bb4;
+      }
+  
+      bb3: {
+          Coverage::ExpressionUsed(0);
+-         Coverage::BlockMarker(0);
++         nop;
+          _0 = const ();
+          goto -> bb4;
+      }
+  
+      bb4: {
+          Coverage::ExpressionUsed(1);
+          StorageDead(_1);
+          return;
+      }
+  
+      bb5 (cleanup): {
+          resume;
+      }
+  }
+  
diff --git a/tests/mir-opt/instrument_coverage_cleanup.main.InstrumentCoverage.diff b/tests/mir-opt/instrument_coverage_cleanup.main.InstrumentCoverage.diff
new file mode 100644
index 00000000000..8757559149a
--- /dev/null
+++ b/tests/mir-opt/instrument_coverage_cleanup.main.InstrumentCoverage.diff
@@ -0,0 +1,53 @@
+- // MIR for `main` before InstrumentCoverage
++ // MIR for `main` after InstrumentCoverage
+  
+  fn main() -> () {
+      let mut _0: ();
+      let mut _1: bool;
+  
+      coverage branch { true: BlockMarkerId(0), false: BlockMarkerId(1) } => /the/src/instrument_coverage_cleanup.rs:15:8: 15:36 (#0)
+  
++     coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Subtract, rhs: Counter(1) };
++     coverage ExpressionId(1) => Expression { lhs: Counter(1), op: Add, rhs: Expression(0) };
++     coverage Code(Counter(0)) => /the/src/instrument_coverage_cleanup.rs:14:1 - 15:36;
++     coverage Code(Expression(0)) => /the/src/instrument_coverage_cleanup.rs:15:37 - 15:39;
++     coverage Code(Counter(1)) => /the/src/instrument_coverage_cleanup.rs:15:39 - 15:40;
++     coverage Code(Expression(1)) => /the/src/instrument_coverage_cleanup.rs:16:1 - 16:2;
++     coverage Branch { true_term: Expression(0), false_term: Counter(1) } => /the/src/instrument_coverage_cleanup.rs:15:8 - 15:36;
++ 
+      bb0: {
++         Coverage::CounterIncrement(0);
+          Coverage::SpanMarker;
+          StorageLive(_1);
+          _1 = std::hint::black_box::<bool>(const true) -> [return: bb1, unwind: bb5];
+      }
+  
+      bb1: {
+          switchInt(move _1) -> [0: bb3, otherwise: bb2];
+      }
+  
+      bb2: {
++         Coverage::CounterIncrement(1);
+          Coverage::BlockMarker(1);
+          _0 = const ();
+          goto -> bb4;
+      }
+  
+      bb3: {
++         Coverage::ExpressionUsed(0);
+          Coverage::BlockMarker(0);
+          _0 = const ();
+          goto -> bb4;
+      }
+  
+      bb4: {
++         Coverage::ExpressionUsed(1);
+          StorageDead(_1);
+          return;
+      }
+  
+      bb5 (cleanup): {
+          resume;
+      }
+  }
+  
diff --git a/tests/mir-opt/instrument_coverage_cleanup.rs b/tests/mir-opt/instrument_coverage_cleanup.rs
new file mode 100644
index 00000000000..8a2fd67139b
--- /dev/null
+++ b/tests/mir-opt/instrument_coverage_cleanup.rs
@@ -0,0 +1,22 @@
+// Test that CleanupPostBorrowck cleans up the marker statements that are
+// inserted during MIR building (after InstrumentCoverage is done with them),
+// but leaves the statements that were added by InstrumentCoverage.
+//
+// Removed statement kinds: BlockMarker, SpanMarker
+// Retained statement kinds: CounterIncrement, ExpressionUsed
+
+//@ unit-test: InstrumentCoverage
+//@ compile-flags: -Cinstrument-coverage -Zcoverage-options=branch -Zno-profiler-runtime
+//@ compile-flags: --remap-path-prefix={{src-base}}=/the/src
+
+// EMIT_MIR instrument_coverage_cleanup.main.InstrumentCoverage.diff
+// EMIT_MIR instrument_coverage_cleanup.main.CleanupPostBorrowck.diff
+fn main() {
+    if !core::hint::black_box(true) {}
+}
+
+// CHECK-NOT: Coverage::BlockMarker
+// CHECK-NOT: Coverage::SpanMarker
+// CHECK:     Coverage::CounterIncrement
+// CHECK-NOT: Coverage::BlockMarker
+// CHECK-NOT: Coverage::SpanMarker
diff --git a/tests/mir-opt/pre-codegen/duplicate_switch_targets.rs b/tests/mir-opt/pre-codegen/duplicate_switch_targets.rs
index 67540676f4a..561bafa9651 100644
--- a/tests/mir-opt/pre-codegen/duplicate_switch_targets.rs
+++ b/tests/mir-opt/pre-codegen/duplicate_switch_targets.rs
@@ -1,6 +1,5 @@
 // skip-filecheck
 //@ compile-flags: -O -Zmir-opt-level=2 -Cdebuginfo=0
-//@ ignore-debug: standard library debug assertions add a panic that breaks this optimization
 
 #![crate_type = "lib"]
 
diff --git a/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir
index 0597e453e22..455e4ba7244 100644
--- a/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/duplicate_switch_targets.ub_if_b.PreCodegen.after.mir
@@ -9,6 +9,10 @@ fn ub_if_b(_1: Thing) -> Thing {
         let _4: ();
         scope 2 {
         }
+        scope 3 (inlined core::ub_checks::check_language_ub) {
+            scope 4 (inlined core::ub_checks::check_language_ub::runtime) {
+            }
+        }
     }
 
     bb0: {
@@ -23,7 +27,7 @@ fn ub_if_b(_1: Thing) -> Thing {
 
     bb2: {
         StorageLive(_3);
-        _3 = UbCheck(LanguageUb);
+        _3 = UbChecks();
         assume(_3);
         _4 = unreachable_unchecked::precondition_check() -> [return: bb3, unwind unreachable];
     }
diff --git a/tests/mir-opt/pre-codegen/mem_replace.rs b/tests/mir-opt/pre-codegen/mem_replace.rs
index 9cb3a839956..a68fe31f609 100644
--- a/tests/mir-opt/pre-codegen/mem_replace.rs
+++ b/tests/mir-opt/pre-codegen/mem_replace.rs
@@ -1,6 +1,6 @@
 // skip-filecheck
 //@ compile-flags: -O -C debuginfo=0 -Zmir-opt-level=2 -Zinline-mir
-//@ ignore-debug the standard library debug assertions leak into this test
+//@ ignore-debug: precondition checks on ptr::read/write are under cfg(debug_assertions)
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
 #![crate_type = "lib"]
diff --git a/tests/mir-opt/pre-codegen/slice_index.rs b/tests/mir-opt/pre-codegen/slice_index.rs
index 1d977ee9214..c9dd72d8be2 100644
--- a/tests/mir-opt/pre-codegen/slice_index.rs
+++ b/tests/mir-opt/pre-codegen/slice_index.rs
@@ -1,6 +1,5 @@
 // skip-filecheck
 //@ compile-flags: -O -C debuginfo=0 -Zmir-opt-level=2
-//@ ignore-debug the standard library debug assertions leak into this test
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
 #![crate_type = "lib"]
diff --git a/tests/mir-opt/pre-codegen/slice_iter.rs b/tests/mir-opt/pre-codegen/slice_iter.rs
index 0fbd3706544..86f37ca4d13 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.rs
+++ b/tests/mir-opt/pre-codegen/slice_iter.rs
@@ -1,6 +1,5 @@
 // skip-filecheck
 //@ compile-flags: -O -C debuginfo=0 -Zmir-opt-level=2
-//@ ignore-debug the standard library debug assertions leak into this test
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
 #![crate_type = "lib"]
diff --git a/tests/pretty/postfix-match.rs b/tests/pretty/postfix-match.rs
new file mode 100644
index 00000000000..5bb54e15275
--- /dev/null
+++ b/tests/pretty/postfix-match.rs
@@ -0,0 +1,21 @@
+#![feature(postfix_match)]
+
+fn main() {
+    let val = Some(42);
+
+    val.match {
+        Some(_) => 2,
+        _ => 1
+    };
+
+
+    Some(2).match {
+        Some(_) => true,
+        None => false
+    }.match {
+        false => "ferris is cute",
+        true => "I turn cats in to petted cats",
+    }.match {
+        _ => (),
+    }
+}
diff --git a/tests/run-make-fulldeps/obtain-borrowck/driver.rs b/tests/run-make-fulldeps/obtain-borrowck/driver.rs
index 2e3bf70e144..e67ec8690f8 100644
--- a/tests/run-make-fulldeps/obtain-borrowck/driver.rs
+++ b/tests/run-make-fulldeps/obtain-borrowck/driver.rs
@@ -68,7 +68,7 @@ impl rustc_driver::Callbacks for CompilerCalls {
             let mut bodies = Vec::new();
 
             let crate_items = tcx.hir_crate_items(());
-            for id in crate_items.items() {
+            for id in crate_items.free_items() {
                 if matches!(tcx.def_kind(id.owner_id), DefKind::Fn) {
                     bodies.push(id.owner_id);
                 }
diff --git a/tests/run-make/compiler-builtins/rmake.rs b/tests/run-make/compiler-builtins/rmake.rs
new file mode 100644
index 00000000000..e7a5e8addbe
--- /dev/null
+++ b/tests/run-make/compiler-builtins/rmake.rs
@@ -0,0 +1,142 @@
+//! The compiler_builtins library is special. It can call functions in core, but it must not
+//! require linkage against a build of core. If it ever does, building the standard library *may*
+//! result in linker errors, depending on whether the linker in use applies optimizations first or
+//! resolves symbols first. So the portable and safe approach is to forbid such a linkage
+//! requirement entirely.
+//!
+//! In addition, whether compiler_builtins requires linkage against core can depend on optimization
+//! settings. Turning off optimizations and enabling debug assertions tends to produce the most
+//! dependence on core that is possible, so that is the configuration we test here.
+
+#![deny(warnings)]
+
+extern crate run_make_support;
+
+use run_make_support::object;
+use run_make_support::object::read::archive::ArchiveFile;
+use run_make_support::object::read::Object;
+use run_make_support::object::ObjectSection;
+use run_make_support::object::ObjectSymbol;
+use run_make_support::object::RelocationTarget;
+use run_make_support::out_dir;
+use std::collections::HashSet;
+
+const MANIFEST: &str = r#"
+[package]
+name = "scratch"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+path = "lib.rs""#;
+
+fn main() {
+    let target_dir = out_dir().join("target");
+    let target = std::env::var("TARGET").unwrap();
+    if target.starts_with("wasm") || target.starts_with("nvptx") {
+        // wasm and nvptx targets don't produce rlib files that object can parse.
+        return;
+    }
+
+    println!("Testing compiler_builtins for {}", target);
+
+    // Set up the tiniest Cargo project: An empty no_std library. Just enough to run -Zbuild-std.
+    let manifest_path = out_dir().join("Cargo.toml");
+    std::fs::write(&manifest_path, MANIFEST.as_bytes()).unwrap();
+    std::fs::write(out_dir().join("lib.rs"), b"#![no_std]").unwrap();
+
+    let path = std::env::var("PATH").unwrap();
+    let rustc = std::env::var("RUSTC").unwrap();
+    let bootstrap_cargo = std::env::var("BOOTSTRAP_CARGO").unwrap();
+    let status = std::process::Command::new(bootstrap_cargo)
+        .args([
+            "build",
+            "--manifest-path",
+            manifest_path.to_str().unwrap(),
+            "-Zbuild-std=core",
+            "--target",
+            &target,
+        ])
+        .env_clear()
+        .env("PATH", path)
+        .env("RUSTC", rustc)
+        .env("RUSTFLAGS", "-Copt-level=0 -Cdebug-assertions=yes")
+        .env("CARGO_TARGET_DIR", &target_dir)
+        .env("RUSTC_BOOTSTRAP", "1")
+        .status()
+        .unwrap();
+
+    assert!(status.success());
+
+    let rlibs_path = target_dir.join(target).join("debug").join("deps");
+    let compiler_builtins_rlib = std::fs::read_dir(rlibs_path)
+        .unwrap()
+        .find_map(|e| {
+            let path = e.unwrap().path();
+            let file_name = path.file_name().unwrap().to_str().unwrap();
+            if file_name.starts_with("libcompiler_builtins") && file_name.ends_with(".rlib") {
+                Some(path)
+            } else {
+                None
+            }
+        })
+        .unwrap();
+
+    // rlib files are archives, where the archive members each a CGU, and we also have one called
+    // lib.rmeta which is the encoded metadata. Each of the CGUs is an object file.
+    let data = std::fs::read(compiler_builtins_rlib).unwrap();
+
+    let mut defined_symbols = HashSet::new();
+    let mut undefined_relocations = HashSet::new();
+
+    let archive = ArchiveFile::parse(&*data).unwrap();
+    for member in archive.members() {
+        let member = member.unwrap();
+        if member.name() == b"lib.rmeta" {
+            continue;
+        }
+        let data = member.data(&*data).unwrap();
+        let object = object::File::parse(&*data).unwrap();
+
+        // Record all defined symbols in this CGU.
+        for symbol in object.symbols() {
+            if !symbol.is_undefined() {
+                let name = symbol.name().unwrap();
+                defined_symbols.insert(name);
+            }
+        }
+
+        // Find any relocations against undefined symbols. Calls within this CGU are relocations
+        // against a defined symbol.
+        for (_offset, relocation) in object.sections().flat_map(|section| section.relocations()) {
+            let RelocationTarget::Symbol(symbol_index) = relocation.target() else {
+                continue;
+            };
+            let symbol = object.symbol_by_index(symbol_index).unwrap();
+            if symbol.is_undefined() {
+                let name = symbol.name().unwrap();
+                undefined_relocations.insert(name);
+            }
+        }
+    }
+
+    // We can have symbols in the compiler_builtins rlib that are actually from core, if they were
+    // monomorphized in the compiler_builtins crate. This is totally fine, because though the call
+    // is to a function in core, it's resolved internally.
+    //
+    // It is normal to have relocations against symbols not defined in the rlib for things like
+    // unwinding, or math functions provided the target's platform libraries. Finding these is not
+    // a problem, we want to specifically ban relocations against core which are not resolved
+    // internally.
+    undefined_relocations
+        .retain(|symbol| !defined_symbols.contains(symbol) && symbol.contains("core"));
+
+    if !undefined_relocations.is_empty() {
+        panic!(
+            "compiler_builtins must not link against core, but it does. \n\
+            These symbols may be undefined in a debug build of compiler_builtins:\n\
+            {:?}",
+            undefined_relocations
+        );
+    }
+}
diff --git a/tests/run-make/rustdoc-test-args/foo.rs b/tests/run-make/rustdoc-test-args/foo.rs
new file mode 100644
index 00000000000..51d17849fd7
--- /dev/null
+++ b/tests/run-make/rustdoc-test-args/foo.rs
@@ -0,0 +1,3 @@
+//! ```
+//! let x = 12;
+//! ```
diff --git a/tests/run-make/rustdoc-test-args/rmake.rs b/tests/run-make/rustdoc-test-args/rmake.rs
new file mode 100644
index 00000000000..808d13928eb
--- /dev/null
+++ b/tests/run-make/rustdoc-test-args/rmake.rs
@@ -0,0 +1,18 @@
+extern crate run_make_support;
+
+use run_make_support::{out_dir, rustdoc};
+use std::{fs, iter};
+use std::path::Path;
+
+fn generate_a_lot_of_cfgs(path: &Path) {
+    let content = iter::repeat("--cfg=a\n").take(100_000).collect::<String>();
+    fs::write(path, content.as_bytes()).expect("failed to create args file");
+}
+
+fn main() {
+    let arg_file = out_dir().join("args");
+    generate_a_lot_of_cfgs(&arg_file);
+
+    let arg_file = format!("@{}", arg_file.display());
+    rustdoc().arg("--test").arg(&arg_file).arg("foo.rs").run();
+}
diff --git a/tests/rustdoc-ui/invalid_associated_const.rs b/tests/rustdoc-ui/invalid_associated_const.rs
index 6ab8c36f740..6f211a383a6 100644
--- a/tests/rustdoc-ui/invalid_associated_const.rs
+++ b/tests/rustdoc-ui/invalid_associated_const.rs
@@ -3,6 +3,7 @@
 trait T {
     type A: S<C<X = 0i32> = 34>;
     //~^ ERROR associated type bindings are not allowed here
+    //~| ERROR associated type bindings are not allowed here
 }
 
 trait S {
diff --git a/tests/rustdoc-ui/invalid_associated_const.stderr b/tests/rustdoc-ui/invalid_associated_const.stderr
index 9c6ae0f76c6..1eb6d2714e3 100644
--- a/tests/rustdoc-ui/invalid_associated_const.stderr
+++ b/tests/rustdoc-ui/invalid_associated_const.stderr
@@ -4,6 +4,14 @@ error[E0229]: associated type bindings are not allowed here
 LL |     type A: S<C<X = 0i32> = 34>;
    |                 ^^^^^^^^ associated type not allowed here
 
-error: aborting due to 1 previous error
+error[E0229]: associated type bindings are not allowed here
+  --> $DIR/invalid_associated_const.rs:4:17
+   |
+LL |     type A: S<C<X = 0i32> = 34>;
+   |                 ^^^^^^^^ associated type not allowed here
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0229`.
diff --git a/tests/rustdoc-ui/issue-102467.rs b/tests/rustdoc-ui/issue-102467.rs
index bff876e41d6..a27e6156979 100644
--- a/tests/rustdoc-ui/issue-102467.rs
+++ b/tests/rustdoc-ui/issue-102467.rs
@@ -6,6 +6,7 @@
 trait T {
     type A: S<C<X = 0i32> = 34>;
     //~^ ERROR associated type bindings are not allowed here
+    //~| ERROR associated type bindings are not allowed here
 }
 
 trait S {
diff --git a/tests/rustdoc-ui/issue-102467.stderr b/tests/rustdoc-ui/issue-102467.stderr
index 4a769f94cf2..f54a50a4e19 100644
--- a/tests/rustdoc-ui/issue-102467.stderr
+++ b/tests/rustdoc-ui/issue-102467.stderr
@@ -4,6 +4,14 @@ error[E0229]: associated type bindings are not allowed here
 LL |     type A: S<C<X = 0i32> = 34>;
    |                 ^^^^^^^^ associated type not allowed here
 
-error: aborting due to 1 previous error
+error[E0229]: associated type bindings are not allowed here
+  --> $DIR/issue-102467.rs:7:17
+   |
+LL |     type A: S<C<X = 0i32> = 34>;
+   |                 ^^^^^^^^ associated type not allowed here
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0229`.
diff --git a/tests/rustdoc-ui/issues/issue-96287.rs b/tests/rustdoc-ui/issues/issue-96287.rs
index 08cc7ef4c90..b490c2fc03f 100644
--- a/tests/rustdoc-ui/issues/issue-96287.rs
+++ b/tests/rustdoc-ui/issues/issue-96287.rs
@@ -6,6 +6,7 @@ pub trait TraitWithAssoc {
 
 pub type Foo<V> = impl Trait<V::Assoc>;
 //~^ ERROR
+//~| ERROR
 
 pub trait Trait<U> {}
 
diff --git a/tests/rustdoc-ui/issues/issue-96287.stderr b/tests/rustdoc-ui/issues/issue-96287.stderr
index 62d81534a98..9aba0332164 100644
--- a/tests/rustdoc-ui/issues/issue-96287.stderr
+++ b/tests/rustdoc-ui/issues/issue-96287.stderr
@@ -9,6 +9,18 @@ help: consider restricting type parameter `V`
 LL | pub type Foo<V: TraitWithAssoc> = impl Trait<V::Assoc>;
    |               ++++++++++++++++
 
-error: aborting due to 1 previous error
+error[E0220]: associated type `Assoc` not found for `V`
+  --> $DIR/issue-96287.rs:7:33
+   |
+LL | pub type Foo<V> = impl Trait<V::Assoc>;
+   |                                 ^^^^^ there is an associated type `Assoc` in the trait `TraitWithAssoc`
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: consider restricting type parameter `V`
+   |
+LL | pub type Foo<V: TraitWithAssoc> = impl Trait<V::Assoc>;
+   |               ++++++++++++++++
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0220`.
diff --git a/tests/ui/asm/aarch64/type-check-3.stderr b/tests/ui/asm/aarch64/type-check-3.stderr
index f710df2dcde..9e37bb4c203 100644
--- a/tests/ui/asm/aarch64/type-check-3.stderr
+++ b/tests/ui/asm/aarch64/type-check-3.stderr
@@ -4,8 +4,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(reg) 0u8);
    |               ^^           --- for this argument
    |
-   = help: use `{0:w}` to have the register formatted as `w0`
-   = help: or use `{0:x}` to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0` (for 32-bit values)
+   = help: or use `{0:x}` to keep the default formatting of `x0` (for 64-bit values)
    = note: `#[warn(asm_sub_register)]` on by default
 
 warning: formatting may not be suitable for sub-register argument
@@ -14,8 +14,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(reg) 0u16);
    |               ^^           ---- for this argument
    |
-   = help: use `{0:w}` to have the register formatted as `w0`
-   = help: or use `{0:x}` to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0` (for 32-bit values)
+   = help: or use `{0:x}` to keep the default formatting of `x0` (for 64-bit values)
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:52:15
@@ -23,8 +23,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(reg) 0i32);
    |               ^^           ---- for this argument
    |
-   = help: use `{0:w}` to have the register formatted as `w0`
-   = help: or use `{0:x}` to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0` (for 32-bit values)
+   = help: or use `{0:x}` to keep the default formatting of `x0` (for 64-bit values)
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:54:15
@@ -32,8 +32,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(reg) 0f32);
    |               ^^           ---- for this argument
    |
-   = help: use `{0:w}` to have the register formatted as `w0`
-   = help: or use `{0:x}` to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0` (for 32-bit values)
+   = help: or use `{0:x}` to keep the default formatting of `x0` (for 64-bit values)
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:57:15
@@ -41,8 +41,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(vreg) 0i16);
    |               ^^            ---- for this argument
    |
-   = help: use `{0:h}` to have the register formatted as `h0`
-   = help: or use `{0:v}` to keep the default formatting of `v0`
+   = help: use `{0:h}` to have the register formatted as `h0` (for 16-bit values)
+   = help: or use `{0:v}` to keep the default formatting of `v0` (for 128-bit values)
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:59:15
@@ -50,8 +50,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(vreg) 0f32);
    |               ^^            ---- for this argument
    |
-   = help: use `{0:s}` to have the register formatted as `s0`
-   = help: or use `{0:v}` to keep the default formatting of `v0`
+   = help: use `{0:s}` to have the register formatted as `s0` (for 32-bit values)
+   = help: or use `{0:v}` to keep the default formatting of `v0` (for 128-bit values)
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:61:15
@@ -59,8 +59,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(vreg) 0f64);
    |               ^^            ---- for this argument
    |
-   = help: use `{0:d}` to have the register formatted as `d0`
-   = help: or use `{0:v}` to keep the default formatting of `v0`
+   = help: use `{0:d}` to have the register formatted as `d0` (for 64-bit values)
+   = help: or use `{0:v}` to keep the default formatting of `v0` (for 128-bit values)
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:63:15
@@ -68,8 +68,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(vreg_low16) 0f64);
    |               ^^                  ---- for this argument
    |
-   = help: use `{0:d}` to have the register formatted as `d0`
-   = help: or use `{0:v}` to keep the default formatting of `v0`
+   = help: use `{0:d}` to have the register formatted as `d0` (for 64-bit values)
+   = help: or use `{0:v}` to keep the default formatting of `v0` (for 128-bit values)
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:66:15
@@ -77,8 +77,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{0} {0}", in(reg) 0i16);
    |               ^^^ ^^^           ---- for this argument
    |
-   = help: use `{0:w}` to have the register formatted as `w0`
-   = help: or use `{0:x}` to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0` (for 32-bit values)
+   = help: or use `{0:x}` to keep the default formatting of `x0` (for 64-bit values)
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:68:15
@@ -86,8 +86,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{0} {0:x}", in(reg) 0i16);
    |               ^^^                 ---- for this argument
    |
-   = help: use `{0:w}` to have the register formatted as `w0`
-   = help: or use `{0:x}` to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0` (for 32-bit values)
+   = help: or use `{0:x}` to keep the default formatting of `x0` (for 64-bit values)
 
 error: type `i128` cannot be used with this register class
   --> $DIR/type-check-3.rs:73:28
diff --git a/tests/ui/asm/bad-template.aarch64.stderr b/tests/ui/asm/bad-template.aarch64.stderr
index b18946d7c6d..5023cf317d7 100644
--- a/tests/ui/asm/bad-template.aarch64.stderr
+++ b/tests/ui/asm/bad-template.aarch64.stderr
@@ -194,8 +194,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{:foo}", in(reg) foo);
    |               ^^^^^^           --- for this argument
    |
-   = help: use `{0:w}` to have the register formatted as `w0`
-   = help: or use `{0:x}` to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0` (for 32-bit values)
+   = help: or use `{0:x}` to keep the default formatting of `x0` (for 64-bit values)
    = note: `#[warn(asm_sub_register)]` on by default
 
 error: aborting due to 21 previous errors; 1 warning emitted
diff --git a/tests/ui/asm/bad-template.x86_64.stderr b/tests/ui/asm/bad-template.x86_64.stderr
index 2f584c30a32..1b9775636f5 100644
--- a/tests/ui/asm/bad-template.x86_64.stderr
+++ b/tests/ui/asm/bad-template.x86_64.stderr
@@ -194,8 +194,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{:foo}", in(reg) foo);
    |               ^^^^^^           --- for this argument
    |
-   = help: use `{0:e}` to have the register formatted as `eax`
-   = help: or use `{0:r}` to keep the default formatting of `rax`
+   = help: use `{0:e}` to have the register formatted as `eax` (for 32-bit values)
+   = help: or use `{0:r}` to keep the default formatting of `rax` (for 64-bit values)
    = note: `#[warn(asm_sub_register)]` on by default
 
 error: aborting due to 21 previous errors; 1 warning emitted
diff --git a/tests/ui/asm/x86_64/type-check-3.stderr b/tests/ui/asm/x86_64/type-check-3.stderr
index 1baf50ff6e0..34bfcd71cac 100644
--- a/tests/ui/asm/x86_64/type-check-3.stderr
+++ b/tests/ui/asm/x86_64/type-check-3.stderr
@@ -44,8 +44,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{0} {0}", in(reg) 0i16);
    |               ^^^ ^^^           ---- for this argument
    |
-   = help: use `{0:x}` to have the register formatted as `ax`
-   = help: or use `{0:r}` to keep the default formatting of `rax`
+   = help: use `{0:x}` to have the register formatted as `ax` (for 16-bit values)
+   = help: or use `{0:r}` to keep the default formatting of `rax` (for 64-bit values)
    = note: `#[warn(asm_sub_register)]` on by default
 
 warning: formatting may not be suitable for sub-register argument
@@ -54,8 +54,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{0} {0:x}", in(reg) 0i16);
    |               ^^^                 ---- for this argument
    |
-   = help: use `{0:x}` to have the register formatted as `ax`
-   = help: or use `{0:r}` to keep the default formatting of `rax`
+   = help: use `{0:x}` to have the register formatted as `ax` (for 16-bit values)
+   = help: or use `{0:r}` to keep the default formatting of `rax` (for 64-bit values)
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:38:15
@@ -63,8 +63,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(reg) 0i32);
    |               ^^           ---- for this argument
    |
-   = help: use `{0:e}` to have the register formatted as `eax`
-   = help: or use `{0:r}` to keep the default formatting of `rax`
+   = help: use `{0:e}` to have the register formatted as `eax` (for 32-bit values)
+   = help: or use `{0:r}` to keep the default formatting of `rax` (for 64-bit values)
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:41:15
@@ -72,8 +72,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(ymm_reg) 0i64);
    |               ^^               ---- for this argument
    |
-   = help: use `{0:x}` to have the register formatted as `xmm0`
-   = help: or use `{0:y}` to keep the default formatting of `ymm0`
+   = help: use `{0:x}` to have the register formatted as `xmm0` (for 128-bit values)
+   = help: or use `{0:y}` to keep the default formatting of `ymm0` (for 256-bit values)
 
 error: type `i8` cannot be used with this register class
   --> $DIR/type-check-3.rs:52:28
diff --git a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs b/tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs
index aaf16181030..06fd0a024f0 100644
--- a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs
+++ b/tests/ui/associated-consts/assoc-const-eq-param-in-ty.rs
@@ -37,8 +37,19 @@ fn take2<P: Project<SELF = {}>>(_: P) {}
 
 trait Iface<'r> {
     //~^ NOTE the lifetime parameter `'r` is defined here
+    //~| NOTE the lifetime parameter `'r` is defined here
     type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
     //~^ ERROR the type of the associated constant `K` must not depend on generic parameters
+    //~| ERROR the type of the associated constant `K` must not depend on generic parameters
+    //~| NOTE its type must not depend on the lifetime parameter `'r`
+    //~| NOTE `K` has type `&'r [Self; Q]`
+    //~| ERROR the type of the associated constant `K` must not depend on `Self`
+    //~| NOTE its type must not depend on `Self`
+    //~| NOTE `K` has type `&'r [Self; Q]`
+    //~| ERROR the type of the associated constant `K` must not depend on generic parameters
+    //~| NOTE its type must not depend on the const parameter `Q`
+    //~| NOTE the const parameter `Q` is defined here
+    //~| NOTE `K` has type `&'r [Self; Q]`
     //~| NOTE its type must not depend on the lifetime parameter `'r`
     //~| NOTE `K` has type `&'r [Self; Q]`
     //~| ERROR the type of the associated constant `K` must not depend on `Self`
@@ -48,6 +59,9 @@ trait Iface<'r> {
     //~| NOTE its type must not depend on the const parameter `Q`
     //~| NOTE the const parameter `Q` is defined here
     //~| NOTE `K` has type `&'r [Self; Q]`
+    //~| NOTE duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+    //~| NOTE duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+    //~| NOTE duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
     where
         Self: Sized + 'r;
 }
diff --git a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr b/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr
index 077ac6e7f93..6b7b714fff1 100644
--- a/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr
+++ b/tests/ui/associated-consts/assoc-const-eq-param-in-ty.stderr
@@ -44,18 +44,18 @@ LL | fn take2<P: Project<SELF = {}>>(_: P) {}
    = note: `SELF` has type `P`
 
 error: the type of the associated constant `K` must not depend on generic parameters
-  --> $DIR/assoc-const-eq-param-in-ty.rs:40:52
+  --> $DIR/assoc-const-eq-param-in-ty.rs:41:52
    |
 LL | trait Iface<'r> {
    |             -- the lifetime parameter `'r` is defined here
-LL |
+...
 LL |     type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
    |                                                    ^ its type must not depend on the lifetime parameter `'r`
    |
    = note: `K` has type `&'r [Self; Q]`
 
 error: the type of the associated constant `K` must not depend on `Self`
-  --> $DIR/assoc-const-eq-param-in-ty.rs:40:52
+  --> $DIR/assoc-const-eq-param-in-ty.rs:41:52
    |
 LL |     type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
    |                                                    ^ its type must not depend on `Self`
@@ -63,7 +63,7 @@ LL |     type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
    = note: `K` has type `&'r [Self; Q]`
 
 error: the type of the associated constant `K` must not depend on generic parameters
-  --> $DIR/assoc-const-eq-param-in-ty.rs:40:52
+  --> $DIR/assoc-const-eq-param-in-ty.rs:41:52
    |
 LL |     type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
    |                      -                             ^ its type must not depend on the const parameter `Q`
@@ -72,5 +72,37 @@ LL |     type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
    |
    = note: `K` has type `&'r [Self; Q]`
 
-error: aborting due to 8 previous errors
+error: the type of the associated constant `K` must not depend on generic parameters
+  --> $DIR/assoc-const-eq-param-in-ty.rs:41:52
+   |
+LL | trait Iface<'r> {
+   |             -- the lifetime parameter `'r` is defined here
+...
+LL |     type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
+   |                                                    ^ its type must not depend on the lifetime parameter `'r`
+   |
+   = note: `K` has type `&'r [Self; Q]`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: the type of the associated constant `K` must not depend on `Self`
+  --> $DIR/assoc-const-eq-param-in-ty.rs:41:52
+   |
+LL |     type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
+   |                                                    ^ its type must not depend on `Self`
+   |
+   = note: `K` has type `&'r [Self; Q]`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: the type of the associated constant `K` must not depend on generic parameters
+  --> $DIR/assoc-const-eq-param-in-ty.rs:41:52
+   |
+LL |     type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
+   |                      -                             ^ its type must not depend on the const parameter `Q`
+   |                      |
+   |                      the const parameter `Q` is defined here
+   |
+   = note: `K` has type `&'r [Self; Q]`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 11 previous errors
 
diff --git a/tests/ui/associated-consts/issue-102335-const.rs b/tests/ui/associated-consts/issue-102335-const.rs
index f60cb92da7f..969c2c43b71 100644
--- a/tests/ui/associated-consts/issue-102335-const.rs
+++ b/tests/ui/associated-consts/issue-102335-const.rs
@@ -3,6 +3,7 @@
 trait T {
     type A: S<C<X = 0i32> = 34>;
     //~^ ERROR associated type bindings are not allowed here
+    //~| ERROR associated type bindings are not allowed here
 }
 
 trait S {
diff --git a/tests/ui/associated-consts/issue-102335-const.stderr b/tests/ui/associated-consts/issue-102335-const.stderr
index b69dfd51ea8..2a70425a3cc 100644
--- a/tests/ui/associated-consts/issue-102335-const.stderr
+++ b/tests/ui/associated-consts/issue-102335-const.stderr
@@ -4,6 +4,14 @@ error[E0229]: associated type bindings are not allowed here
 LL |     type A: S<C<X = 0i32> = 34>;
    |                 ^^^^^^^^ associated type not allowed here
 
-error: aborting due to 1 previous error
+error[E0229]: associated type bindings are not allowed here
+  --> $DIR/issue-102335-const.rs:4:17
+   |
+LL |     type A: S<C<X = 0i32> = 34>;
+   |                 ^^^^^^^^ associated type not allowed here
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0229`.
diff --git a/tests/ui/associated-inherent-types/issue-109299-1.rs b/tests/ui/associated-inherent-types/issue-109299-1.rs
index b86e2e31e06..4546785f0b1 100644
--- a/tests/ui/associated-inherent-types/issue-109299-1.rs
+++ b/tests/ui/associated-inherent-types/issue-109299-1.rs
@@ -7,7 +7,9 @@ impl Lexer<i32> {
     type Cursor = ();
 }
 
-type X = impl for<T> Fn() -> Lexer<T>::Cursor; //~ ERROR associated type `Cursor` not found for `Lexer<T>` in the current scope
-//~^ ERROR: unconstrained opaque type
+type X = impl for<T> Fn() -> Lexer<T>::Cursor;
+//~^ ERROR associated type `Cursor` not found for `Lexer<T>` in the current scope
+//~| ERROR associated type `Cursor` not found for `Lexer<T>` in the current scope
+//~| ERROR: unconstrained opaque type
 
 fn main() {}
diff --git a/tests/ui/associated-inherent-types/issue-109299-1.stderr b/tests/ui/associated-inherent-types/issue-109299-1.stderr
index 5848fa4087d..07a00b6b9a9 100644
--- a/tests/ui/associated-inherent-types/issue-109299-1.stderr
+++ b/tests/ui/associated-inherent-types/issue-109299-1.stderr
@@ -10,6 +10,19 @@ LL | type X = impl for<T> Fn() -> Lexer<T>::Cursor;
    = note: the associated type was found for
            - `Lexer<i32>`
 
+error[E0220]: associated type `Cursor` not found for `Lexer<T>` in the current scope
+  --> $DIR/issue-109299-1.rs:10:40
+   |
+LL | struct Lexer<T>(T);
+   | --------------- associated item `Cursor` not found for this struct
+...
+LL | type X = impl for<T> Fn() -> Lexer<T>::Cursor;
+   |                                        ^^^^^^ associated item not found in `Lexer<T>`
+   |
+   = note: the associated type was found for
+           - `Lexer<i32>`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
 error: unconstrained opaque type
   --> $DIR/issue-109299-1.rs:10:10
    |
@@ -18,6 +31,6 @@ LL | type X = impl for<T> Fn() -> Lexer<T>::Cursor;
    |
    = note: `X` must be used in combination with a concrete type within the same module
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0220`.
diff --git a/tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid-2.rs b/tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid-2.rs
new file mode 100644
index 00000000000..1768b006622
--- /dev/null
+++ b/tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid-2.rs
@@ -0,0 +1,18 @@
+trait Id {
+    type This: ?Sized;
+}
+impl<T: ?Sized> Id for T {
+    type This = T;
+}
+
+trait Trait {
+    type Assoc: Id<This: Copy>;
+}
+
+// We can't see use the `T::Assoc::This: Copy` bound to prove `T::Assoc: Copy`
+fn foo<T: Trait>(x: T::Assoc) -> (T::Assoc, T::Assoc) {
+    (x, x)
+    //~^ ERROR use of moved value
+}
+
+fn main() {}
diff --git a/tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid-2.stderr b/tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid-2.stderr
new file mode 100644
index 00000000000..cd0e026905c
--- /dev/null
+++ b/tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid-2.stderr
@@ -0,0 +1,13 @@
+error[E0382]: use of moved value: `x`
+  --> $DIR/cant-see-copy-bound-from-child-rigid-2.rs:14:9
+   |
+LL | fn foo<T: Trait>(x: T::Assoc) -> (T::Assoc, T::Assoc) {
+   |                  - move occurs because `x` has type `<T as Trait>::Assoc`, which does not implement the `Copy` trait
+LL |     (x, x)
+   |      -  ^ value used here after move
+   |      |
+   |      value moved here
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid.rs b/tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid.rs
new file mode 100644
index 00000000000..6b3fd7e898d
--- /dev/null
+++ b/tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid.rs
@@ -0,0 +1,18 @@
+trait Id {
+    type This: ?Sized;
+}
+
+trait Trait {
+    type Assoc: Id<This: Copy>;
+}
+
+// We can't see use the `T::Assoc::This: Copy` bound to prove `T::Assoc: Copy`
+fn foo<T: Trait>(x: T::Assoc) -> (T::Assoc, T::Assoc)
+where
+    T::Assoc: Id<This = T::Assoc>,
+{
+    (x, x)
+    //~^ ERROR use of moved value
+}
+
+fn main() {}
diff --git a/tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid.stderr b/tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid.stderr
new file mode 100644
index 00000000000..3ed73918de3
--- /dev/null
+++ b/tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid.stderr
@@ -0,0 +1,14 @@
+error[E0382]: use of moved value: `x`
+  --> $DIR/cant-see-copy-bound-from-child-rigid.rs:14:9
+   |
+LL | fn foo<T: Trait>(x: T::Assoc) -> (T::Assoc, T::Assoc)
+   |                  - move occurs because `x` has type `<T as Trait>::Assoc`, which does not implement the `Copy` trait
+...
+LL |     (x, x)
+   |      -  ^ value used here after move
+   |      |
+   |      value moved here
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/associated-type-bounds/dont-imply-atb-in-closure-inference.rs b/tests/ui/associated-type-bounds/dont-imply-atb-in-closure-inference.rs
new file mode 100644
index 00000000000..fecb3b15338
--- /dev/null
+++ b/tests/ui/associated-type-bounds/dont-imply-atb-in-closure-inference.rs
@@ -0,0 +1,21 @@
+//@ check-pass
+
+#![feature(type_alias_impl_trait)]
+
+trait IsPtr {
+    type Assoc;
+}
+impl<T> IsPtr for T {
+    type Assoc = fn(i32);
+}
+
+type Tait = impl IsPtr<Assoc: Fn(i32)> + Fn(u32);
+
+fn hello()
+where
+    Tait:,
+{
+    let _: Tait = |x| {};
+}
+
+fn main() {}
diff --git a/tests/ui/associated-type-bounds/duplicate.rs b/tests/ui/associated-type-bounds/duplicate.rs
index 06a1993da72..2b4a01376d7 100644
--- a/tests/ui/associated-type-bounds/duplicate.rs
+++ b/tests/ui/associated-type-bounds/duplicate.rs
@@ -132,16 +132,19 @@ where
 
 fn FRPIT1() -> impl Iterator<Item: Copy, Item: Send> {
     //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
+    //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
     iter::empty()
     //~^ ERROR type annotations needed
 }
 fn FRPIT2() -> impl Iterator<Item: Copy, Item: Copy> {
     //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
+    //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
     iter::empty()
     //~^ ERROR type annotations needed
 }
 fn FRPIT3() -> impl Iterator<Item: 'static, Item: 'static> {
     //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
+    //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
     iter::empty()
     //~^ ERROR type annotations needed
 }
@@ -182,10 +185,13 @@ type ETAI3<T: Iterator<Item: 'static, Item: 'static>> = impl Copy;
 //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
 type ETAI4 = impl Iterator<Item: Copy, Item: Send>;
 //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
+//~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
 type ETAI5 = impl Iterator<Item: Copy, Item: Copy>;
 //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
+//~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
 type ETAI6 = impl Iterator<Item: 'static, Item: 'static>;
 //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
+//~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
 
 trait TRI1<T: Iterator<Item: Copy, Item: Send>> {}
 //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
@@ -250,14 +256,17 @@ where
 trait TRA1 {
     type A: Iterator<Item: Copy, Item: Send>;
     //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
+    //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
 }
 trait TRA2 {
     type A: Iterator<Item: Copy, Item: Copy>;
     //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
+    //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
 }
 trait TRA3 {
     type A: Iterator<Item: 'static, Item: 'static>;
     //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
+    //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
 }
 
 fn main() {}
diff --git a/tests/ui/associated-type-bounds/duplicate.stderr b/tests/ui/associated-type-bounds/duplicate.stderr
index 2d298f0a013..cf4809991c3 100644
--- a/tests/ui/associated-type-bounds/duplicate.stderr
+++ b/tests/ui/associated-type-bounds/duplicate.stderr
@@ -198,8 +198,18 @@ LL | fn FRPIT1() -> impl Iterator<Item: Copy, Item: Send> {
    |                              |
    |                              `Item` bound here first
 
+error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
+  --> $DIR/duplicate.rs:133:42
+   |
+LL | fn FRPIT1() -> impl Iterator<Item: Copy, Item: Send> {
+   |                              ----------  ^^^^^^^^^^ re-bound here
+   |                              |
+   |                              `Item` bound here first
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
 error[E0282]: type annotations needed
-  --> $DIR/duplicate.rs:135:5
+  --> $DIR/duplicate.rs:136:5
    |
 LL |     iter::empty()
    |     ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty`
@@ -210,15 +220,25 @@ LL |     iter::empty::<T>()
    |                +++++
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:138:42
+  --> $DIR/duplicate.rs:139:42
+   |
+LL | fn FRPIT2() -> impl Iterator<Item: Copy, Item: Copy> {
+   |                              ----------  ^^^^^^^^^^ re-bound here
+   |                              |
+   |                              `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
+  --> $DIR/duplicate.rs:139:42
    |
 LL | fn FRPIT2() -> impl Iterator<Item: Copy, Item: Copy> {
    |                              ----------  ^^^^^^^^^^ re-bound here
    |                              |
    |                              `Item` bound here first
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0282]: type annotations needed
-  --> $DIR/duplicate.rs:140:5
+  --> $DIR/duplicate.rs:142:5
    |
 LL |     iter::empty()
    |     ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty`
@@ -229,15 +249,25 @@ LL |     iter::empty::<T>()
    |                +++++
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:143:45
+  --> $DIR/duplicate.rs:145:45
+   |
+LL | fn FRPIT3() -> impl Iterator<Item: 'static, Item: 'static> {
+   |                              -------------  ^^^^^^^^^^^^^ re-bound here
+   |                              |
+   |                              `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
+  --> $DIR/duplicate.rs:145:45
    |
 LL | fn FRPIT3() -> impl Iterator<Item: 'static, Item: 'static> {
    |                              -------------  ^^^^^^^^^^^^^ re-bound here
    |                              |
    |                              `Item` bound here first
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0282]: type annotations needed
-  --> $DIR/duplicate.rs:145:5
+  --> $DIR/duplicate.rs:148:5
    |
 LL |     iter::empty()
    |     ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty`
@@ -248,7 +278,7 @@ LL |     iter::empty::<T>()
    |                +++++
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:148:40
+  --> $DIR/duplicate.rs:151:40
    |
 LL | fn FAPIT1(_: impl Iterator<Item: Copy, Item: Send>) {}
    |                            ----------  ^^^^^^^^^^ re-bound here
@@ -256,7 +286,7 @@ LL | fn FAPIT1(_: impl Iterator<Item: Copy, Item: Send>) {}
    |                            `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:150:40
+  --> $DIR/duplicate.rs:153:40
    |
 LL | fn FAPIT2(_: impl Iterator<Item: Copy, Item: Copy>) {}
    |                            ----------  ^^^^^^^^^^ re-bound here
@@ -264,7 +294,7 @@ LL | fn FAPIT2(_: impl Iterator<Item: Copy, Item: Copy>) {}
    |                            `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:152:43
+  --> $DIR/duplicate.rs:155:43
    |
 LL | fn FAPIT3(_: impl Iterator<Item: 'static, Item: 'static>) {}
    |                            -------------  ^^^^^^^^^^^^^ re-bound here
@@ -272,7 +302,7 @@ LL | fn FAPIT3(_: impl Iterator<Item: 'static, Item: 'static>) {}
    |                            `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:155:35
+  --> $DIR/duplicate.rs:158:35
    |
 LL | type TAI1<T: Iterator<Item: Copy, Item: Send>> = T;
    |                       ----------  ^^^^^^^^^^ re-bound here
@@ -280,7 +310,7 @@ LL | type TAI1<T: Iterator<Item: Copy, Item: Send>> = T;
    |                       `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:157:35
+  --> $DIR/duplicate.rs:160:35
    |
 LL | type TAI2<T: Iterator<Item: Copy, Item: Copy>> = T;
    |                       ----------  ^^^^^^^^^^ re-bound here
@@ -288,7 +318,7 @@ LL | type TAI2<T: Iterator<Item: Copy, Item: Copy>> = T;
    |                       `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:159:38
+  --> $DIR/duplicate.rs:162:38
    |
 LL | type TAI3<T: Iterator<Item: 'static, Item: 'static>> = T;
    |                       -------------  ^^^^^^^^^^^^^ re-bound here
@@ -296,7 +326,7 @@ LL | type TAI3<T: Iterator<Item: 'static, Item: 'static>> = T;
    |                       `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:163:29
+  --> $DIR/duplicate.rs:166:29
    |
 LL |     T: Iterator<Item: Copy, Item: Send>,
    |                 ----------  ^^^^^^^^^^ re-bound here
@@ -304,7 +334,7 @@ LL |     T: Iterator<Item: Copy, Item: Send>,
    |                 `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:168:29
+  --> $DIR/duplicate.rs:171:29
    |
 LL |     T: Iterator<Item: Copy, Item: Copy>,
    |                 ----------  ^^^^^^^^^^ re-bound here
@@ -312,7 +342,7 @@ LL |     T: Iterator<Item: Copy, Item: Copy>,
    |                 `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:173:32
+  --> $DIR/duplicate.rs:176:32
    |
 LL |     T: Iterator<Item: 'static, Item: 'static>,
    |                 -------------  ^^^^^^^^^^^^^ re-bound here
@@ -320,7 +350,7 @@ LL |     T: Iterator<Item: 'static, Item: 'static>,
    |                 `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:177:36
+  --> $DIR/duplicate.rs:180:36
    |
 LL | type ETAI1<T: Iterator<Item: Copy, Item: Send>> = impl Copy;
    |                        ----------  ^^^^^^^^^^ re-bound here
@@ -328,7 +358,7 @@ LL | type ETAI1<T: Iterator<Item: Copy, Item: Send>> = impl Copy;
    |                        `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:179:36
+  --> $DIR/duplicate.rs:182:36
    |
 LL | type ETAI2<T: Iterator<Item: Copy, Item: Copy>> = impl Copy;
    |                        ----------  ^^^^^^^^^^ re-bound here
@@ -336,7 +366,7 @@ LL | type ETAI2<T: Iterator<Item: Copy, Item: Copy>> = impl Copy;
    |                        `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:181:39
+  --> $DIR/duplicate.rs:184:39
    |
 LL | type ETAI3<T: Iterator<Item: 'static, Item: 'static>> = impl Copy;
    |                        -------------  ^^^^^^^^^^^^^ re-bound here
@@ -344,23 +374,43 @@ LL | type ETAI3<T: Iterator<Item: 'static, Item: 'static>> = impl Copy;
    |                        `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:183:40
+  --> $DIR/duplicate.rs:186:40
+   |
+LL | type ETAI4 = impl Iterator<Item: Copy, Item: Send>;
+   |                            ----------  ^^^^^^^^^^ re-bound here
+   |                            |
+   |                            `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
+  --> $DIR/duplicate.rs:186:40
    |
 LL | type ETAI4 = impl Iterator<Item: Copy, Item: Send>;
    |                            ----------  ^^^^^^^^^^ re-bound here
    |                            |
    |                            `Item` bound here first
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
+  --> $DIR/duplicate.rs:189:40
+   |
+LL | type ETAI5 = impl Iterator<Item: Copy, Item: Copy>;
+   |                            ----------  ^^^^^^^^^^ re-bound here
+   |                            |
+   |                            `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:185:40
+  --> $DIR/duplicate.rs:189:40
    |
 LL | type ETAI5 = impl Iterator<Item: Copy, Item: Copy>;
    |                            ----------  ^^^^^^^^^^ re-bound here
    |                            |
    |                            `Item` bound here first
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:187:43
+  --> $DIR/duplicate.rs:192:43
    |
 LL | type ETAI6 = impl Iterator<Item: 'static, Item: 'static>;
    |                            -------------  ^^^^^^^^^^^^^ re-bound here
@@ -368,7 +418,17 @@ LL | type ETAI6 = impl Iterator<Item: 'static, Item: 'static>;
    |                            `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:190:36
+  --> $DIR/duplicate.rs:192:43
+   |
+LL | type ETAI6 = impl Iterator<Item: 'static, Item: 'static>;
+   |                            -------------  ^^^^^^^^^^^^^ re-bound here
+   |                            |
+   |                            `Item` bound here first
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
+  --> $DIR/duplicate.rs:196:36
    |
 LL | trait TRI1<T: Iterator<Item: Copy, Item: Send>> {}
    |                        ----------  ^^^^^^^^^^ re-bound here
@@ -376,7 +436,7 @@ LL | trait TRI1<T: Iterator<Item: Copy, Item: Send>> {}
    |                        `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:192:36
+  --> $DIR/duplicate.rs:198:36
    |
 LL | trait TRI2<T: Iterator<Item: Copy, Item: Copy>> {}
    |                        ----------  ^^^^^^^^^^ re-bound here
@@ -384,7 +444,7 @@ LL | trait TRI2<T: Iterator<Item: Copy, Item: Copy>> {}
    |                        `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:194:39
+  --> $DIR/duplicate.rs:200:39
    |
 LL | trait TRI3<T: Iterator<Item: 'static, Item: 'static>> {}
    |                        -------------  ^^^^^^^^^^^^^ re-bound here
@@ -392,7 +452,7 @@ LL | trait TRI3<T: Iterator<Item: 'static, Item: 'static>> {}
    |                        `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:196:34
+  --> $DIR/duplicate.rs:202:34
    |
 LL | trait TRS1: Iterator<Item: Copy, Item: Send> {}
    |                      ----------  ^^^^^^^^^^ re-bound here
@@ -400,7 +460,7 @@ LL | trait TRS1: Iterator<Item: Copy, Item: Send> {}
    |                      `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:196:34
+  --> $DIR/duplicate.rs:202:34
    |
 LL | trait TRS1: Iterator<Item: Copy, Item: Send> {}
    |                      ----------  ^^^^^^^^^^ re-bound here
@@ -410,7 +470,7 @@ LL | trait TRS1: Iterator<Item: Copy, Item: Send> {}
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:196:34
+  --> $DIR/duplicate.rs:202:34
    |
 LL | trait TRS1: Iterator<Item: Copy, Item: Send> {}
    |                      ----------  ^^^^^^^^^^ re-bound here
@@ -420,7 +480,7 @@ LL | trait TRS1: Iterator<Item: Copy, Item: Send> {}
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:200:34
+  --> $DIR/duplicate.rs:206:34
    |
 LL | trait TRS2: Iterator<Item: Copy, Item: Copy> {}
    |                      ----------  ^^^^^^^^^^ re-bound here
@@ -428,7 +488,7 @@ LL | trait TRS2: Iterator<Item: Copy, Item: Copy> {}
    |                      `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:200:34
+  --> $DIR/duplicate.rs:206:34
    |
 LL | trait TRS2: Iterator<Item: Copy, Item: Copy> {}
    |                      ----------  ^^^^^^^^^^ re-bound here
@@ -438,7 +498,7 @@ LL | trait TRS2: Iterator<Item: Copy, Item: Copy> {}
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:200:34
+  --> $DIR/duplicate.rs:206:34
    |
 LL | trait TRS2: Iterator<Item: Copy, Item: Copy> {}
    |                      ----------  ^^^^^^^^^^ re-bound here
@@ -448,7 +508,7 @@ LL | trait TRS2: Iterator<Item: Copy, Item: Copy> {}
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:204:37
+  --> $DIR/duplicate.rs:210:37
    |
 LL | trait TRS3: Iterator<Item: 'static, Item: 'static> {}
    |                      -------------  ^^^^^^^^^^^^^ re-bound here
@@ -456,7 +516,7 @@ LL | trait TRS3: Iterator<Item: 'static, Item: 'static> {}
    |                      `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:204:37
+  --> $DIR/duplicate.rs:210:37
    |
 LL | trait TRS3: Iterator<Item: 'static, Item: 'static> {}
    |                      -------------  ^^^^^^^^^^^^^ re-bound here
@@ -466,7 +526,7 @@ LL | trait TRS3: Iterator<Item: 'static, Item: 'static> {}
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:204:37
+  --> $DIR/duplicate.rs:210:37
    |
 LL | trait TRS3: Iterator<Item: 'static, Item: 'static> {}
    |                      -------------  ^^^^^^^^^^^^^ re-bound here
@@ -476,7 +536,7 @@ LL | trait TRS3: Iterator<Item: 'static, Item: 'static> {}
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:210:29
+  --> $DIR/duplicate.rs:216:29
    |
 LL |     T: Iterator<Item: Copy, Item: Send>,
    |                 ----------  ^^^^^^^^^^ re-bound here
@@ -484,7 +544,7 @@ LL |     T: Iterator<Item: Copy, Item: Send>,
    |                 `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:216:29
+  --> $DIR/duplicate.rs:222:29
    |
 LL |     T: Iterator<Item: Copy, Item: Copy>,
    |                 ----------  ^^^^^^^^^^ re-bound here
@@ -492,7 +552,7 @@ LL |     T: Iterator<Item: Copy, Item: Copy>,
    |                 `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:222:32
+  --> $DIR/duplicate.rs:228:32
    |
 LL |     T: Iterator<Item: 'static, Item: 'static>,
    |                 -------------  ^^^^^^^^^^^^^ re-bound here
@@ -500,7 +560,7 @@ LL |     T: Iterator<Item: 'static, Item: 'static>,
    |                 `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:228:32
+  --> $DIR/duplicate.rs:234:32
    |
 LL |     Self: Iterator<Item: Copy, Item: Send>,
    |                    ----------  ^^^^^^^^^^ re-bound here
@@ -508,7 +568,7 @@ LL |     Self: Iterator<Item: Copy, Item: Send>,
    |                    `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:228:32
+  --> $DIR/duplicate.rs:234:32
    |
 LL |     Self: Iterator<Item: Copy, Item: Send>,
    |                    ----------  ^^^^^^^^^^ re-bound here
@@ -518,7 +578,7 @@ LL |     Self: Iterator<Item: Copy, Item: Send>,
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:228:32
+  --> $DIR/duplicate.rs:234:32
    |
 LL |     Self: Iterator<Item: Copy, Item: Send>,
    |                    ----------  ^^^^^^^^^^ re-bound here
@@ -528,7 +588,7 @@ LL |     Self: Iterator<Item: Copy, Item: Send>,
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:236:32
+  --> $DIR/duplicate.rs:242:32
    |
 LL |     Self: Iterator<Item: Copy, Item: Copy>,
    |                    ----------  ^^^^^^^^^^ re-bound here
@@ -536,7 +596,7 @@ LL |     Self: Iterator<Item: Copy, Item: Copy>,
    |                    `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:236:32
+  --> $DIR/duplicate.rs:242:32
    |
 LL |     Self: Iterator<Item: Copy, Item: Copy>,
    |                    ----------  ^^^^^^^^^^ re-bound here
@@ -546,7 +606,7 @@ LL |     Self: Iterator<Item: Copy, Item: Copy>,
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:236:32
+  --> $DIR/duplicate.rs:242:32
    |
 LL |     Self: Iterator<Item: Copy, Item: Copy>,
    |                    ----------  ^^^^^^^^^^ re-bound here
@@ -556,7 +616,7 @@ LL |     Self: Iterator<Item: Copy, Item: Copy>,
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:244:35
+  --> $DIR/duplicate.rs:250:35
    |
 LL |     Self: Iterator<Item: 'static, Item: 'static>,
    |                    -------------  ^^^^^^^^^^^^^ re-bound here
@@ -564,7 +624,7 @@ LL |     Self: Iterator<Item: 'static, Item: 'static>,
    |                    `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:244:35
+  --> $DIR/duplicate.rs:250:35
    |
 LL |     Self: Iterator<Item: 'static, Item: 'static>,
    |                    -------------  ^^^^^^^^^^^^^ re-bound here
@@ -574,7 +634,7 @@ LL |     Self: Iterator<Item: 'static, Item: 'static>,
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:244:35
+  --> $DIR/duplicate.rs:250:35
    |
 LL |     Self: Iterator<Item: 'static, Item: 'static>,
    |                    -------------  ^^^^^^^^^^^^^ re-bound here
@@ -584,30 +644,60 @@ LL |     Self: Iterator<Item: 'static, Item: 'static>,
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:251:34
+  --> $DIR/duplicate.rs:257:34
+   |
+LL |     type A: Iterator<Item: Copy, Item: Send>;
+   |                      ----------  ^^^^^^^^^^ re-bound here
+   |                      |
+   |                      `Item` bound here first
+
+error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
+  --> $DIR/duplicate.rs:257:34
    |
 LL |     type A: Iterator<Item: Copy, Item: Send>;
    |                      ----------  ^^^^^^^^^^ re-bound here
    |                      |
    |                      `Item` bound here first
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
+  --> $DIR/duplicate.rs:262:34
+   |
+LL |     type A: Iterator<Item: Copy, Item: Copy>;
+   |                      ----------  ^^^^^^^^^^ re-bound here
+   |                      |
+   |                      `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:255:34
+  --> $DIR/duplicate.rs:262:34
    |
 LL |     type A: Iterator<Item: Copy, Item: Copy>;
    |                      ----------  ^^^^^^^^^^ re-bound here
    |                      |
    |                      `Item` bound here first
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:259:37
+  --> $DIR/duplicate.rs:267:37
    |
 LL |     type A: Iterator<Item: 'static, Item: 'static>;
    |                      -------------  ^^^^^^^^^^^^^ re-bound here
    |                      |
    |                      `Item` bound here first
 
-error: aborting due to 72 previous errors
+error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
+  --> $DIR/duplicate.rs:267:37
+   |
+LL |     type A: Iterator<Item: 'static, Item: 'static>;
+   |                      -------------  ^^^^^^^^^^^^^ re-bound here
+   |                      |
+   |                      `Item` bound here first
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 81 previous errors
 
 Some errors have detailed explanations: E0282, E0719.
 For more information about an error, try `rustc --explain E0282`.
diff --git a/tests/ui/associated-type-bounds/issue-102335-ty.rs b/tests/ui/associated-type-bounds/issue-102335-ty.rs
index 363df73c1ff..5fd8b71e679 100644
--- a/tests/ui/associated-type-bounds/issue-102335-ty.rs
+++ b/tests/ui/associated-type-bounds/issue-102335-ty.rs
@@ -1,6 +1,7 @@
 trait T {
     type A: S<C<i32 = u32> = ()>;
     //~^ ERROR associated type bindings are not allowed here
+    //~| ERROR associated type bindings are not allowed here
 }
 
 trait Q {}
diff --git a/tests/ui/associated-type-bounds/issue-102335-ty.stderr b/tests/ui/associated-type-bounds/issue-102335-ty.stderr
index 561ca15ab0d..3bd7566ad1e 100644
--- a/tests/ui/associated-type-bounds/issue-102335-ty.stderr
+++ b/tests/ui/associated-type-bounds/issue-102335-ty.stderr
@@ -4,6 +4,14 @@ error[E0229]: associated type bindings are not allowed here
 LL |     type A: S<C<i32 = u32> = ()>;
    |                 ^^^^^^^^^ associated type not allowed here
 
-error: aborting due to 1 previous error
+error[E0229]: associated type bindings are not allowed here
+  --> $DIR/issue-102335-ty.rs:2:17
+   |
+LL |     type A: S<C<i32 = u32> = ()>;
+   |                 ^^^^^^^^^ associated type not allowed here
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0229`.
diff --git a/tests/ui/associated-type-bounds/issue-99828.rs b/tests/ui/associated-type-bounds/issue-99828.rs
index 67ba50f3cbc..ab3654131f1 100644
--- a/tests/ui/associated-type-bounds/issue-99828.rs
+++ b/tests/ui/associated-type-bounds/issue-99828.rs
@@ -1,5 +1,6 @@
 fn get_iter(vec: &[i32]) -> impl Iterator<Item = {}> + '_ {
     //~^ ERROR expected type, found constant
+    //~| ERROR expected type, found constant
     //~| ERROR associated const equality is incomplete
     vec.iter()
 }
diff --git a/tests/ui/associated-type-bounds/issue-99828.stderr b/tests/ui/associated-type-bounds/issue-99828.stderr
index 911f3ff0f5e..132d5251987 100644
--- a/tests/ui/associated-type-bounds/issue-99828.stderr
+++ b/tests/ui/associated-type-bounds/issue-99828.stderr
@@ -19,6 +19,18 @@ LL | fn get_iter(vec: &[i32]) -> impl Iterator<Item = {}> + '_ {
 note: the associated type is defined here
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
 
-error: aborting due to 2 previous errors
+error: expected type, found constant
+  --> $DIR/issue-99828.rs:1:50
+   |
+LL | fn get_iter(vec: &[i32]) -> impl Iterator<Item = {}> + '_ {
+   |                                           ----   ^^ unexpected constant
+   |                                           |
+   |                                           expected a type because of this associated type
+   |
+note: the associated type is defined here
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout b/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout
index 47b39e5246d..d6fb643702c 100644
--- a/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout
+++ b/tests/ui/async-await/future-sizes/async-awaiting-fut.stdout
@@ -2,7 +2,7 @@ print-type-size type: `{async fn body@$DIR/async-awaiting-fut.rs:21:21: 24:2}`:
 print-type-size     discriminant: 1 bytes
 print-type-size     variant `Unresumed`: 0 bytes
 print-type-size     variant `Suspend0`: 3077 bytes
-print-type-size         local `.__awaitee`: 3077 bytes
+print-type-size         local `.__awaitee`: 3077 bytes, type: {async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2}
 print-type-size     variant `Returned`: 0 bytes
 print-type-size     variant `Panicked`: 0 bytes
 print-type-size type: `std::mem::ManuallyDrop<{async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2}>`: 3077 bytes, alignment: 1 bytes
@@ -19,19 +19,19 @@ print-type-size     variant `Suspend0`: 2052 bytes
 print-type-size         upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
 print-type-size         padding: 1 bytes
 print-type-size         local `.fut`: 1025 bytes, alignment: 1 bytes
-print-type-size         local `..coroutine_field4`: 1 bytes
-print-type-size         local `.__awaitee`: 1 bytes
+print-type-size         local `..coroutine_field4`: 1 bytes, type: bool
+print-type-size         local `.__awaitee`: 1 bytes, type: {async fn body@$DIR/async-awaiting-fut.rs:6:17: 6:19}
 print-type-size     variant `Suspend1`: 3076 bytes
 print-type-size         upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
 print-type-size         padding: 1026 bytes
-print-type-size         local `..coroutine_field4`: 1 bytes, alignment: 1 bytes
-print-type-size         local `.__awaitee`: 1025 bytes
+print-type-size         local `..coroutine_field4`: 1 bytes, alignment: 1 bytes, type: bool
+print-type-size         local `.__awaitee`: 1025 bytes, type: {async fn body@$DIR/async-awaiting-fut.rs:8:35: 8:37}
 print-type-size     variant `Suspend2`: 2052 bytes
 print-type-size         upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
 print-type-size         padding: 1 bytes
 print-type-size         local `.fut`: 1025 bytes, alignment: 1 bytes
-print-type-size         local `..coroutine_field4`: 1 bytes
-print-type-size         local `.__awaitee`: 1 bytes
+print-type-size         local `..coroutine_field4`: 1 bytes, type: bool
+print-type-size         local `.__awaitee`: 1 bytes, type: {async fn body@$DIR/async-awaiting-fut.rs:6:17: 6:19}
 print-type-size     variant `Returned`: 1025 bytes
 print-type-size         upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
 print-type-size     variant `Panicked`: 1025 bytes
diff --git a/tests/ui/async-await/future-sizes/large-arg.stdout b/tests/ui/async-await/future-sizes/large-arg.stdout
index 005460df626..589df102af4 100644
--- a/tests/ui/async-await/future-sizes/large-arg.stdout
+++ b/tests/ui/async-await/future-sizes/large-arg.stdout
@@ -2,7 +2,7 @@ print-type-size type: `{async fn body@$DIR/large-arg.rs:6:21: 8:2}`: 3076 bytes,
 print-type-size     discriminant: 1 bytes
 print-type-size     variant `Unresumed`: 0 bytes
 print-type-size     variant `Suspend0`: 3075 bytes
-print-type-size         local `.__awaitee`: 3075 bytes
+print-type-size         local `.__awaitee`: 3075 bytes, type: {async fn body@$DIR/large-arg.rs:10:30: 12:2}
 print-type-size     variant `Returned`: 0 bytes
 print-type-size     variant `Panicked`: 0 bytes
 print-type-size type: `std::mem::ManuallyDrop<{async fn body@$DIR/large-arg.rs:10:30: 12:2}>`: 3075 bytes, alignment: 1 bytes
@@ -17,7 +17,7 @@ print-type-size     variant `Unresumed`: 1024 bytes
 print-type-size         upvar `.t`: 1024 bytes
 print-type-size     variant `Suspend0`: 3074 bytes
 print-type-size         upvar `.t`: 1024 bytes
-print-type-size         local `.__awaitee`: 2050 bytes
+print-type-size         local `.__awaitee`: 2050 bytes, type: {async fn body@$DIR/large-arg.rs:13:26: 15:2}
 print-type-size     variant `Returned`: 1024 bytes
 print-type-size         upvar `.t`: 1024 bytes
 print-type-size     variant `Panicked`: 1024 bytes
@@ -34,7 +34,7 @@ print-type-size     variant `Unresumed`: 1024 bytes
 print-type-size         upvar `.t`: 1024 bytes
 print-type-size     variant `Suspend0`: 2049 bytes
 print-type-size         upvar `.t`: 1024 bytes
-print-type-size         local `.__awaitee`: 1025 bytes
+print-type-size         local `.__awaitee`: 1025 bytes, type: {async fn body@$DIR/large-arg.rs:16:26: 18:2}
 print-type-size     variant `Returned`: 1024 bytes
 print-type-size         upvar `.t`: 1024 bytes
 print-type-size     variant `Panicked`: 1024 bytes
diff --git a/tests/ui/async-await/in-trait/return-not-existing-pair.rs b/tests/ui/async-await/in-trait/return-not-existing-pair.rs
index 68be1358f81..3889efe1f2a 100644
--- a/tests/ui/async-await/in-trait/return-not-existing-pair.rs
+++ b/tests/ui/async-await/in-trait/return-not-existing-pair.rs
@@ -9,8 +9,7 @@ trait MyTrait<'a, 'b, T> {
 impl<'a, 'b, T, U> MyTrait<T> for U {
     //~^ ERROR: implicit elided lifetime not allowed here [E0726]
     async fn foo(_: T) -> (&'a U, &'b T) {}
-    //~^ ERROR: method `foo` has a `&self` declaration in the trait, but not in the impl [E0186]
-    //~| ERROR: mismatched types [E0308]
+    //~^ ERROR: mismatched types [E0308]
 }
 
 fn main() {}
diff --git a/tests/ui/async-await/in-trait/return-not-existing-pair.stderr b/tests/ui/async-await/in-trait/return-not-existing-pair.stderr
index 4694e608097..13d3606abba 100644
--- a/tests/ui/async-await/in-trait/return-not-existing-pair.stderr
+++ b/tests/ui/async-await/in-trait/return-not-existing-pair.stderr
@@ -15,15 +15,6 @@ error[E0412]: cannot find type `ConnImpl` in this scope
 LL |     async fn foo(&'a self, key: &'b T) -> (&'a ConnImpl, &'b T);
    |                                                ^^^^^^^^ not found in this scope
 
-error[E0186]: method `foo` has a `&self` declaration in the trait, but not in the impl
-  --> $DIR/return-not-existing-pair.rs:11:5
-   |
-LL |     async fn foo(&'a self, key: &'b T) -> (&'a ConnImpl, &'b T);
-   |     ------------------------------------------------------------ `&self` used in trait
-...
-LL |     async fn foo(_: T) -> (&'a U, &'b T) {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&self` in impl
-
 error[E0308]: mismatched types
   --> $DIR/return-not-existing-pair.rs:11:42
    |
@@ -33,7 +24,7 @@ LL |     async fn foo(_: T) -> (&'a U, &'b T) {}
    = note:  expected tuple `(&'a U, &'b T)`
            found unit type `()`
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0186, E0308, E0412, E0726.
-For more information about an error, try `rustc --explain E0186`.
+Some errors have detailed explanations: E0308, E0412, E0726.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/async-await/in-trait/unconstrained-impl-region.rs b/tests/ui/async-await/in-trait/unconstrained-impl-region.rs
index 9382c232364..95ba1f3f277 100644
--- a/tests/ui/async-await/in-trait/unconstrained-impl-region.rs
+++ b/tests/ui/async-await/in-trait/unconstrained-impl-region.rs
@@ -14,6 +14,7 @@ impl<'a> Actor for () {
 //~^ ERROR the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
     type Message = &'a ();
     async fn on_mount(self, _: impl Inbox<&'a ()>) {}
+    //~^ ERROR the trait bound `impl Inbox<&'a ()>: Inbox<&'a ()>` is not satisfied
 }
 
 fn main() {}
diff --git a/tests/ui/async-await/in-trait/unconstrained-impl-region.stderr b/tests/ui/async-await/in-trait/unconstrained-impl-region.stderr
index ef7e4ef0eb8..66819d1fcf7 100644
--- a/tests/ui/async-await/in-trait/unconstrained-impl-region.stderr
+++ b/tests/ui/async-await/in-trait/unconstrained-impl-region.stderr
@@ -1,9 +1,26 @@
+error[E0277]: the trait bound `impl Inbox<&'a ()>: Inbox<&'a ()>` is not satisfied
+  --> $DIR/unconstrained-impl-region.rs:16:5
+   |
+LL |     async fn on_mount(self, _: impl Inbox<&'a ()>) {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Inbox<&'a ()>` is not implemented for `impl Inbox<&'a ()>`
+   |
+note: required by a bound in `<() as Actor>::on_mount`
+  --> $DIR/unconstrained-impl-region.rs:16:37
+   |
+LL |     async fn on_mount(self, _: impl Inbox<&'a ()>) {}
+   |                                     ^^^^^^^^^^^^^ required by this bound in `<() as Actor>::on_mount`
+help: consider further restricting this bound
+   |
+LL |     async fn on_mount(self, _: impl Inbox<&'a ()> + Inbox<&'a ()>) {}
+   |                                                   +++++++++++++++
+
 error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
   --> $DIR/unconstrained-impl-region.rs:13:6
    |
 LL | impl<'a> Actor for () {
    |      ^^ unconstrained lifetime parameter
 
-error: aborting due to 1 previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0207`.
+Some errors have detailed explanations: E0207, E0277.
+For more information about an error, try `rustc --explain E0207`.
diff --git a/tests/ui/async-await/issues/issue-65159.rs b/tests/ui/async-await/issues/issue-65159.rs
index 781f8fe88d4..78492d55fda 100644
--- a/tests/ui/async-await/issues/issue-65159.rs
+++ b/tests/ui/async-await/issues/issue-65159.rs
@@ -4,6 +4,7 @@
 
 async fn copy() -> Result<()>
 //~^ ERROR enum takes 2 generic arguments
+//~| ERROR enum takes 2 generic arguments
 {
     Ok(())
 }
diff --git a/tests/ui/async-await/issues/issue-65159.stderr b/tests/ui/async-await/issues/issue-65159.stderr
index 19512116a66..834927060b1 100644
--- a/tests/ui/async-await/issues/issue-65159.stderr
+++ b/tests/ui/async-await/issues/issue-65159.stderr
@@ -11,6 +11,20 @@ help: add missing generic argument
 LL | async fn copy() -> Result<(), E>
    |                             +++
 
-error: aborting due to 1 previous error
+error[E0107]: enum takes 2 generic arguments but 1 generic argument was supplied
+  --> $DIR/issue-65159.rs:5:20
+   |
+LL | async fn copy() -> Result<()>
+   |                    ^^^^^^ -- supplied 1 generic argument
+   |                    |
+   |                    expected 2 generic arguments
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: add missing generic argument
+   |
+LL | async fn copy() -> Result<(), E>
+   |                             +++
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0107`.
diff --git a/tests/ui/async-await/send-bound-async-closure.rs b/tests/ui/async-await/send-bound-async-closure.rs
index 2732fa5d466..e4a9ae4cc75 100644
--- a/tests/ui/async-await/send-bound-async-closure.rs
+++ b/tests/ui/async-await/send-bound-async-closure.rs
@@ -1,5 +1,8 @@
 //@ edition: 2021
 //@ check-pass
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
 
 // This test verifies that we do not create a query cycle when typechecking has several inference
 // variables that point to the same coroutine interior type.
diff --git a/tests/ui/borrowck/ice-mutability-error-slicing-121807.rs b/tests/ui/borrowck/ice-mutability-error-slicing-121807.rs
new file mode 100644
index 00000000000..bbdd895d763
--- /dev/null
+++ b/tests/ui/borrowck/ice-mutability-error-slicing-121807.rs
@@ -0,0 +1,27 @@
+//@ edition:2015
+// test for ICE #121807 begin <= end (12 <= 11) when slicing 'Self::Assoc<'_>'
+// fixed by #122749
+
+trait MemoryUnit { // ERROR: not all trait items implemented, missing: `read_word`
+    extern "C" fn read_word(&mut self) -> u8;
+    extern "C" fn read_dword(Self::Assoc<'_>) -> u16;
+    //~^ WARN anonymous parameters are deprecated and will be removed in the next edition
+    //~^^ WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
+    //~^^^ ERROR associated type `Assoc` not found for `Self`
+}
+
+struct ROM {}
+
+impl MemoryUnit for ROM {
+//~^ ERROR not all trait items implemented, missing: `read_word`
+    extern "C" fn read_dword(&'s self) -> u16 {
+    //~^ ERROR use of undeclared lifetime name `'s`
+    //~^^ ERROR method `read_dword` has a `&self` declaration in the impl, but not in the trait
+        let a16 = self.read_word() as u16;
+        let b16 = self.read_word() as u16;
+
+        (b16 << 8) | a16
+    }
+}
+
+pub fn main() {}
diff --git a/tests/ui/borrowck/ice-mutability-error-slicing-121807.stderr b/tests/ui/borrowck/ice-mutability-error-slicing-121807.stderr
new file mode 100644
index 00000000000..3a6b8008fce
--- /dev/null
+++ b/tests/ui/borrowck/ice-mutability-error-slicing-121807.stderr
@@ -0,0 +1,53 @@
+error[E0261]: use of undeclared lifetime name `'s`
+  --> $DIR/ice-mutability-error-slicing-121807.rs:17:31
+   |
+LL |     extern "C" fn read_dword(&'s self) -> u16 {
+   |                               ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'s` here
+   |
+LL |     extern "C" fn read_dword<'s>(&'s self) -> u16 {
+   |                             ++++
+help: consider introducing lifetime `'s` here
+   |
+LL | impl<'s> MemoryUnit for ROM {
+   |     ++++
+
+warning: anonymous parameters are deprecated and will be removed in the next edition
+  --> $DIR/ice-mutability-error-slicing-121807.rs:7:30
+   |
+LL |     extern "C" fn read_dword(Self::Assoc<'_>) -> u16;
+   |                              ^^^^^^^^^^^^^^^ help: try naming the parameter or explicitly ignoring it: `_: Self::Assoc<'_>`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
+   = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686>
+   = note: `#[warn(anonymous_parameters)]` on by default
+
+error[E0220]: associated type `Assoc` not found for `Self`
+  --> $DIR/ice-mutability-error-slicing-121807.rs:7:36
+   |
+LL |     extern "C" fn read_dword(Self::Assoc<'_>) -> u16;
+   |                                    ^^^^^ associated type `Assoc` not found
+
+error[E0185]: method `read_dword` has a `&self` declaration in the impl, but not in the trait
+  --> $DIR/ice-mutability-error-slicing-121807.rs:17:5
+   |
+LL |     extern "C" fn read_dword(Self::Assoc<'_>) -> u16;
+   |     ------------------------------------------------- trait method declared without `&self`
+...
+LL |     extern "C" fn read_dword(&'s self) -> u16 {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&self` used in impl
+
+error[E0046]: not all trait items implemented, missing: `read_word`
+  --> $DIR/ice-mutability-error-slicing-121807.rs:15:1
+   |
+LL |     extern "C" fn read_word(&mut self) -> u8;
+   |     ----------------------------------------- `read_word` from trait
+...
+LL | impl MemoryUnit for ROM {
+   | ^^^^^^^^^^^^^^^^^^^^^^^ missing `read_word` in implementation
+
+error: aborting due to 4 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0046, E0185, E0220, E0261.
+For more information about an error, try `rustc --explain E0046`.
diff --git a/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs b/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs
index 15be5fb3fac..ebffa237f96 100644
--- a/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs
+++ b/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.rs
@@ -15,7 +15,9 @@ impl MarketMultiplier {
 
 async fn buy_lock(coroutine: &Mutex<MarketMultiplier>) -> LockedMarket<'_> {
     //~^ ERROR struct takes 0 lifetime arguments but 1 lifetime argument was supplied
-    //~^^ ERROR struct takes 1 generic argument but 0 generic arguments were supplied
+    //~| ERROR struct takes 1 generic argument but 0 generic arguments were supplied
+    //~| ERROR struct takes 0 lifetime arguments but 1 lifetime argument was supplied
+    //~| ERROR struct takes 1 generic argument but 0 generic arguments were supplied
     LockedMarket(coroutine.lock().unwrap().buy())
 }
 
diff --git a/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr b/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr
index 516c1d065e6..c0b6dcd1512 100644
--- a/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr
+++ b/tests/ui/borrowck/issue-82126-mismatched-subst-and-hir.stderr
@@ -7,7 +7,7 @@ LL | async fn buy_lock(coroutine: &Mutex<MarketMultiplier>) -> LockedMarket<'_>
    |                                                           expected 0 lifetime arguments
    |
 note: struct defined here, with 0 lifetime parameters
-  --> $DIR/issue-82126-mismatched-subst-and-hir.rs:22:8
+  --> $DIR/issue-82126-mismatched-subst-and-hir.rs:24:8
    |
 LL | struct LockedMarket<T>(T);
    |        ^^^^^^^^^^^^
@@ -19,7 +19,7 @@ LL | async fn buy_lock(coroutine: &Mutex<MarketMultiplier>) -> LockedMarket<'_>
    |                                                           ^^^^^^^^^^^^ expected 1 generic argument
    |
 note: struct defined here, with 1 generic parameter: `T`
-  --> $DIR/issue-82126-mismatched-subst-and-hir.rs:22:8
+  --> $DIR/issue-82126-mismatched-subst-and-hir.rs:24:8
    |
 LL | struct LockedMarket<T>(T);
    |        ^^^^^^^^^^^^ -
@@ -28,6 +28,38 @@ help: add missing generic argument
 LL | async fn buy_lock(coroutine: &Mutex<MarketMultiplier>) -> LockedMarket<'_, T> {
    |                                                                          +++
 
-error: aborting due to 2 previous errors
+error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supplied
+  --> $DIR/issue-82126-mismatched-subst-and-hir.rs:16:59
+   |
+LL | async fn buy_lock(coroutine: &Mutex<MarketMultiplier>) -> LockedMarket<'_> {
+   |                                                           ^^^^^^^^^^^^---- help: remove these generics
+   |                                                           |
+   |                                                           expected 0 lifetime arguments
+   |
+note: struct defined here, with 0 lifetime parameters
+  --> $DIR/issue-82126-mismatched-subst-and-hir.rs:24:8
+   |
+LL | struct LockedMarket<T>(T);
+   |        ^^^^^^^^^^^^
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0107]: struct takes 1 generic argument but 0 generic arguments were supplied
+  --> $DIR/issue-82126-mismatched-subst-and-hir.rs:16:59
+   |
+LL | async fn buy_lock(coroutine: &Mutex<MarketMultiplier>) -> LockedMarket<'_> {
+   |                                                           ^^^^^^^^^^^^ expected 1 generic argument
+   |
+note: struct defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-82126-mismatched-subst-and-hir.rs:24:8
+   |
+LL | struct LockedMarket<T>(T);
+   |        ^^^^^^^^^^^^ -
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: add missing generic argument
+   |
+LL | async fn buy_lock(coroutine: &Mutex<MarketMultiplier>) -> LockedMarket<'_, T> {
+   |                                                                          +++
+
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0107`.
diff --git a/tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.rs b/tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.rs
new file mode 100644
index 00000000000..b9e729bff62
--- /dev/null
+++ b/tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.rs
@@ -0,0 +1,26 @@
+// issue: rust-lang/rust#104779
+// ICE region infer, IndexMap: key not found
+
+struct Inv<'a>(&'a mut &'a ());
+enum Foo<T> {
+    Bar,
+    Var(T),
+}
+type Subtype = Foo<for<'a, 'b> fn(Inv<'a>, Inv<'b>)>;
+type Supertype = Foo<for<'a> fn(Inv<'a>, Inv<'a>)>;
+
+fn foo() -> impl Sized {
+//~^ WARN function cannot return without recursing
+    loop {
+        match foo() {
+        //~^ ERROR higher-ranked subtype error
+        //~^^ ERROR higher-ranked subtype error
+            Subtype::Bar => (),
+            //~^ ERROR higher-ranked subtype error
+            //~^^ ERROR higher-ranked subtype error
+            Supertype::Var(x) => {}
+        }
+    }
+}
+
+pub fn main() {}
diff --git a/tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.stderr b/tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.stderr
new file mode 100644
index 00000000000..887cb14a769
--- /dev/null
+++ b/tests/ui/borrowck/opaque-types-patterns-subtyping-ice-104779.stderr
@@ -0,0 +1,42 @@
+warning: function cannot return without recursing
+  --> $DIR/opaque-types-patterns-subtyping-ice-104779.rs:12:1
+   |
+LL | fn foo() -> impl Sized {
+   | ^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+...
+LL |         match foo() {
+   |               ----- recursive call site
+   |
+   = help: a `loop` may express intention better if this is on purpose
+   = note: `#[warn(unconditional_recursion)]` on by default
+
+error: higher-ranked subtype error
+  --> $DIR/opaque-types-patterns-subtyping-ice-104779.rs:15:15
+   |
+LL |         match foo() {
+   |               ^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/opaque-types-patterns-subtyping-ice-104779.rs:15:15
+   |
+LL |         match foo() {
+   |               ^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: higher-ranked subtype error
+  --> $DIR/opaque-types-patterns-subtyping-ice-104779.rs:18:13
+   |
+LL |             Subtype::Bar => (),
+   |             ^^^^^^^^^^^^
+
+error: higher-ranked subtype error
+  --> $DIR/opaque-types-patterns-subtyping-ice-104779.rs:18:13
+   |
+LL |             Subtype::Bar => (),
+   |             ^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 4 previous errors; 1 warning emitted
+
diff --git a/tests/ui/cfg/cfg-false-feature.stderr b/tests/ui/cfg/cfg-false-feature.stderr
index 9309b59ca59..542aeaf5caf 100644
--- a/tests/ui/cfg/cfg-false-feature.stderr
+++ b/tests/ui/cfg/cfg-false-feature.stderr
@@ -1,15 +1,3 @@
-warning: trait aliases are experimental
-  --> $DIR/cfg-false-feature.rs:12:1
-   |
-LL | trait A = Clone;
-   | ^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #41517 <https://github.com/rust-lang/rust/issues/41517> for more information
-   = help: add `#![feature(trait_alias)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = warning: unstable syntax can change at any point in the future, causing a hard error!
-   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
-
 warning: box pattern syntax is experimental
   --> $DIR/cfg-false-feature.rs:16:9
    |
@@ -22,5 +10,17 @@ LL |     let box _ = Box::new(0);
    = warning: unstable syntax can change at any point in the future, causing a hard error!
    = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
 
+warning: trait aliases are experimental
+  --> $DIR/cfg-false-feature.rs:12:1
+   |
+LL | trait A = Clone;
+   | ^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #41517 <https://github.com/rust-lang/rust/issues/41517> for more information
+   = help: add `#![feature(trait_alias)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = warning: unstable syntax can change at any point in the future, causing a hard error!
+   = note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
+
 warning: 2 warnings emitted
 
diff --git a/tests/ui/const-generics/generic_const_exprs/ice-generics_of-no-entry-found-for-key-113017.rs b/tests/ui/const-generics/generic_const_exprs/ice-generics_of-no-entry-found-for-key-113017.rs
new file mode 100644
index 00000000000..a2f8c876b5e
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/ice-generics_of-no-entry-found-for-key-113017.rs
@@ -0,0 +1,13 @@
+// test for ICE "no entry found for key" in generics_of.rs #113017
+
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+pub fn foo()
+where
+    for<const N: usize = { || {}; 1 }> ():,
+    //~^ ERROR only lifetime parameters can be used in this context
+    //~^^  ERROR defaults for generic parameters are not allowed in `for<...>` binders
+{}
+
+pub fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/ice-generics_of-no-entry-found-for-key-113017.stderr b/tests/ui/const-generics/generic_const_exprs/ice-generics_of-no-entry-found-for-key-113017.stderr
new file mode 100644
index 00000000000..edf27f58efd
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/ice-generics_of-no-entry-found-for-key-113017.stderr
@@ -0,0 +1,19 @@
+error[E0658]: only lifetime parameters can be used in this context
+  --> $DIR/ice-generics_of-no-entry-found-for-key-113017.rs:8:15
+   |
+LL |     for<const N: usize = { || {}; 1 }> ():,
+   |               ^
+   |
+   = note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
+   = help: add `#![feature(non_lifetime_binders)]` 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: defaults for generic parameters are not allowed in `for<...>` binders
+  --> $DIR/ice-generics_of-no-entry-found-for-key-113017.rs:8:9
+   |
+LL |     for<const N: usize = { || {}; 1 }> ():,
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/const-generics/generic_const_exprs/ice-predicates-of-no-entry-found-for-key-119275.rs b/tests/ui/const-generics/generic_const_exprs/ice-predicates-of-no-entry-found-for-key-119275.rs
new file mode 100644
index 00000000000..4ba696f4ae0
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/ice-predicates-of-no-entry-found-for-key-119275.rs
@@ -0,0 +1,18 @@
+// test for ICE #119275 "no entry found for key" in predicates_of.rs
+
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+fn bug<const N: Nat>(&self)
+//~^ ERROR `self` parameter is only allowed in associated functions
+//~^^ ERROR cannot find type `Nat` in this scope
+where
+    for<const N: usize = 3, T = u32> [(); COT::BYTES]:,
+    //~^ ERROR only lifetime parameters can be used in this context
+    //~^^ ERROR defaults for generic parameters are not allowed in `for<...>` binders
+    //~^^^ ERROR defaults for generic parameters are not allowed in `for<...>` binders
+    //~^^^^ ERROR failed to resolve: use of undeclared type `COT`
+{
+}
+
+pub fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/ice-predicates-of-no-entry-found-for-key-119275.stderr b/tests/ui/const-generics/generic_const_exprs/ice-predicates-of-no-entry-found-for-key-119275.stderr
new file mode 100644
index 00000000000..ee0ec38ab06
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/ice-predicates-of-no-entry-found-for-key-119275.stderr
@@ -0,0 +1,46 @@
+error: `self` parameter is only allowed in associated functions
+  --> $DIR/ice-predicates-of-no-entry-found-for-key-119275.rs:6:22
+   |
+LL | fn bug<const N: Nat>(&self)
+   |                      ^^^^^ not semantically valid as function parameter
+   |
+   = note: associated functions are those in `impl` or `trait` definitions
+
+error[E0412]: cannot find type `Nat` in this scope
+  --> $DIR/ice-predicates-of-no-entry-found-for-key-119275.rs:6:17
+   |
+LL | fn bug<const N: Nat>(&self)
+   |                 ^^^ not found in this scope
+
+error[E0658]: only lifetime parameters can be used in this context
+  --> $DIR/ice-predicates-of-no-entry-found-for-key-119275.rs:10:15
+   |
+LL |     for<const N: usize = 3, T = u32> [(); COT::BYTES]:,
+   |               ^             ^
+   |
+   = note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
+   = help: add `#![feature(non_lifetime_binders)]` 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: defaults for generic parameters are not allowed in `for<...>` binders
+  --> $DIR/ice-predicates-of-no-entry-found-for-key-119275.rs:10:9
+   |
+LL |     for<const N: usize = 3, T = u32> [(); COT::BYTES]:,
+   |         ^^^^^^^^^^^^^^^^^^
+
+error: defaults for generic parameters are not allowed in `for<...>` binders
+  --> $DIR/ice-predicates-of-no-entry-found-for-key-119275.rs:10:29
+   |
+LL |     for<const N: usize = 3, T = u32> [(); COT::BYTES]:,
+   |                             ^^^^^^^
+
+error[E0433]: failed to resolve: use of undeclared type `COT`
+  --> $DIR/ice-predicates-of-no-entry-found-for-key-119275.rs:10:43
+   |
+LL |     for<const N: usize = 3, T = u32> [(); COT::BYTES]:,
+   |                                           ^^^ use of undeclared type `COT`
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0412, E0433, E0658.
+For more information about an error, try `rustc --explain E0412`.
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-109141.rs b/tests/ui/const-generics/generic_const_exprs/issue-109141.rs
index 148c3bda8d2..c6dd981cced 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-109141.rs
+++ b/tests/ui/const-generics/generic_const_exprs/issue-109141.rs
@@ -4,6 +4,7 @@
 impl EntriesBuffer {
     fn a(&self) -> impl Iterator {
         self.0.iter_mut() //~ ERROR: cannot borrow `*self.0` as mutable, as it is behind a `&` reference
+                          //~| ERROR captures lifetime that does not appear in bounds
     }
 }
 
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-109141.stderr b/tests/ui/const-generics/generic_const_exprs/issue-109141.stderr
index 8b8489ac2bc..7a9572d000d 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-109141.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/issue-109141.stderr
@@ -1,5 +1,5 @@
 error[E0425]: cannot find value `HashesEntryLEN` in this scope
-  --> $DIR/issue-109141.rs:10:32
+  --> $DIR/issue-109141.rs:11:32
    |
 LL | struct EntriesBuffer(Box<[[u8; HashesEntryLEN]; 5]>);
    |                                ^^^^^^^^^^^^^^ not found in this scope
@@ -20,7 +20,22 @@ help: consider changing this to be a mutable reference
 LL |     fn a(&mut self) -> impl Iterator {
    |          ~~~~~~~~~
 
-error: aborting due to 2 previous errors
+error[E0700]: hidden type for `impl Iterator` captures lifetime that does not appear in bounds
+  --> $DIR/issue-109141.rs:6:9
+   |
+LL |     fn a(&self) -> impl Iterator {
+   |          -----     ------------- opaque type defined here
+   |          |
+   |          hidden type `std::slice::IterMut<'_, [u8; {const error}]>` captures the anonymous lifetime defined here
+LL |         self.0.iter_mut()
+   |         ^^^^^^^^^^^^^^^^^
+   |
+help: to declare that `impl Iterator` captures `'_`, you can add an explicit `'_` lifetime bound
+   |
+LL |     fn a(&self) -> impl Iterator + '_ {
+   |                                  ++++
+
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0425, E0596.
+Some errors have detailed explanations: E0425, E0596, E0700.
 For more information about an error, try `rustc --explain E0425`.
diff --git a/tests/ui/const-generics/generic_const_exprs/poly-const-uneval-ice-106423.rs b/tests/ui/const-generics/generic_const_exprs/poly-const-uneval-ice-106423.rs
new file mode 100644
index 00000000000..ed5ba32b621
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/poly-const-uneval-ice-106423.rs
@@ -0,0 +1,57 @@
+// issue: rust-lang/rust#106423
+// ICE collection encountered polymorphic constant: UnevaluatedConst {..}
+//@ edition:2021
+//@ check-pass
+
+#![feature(generic_const_exprs, generic_arg_infer)]
+#![allow(incomplete_features)]
+#![allow(unused)]
+
+use core::mem::MaybeUninit;
+
+pub struct Arr<T, const N: usize> {
+    v: [MaybeUninit<T>; N],
+}
+
+impl<T, const N: usize> Arr<T, N> {
+    const ELEM: MaybeUninit<T> = MaybeUninit::uninit();
+    const INIT: [MaybeUninit<T>; N] = [Self::ELEM; N]; // important for optimization of `new`
+
+    fn new() -> Self {
+        Arr { v: Self::INIT }
+    }
+}
+
+pub struct BaFormatFilter<const N: usize> {}
+
+pub enum DigitalFilter<const N: usize>
+where
+    [(); N * 2 + 1]: Sized,
+    [(); N * 2]: Sized,
+{
+    Ba(BaFormatFilter<{ N * 2 + 1 }>),
+}
+
+pub fn iirfilter_st_copy<const N: usize, const M: usize>(_: [f32; M]) -> DigitalFilter<N>
+where
+    [(); N * 2 + 1]: Sized,
+    [(); N * 2]: Sized,
+{
+    let zpk = zpk2tf_st(&Arr::<f32, { N * 2 }>::new(), &Arr::<f32, { N * 2 }>::new());
+    DigitalFilter::Ba(zpk)
+}
+
+pub fn zpk2tf_st<const N: usize>(
+    _z: &Arr<f32, N>,
+    _p: &Arr<f32, N>,
+) -> BaFormatFilter<{ N + 1 }>
+where
+    [(); N + 1]: Sized,
+{
+    BaFormatFilter {}
+}
+
+
+fn main() {
+    iirfilter_st_copy::<4, 2>([10., 50.,]);
+}
diff --git a/tests/ui/const-generics/ice-unexpected-inference-var-122549.rs b/tests/ui/const-generics/ice-unexpected-inference-var-122549.rs
new file mode 100644
index 00000000000..126ea667290
--- /dev/null
+++ b/tests/ui/const-generics/ice-unexpected-inference-var-122549.rs
@@ -0,0 +1,29 @@
+// Regression test for https://github.com/rust-lang/rust/issues/122549
+// was fixed by https://github.com/rust-lang/rust/pull/122749
+
+trait ConstChunksExactTrait<T> {
+    fn const_chunks_exact<const N: usize>(&self) -> ConstChunksExact<'a, T, { N }>;
+    //~^ ERROR undeclared lifetime
+}
+
+impl<T> ConstChunksExactTrait<T> for [T] {}
+//~^ ERROR not all trait items implemented, missing: `const_chunks_exact`
+struct ConstChunksExact<'rem, T: 'a, const N: usize> {}
+//~^ ERROR use of undeclared lifetime name `'a`
+//~^^ ERROR lifetime parameter
+//~^^^ ERROR type parameter
+impl<'a, T, const N: usize> Iterator for ConstChunksExact<'a, T, {}> {
+//~^ ERROR the const parameter `N` is not constrained by the impl trait, self type, or predicates
+//~^^ ERROR mismatched types
+    type Item = &'a [T; N];
+}
+
+fn main() {
+    let slice = &[1i32, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+
+    let mut iter = [[1, 2, 3], [4, 5, 6], [7, 8, 9]].iter();
+
+    for a in slice.const_chunks_exact::<3>() {
+        assert_eq!(a, iter.next().unwrap());
+    }
+}
diff --git a/tests/ui/const-generics/ice-unexpected-inference-var-122549.stderr b/tests/ui/const-generics/ice-unexpected-inference-var-122549.stderr
new file mode 100644
index 00000000000..afad3388145
--- /dev/null
+++ b/tests/ui/const-generics/ice-unexpected-inference-var-122549.stderr
@@ -0,0 +1,67 @@
+error[E0261]: use of undeclared lifetime name `'a`
+  --> $DIR/ice-unexpected-inference-var-122549.rs:5:70
+   |
+LL |     fn const_chunks_exact<const N: usize>(&self) -> ConstChunksExact<'a, T, { N }>;
+   |                                                                      ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'a` here
+   |
+LL |     fn const_chunks_exact<'a, const N: usize>(&self) -> ConstChunksExact<'a, T, { N }>;
+   |                           +++
+help: consider introducing lifetime `'a` here
+   |
+LL | trait ConstChunksExactTrait<'a, T> {
+   |                             +++
+
+error[E0261]: use of undeclared lifetime name `'a`
+  --> $DIR/ice-unexpected-inference-var-122549.rs:11:34
+   |
+LL | struct ConstChunksExact<'rem, T: 'a, const N: usize> {}
+   |                         -        ^^ undeclared lifetime
+   |                         |
+   |                         help: consider introducing lifetime `'a` here: `'a,`
+
+error[E0046]: not all trait items implemented, missing: `const_chunks_exact`
+  --> $DIR/ice-unexpected-inference-var-122549.rs:9:1
+   |
+LL |     fn const_chunks_exact<const N: usize>(&self) -> ConstChunksExact<'a, T, { N }>;
+   |     ------------------------------------------------------------------------------- `const_chunks_exact` from trait
+...
+LL | impl<T> ConstChunksExactTrait<T> for [T] {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `const_chunks_exact` in implementation
+
+error[E0392]: lifetime parameter `'rem` is never used
+  --> $DIR/ice-unexpected-inference-var-122549.rs:11:25
+   |
+LL | struct ConstChunksExact<'rem, T: 'a, const N: usize> {}
+   |                         ^^^^ unused lifetime parameter
+   |
+   = help: consider removing `'rem`, referring to it in a field, or using a marker such as `PhantomData`
+
+error[E0392]: type parameter `T` is never used
+  --> $DIR/ice-unexpected-inference-var-122549.rs:11:31
+   |
+LL | struct ConstChunksExact<'rem, T: 'a, const N: usize> {}
+   |                               ^ unused type parameter
+   |
+   = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+
+error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/ice-unexpected-inference-var-122549.rs:15:13
+   |
+LL | impl<'a, T, const N: usize> Iterator for ConstChunksExact<'a, T, {}> {
+   |             ^^^^^^^^^^^^^^ unconstrained const parameter
+   |
+   = note: expressions using a const parameter must map each value to a distinct output value
+   = note: proving the result of expressions other than the parameter are unique is not supported
+
+error[E0308]: mismatched types
+  --> $DIR/ice-unexpected-inference-var-122549.rs:15:66
+   |
+LL | impl<'a, T, const N: usize> Iterator for ConstChunksExact<'a, T, {}> {
+   |                                                                  ^^ expected `usize`, found `()`
+
+error: aborting due to 7 previous errors
+
+Some errors have detailed explanations: E0046, E0207, E0261, E0308, E0392.
+For more information about an error, try `rustc --explain E0046`.
diff --git a/tests/ui/const-generics/late-bound-vars/late-bound-in-return-issue-77357.stderr b/tests/ui/const-generics/late-bound-vars/late-bound-in-return-issue-77357.stderr
index e42bb6e8cc5..7bef98b1d5d 100644
--- a/tests/ui/const-generics/late-bound-vars/late-bound-in-return-issue-77357.stderr
+++ b/tests/ui/const-generics/late-bound-vars/late-bound-in-return-issue-77357.stderr
@@ -4,46 +4,5 @@ error: cannot capture late-bound lifetime in constant
 LL | fn bug<'a, T>() -> &'static dyn MyTrait<[(); { |x: &'a u32| { x }; 4 }]> {
    |        -- lifetime defined here                     ^^
 
-error: overly complex generic constant
-  --> $DIR/late-bound-in-return-issue-77357.rs:9:46
-   |
-LL | fn bug<'a, T>() -> &'static dyn MyTrait<[(); { |x: &'a u32| { x }; 4 }]> {
-   |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^ blocks are not supported in generic constants
-   |
-   = help: consider moving this anonymous constant into a `const` function
-   = note: this operation may be supported in the future
-
-error[E0391]: cycle detected when evaluating type-level constant
-  --> $DIR/late-bound-in-return-issue-77357.rs:9:46
-   |
-LL | fn bug<'a, T>() -> &'static dyn MyTrait<[(); { |x: &'a u32| { x }; 4 }]> {
-   |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: ...which requires const-evaluating + checking `bug::{constant#0}`...
-  --> $DIR/late-bound-in-return-issue-77357.rs:9:46
-   |
-LL | fn bug<'a, T>() -> &'static dyn MyTrait<[(); { |x: &'a u32| { x }; 4 }]> {
-   |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires caching mir of `bug::{constant#0}` for CTFE...
-  --> $DIR/late-bound-in-return-issue-77357.rs:9:46
-   |
-LL | fn bug<'a, T>() -> &'static dyn MyTrait<[(); { |x: &'a u32| { x }; 4 }]> {
-   |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires elaborating drops for `bug::{constant#0}`...
-  --> $DIR/late-bound-in-return-issue-77357.rs:9:46
-   |
-LL | fn bug<'a, T>() -> &'static dyn MyTrait<[(); { |x: &'a u32| { x }; 4 }]> {
-   |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires borrow-checking `bug::{constant#0}`...
-  --> $DIR/late-bound-in-return-issue-77357.rs:9:46
-   |
-LL | fn bug<'a, T>() -> &'static dyn MyTrait<[(); { |x: &'a u32| { x }; 4 }]> {
-   |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which requires normalizing `Binder { value: ConstEvaluatable(UnevaluatedConst { def: DefId(0:8 ~ late_bound_in_return_issue_77357[9394]::bug::{constant#0}), args: [T/#0] }: usize), bound_vars: [] }`...
-   = note: ...which again requires evaluating type-level constant, completing the cycle
-   = note: cycle used when normalizing `&dyn MyTrait<[(); { |x: &'a u32| { x }; 4 }]>`
-   = 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 3 previous errors
+error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0391`.
diff --git a/tests/ui/const-generics/min_const_generics/macro-fail.rs b/tests/ui/const-generics/min_const_generics/macro-fail.rs
index f3df96d468c..2f101ecfb1f 100644
--- a/tests/ui/const-generics/min_const_generics/macro-fail.rs
+++ b/tests/ui/const-generics/min_const_generics/macro-fail.rs
@@ -13,6 +13,7 @@ impl<const N: usize> Marker<N> for Example<N> {}
 
 fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
   //~^ ERROR: type provided when a constant was expected
+  //~| ERROR: type provided when a constant was expected
   Example::<gimme_a_const!(marker)>
   //~^ ERROR: type provided when a constant was expected
 }
diff --git a/tests/ui/const-generics/min_const_generics/macro-fail.stderr b/tests/ui/const-generics/min_const_generics/macro-fail.stderr
index 06a111008a3..34764982bb0 100644
--- a/tests/ui/const-generics/min_const_generics/macro-fail.stderr
+++ b/tests/ui/const-generics/min_const_generics/macro-fail.stderr
@@ -1,5 +1,5 @@
 error: expected type, found `{`
-  --> $DIR/macro-fail.rs:29:27
+  --> $DIR/macro-fail.rs:30:27
    |
 LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
    |                                 ----------------------
@@ -13,7 +13,7 @@ LL |       ($rusty: ident) => {{ let $rusty = 3; *&$rusty }}
    = note: this error originates in the macro `gimme_a_const` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: expected type, found `{`
-  --> $DIR/macro-fail.rs:29:27
+  --> $DIR/macro-fail.rs:30:27
    |
 LL |   Example::<gimme_a_const!(marker)>
    |             ----------------------
@@ -41,7 +41,7 @@ LL |   let _fail = Example::<external_macro!()>;
    = note: this error originates in the macro `external_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: unexpected end of macro invocation
-  --> $DIR/macro-fail.rs:39:25
+  --> $DIR/macro-fail.rs:40:25
    |
 LL |     macro_rules! gimme_a_const {
    |     -------------------------- when calling this macro
@@ -50,7 +50,7 @@ LL |   let _fail = Example::<gimme_a_const!()>;
    |                         ^^^^^^^^^^^^^^^^ missing tokens in macro arguments
    |
 note: while trying to match meta-variable `$rusty:ident`
-  --> $DIR/macro-fail.rs:29:8
+  --> $DIR/macro-fail.rs:30:8
    |
 LL |       ($rusty: ident) => {{ let $rusty = 3; *&$rusty }}
    |        ^^^^^^^^^^^^^
@@ -62,23 +62,31 @@ LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
    |                                 ^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0747]: type provided when a constant was expected
-  --> $DIR/macro-fail.rs:16:13
+  --> $DIR/macro-fail.rs:14:33
+   |
+LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0747]: type provided when a constant was expected
+  --> $DIR/macro-fail.rs:17:13
    |
 LL |   Example::<gimme_a_const!(marker)>
    |             ^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0747]: type provided when a constant was expected
-  --> $DIR/macro-fail.rs:36:25
+  --> $DIR/macro-fail.rs:37:25
    |
 LL |   let _fail = Example::<external_macro!()>;
    |                         ^^^^^^^^^^^^^^^^^
 
 error[E0747]: type provided when a constant was expected
-  --> $DIR/macro-fail.rs:39:25
+  --> $DIR/macro-fail.rs:40:25
    |
 LL |   let _fail = Example::<gimme_a_const!()>;
    |                         ^^^^^^^^^^^^^^^^
 
-error: aborting due to 8 previous errors
+error: aborting due to 9 previous errors
 
 For more information about this error, try `rustc --explain E0747`.
diff --git a/tests/ui/const-generics/occurs-check/unify-fixpoint.rs b/tests/ui/const-generics/occurs-check/unify-fixpoint.rs
index 1c1ed41051d..02bc90988e2 100644
--- a/tests/ui/const-generics/occurs-check/unify-fixpoint.rs
+++ b/tests/ui/const-generics/occurs-check/unify-fixpoint.rs
@@ -1,3 +1,8 @@
+// -Zunstable-options added as test for ICE #97725 (left == right)`
+// left: `Binder(<[u8; _] as std::default::Default>, [])`,
+// right: `Binder(<[u8; 4] as std::default::Default>, [])
+
+//@ compile-flags: -Zunstable-options
 //@ check-pass
 #![feature(generic_const_exprs)] //~ WARN the feature `generic_const_exprs` is incomplete
 
diff --git a/tests/ui/const-generics/occurs-check/unify-fixpoint.stderr b/tests/ui/const-generics/occurs-check/unify-fixpoint.stderr
index fe3f24a67a2..8b63e8c55d5 100644
--- a/tests/ui/const-generics/occurs-check/unify-fixpoint.stderr
+++ b/tests/ui/const-generics/occurs-check/unify-fixpoint.stderr
@@ -1,5 +1,5 @@
 warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/unify-fixpoint.rs:2:12
+  --> $DIR/unify-fixpoint.rs:7:12
    |
 LL | #![feature(generic_const_exprs)]
    |            ^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/const-generics/transmute-fail.rs b/tests/ui/const-generics/transmute-fail.rs
index d7bf1b47fb5..90afd232534 100644
--- a/tests/ui/const-generics/transmute-fail.rs
+++ b/tests/ui/const-generics/transmute-fail.rs
@@ -32,4 +32,79 @@ fn overflow(v: [[[u32; 8888888]; 9999999]; 777777777]) -> [[[u32; 9999999]; 7777
   }
 }
 
+fn transpose<const W: usize, const H: usize>(v: [[u32;H]; W]) -> [[u32; W]; H] {
+  unsafe {
+    std::mem::transmute(v)
+    //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types
+  }
+}
+
+fn ident<const W: usize, const H: usize>(v: [[u32; H]; W]) -> [[u32; H]; W] {
+  unsafe {
+    std::mem::transmute(v)
+  }
+}
+
+fn flatten<const W: usize, const H: usize>(v: [[u32; H]; W]) -> [u32; W * H] {
+  unsafe {
+    std::mem::transmute(v)
+    //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types
+  }
+}
+
+fn coagulate<const W: usize, const H: usize>(v: [u32; H*W]) -> [[u32; W];H] {
+  unsafe {
+    std::mem::transmute(v)
+    //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types
+  }
+}
+
+fn flatten_3d<const W: usize, const H: usize, const D: usize>(
+  v: [[[u32; D]; H]; W]
+) -> [u32; D * W * H] {
+  unsafe {
+    std::mem::transmute(v)
+    //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types
+  }
+}
+
+fn flatten_somewhat<const W: usize, const H: usize, const D: usize>(
+  v: [[[u32; D]; H]; W]
+) -> [[u32; D * W]; H] {
+  unsafe {
+    std::mem::transmute(v)
+    //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types
+  }
+}
+
+fn known_size<const L: usize>(v: [u16; L]) -> [u8; L * 2] {
+  unsafe {
+    std::mem::transmute(v)
+    //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types
+  }
+}
+
+fn condense_bytes<const L: usize>(v: [u8; L * 2]) -> [u16; L] {
+  unsafe {
+    std::mem::transmute(v)
+    //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types
+  }
+}
+
+fn singleton_each<const L: usize>(v: [u8; L]) -> [[u8;1]; L] {
+  unsafe {
+    std::mem::transmute(v)
+    //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types
+  }
+}
+
+fn transpose_with_const<const W: usize, const H: usize>(
+  v: [[u32; 2 * H]; W + W]
+) -> [[u32; W + W]; 2 * H] {
+  unsafe {
+    std::mem::transmute(v)
+    //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types
+  }
+}
+
 fn main() {}
diff --git a/tests/ui/const-generics/transmute-fail.stderr b/tests/ui/const-generics/transmute-fail.stderr
index 397e3be768a..1b0d1ea50d0 100644
--- a/tests/ui/const-generics/transmute-fail.stderr
+++ b/tests/ui/const-generics/transmute-fail.stderr
@@ -4,8 +4,8 @@ error[E0512]: cannot transmute between types of different sizes, or dependently-
 LL |     std::mem::transmute(v)
    |     ^^^^^^^^^^^^^^^^^^^
    |
-   = note: source type: `[[u32; H+1]; W]` (generic size (H + 1) * 4 * W)
-   = note: target type: `[[u32; W+1]; H]` (generic size (W + 1) * 4 * H)
+   = note: source type: `[[u32; H+1]; W]` (size can vary because of [u32; H+1])
+   = note: target type: `[[u32; W+1]; H]` (size can vary because of [u32; W+1])
 
 error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
   --> $DIR/transmute-fail.rs:16:5
@@ -22,8 +22,8 @@ error[E0512]: cannot transmute between types of different sizes, or dependently-
 LL |     std::mem::transmute(v)
    |     ^^^^^^^^^^^^^^^^^^^
    |
-   = note: source type: `[[u32; H]; W]` (generic size 4 * H * W)
-   = note: target type: `[u32; W * H * H]` (generic size 4 * H * H * W)
+   = note: source type: `[[u32; H]; W]` (size can vary because of [u32; H])
+   = note: target type: `[u32; W * H * H]` (this type does not have a fixed size)
 
 error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
   --> $DIR/transmute-fail.rs:30:5
@@ -34,6 +34,87 @@ LL |     std::mem::transmute(v)
    = note: source type: `[[[u32; 8888888]; 9999999]; 777777777]` (values of the type `[[u32; 8888888]; 9999999]` are too big for the current architecture)
    = note: target type: `[[[u32; 9999999]; 777777777]; 8888888]` (values of the type `[[u32; 9999999]; 777777777]` are too big for the current architecture)
 
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/transmute-fail.rs:37:5
+   |
+LL |     std::mem::transmute(v)
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[[u32; H]; W]` (size can vary because of [u32; H])
+   = note: target type: `[[u32; W]; H]` (size can vary because of [u32; W])
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/transmute-fail.rs:50:5
+   |
+LL |     std::mem::transmute(v)
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[[u32; H]; W]` (size can vary because of [u32; H])
+   = note: target type: `[u32; W * H]` (this type does not have a fixed size)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/transmute-fail.rs:57:5
+   |
+LL |     std::mem::transmute(v)
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[u32; H*W]` (this type does not have a fixed size)
+   = note: target type: `[[u32; W]; H]` (size can vary because of [u32; W])
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/transmute-fail.rs:66:5
+   |
+LL |     std::mem::transmute(v)
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[[[u32; D]; H]; W]` (size can vary because of [u32; D])
+   = note: target type: `[u32; D * W * H]` (this type does not have a fixed size)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/transmute-fail.rs:75:5
+   |
+LL |     std::mem::transmute(v)
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[[[u32; D]; H]; W]` (size can vary because of [u32; D])
+   = note: target type: `[[u32; D * W]; H]` (size can vary because of [u32; D * W])
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/transmute-fail.rs:82:5
+   |
+LL |     std::mem::transmute(v)
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[u16; L]` (this type does not have a fixed size)
+   = note: target type: `[u8; L * 2]` (this type does not have a fixed size)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/transmute-fail.rs:89:5
+   |
+LL |     std::mem::transmute(v)
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[u8; L * 2]` (this type does not have a fixed size)
+   = note: target type: `[u16; L]` (this type does not have a fixed size)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/transmute-fail.rs:96:5
+   |
+LL |     std::mem::transmute(v)
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[u8; L]` (this type does not have a fixed size)
+   = note: target type: `[[u8; 1]; L]` (this type does not have a fixed size)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/transmute-fail.rs:105:5
+   |
+LL |     std::mem::transmute(v)
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `[[u32; 2 * H]; W + W]` (size can vary because of [u32; 2 * H])
+   = note: target type: `[[u32; W + W]; 2 * H]` (size can vary because of [u32; W + W])
+
 error[E0308]: mismatched types
   --> $DIR/transmute-fail.rs:12:53
    |
@@ -46,7 +127,7 @@ error[E0308]: mismatched types
 LL | fn bar<const W: bool, const H: usize>(v: [[u32; H]; W]) -> [[u32; W]; H] {
    |                                                                   ^ expected `usize`, found `bool`
 
-error: aborting due to 6 previous errors
+error: aborting due to 15 previous errors
 
 Some errors have detailed explanations: E0308, E0512.
 For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/const-generics/transmute.rs b/tests/ui/const-generics/transmute.rs
index 245fcf5670e..e8ab8637932 100644
--- a/tests/ui/const-generics/transmute.rs
+++ b/tests/ui/const-generics/transmute.rs
@@ -3,81 +3,12 @@
 #![feature(transmute_generic_consts)]
 #![allow(incomplete_features)]
 
-fn transpose<const W: usize, const H: usize>(v: [[u32;H]; W]) -> [[u32; W]; H] {
-  unsafe {
-    std::mem::transmute(v)
-  }
-}
-
 fn ident<const W: usize, const H: usize>(v: [[u32; H]; W]) -> [[u32; H]; W] {
   unsafe {
     std::mem::transmute(v)
   }
 }
 
-fn flatten<const W: usize, const H: usize>(v: [[u32; H]; W]) -> [u32; W * H] {
-  unsafe {
-    std::mem::transmute(v)
-  }
-}
-
-fn coagulate<const W: usize, const H: usize>(v: [u32; H*W]) -> [[u32; W];H] {
-  unsafe {
-    std::mem::transmute(v)
-  }
-}
-
-fn flatten_3d<const W: usize, const H: usize, const D: usize>(
-  v: [[[u32; D]; H]; W]
-) -> [u32; D * W * H] {
-  unsafe {
-    std::mem::transmute(v)
-  }
-}
-
-fn flatten_somewhat<const W: usize, const H: usize, const D: usize>(
-  v: [[[u32; D]; H]; W]
-) -> [[u32; D * W]; H] {
-  unsafe {
-    std::mem::transmute(v)
-  }
-}
-
-fn known_size<const L: usize>(v: [u16; L]) -> [u8; L * 2] {
-  unsafe {
-    std::mem::transmute(v)
-  }
-}
-
-fn condense_bytes<const L: usize>(v: [u8; L * 2]) -> [u16; L] {
-  unsafe {
-    std::mem::transmute(v)
-  }
-}
-
-fn singleton_each<const L: usize>(v: [u8; L]) -> [[u8;1]; L] {
-  unsafe {
-    std::mem::transmute(v)
-  }
-}
-
-fn transpose_with_const<const W: usize, const H: usize>(
-  v: [[u32; 2 * H]; W + W]
-) -> [[u32; W + W]; 2 * H] {
-  unsafe {
-    std::mem::transmute(v)
-  }
-}
-
 fn main() {
-  let _ = transpose([[0; 8]; 16]);
-  let _ = transpose_with_const::<8,4>([[0; 8]; 16]);
   let _ = ident([[0; 8]; 16]);
-  let _ = flatten([[0; 13]; 5]);
-  let _: [[_; 5]; 13] = coagulate([0; 65]);
-  let _ = flatten_3d([[[0; 3]; 13]; 5]);
-  let _ = flatten_somewhat([[[0; 3]; 13]; 5]);
-  let _ = known_size([16; 13]);
-  let _: [u16; 5] = condense_bytes([16u8; 10]);
-  let _ = singleton_each([16; 10]);
 }
diff --git a/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.rs b/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.rs
new file mode 100644
index 00000000000..dc9782295c1
--- /dev/null
+++ b/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.rs
@@ -0,0 +1,20 @@
+// test for #112824 ICE type mismatching when copying!
+
+pub struct Opcode(pub u8);
+
+pub struct Opcode2(&'a S);
+//~^ ERROR use of undeclared lifetime name `'a`
+//~^^ ERROR cannot find type `S` in this scope
+
+impl Opcode2 {
+    pub const OP2: Opcode2 = Opcode2(Opcode(0x1));
+}
+
+pub fn example2(msg_type: Opcode2) -> impl FnMut(&[u8]) {
+    move |i| match msg_type {
+        Opcode2::OP2 => unimplemented!(),
+        //~^ ERROR could not evaluate constant pattern
+    }
+}
+
+pub fn main() {}
diff --git a/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.stderr b/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.stderr
new file mode 100644
index 00000000000..9442eac0cf5
--- /dev/null
+++ b/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.stderr
@@ -0,0 +1,29 @@
+error[E0261]: use of undeclared lifetime name `'a`
+  --> $DIR/ice-type-mismatch-when-copying-112824.rs:5:21
+   |
+LL | pub struct Opcode2(&'a S);
+   |                   - ^^ undeclared lifetime
+   |                   |
+   |                   help: consider introducing lifetime `'a` here: `<'a>`
+
+error[E0412]: cannot find type `S` in this scope
+  --> $DIR/ice-type-mismatch-when-copying-112824.rs:5:24
+   |
+LL | pub struct Opcode2(&'a S);
+   |                        ^ not found in this scope
+   |
+help: you might be missing a type parameter
+   |
+LL | pub struct Opcode2<S>(&'a S);
+   |                   +++
+
+error: could not evaluate constant pattern
+  --> $DIR/ice-type-mismatch-when-copying-112824.rs:15:9
+   |
+LL |         Opcode2::OP2 => unimplemented!(),
+   |         ^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0261, E0412.
+For more information about an error, try `rustc --explain E0261`.
diff --git a/tests/ui/consts/missing_span_in_backtrace.stderr b/tests/ui/consts/missing_span_in_backtrace.stderr
index 3e3e8e976be..9e0506e7e38 100644
--- a/tests/ui/consts/missing_span_in_backtrace.stderr
+++ b/tests/ui/consts/missing_span_in_backtrace.stderr
@@ -5,8 +5,6 @@ error[E0080]: evaluation of constant value failed
    |
 note: inside `std::ptr::read::<MaybeUninit<MaybeUninit<u8>>>`
   --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-note: inside `mem::swap_simple::<MaybeUninit<MaybeUninit<u8>>>`
-  --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
 note: inside `std::ptr::swap_nonoverlapping_simple_untyped::<MaybeUninit<u8>>`
   --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
 note: inside `swap_nonoverlapping::<MaybeUninit<u8>>`
diff --git a/tests/ui/consts/required-consts/collect-in-called-fn.noopt.stderr b/tests/ui/consts/required-consts/collect-in-called-fn.noopt.stderr
index 14a4cb0217f..c3b641a899a 100644
--- a/tests/ui/consts/required-consts/collect-in-called-fn.noopt.stderr
+++ b/tests/ui/consts/required-consts/collect-in-called-fn.noopt.stderr
@@ -1,19 +1,19 @@
 error[E0080]: evaluation of `Fail::<i32>::C` failed
-  --> $DIR/collect-in-called-fn.rs:9:19
+  --> $DIR/collect-in-called-fn.rs:10:19
    |
 LL |     const C: () = panic!();
-   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-called-fn.rs:9:19
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-called-fn.rs:10:19
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 note: erroneous constant encountered
-  --> $DIR/collect-in-called-fn.rs:18:17
+  --> $DIR/collect-in-called-fn.rs:19:17
    |
 LL |         let _ = Fail::<T>::C;
    |                 ^^^^^^^^^^^^
 
 note: the above error was encountered while instantiating `fn called::<i32>`
-  --> $DIR/collect-in-called-fn.rs:23:5
+  --> $DIR/collect-in-called-fn.rs:24:5
    |
 LL |     called::<i32>();
    |     ^^^^^^^^^^^^^^^
diff --git a/tests/ui/consts/required-consts/collect-in-called-fn.opt.stderr b/tests/ui/consts/required-consts/collect-in-called-fn.opt.stderr
index 14a4cb0217f..c3b641a899a 100644
--- a/tests/ui/consts/required-consts/collect-in-called-fn.opt.stderr
+++ b/tests/ui/consts/required-consts/collect-in-called-fn.opt.stderr
@@ -1,19 +1,19 @@
 error[E0080]: evaluation of `Fail::<i32>::C` failed
-  --> $DIR/collect-in-called-fn.rs:9:19
+  --> $DIR/collect-in-called-fn.rs:10:19
    |
 LL |     const C: () = panic!();
-   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-called-fn.rs:9:19
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-called-fn.rs:10:19
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 note: erroneous constant encountered
-  --> $DIR/collect-in-called-fn.rs:18:17
+  --> $DIR/collect-in-called-fn.rs:19:17
    |
 LL |         let _ = Fail::<T>::C;
    |                 ^^^^^^^^^^^^
 
 note: the above error was encountered while instantiating `fn called::<i32>`
-  --> $DIR/collect-in-called-fn.rs:23:5
+  --> $DIR/collect-in-called-fn.rs:24:5
    |
 LL |     called::<i32>();
    |     ^^^^^^^^^^^^^^^
diff --git a/tests/ui/consts/required-consts/collect-in-called-fn.rs b/tests/ui/consts/required-consts/collect-in-called-fn.rs
index 55133a10cd9..93947950af2 100644
--- a/tests/ui/consts/required-consts/collect-in-called-fn.rs
+++ b/tests/ui/consts/required-consts/collect-in-called-fn.rs
@@ -1,5 +1,6 @@
 //@revisions: noopt opt
 //@ build-fail
+//@[noopt] compile-flags: -Copt-level=0
 //@[opt] compile-flags: -O
 //! Make sure we detect erroneous constants post-monomorphization even when they are unused. This is
 //! crucial, people rely on it for soundness. (https://github.com/rust-lang/rust/issues/112090)
diff --git a/tests/ui/consts/required-consts/collect-in-dead-closure.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-closure.noopt.stderr
new file mode 100644
index 00000000000..75c3575a110
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-closure.noopt.stderr
@@ -0,0 +1,23 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/collect-in-dead-closure.rs:9:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-closure.rs:9:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/collect-in-dead-closure.rs:17:17
+   |
+LL |         let _ = Fail::<T>::C;
+   |                 ^^^^^^^^^^^^
+
+note: the above error was encountered while instantiating `fn not_called::<i32>`
+  --> $DIR/collect-in-dead-closure.rs:24:33
+   |
+LL |         let _closure: fn() = || not_called::<T>();
+   |                                 ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-dead-closure.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-closure.opt.stderr
new file mode 100644
index 00000000000..75c3575a110
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-closure.opt.stderr
@@ -0,0 +1,23 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/collect-in-dead-closure.rs:9:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-closure.rs:9:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/collect-in-dead-closure.rs:17:17
+   |
+LL |         let _ = Fail::<T>::C;
+   |                 ^^^^^^^^^^^^
+
+note: the above error was encountered while instantiating `fn not_called::<i32>`
+  --> $DIR/collect-in-dead-closure.rs:24:33
+   |
+LL |         let _closure: fn() = || not_called::<T>();
+   |                                 ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-dead-closure.rs b/tests/ui/consts/required-consts/collect-in-dead-closure.rs
new file mode 100644
index 00000000000..a00214c62db
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-closure.rs
@@ -0,0 +1,30 @@
+//@revisions: noopt opt
+//@ build-fail
+//@[noopt] compile-flags: -Copt-level=0
+//@[opt] compile-flags: -O
+//! This fails without optimizations, so it should also fail with optimizations.
+
+struct Fail<T>(T);
+impl<T> Fail<T> {
+    const C: () = panic!(); //~ERROR evaluation of `Fail::<i32>::C` failed
+}
+
+// This function is not actually called, but it is mentioned in a closure that is coerced to a
+// function pointer in dead code in a function that is called. Make sure we still find this error.
+#[inline(never)]
+fn not_called<T>() {
+    if false {
+        let _ = Fail::<T>::C;
+    }
+}
+
+#[inline(never)]
+fn called<T>() {
+    if false {
+        let _closure: fn() = || not_called::<T>();
+    }
+}
+
+pub fn main() {
+    called::<i32>();
+}
diff --git a/tests/ui/consts/required-consts/collect-in-dead-drop.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-drop.noopt.stderr
index 0bf231d09f1..73790f7517d 100644
--- a/tests/ui/consts/required-consts/collect-in-dead-drop.noopt.stderr
+++ b/tests/ui/consts/required-consts/collect-in-dead-drop.noopt.stderr
@@ -1,13 +1,13 @@
 error[E0080]: evaluation of `Fail::<i32>::C` failed
-  --> $DIR/collect-in-dead-drop.rs:12:19
+  --> $DIR/collect-in-dead-drop.rs:9:19
    |
 LL |     const C: () = panic!();
-   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-drop.rs:12:19
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-drop.rs:9:19
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 note: erroneous constant encountered
-  --> $DIR/collect-in-dead-drop.rs:19:17
+  --> $DIR/collect-in-dead-drop.rs:16:17
    |
 LL |         let _ = Fail::<T>::C;
    |                 ^^^^^^^^^^^^
diff --git a/tests/ui/consts/required-consts/collect-in-dead-drop.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-drop.opt.stderr
new file mode 100644
index 00000000000..73790f7517d
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-drop.opt.stderr
@@ -0,0 +1,20 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/collect-in-dead-drop.rs:9:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-drop.rs:9:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/collect-in-dead-drop.rs:16:17
+   |
+LL |         let _ = Fail::<T>::C;
+   |                 ^^^^^^^^^^^^
+
+note: the above error was encountered while instantiating `fn <Fail<i32> as std::ops::Drop>::drop`
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-dead-drop.rs b/tests/ui/consts/required-consts/collect-in-dead-drop.rs
index c9ffcec6903..389fcf5dfc9 100644
--- a/tests/ui/consts/required-consts/collect-in-dead-drop.rs
+++ b/tests/ui/consts/required-consts/collect-in-dead-drop.rs
@@ -1,15 +1,12 @@
 //@revisions: noopt opt
-//@[noopt] build-fail
+//@ build-fail
+//@[noopt] compile-flags: -Copt-level=0
 //@[opt] compile-flags: -O
-//FIXME: `opt` revision currently does not stop with an error due to
-//<https://github.com/rust-lang/rust/issues/107503>.
-//@[opt] build-pass
-//! Make sure we detect erroneous constants post-monomorphization even when they are unused. This is
-//! crucial, people rely on it for soundness. (https://github.com/rust-lang/rust/issues/112090)
+//! This fails without optimizations, so it should also fail with optimizations.
 
 struct Fail<T>(T);
 impl<T> Fail<T> {
-    const C: () = panic!(); //[noopt]~ERROR evaluation of `Fail::<i32>::C` failed
+    const C: () = panic!(); //~ERROR evaluation of `Fail::<i32>::C` failed
 }
 
 // This function is not actually called, but is mentioned implicitly as destructor in dead code in a
diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.noopt.stderr
new file mode 100644
index 00000000000..706c0d55b62
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.noopt.stderr
@@ -0,0 +1,20 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/collect-in-dead-fn-behind-assoc-type.rs:10:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-fn-behind-assoc-type.rs:10:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/collect-in-dead-fn-behind-assoc-type.rs:16:17
+   |
+LL |         let _ = Fail::<T>::C;
+   |                 ^^^^^^^^^^^^
+
+note: the above error was encountered while instantiating `fn not_called::<i32>`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.opt.stderr
new file mode 100644
index 00000000000..706c0d55b62
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.opt.stderr
@@ -0,0 +1,20 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/collect-in-dead-fn-behind-assoc-type.rs:10:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-fn-behind-assoc-type.rs:10:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/collect-in-dead-fn-behind-assoc-type.rs:16:17
+   |
+LL |         let _ = Fail::<T>::C;
+   |                 ^^^^^^^^^^^^
+
+note: the above error was encountered while instantiating `fn not_called::<i32>`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.rs b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.rs
new file mode 100644
index 00000000000..9c36af50bb7
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-assoc-type.rs
@@ -0,0 +1,49 @@
+#![feature(impl_trait_in_assoc_type)]
+//@revisions: noopt opt
+//@ build-fail
+//@[noopt] compile-flags: -Copt-level=0
+//@[opt] compile-flags: -O
+//! This fails without optimizations, so it should also fail with optimizations.
+
+struct Fail<T>(T);
+impl<T> Fail<T> {
+    const C: () = panic!(); //~ERROR evaluation of `Fail::<i32>::C` failed
+}
+
+#[inline(never)]
+fn not_called<T>() {
+    if false {
+        let _ = Fail::<T>::C;
+    }
+}
+
+#[inline(never)]
+fn callit_not(f: impl Fn()) {
+    if false {
+        f();
+    }
+}
+
+// Using `Fn` here is important; with `FnOnce` another shim gets involved which somehow makes this
+// easier to collect properly.
+trait Hideaway {
+    type T: Fn();
+    const C: Self::T;
+}
+impl Hideaway for () {
+    type T = impl Fn();
+    const C: Self::T = not_called::<i32>;
+}
+
+#[inline(never)]
+fn reveal<T: Hideaway>() {
+    if false {
+        callit_not(T::C);
+    }
+}
+
+fn main() {
+    if false {
+        reveal::<()>()
+    }
+}
diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.noopt.stderr
new file mode 100644
index 00000000000..581edd2b7b8
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.noopt.stderr
@@ -0,0 +1,20 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/collect-in-dead-fn-behind-generic.rs:9:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-fn-behind-generic.rs:9:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/collect-in-dead-fn-behind-generic.rs:15:17
+   |
+LL |         let _ = Fail::<T>::C;
+   |                 ^^^^^^^^^^^^
+
+note: the above error was encountered while instantiating `fn not_called::<i32>`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.opt.stderr
new file mode 100644
index 00000000000..581edd2b7b8
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.opt.stderr
@@ -0,0 +1,20 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/collect-in-dead-fn-behind-generic.rs:9:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-fn-behind-generic.rs:9:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/collect-in-dead-fn-behind-generic.rs:15:17
+   |
+LL |         let _ = Fail::<T>::C;
+   |                 ^^^^^^^^^^^^
+
+note: the above error was encountered while instantiating `fn not_called::<i32>`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.rs b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.rs
new file mode 100644
index 00000000000..5829d914ee1
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-generic.rs
@@ -0,0 +1,30 @@
+//@revisions: noopt opt
+//@ build-fail
+//@[noopt] compile-flags: -Copt-level=0
+//@[opt] compile-flags: -O
+//! This fails without optimizations, so it should also fail with optimizations.
+
+struct Fail<T>(T);
+impl<T> Fail<T> {
+    const C: () = panic!(); //~ERROR evaluation of `Fail::<i32>::C` failed
+}
+
+#[inline(never)]
+fn not_called<T>() {
+    if false {
+        let _ = Fail::<T>::C;
+    }
+}
+
+#[inline(never)]
+fn callit_not(f: impl Fn()) {
+    if false {
+        f();
+    }
+}
+
+fn main() {
+    if false {
+        callit_not(not_called::<i32>)
+    }
+}
diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.noopt.stderr
new file mode 100644
index 00000000000..07e46b8a816
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.noopt.stderr
@@ -0,0 +1,20 @@
+error[E0080]: evaluation of `m::Fail::<i32>::C` failed
+  --> $DIR/collect-in-dead-fn-behind-opaque-type.rs:11:23
+   |
+LL |         const C: () = panic!();
+   |                       ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-fn-behind-opaque-type.rs:11:23
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/collect-in-dead-fn-behind-opaque-type.rs:19:21
+   |
+LL |             let _ = Fail::<T>::C;
+   |                     ^^^^^^^^^^^^
+
+note: the above error was encountered while instantiating `fn m::not_called::<i32>`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.opt.stderr
new file mode 100644
index 00000000000..07e46b8a816
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.opt.stderr
@@ -0,0 +1,20 @@
+error[E0080]: evaluation of `m::Fail::<i32>::C` failed
+  --> $DIR/collect-in-dead-fn-behind-opaque-type.rs:11:23
+   |
+LL |         const C: () = panic!();
+   |                       ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-fn-behind-opaque-type.rs:11:23
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/collect-in-dead-fn-behind-opaque-type.rs:19:21
+   |
+LL |             let _ = Fail::<T>::C;
+   |                     ^^^^^^^^^^^^
+
+note: the above error was encountered while instantiating `fn m::not_called::<i32>`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.rs b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.rs
new file mode 100644
index 00000000000..795e021ceb0
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-fn-behind-opaque-type.rs
@@ -0,0 +1,37 @@
+//@revisions: noopt opt
+//@ build-fail
+//@[noopt] compile-flags: -Copt-level=0
+//@[opt] compile-flags: -O
+//! This fails without optimizations, so it should also fail with optimizations.
+#![feature(type_alias_impl_trait)]
+
+mod m {
+    struct Fail<T>(T);
+    impl<T> Fail<T> {
+        const C: () = panic!(); //~ERROR evaluation of `m::Fail::<i32>::C` failed
+    }
+
+    pub type NotCalledFn = impl Fn();
+
+    #[inline(never)]
+    fn not_called<T>() {
+        if false {
+            let _ = Fail::<T>::C;
+        }
+    }
+
+    fn mk_not_called() -> NotCalledFn {
+        not_called::<i32>
+    }
+}
+
+fn main() {
+    // This does not involve a constant of `FnDef` type, it generates the value via unsafe
+    // shenanigans instead. This ensures that we check all `FnDef` types that occur in a function,
+    // not just those of constants. Furthermore the `FnDef` is behind an opaque type which bust be
+    // normalized away to reveal the function type.
+    if false {
+        let x: m::NotCalledFn = unsafe { std::mem::transmute(()) };
+        x();
+    }
+}
diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fn.noopt.stderr
index 8bb99efe8e4..52462076ff9 100644
--- a/tests/ui/consts/required-consts/collect-in-dead-fn.noopt.stderr
+++ b/tests/ui/consts/required-consts/collect-in-dead-fn.noopt.stderr
@@ -1,19 +1,19 @@
 error[E0080]: evaluation of `Fail::<i32>::C` failed
-  --> $DIR/collect-in-dead-fn.rs:12:19
+  --> $DIR/collect-in-dead-fn.rs:9:19
    |
 LL |     const C: () = panic!();
-   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-fn.rs:12:19
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-fn.rs:9:19
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 note: erroneous constant encountered
-  --> $DIR/collect-in-dead-fn.rs:22:17
+  --> $DIR/collect-in-dead-fn.rs:19:17
    |
 LL |         let _ = Fail::<T>::C;
    |                 ^^^^^^^^^^^^
 
 note: the above error was encountered while instantiating `fn not_called::<i32>`
-  --> $DIR/collect-in-dead-fn.rs:29:9
+  --> $DIR/collect-in-dead-fn.rs:26:9
    |
 LL |         not_called::<T>();
    |         ^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fn.opt.stderr
new file mode 100644
index 00000000000..52462076ff9
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-fn.opt.stderr
@@ -0,0 +1,23 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/collect-in-dead-fn.rs:9:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-fn.rs:9:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/collect-in-dead-fn.rs:19:17
+   |
+LL |         let _ = Fail::<T>::C;
+   |                 ^^^^^^^^^^^^
+
+note: the above error was encountered while instantiating `fn not_called::<i32>`
+  --> $DIR/collect-in-dead-fn.rs:26:9
+   |
+LL |         not_called::<T>();
+   |         ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn.rs b/tests/ui/consts/required-consts/collect-in-dead-fn.rs
index 9e6b1519153..1c95e0c303f 100644
--- a/tests/ui/consts/required-consts/collect-in-dead-fn.rs
+++ b/tests/ui/consts/required-consts/collect-in-dead-fn.rs
@@ -1,15 +1,12 @@
 //@revisions: noopt opt
-//@[noopt] build-fail
+//@ build-fail
+//@[noopt] compile-flags: -Copt-level=0
 //@[opt] compile-flags: -O
-//FIXME: `opt` revision currently does not stop with an error due to
-//<https://github.com/rust-lang/rust/issues/107503>.
-//@[opt] build-pass
-//! Make sure we detect erroneous constants post-monomorphization even when they are unused. This is
-//! crucial, people rely on it for soundness. (https://github.com/rust-lang/rust/issues/112090)
+//! This fails without optimizations, so it should also fail with optimizations.
 
 struct Fail<T>(T);
 impl<T> Fail<T> {
-    const C: () = panic!(); //[noopt]~ERROR evaluation of `Fail::<i32>::C` failed
+    const C: () = panic!(); //~ERROR evaluation of `Fail::<i32>::C` failed
 }
 
 // This function is not actually called, but it is mentioned in dead code in a function that is
diff --git a/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.noopt.stderr
new file mode 100644
index 00000000000..dea2a342383
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.noopt.stderr
@@ -0,0 +1,20 @@
+error[E0080]: evaluation of `Late::<i32>::FAIL` failed
+  --> $DIR/collect-in-dead-fnptr-in-const.rs:9:22
+   |
+LL |     const FAIL: () = panic!();
+   |                      ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-fnptr-in-const.rs:9:22
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/collect-in-dead-fnptr-in-const.rs:10:28
+   |
+LL |     const FNPTR: fn() = || Self::FAIL;
+   |                            ^^^^^^^^^^
+
+note: the above error was encountered while instantiating `fn Late::<i32>::FNPTR::{closure#0}`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.opt.stderr
new file mode 100644
index 00000000000..dea2a342383
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.opt.stderr
@@ -0,0 +1,20 @@
+error[E0080]: evaluation of `Late::<i32>::FAIL` failed
+  --> $DIR/collect-in-dead-fnptr-in-const.rs:9:22
+   |
+LL |     const FAIL: () = panic!();
+   |                      ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-fnptr-in-const.rs:9:22
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/collect-in-dead-fnptr-in-const.rs:10:28
+   |
+LL |     const FNPTR: fn() = || Self::FAIL;
+   |                            ^^^^^^^^^^
+
+note: the above error was encountered while instantiating `fn Late::<i32>::FNPTR::{closure#0}`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.rs b/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.rs
new file mode 100644
index 00000000000..8b6344c93f3
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-fnptr-in-const.rs
@@ -0,0 +1,34 @@
+//@revisions: noopt opt
+//@ build-fail
+//@[noopt] compile-flags: -Copt-level=0
+//@[opt] compile-flags: -O
+//! This fails without optimizations, so it should also fail with optimizations.
+
+struct Late<T>(T);
+impl<T> Late<T> {
+    const FAIL: () = panic!(); //~ERROR evaluation of `Late::<i32>::FAIL` failed
+    const FNPTR: fn() = || Self::FAIL;
+}
+
+// This function is not actually called, but it is mentioned in dead code in a function that is
+// called. The function then mentions a const that evaluates to a fnptr that points to a function
+// that used a const that fails to evaluate.
+// This tests that when processing mentioned items, we also check the fnptrs in the final values
+// of consts that we encounter.
+#[inline(never)]
+fn not_called<T>() {
+    if false {
+        let _ = Late::<T>::FNPTR;
+    }
+}
+
+#[inline(never)]
+fn called<T>() {
+    if false {
+        not_called::<T>();
+    }
+}
+
+pub fn main() {
+    called::<i32>();
+}
diff --git a/tests/ui/consts/required-consts/collect-in-dead-fnptr.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fnptr.noopt.stderr
new file mode 100644
index 00000000000..51c68782687
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-fnptr.noopt.stderr
@@ -0,0 +1,23 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/collect-in-dead-fnptr.rs:9:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-fnptr.rs:9:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/collect-in-dead-fnptr.rs:18:17
+   |
+LL |         let _ = Fail::<T>::C;
+   |                 ^^^^^^^^^^^^
+
+note: the above error was encountered while instantiating `fn not_called::<i32>`
+  --> $DIR/collect-in-dead-fnptr.rs:27:28
+   |
+LL |         let _fnptr: fn() = not_called::<T>;
+   |                            ^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-dead-fnptr.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fnptr.opt.stderr
new file mode 100644
index 00000000000..51c68782687
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-fnptr.opt.stderr
@@ -0,0 +1,23 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/collect-in-dead-fnptr.rs:9:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-fnptr.rs:9:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/collect-in-dead-fnptr.rs:18:17
+   |
+LL |         let _ = Fail::<T>::C;
+   |                 ^^^^^^^^^^^^
+
+note: the above error was encountered while instantiating `fn not_called::<i32>`
+  --> $DIR/collect-in-dead-fnptr.rs:27:28
+   |
+LL |         let _fnptr: fn() = not_called::<T>;
+   |                            ^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-dead-fnptr.rs b/tests/ui/consts/required-consts/collect-in-dead-fnptr.rs
new file mode 100644
index 00000000000..acbe34829e8
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-fnptr.rs
@@ -0,0 +1,33 @@
+//@revisions: noopt opt
+//@ build-fail
+//@[noopt] compile-flags: -Copt-level=0
+//@[opt] compile-flags: -O
+//! This fails without optimizations, so it should also fail with optimizations.
+
+struct Fail<T>(T);
+impl<T> Fail<T> {
+    const C: () = panic!(); //~ERROR evaluation of `Fail::<i32>::C` failed
+}
+
+// This function is not actually called, but it is mentioned in dead code in a function that is
+// called. Make sure we still find this error.
+// This ensures that we consider ReifyFnPointer coercions when gathering "mentioned" items.
+#[inline(never)]
+fn not_called<T>() {
+    if false {
+        let _ = Fail::<T>::C;
+    }
+}
+
+#[inline(never)]
+fn called<T>() {
+    if false {
+        // We don't call the function, but turn it to a function pointer.
+        // Make sure it still gest added to `mentioned_items`.
+        let _fnptr: fn() = not_called::<T>;
+    }
+}
+
+pub fn main() {
+    called::<i32>();
+}
diff --git a/tests/ui/consts/required-consts/collect-in-dead-forget.rs b/tests/ui/consts/required-consts/collect-in-dead-forget.rs
index 720b7a499f7..7586004116c 100644
--- a/tests/ui/consts/required-consts/collect-in-dead-forget.rs
+++ b/tests/ui/consts/required-consts/collect-in-dead-forget.rs
@@ -1,8 +1,8 @@
 //@revisions: noopt opt
 //@build-pass
+//@[noopt] compile-flags: -Copt-level=0
 //@[opt] compile-flags: -O
-//! Make sure we detect erroneous constants post-monomorphization even when they are unused. This is
-//! crucial, people rely on it for soundness. (https://github.com/rust-lang/rust/issues/112090)
+//! This passes without optimizations, so it can (and should) also pass with optimizations.
 
 struct Fail<T>(T);
 impl<T> Fail<T> {
diff --git a/tests/ui/consts/required-consts/collect-in-dead-move.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-move.noopt.stderr
index 5b1df78b232..2ab1f80e2d3 100644
--- a/tests/ui/consts/required-consts/collect-in-dead-move.noopt.stderr
+++ b/tests/ui/consts/required-consts/collect-in-dead-move.noopt.stderr
@@ -1,13 +1,13 @@
 error[E0080]: evaluation of `Fail::<i32>::C` failed
-  --> $DIR/collect-in-dead-move.rs:12:19
+  --> $DIR/collect-in-dead-move.rs:9:19
    |
 LL |     const C: () = panic!();
-   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-move.rs:12:19
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-move.rs:9:19
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 note: erroneous constant encountered
-  --> $DIR/collect-in-dead-move.rs:19:17
+  --> $DIR/collect-in-dead-move.rs:16:17
    |
 LL |         let _ = Fail::<T>::C;
    |                 ^^^^^^^^^^^^
diff --git a/tests/ui/consts/required-consts/collect-in-dead-move.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-move.opt.stderr
new file mode 100644
index 00000000000..2ab1f80e2d3
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-move.opt.stderr
@@ -0,0 +1,20 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/collect-in-dead-move.rs:9:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-move.rs:9:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/collect-in-dead-move.rs:16:17
+   |
+LL |         let _ = Fail::<T>::C;
+   |                 ^^^^^^^^^^^^
+
+note: the above error was encountered while instantiating `fn <Fail<i32> as std::ops::Drop>::drop`
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-dead-move.rs b/tests/ui/consts/required-consts/collect-in-dead-move.rs
index f3a6ba8a657..6a224a375cf 100644
--- a/tests/ui/consts/required-consts/collect-in-dead-move.rs
+++ b/tests/ui/consts/required-consts/collect-in-dead-move.rs
@@ -1,15 +1,12 @@
 //@revisions: noopt opt
-//@[noopt] build-fail
+//@ build-fail
+//@[noopt] compile-flags: -Copt-level=0
 //@[opt] compile-flags: -O
-//FIXME: `opt` revision currently does not stop with an error due to
-//<https://github.com/rust-lang/rust/issues/107503>.
-//@[opt] build-pass
-//! Make sure we detect erroneous constants post-monomorphization even when they are unused. This is
-//! crucial, people rely on it for soundness. (https://github.com/rust-lang/rust/issues/112090)
+//! This fails without optimizations, so it should also fail with optimizations.
 
 struct Fail<T>(T);
 impl<T> Fail<T> {
-    const C: () = panic!(); //[noopt]~ERROR evaluation of `Fail::<i32>::C` failed
+    const C: () = panic!(); //~ERROR evaluation of `Fail::<i32>::C` failed
 }
 
 // This function is not actually called, but is mentioned implicitly as destructor in dead code in a
diff --git a/tests/ui/consts/required-consts/collect-in-dead-vtable.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-vtable.noopt.stderr
index 56b6989b441..b4e18706489 100644
--- a/tests/ui/consts/required-consts/collect-in-dead-vtable.noopt.stderr
+++ b/tests/ui/consts/required-consts/collect-in-dead-vtable.noopt.stderr
@@ -1,21 +1,21 @@
 error[E0080]: evaluation of `Fail::<i32>::C` failed
-  --> $DIR/collect-in-dead-vtable.rs:12:19
+  --> $DIR/collect-in-dead-vtable.rs:9:19
    |
 LL |     const C: () = panic!();
-   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-vtable.rs:12:19
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-vtable.rs:9:19
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 note: erroneous constant encountered
-  --> $DIR/collect-in-dead-vtable.rs:26:21
+  --> $DIR/collect-in-dead-vtable.rs:22:21
    |
 LL |             let _ = Fail::<T>::C;
    |                     ^^^^^^^^^^^^
 
 note: the above error was encountered while instantiating `fn <std::vec::Vec<i32> as MyTrait>::not_called`
-  --> $DIR/collect-in-dead-vtable.rs:35:40
+  --> $DIR/collect-in-dead-vtable.rs:31:40
    |
-LL |         let gen_vtable: &dyn MyTrait = &v; // vtable "appears" here
+LL |         let gen_vtable: &dyn MyTrait = &v; // vtable is "mentioned" here
    |                                        ^^
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/consts/required-consts/collect-in-dead-vtable.opt.stderr b/tests/ui/consts/required-consts/collect-in-dead-vtable.opt.stderr
new file mode 100644
index 00000000000..b4e18706489
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-vtable.opt.stderr
@@ -0,0 +1,23 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/collect-in-dead-vtable.rs:9:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-vtable.rs:9:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/collect-in-dead-vtable.rs:22:21
+   |
+LL |             let _ = Fail::<T>::C;
+   |                     ^^^^^^^^^^^^
+
+note: the above error was encountered while instantiating `fn <std::vec::Vec<i32> as MyTrait>::not_called`
+  --> $DIR/collect-in-dead-vtable.rs:31:40
+   |
+LL |         let gen_vtable: &dyn MyTrait = &v; // vtable is "mentioned" here
+   |                                        ^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-dead-vtable.rs b/tests/ui/consts/required-consts/collect-in-dead-vtable.rs
index f21a1cc1fc2..f63207eafec 100644
--- a/tests/ui/consts/required-consts/collect-in-dead-vtable.rs
+++ b/tests/ui/consts/required-consts/collect-in-dead-vtable.rs
@@ -1,15 +1,12 @@
 //@revisions: noopt opt
-//@[noopt] build-fail
+//@ build-fail
+//@[noopt] compile-flags: -Copt-level=0
 //@[opt] compile-flags: -O
-//FIXME: `opt` revision currently does not stop with an error due to
-//<https://github.com/rust-lang/rust/issues/107503>.
-//@[opt] build-pass
-//! Make sure we detect erroneous constants post-monomorphization even when they are unused. This is
-//! crucial, people rely on it for soundness. (https://github.com/rust-lang/rust/issues/112090)
+//! This fails without optimizations, so it should also fail with optimizations.
 
 struct Fail<T>(T);
 impl<T> Fail<T> {
-    const C: () = panic!(); //[noopt]~ERROR evaluation of `Fail::<i32>::C` failed
+    const C: () = panic!(); //~ERROR evaluation of `Fail::<i32>::C` failed
 }
 
 trait MyTrait {
@@ -18,8 +15,7 @@ trait MyTrait {
 
 // This function is not actually called, but it is mentioned in a vtable in a function that is
 // called. Make sure we still find this error.
-// This relies on mono-item collection checking `required_consts` in functions that are referenced
-// in vtables that syntactically appear in collected functions (even inside dead code).
+// This ensures that we are properly considering vtables when gathering "mentioned" items.
 impl<T> MyTrait for Vec<T> {
     fn not_called(&self) {
         if false {
@@ -32,7 +28,7 @@ impl<T> MyTrait for Vec<T> {
 fn called<T>() {
     if false {
         let v: Vec<T> = Vec::new();
-        let gen_vtable: &dyn MyTrait = &v; // vtable "appears" here
+        let gen_vtable: &dyn MyTrait = &v; // vtable is "mentioned" here
     }
 }
 
diff --git a/tests/ui/consts/required-consts/interpret-in-const-called-fn.noopt.stderr b/tests/ui/consts/required-consts/interpret-in-const-called-fn.noopt.stderr
index 75304591b9f..0e3bbbcc2ec 100644
--- a/tests/ui/consts/required-consts/interpret-in-const-called-fn.noopt.stderr
+++ b/tests/ui/consts/required-consts/interpret-in-const-called-fn.noopt.stderr
@@ -1,13 +1,13 @@
 error[E0080]: evaluation of `Fail::<i32>::C` failed
-  --> $DIR/interpret-in-const-called-fn.rs:7:19
+  --> $DIR/interpret-in-const-called-fn.rs:8:19
    |
 LL |     const C: () = panic!();
-   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/interpret-in-const-called-fn.rs:7:19
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/interpret-in-const-called-fn.rs:8:19
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 note: erroneous constant encountered
-  --> $DIR/interpret-in-const-called-fn.rs:16:9
+  --> $DIR/interpret-in-const-called-fn.rs:17:9
    |
 LL |         Fail::<T>::C;
    |         ^^^^^^^^^^^^
diff --git a/tests/ui/consts/required-consts/interpret-in-const-called-fn.opt.stderr b/tests/ui/consts/required-consts/interpret-in-const-called-fn.opt.stderr
index 75304591b9f..0e3bbbcc2ec 100644
--- a/tests/ui/consts/required-consts/interpret-in-const-called-fn.opt.stderr
+++ b/tests/ui/consts/required-consts/interpret-in-const-called-fn.opt.stderr
@@ -1,13 +1,13 @@
 error[E0080]: evaluation of `Fail::<i32>::C` failed
-  --> $DIR/interpret-in-const-called-fn.rs:7:19
+  --> $DIR/interpret-in-const-called-fn.rs:8:19
    |
 LL |     const C: () = panic!();
-   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/interpret-in-const-called-fn.rs:7:19
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/interpret-in-const-called-fn.rs:8:19
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 note: erroneous constant encountered
-  --> $DIR/interpret-in-const-called-fn.rs:16:9
+  --> $DIR/interpret-in-const-called-fn.rs:17:9
    |
 LL |         Fail::<T>::C;
    |         ^^^^^^^^^^^^
diff --git a/tests/ui/consts/required-consts/interpret-in-const-called-fn.rs b/tests/ui/consts/required-consts/interpret-in-const-called-fn.rs
index c409fae0bb9..f2e83f56f37 100644
--- a/tests/ui/consts/required-consts/interpret-in-const-called-fn.rs
+++ b/tests/ui/consts/required-consts/interpret-in-const-called-fn.rs
@@ -1,4 +1,5 @@
 //@revisions: noopt opt
+//@[noopt] compile-flags: -Copt-level=0
 //@[opt] compile-flags: -O
 //! Make sure we error on erroneous consts even if they are unused.
 
diff --git a/tests/ui/consts/required-consts/interpret-in-promoted.noopt.stderr b/tests/ui/consts/required-consts/interpret-in-promoted.noopt.stderr
index 491131daf8d..6ab991b6471 100644
--- a/tests/ui/consts/required-consts/interpret-in-promoted.noopt.stderr
+++ b/tests/ui/consts/required-consts/interpret-in-promoted.noopt.stderr
@@ -6,18 +6,18 @@ error[E0080]: evaluation of constant value failed
 note: inside `unreachable_unchecked`
   --> $SRC_DIR/core/src/hint.rs:LL:COL
 note: inside `ub`
-  --> $DIR/interpret-in-promoted.rs:6:5
+  --> $DIR/interpret-in-promoted.rs:7:5
    |
 LL |     std::hint::unreachable_unchecked();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: inside `FOO`
-  --> $DIR/interpret-in-promoted.rs:12:28
+  --> $DIR/interpret-in-promoted.rs:13:28
    |
 LL |     let _x: &'static () = &ub();
    |                            ^^^^
 
 note: erroneous constant encountered
-  --> $DIR/interpret-in-promoted.rs:12:27
+  --> $DIR/interpret-in-promoted.rs:13:27
    |
 LL |     let _x: &'static () = &ub();
    |                           ^^^^^
diff --git a/tests/ui/consts/required-consts/interpret-in-promoted.opt.stderr b/tests/ui/consts/required-consts/interpret-in-promoted.opt.stderr
index 491131daf8d..6ab991b6471 100644
--- a/tests/ui/consts/required-consts/interpret-in-promoted.opt.stderr
+++ b/tests/ui/consts/required-consts/interpret-in-promoted.opt.stderr
@@ -6,18 +6,18 @@ error[E0080]: evaluation of constant value failed
 note: inside `unreachable_unchecked`
   --> $SRC_DIR/core/src/hint.rs:LL:COL
 note: inside `ub`
-  --> $DIR/interpret-in-promoted.rs:6:5
+  --> $DIR/interpret-in-promoted.rs:7:5
    |
 LL |     std::hint::unreachable_unchecked();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: inside `FOO`
-  --> $DIR/interpret-in-promoted.rs:12:28
+  --> $DIR/interpret-in-promoted.rs:13:28
    |
 LL |     let _x: &'static () = &ub();
    |                            ^^^^
 
 note: erroneous constant encountered
-  --> $DIR/interpret-in-promoted.rs:12:27
+  --> $DIR/interpret-in-promoted.rs:13:27
    |
 LL |     let _x: &'static () = &ub();
    |                           ^^^^^
diff --git a/tests/ui/consts/required-consts/interpret-in-promoted.rs b/tests/ui/consts/required-consts/interpret-in-promoted.rs
index 9c2cf4e70d3..187494180ad 100644
--- a/tests/ui/consts/required-consts/interpret-in-promoted.rs
+++ b/tests/ui/consts/required-consts/interpret-in-promoted.rs
@@ -1,4 +1,5 @@
 //@revisions: noopt opt
+//@[noopt] compile-flags: -Copt-level=0
 //@[opt] compile-flags: -O
 //! Make sure we error on erroneous consts even if they are unused.
 
diff --git a/tests/ui/consts/required-consts/interpret-in-static.noopt.stderr b/tests/ui/consts/required-consts/interpret-in-static.noopt.stderr
index 159c9449fc0..5e8da609e76 100644
--- a/tests/ui/consts/required-consts/interpret-in-static.noopt.stderr
+++ b/tests/ui/consts/required-consts/interpret-in-static.noopt.stderr
@@ -1,13 +1,13 @@
 error[E0080]: evaluation of `Fail::<i32>::C` failed
-  --> $DIR/interpret-in-static.rs:7:19
+  --> $DIR/interpret-in-static.rs:8:19
    |
 LL |     const C: () = panic!();
-   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/interpret-in-static.rs:7:19
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/interpret-in-static.rs:8:19
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 note: erroneous constant encountered
-  --> $DIR/interpret-in-static.rs:15:9
+  --> $DIR/interpret-in-static.rs:16:9
    |
 LL |         Fail::<i32>::C;
    |         ^^^^^^^^^^^^^^
diff --git a/tests/ui/consts/required-consts/interpret-in-static.opt.stderr b/tests/ui/consts/required-consts/interpret-in-static.opt.stderr
index 159c9449fc0..5e8da609e76 100644
--- a/tests/ui/consts/required-consts/interpret-in-static.opt.stderr
+++ b/tests/ui/consts/required-consts/interpret-in-static.opt.stderr
@@ -1,13 +1,13 @@
 error[E0080]: evaluation of `Fail::<i32>::C` failed
-  --> $DIR/interpret-in-static.rs:7:19
+  --> $DIR/interpret-in-static.rs:8:19
    |
 LL |     const C: () = panic!();
-   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/interpret-in-static.rs:7:19
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/interpret-in-static.rs:8:19
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 note: erroneous constant encountered
-  --> $DIR/interpret-in-static.rs:15:9
+  --> $DIR/interpret-in-static.rs:16:9
    |
 LL |         Fail::<i32>::C;
    |         ^^^^^^^^^^^^^^
diff --git a/tests/ui/consts/required-consts/interpret-in-static.rs b/tests/ui/consts/required-consts/interpret-in-static.rs
index 559e281b2b0..8bacd030440 100644
--- a/tests/ui/consts/required-consts/interpret-in-static.rs
+++ b/tests/ui/consts/required-consts/interpret-in-static.rs
@@ -1,4 +1,5 @@
 //@revisions: noopt opt
+//@[noopt] compile-flags: -Copt-level=0
 //@[opt] compile-flags: -O
 //! Make sure we error on erroneous consts even if they are unused.
 
diff --git a/tests/ui/coroutine/gen_block_is_fused_iter.rs b/tests/ui/coroutine/gen_block_is_fused_iter.rs
new file mode 100644
index 00000000000..f3e19a7f54f
--- /dev/null
+++ b/tests/ui/coroutine/gen_block_is_fused_iter.rs
@@ -0,0 +1,21 @@
+//@ revisions: next old
+//@compile-flags: --edition 2024 -Zunstable-options
+//@[next] compile-flags: -Znext-solver
+//@ check-pass
+#![feature(gen_blocks)]
+
+use std::iter::FusedIterator;
+
+fn foo() -> impl FusedIterator {
+    gen { yield 42 }
+}
+
+fn bar() -> impl FusedIterator<Item = u16> {
+    gen { yield 42 }
+}
+
+fn baz() -> impl FusedIterator + Iterator<Item = i64> {
+    gen { yield 42 }
+}
+
+fn main() {}
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs
new file mode 100644
index 00000000000..8d8917fd319
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs
@@ -0,0 +1,45 @@
+#[diagnostic::on_unimplemented(message = "{{Test } thing")]
+//~^WARN unmatched `}` found
+//~|WARN unmatched `}` found
+trait ImportantTrait1 {}
+
+#[diagnostic::on_unimplemented(message = "Test {}")]
+//~^WARN positional format arguments are not allowed here
+//~|WARN positional format arguments are not allowed here
+trait ImportantTrait2 {}
+
+#[diagnostic::on_unimplemented(message = "Test {1:}")]
+//~^WARN positional format arguments are not allowed here
+//~|WARN positional format arguments are not allowed here
+trait ImportantTrait3 {}
+
+#[diagnostic::on_unimplemented(message = "Test {Self:123}")]
+//~^WARN invalid format specifier
+//~|WARN invalid format specifier
+trait ImportantTrait4 {}
+
+#[diagnostic::on_unimplemented(message = "Test {Self:!}")]
+//~^WARN expected `'}'`, found `'!'`
+//~|WARN expected `'}'`, found `'!'`
+//~|WARN unmatched `}` found
+//~|WARN unmatched `}` found
+trait ImportantTrait5 {}
+
+fn check_1(_: impl ImportantTrait1) {}
+fn check_2(_: impl ImportantTrait2) {}
+fn check_3(_: impl ImportantTrait3) {}
+fn check_4(_: impl ImportantTrait4) {}
+fn check_5(_: impl ImportantTrait5) {}
+
+fn main() {
+    check_1(());
+    //~^ERROR {{Test } thing
+    check_2(());
+    //~^ERROR Test {}
+    check_3(());
+    //~^ERROR Test {1}
+    check_4(());
+    //~^ERROR Test ()
+    check_5(());
+    //~^ERROR Test {Self:!}
+}
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr
new file mode 100644
index 00000000000..932e81ca48e
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr
@@ -0,0 +1,193 @@
+warning: unmatched `}` found
+  --> $DIR/broken_format.rs:1:32
+   |
+LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")]
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
+
+warning: positional format arguments are not allowed here
+  --> $DIR/broken_format.rs:6:32
+   |
+LL | #[diagnostic::on_unimplemented(message = "Test {}")]
+   |                                ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: only named format arguments with the name of one of the generic types are allowed in this context
+
+warning: positional format arguments are not allowed here
+  --> $DIR/broken_format.rs:11:32
+   |
+LL | #[diagnostic::on_unimplemented(message = "Test {1:}")]
+   |                                ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: only named format arguments with the name of one of the generic types are allowed in this context
+
+warning: invalid format specifier
+  --> $DIR/broken_format.rs:16:32
+   |
+LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")]
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: no format specifier are supported in this position
+
+warning: expected `'}'`, found `'!'`
+  --> $DIR/broken_format.rs:21:32
+   |
+LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: unmatched `}` found
+  --> $DIR/broken_format.rs:21:32
+   |
+LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: unmatched `}` found
+  --> $DIR/broken_format.rs:1:32
+   |
+LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")]
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0277]: {{Test } thing
+  --> $DIR/broken_format.rs:35:13
+   |
+LL |     check_1(());
+   |     ------- ^^ the trait `ImportantTrait1` is not implemented for `()`
+   |     |
+   |     required by a bound introduced by this call
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/broken_format.rs:4:1
+   |
+LL | trait ImportantTrait1 {}
+   | ^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `check_1`
+  --> $DIR/broken_format.rs:28:20
+   |
+LL | fn check_1(_: impl ImportantTrait1) {}
+   |                    ^^^^^^^^^^^^^^^ required by this bound in `check_1`
+
+warning: positional format arguments are not allowed here
+  --> $DIR/broken_format.rs:6:32
+   |
+LL | #[diagnostic::on_unimplemented(message = "Test {}")]
+   |                                ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: only named format arguments with the name of one of the generic types are allowed in this context
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0277]: Test {}
+  --> $DIR/broken_format.rs:37:13
+   |
+LL |     check_2(());
+   |     ------- ^^ the trait `ImportantTrait2` is not implemented for `()`
+   |     |
+   |     required by a bound introduced by this call
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/broken_format.rs:9:1
+   |
+LL | trait ImportantTrait2 {}
+   | ^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `check_2`
+  --> $DIR/broken_format.rs:29:20
+   |
+LL | fn check_2(_: impl ImportantTrait2) {}
+   |                    ^^^^^^^^^^^^^^^ required by this bound in `check_2`
+
+warning: positional format arguments are not allowed here
+  --> $DIR/broken_format.rs:11:32
+   |
+LL | #[diagnostic::on_unimplemented(message = "Test {1:}")]
+   |                                ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: only named format arguments with the name of one of the generic types are allowed in this context
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0277]: Test {1}
+  --> $DIR/broken_format.rs:39:13
+   |
+LL |     check_3(());
+   |     ------- ^^ the trait `ImportantTrait3` is not implemented for `()`
+   |     |
+   |     required by a bound introduced by this call
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/broken_format.rs:14:1
+   |
+LL | trait ImportantTrait3 {}
+   | ^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `check_3`
+  --> $DIR/broken_format.rs:30:20
+   |
+LL | fn check_3(_: impl ImportantTrait3) {}
+   |                    ^^^^^^^^^^^^^^^ required by this bound in `check_3`
+
+warning: invalid format specifier
+  --> $DIR/broken_format.rs:16:32
+   |
+LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")]
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: no format specifier are supported in this position
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0277]: Test ()
+  --> $DIR/broken_format.rs:41:13
+   |
+LL |     check_4(());
+   |     ------- ^^ the trait `ImportantTrait4` is not implemented for `()`
+   |     |
+   |     required by a bound introduced by this call
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/broken_format.rs:19:1
+   |
+LL | trait ImportantTrait4 {}
+   | ^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `check_4`
+  --> $DIR/broken_format.rs:31:20
+   |
+LL | fn check_4(_: impl ImportantTrait4) {}
+   |                    ^^^^^^^^^^^^^^^ required by this bound in `check_4`
+
+warning: expected `'}'`, found `'!'`
+  --> $DIR/broken_format.rs:21:32
+   |
+LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+warning: unmatched `}` found
+  --> $DIR/broken_format.rs:21:32
+   |
+LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0277]: Test {Self:!}
+  --> $DIR/broken_format.rs:43:13
+   |
+LL |     check_5(());
+   |     ------- ^^ the trait `ImportantTrait5` is not implemented for `()`
+   |     |
+   |     required by a bound introduced by this call
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/broken_format.rs:26:1
+   |
+LL | trait ImportantTrait5 {}
+   | ^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `check_5`
+  --> $DIR/broken_format.rs:32:20
+   |
+LL | fn check_5(_: impl ImportantTrait5) {}
+   |                    ^^^^^^^^^^^^^^^ required by this bound in `check_5`
+
+error: aborting due to 5 previous errors; 12 warnings emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/drop/norm-ice-106444.rs b/tests/ui/drop/norm-ice-106444.rs
new file mode 100644
index 00000000000..b248bc73bbe
--- /dev/null
+++ b/tests/ui/drop/norm-ice-106444.rs
@@ -0,0 +1,16 @@
+// issue: rust-lang/rust#106444
+// ICE failed to normalize
+//@ compile-flags: -Zmir-opt-level=3
+//@ check-pass
+
+#![crate_type="lib"]
+
+pub trait A {
+    type B;
+}
+
+pub struct S<T: A>(T::B);
+
+pub fn foo<T: A>(p: *mut S<T>) {
+    unsafe { core::ptr::drop_in_place(p) };
+}
diff --git a/tests/ui/error-codes/E0637.rs b/tests/ui/error-codes/E0637.rs
index e107ea9521b..382ce3ed01f 100644
--- a/tests/ui/error-codes/E0637.rs
+++ b/tests/ui/error-codes/E0637.rs
@@ -2,9 +2,9 @@ fn underscore_lifetime<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str {
     //~^ ERROR: `'_` cannot be used here [E0637]
     //~| ERROR: missing lifetime specifier
     if str1.len() > str2.len() {
-        str1 //~ ERROR: lifetime may not live long enough
+        str1
     } else {
-        str2 //~ ERROR: lifetime may not live long enough
+        str2
     }
 }
 
diff --git a/tests/ui/error-codes/E0637.stderr b/tests/ui/error-codes/E0637.stderr
index 217881b8e7c..d9db89ddb0c 100644
--- a/tests/ui/error-codes/E0637.stderr
+++ b/tests/ui/error-codes/E0637.stderr
@@ -27,25 +27,7 @@ help: consider introducing a higher-ranked lifetime here
 LL |     T: for<'a> Into<&'a u32>,
    |        +++++++       ++
 
-error: lifetime may not live long enough
-  --> $DIR/E0637.rs:5:9
-   |
-LL | fn underscore_lifetime<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str {
-   |                                  - let's call the lifetime of this reference `'1`
-...
-LL |         str1
-   |         ^^^^ returning this value requires that `'1` must outlive `'static`
-
-error: lifetime may not live long enough
-  --> $DIR/E0637.rs:7:9
-   |
-LL | fn underscore_lifetime<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str {
-   |                                                 - let's call the lifetime of this reference `'2`
-...
-LL |         str2
-   |         ^^^^ returning this value requires that `'2` must outlive `'static`
-
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0106, E0637.
 For more information about an error, try `rustc --explain E0106`.
diff --git a/tests/ui/feature-gates/feature-gate-deref_patterns.rs b/tests/ui/feature-gates/feature-gate-deref_patterns.rs
new file mode 100644
index 00000000000..b43001f2d53
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-deref_patterns.rs
@@ -0,0 +1,9 @@
+fn main() {
+    // We reuse the `box` syntax so this doesn't actually test the feature gate but eh.
+    let box x = Box::new('c'); //~ ERROR box pattern syntax is experimental
+    println!("x: {}", x);
+
+    // `box` syntax is allowed to be cfg-ed out for historical reasons (#65742).
+    #[cfg(FALSE)]
+    let box _x = Box::new('c');
+}
diff --git a/tests/ui/feature-gates/feature-gate-deref_patterns.stderr b/tests/ui/feature-gates/feature-gate-deref_patterns.stderr
new file mode 100644
index 00000000000..48426b50d89
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-deref_patterns.stderr
@@ -0,0 +1,13 @@
+error[E0658]: box pattern syntax is experimental
+  --> $DIR/feature-gate-deref_patterns.rs:3:9
+   |
+LL |     let box x = Box::new('c');
+   |         ^^^^^
+   |
+   = note: see issue #29641 <https://github.com/rust-lang/rust/issues/29641> for more information
+   = help: add `#![feature(box_patterns)]` 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 1 previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-postfix_match.rs b/tests/ui/feature-gates/feature-gate-postfix_match.rs
new file mode 100644
index 00000000000..dce7e81a9ae
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-postfix_match.rs
@@ -0,0 +1,17 @@
+// Testing that postfix match doesn't work without enabling the feature
+
+fn main() {
+    let val = Some(42);
+
+    val.match { //~ ERROR postfix match is experimental
+        Some(42) => "the answer to life, the universe, and everything",
+        _ => "might be the answer to something"
+    };
+
+    // Test that the gate works behind a cfg
+    #[cfg(FALSE)]
+    val.match { //~ ERROR postfix match is experimental
+        Some(42) => "the answer to life, the universe, and everything",
+        _ => "might be the answer to something"
+    };
+}
diff --git a/tests/ui/feature-gates/feature-gate-postfix_match.stderr b/tests/ui/feature-gates/feature-gate-postfix_match.stderr
new file mode 100644
index 00000000000..136838788dd
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-postfix_match.stderr
@@ -0,0 +1,23 @@
+error[E0658]: postfix match is experimental
+  --> $DIR/feature-gate-postfix_match.rs:6:9
+   |
+LL |     val.match {
+   |         ^^^^^
+   |
+   = note: see issue #121618 <https://github.com/rust-lang/rust/issues/121618> for more information
+   = help: add `#![feature(postfix_match)]` 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]: postfix match is experimental
+  --> $DIR/feature-gate-postfix_match.rs:13:9
+   |
+LL |     val.match {
+   |         ^^^^^
+   |
+   = note: see issue #121618 <https://github.com/rust-lang/rust/issues/121618> for more information
+   = help: add `#![feature(postfix_match)]` 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/generic-associated-types/issue-102335-gat.rs b/tests/ui/generic-associated-types/issue-102335-gat.rs
index a7255fdcbf5..3a4a0c10771 100644
--- a/tests/ui/generic-associated-types/issue-102335-gat.rs
+++ b/tests/ui/generic-associated-types/issue-102335-gat.rs
@@ -1,6 +1,7 @@
 trait T {
     type A: S<C<(), i32 = ()> = ()>;
     //~^ ERROR associated type bindings are not allowed here
+    //~| ERROR associated type bindings are not allowed here
 }
 
 trait Q {}
diff --git a/tests/ui/generic-associated-types/issue-102335-gat.stderr b/tests/ui/generic-associated-types/issue-102335-gat.stderr
index 39ca7954ede..f5e782e92fc 100644
--- a/tests/ui/generic-associated-types/issue-102335-gat.stderr
+++ b/tests/ui/generic-associated-types/issue-102335-gat.stderr
@@ -4,6 +4,14 @@ error[E0229]: associated type bindings are not allowed here
 LL |     type A: S<C<(), i32 = ()> = ()>;
    |                     ^^^^^^^^ associated type not allowed here
 
-error: aborting due to 1 previous error
+error[E0229]: associated type bindings are not allowed here
+  --> $DIR/issue-102335-gat.rs:2:21
+   |
+LL |     type A: S<C<(), i32 = ()> = ()>;
+   |                     ^^^^^^^^ associated type not allowed here
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0229`.
diff --git a/tests/ui/generic-associated-types/issue-80433.rs b/tests/ui/generic-associated-types/issue-80433.rs
index 6d23427f16f..53057542440 100644
--- a/tests/ui/generic-associated-types/issue-80433.rs
+++ b/tests/ui/generic-associated-types/issue-80433.rs
@@ -29,5 +29,5 @@ fn test_simpler<'a>(dst: &'a mut impl TestMut<Output = &'a mut f32>)
 
 fn main() {
     let mut t1: E<f32> = Default::default();
-    test_simpler(&mut t1); //~ ERROR does not live long enough
+    test_simpler(&mut t1);
 }
diff --git a/tests/ui/generic-associated-types/issue-80433.stderr b/tests/ui/generic-associated-types/issue-80433.stderr
index 1ca080f5df2..a9a14d3f51c 100644
--- a/tests/ui/generic-associated-types/issue-80433.stderr
+++ b/tests/ui/generic-associated-types/issue-80433.stderr
@@ -48,20 +48,7 @@ LL |         *dst.test_mut() = n.into();
    |          `dst` escapes the function body here
    |          argument requires that `'a` must outlive `'static`
 
-error[E0597]: `t1` does not live long enough
-  --> $DIR/issue-80433.rs:32:18
-   |
-LL |     let mut t1: E<f32> = Default::default();
-   |         ------ binding `t1` declared here
-LL |     test_simpler(&mut t1);
-   |     -------------^^^^^^^-
-   |     |            |
-   |     |            borrowed value does not live long enough
-   |     argument requires that `t1` is borrowed for `'static`
-LL | }
-   | - `t1` dropped here while still borrowed
-
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0107, E0499, E0521, E0597.
+Some errors have detailed explanations: E0107, E0499, E0521.
 For more information about an error, try `rustc --explain E0107`.
diff --git a/tests/ui/generic-associated-types/issue-81712-cyclic-traits.rs b/tests/ui/generic-associated-types/issue-81712-cyclic-traits.rs
index a7cc9a6053e..412eeb6e29a 100644
--- a/tests/ui/generic-associated-types/issue-81712-cyclic-traits.rs
+++ b/tests/ui/generic-associated-types/issue-81712-cyclic-traits.rs
@@ -13,6 +13,7 @@ trait C {
 trait D<T> {
     type CType: C<DType = Self>;
     //~^ ERROR missing generics for associated type
+    //~| ERROR missing generics for associated type
 }
 
 fn main() {}
diff --git a/tests/ui/generic-associated-types/issue-81712-cyclic-traits.stderr b/tests/ui/generic-associated-types/issue-81712-cyclic-traits.stderr
index 5eb988ea042..33c40f88f87 100644
--- a/tests/ui/generic-associated-types/issue-81712-cyclic-traits.stderr
+++ b/tests/ui/generic-associated-types/issue-81712-cyclic-traits.stderr
@@ -14,6 +14,23 @@ help: add missing generic argument
 LL |     type CType: C<DType<T> = Self>;
    |                        +++
 
-error: aborting due to 1 previous error
+error[E0107]: missing generics for associated type `C::DType`
+  --> $DIR/issue-81712-cyclic-traits.rs:14:19
+   |
+LL |     type CType: C<DType = Self>;
+   |                   ^^^^^ expected 1 generic argument
+   |
+note: associated type defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-81712-cyclic-traits.rs:11:10
+   |
+LL |     type DType<T>: D<T, CType = Self>;
+   |          ^^^^^ -
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: add missing generic argument
+   |
+LL |     type CType: C<DType<T> = Self>;
+   |                        +++
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0107`.
diff --git a/tests/ui/generics/generic-type-less-params-with-defaults.rs b/tests/ui/generics/generic-type-less-params-with-defaults.rs
index 6b877ab8aee..d04b1c80d34 100644
--- a/tests/ui/generics/generic-type-less-params-with-defaults.rs
+++ b/tests/ui/generics/generic-type-less-params-with-defaults.rs
@@ -5,7 +5,23 @@ struct Heap;
 struct Vec<T, A = Heap>(
     marker::PhantomData<(T,A)>);
 
+struct HashMap<K, V, S = ()>(marker::PhantomData<(K,V,S)>);
+
 fn main() {
     let _: Vec;
     //~^ ERROR missing generics for struct `Vec`
+    //~| SUGGESTION <T>
+
+    let _x = (1..10).collect::<HashMap>();
+    //~^ ERROR missing generics for struct `HashMap`
+    //~| SUGGESTION <_, _>
+
+    ().extend::<[(); 0]>({
+        fn not_the_extend() {
+            let _: Vec;
+            //~^ ERROR missing generics for struct `Vec`
+            //~| SUGGESTION <T>
+        }
+        []
+    });
 }
diff --git a/tests/ui/generics/generic-type-less-params-with-defaults.stderr b/tests/ui/generics/generic-type-less-params-with-defaults.stderr
index 6f79b09f6cd..a6771a6d5c8 100644
--- a/tests/ui/generics/generic-type-less-params-with-defaults.stderr
+++ b/tests/ui/generics/generic-type-less-params-with-defaults.stderr
@@ -1,5 +1,5 @@
 error[E0107]: missing generics for struct `Vec`
-  --> $DIR/generic-type-less-params-with-defaults.rs:9:12
+  --> $DIR/generic-type-less-params-with-defaults.rs:11:12
    |
 LL |     let _: Vec;
    |            ^^^ expected at least 1 generic argument
@@ -14,6 +14,38 @@ help: add missing generic argument
 LL |     let _: Vec<T>;
    |               +++
 
-error: aborting due to 1 previous error
+error[E0107]: missing generics for struct `HashMap`
+  --> $DIR/generic-type-less-params-with-defaults.rs:15:32
+   |
+LL |     let _x = (1..10).collect::<HashMap>();
+   |                                ^^^^^^^ expected at least 2 generic arguments
+   |
+note: struct defined here, with at least 2 generic parameters: `K`, `V`
+  --> $DIR/generic-type-less-params-with-defaults.rs:8:8
+   |
+LL | struct HashMap<K, V, S = ()>(marker::PhantomData<(K,V,S)>);
+   |        ^^^^^^^ -  -
+help: add missing generic arguments
+   |
+LL |     let _x = (1..10).collect::<HashMap<_, _>>();
+   |                                       ++++++
+
+error[E0107]: missing generics for struct `Vec`
+  --> $DIR/generic-type-less-params-with-defaults.rs:21:20
+   |
+LL |             let _: Vec;
+   |                    ^^^ expected at least 1 generic argument
+   |
+note: struct defined here, with at least 1 generic parameter: `T`
+  --> $DIR/generic-type-less-params-with-defaults.rs:5:8
+   |
+LL | struct Vec<T, A = Heap>(
+   |        ^^^ -
+help: add missing generic argument
+   |
+LL |             let _: Vec<T>;
+   |                       +++
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0107`.
diff --git a/tests/ui/higher-ranked/structually-relate-aliases.rs b/tests/ui/higher-ranked/structually-relate-aliases.rs
new file mode 100644
index 00000000000..8df24702811
--- /dev/null
+++ b/tests/ui/higher-ranked/structually-relate-aliases.rs
@@ -0,0 +1,17 @@
+// regression test for issue #121649.
+
+trait ToUnit<'a> {
+    type Unit;
+}
+
+trait Overlap<T> {}
+
+type Assoc<'a, T> = <T as ToUnit<'a>>::Unit;
+
+impl<T> Overlap<T> for T {}
+
+impl<T> Overlap<for<'a> fn(&'a (), Assoc<'a, T>)> for T {}
+//~^ ERROR 13:17: 13:49: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied [E0277]
+//~| ERROR 13:36: 13:48: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied [E0277]
+
+fn main() {}
diff --git a/tests/ui/higher-ranked/structually-relate-aliases.stderr b/tests/ui/higher-ranked/structually-relate-aliases.stderr
new file mode 100644
index 00000000000..59fab52b221
--- /dev/null
+++ b/tests/ui/higher-ranked/structually-relate-aliases.stderr
@@ -0,0 +1,27 @@
+WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, '^0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit) }
+WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: [?1t, !2_0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a), "'a")], def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit) }
+error[E0277]: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied
+  --> $DIR/structually-relate-aliases.rs:13:36
+   |
+LL | impl<T> Overlap<for<'a> fn(&'a (), Assoc<'a, T>)> for T {}
+   |                                    ^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `T`
+   |
+help: consider restricting type parameter `T`
+   |
+LL | impl<T: for<'a> ToUnit<'a>> Overlap<for<'a> fn(&'a (), Assoc<'a, T>)> for T {}
+   |       ++++++++++++++++++++
+
+error[E0277]: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied
+  --> $DIR/structually-relate-aliases.rs:13:17
+   |
+LL | impl<T> Overlap<for<'a> fn(&'a (), Assoc<'a, T>)> for T {}
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `T`
+   |
+help: consider restricting type parameter `T`
+   |
+LL | impl<T: for<'a> ToUnit<'a>> Overlap<for<'a> fn(&'a (), Assoc<'a, T>)> for T {}
+   |       ++++++++++++++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/impl-not-adjacent-to-type.rs b/tests/ui/impl-not-adjacent-to-type.rs
index 7fc927b1d64..ccf59ed4393 100644
--- a/tests/ui/impl-not-adjacent-to-type.rs
+++ b/tests/ui/impl-not-adjacent-to-type.rs
@@ -3,6 +3,7 @@
 mod foo {
     pub struct Point {
         pub x: i32,
+        #[allow(dead_code)]
         pub y: i32,
     }
 }
diff --git a/tests/ui/impl-trait/fresh-lifetime-from-bare-trait-obj-114664.rs b/tests/ui/impl-trait/fresh-lifetime-from-bare-trait-obj-114664.rs
index 41c5b9f5074..e75cfc88ef4 100644
--- a/tests/ui/impl-trait/fresh-lifetime-from-bare-trait-obj-114664.rs
+++ b/tests/ui/impl-trait/fresh-lifetime-from-bare-trait-obj-114664.rs
@@ -5,6 +5,8 @@
 fn ice() -> impl AsRef<Fn(&())> {
     //~^ WARN trait objects without an explicit `dyn` are deprecated
     //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+    //~| WARN trait objects without an explicit `dyn` are deprecated
+    //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
     Foo
 }
 
diff --git a/tests/ui/impl-trait/fresh-lifetime-from-bare-trait-obj-114664.stderr b/tests/ui/impl-trait/fresh-lifetime-from-bare-trait-obj-114664.stderr
index 3cb3af89bfc..d82b2c0f606 100644
--- a/tests/ui/impl-trait/fresh-lifetime-from-bare-trait-obj-114664.stderr
+++ b/tests/ui/impl-trait/fresh-lifetime-from-bare-trait-obj-114664.stderr
@@ -12,5 +12,19 @@ help: if this is an object-safe trait, use `dyn`
 LL | fn ice() -> impl AsRef<dyn Fn(&())> {
    |                        +++
 
-warning: 1 warning emitted
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/fresh-lifetime-from-bare-trait-obj-114664.rs:5:24
+   |
+LL | fn ice() -> impl AsRef<Fn(&())> {
+   |                        ^^^^^^^
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: if this is an object-safe trait, use `dyn`
+   |
+LL | fn ice() -> impl AsRef<dyn Fn(&())> {
+   |                        +++
+
+warning: 2 warnings emitted
 
diff --git a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs
new file mode 100644
index 00000000000..d6fa56663a3
--- /dev/null
+++ b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs
@@ -0,0 +1,30 @@
+// test for ICE #112823
+// Unexpected parameter Type(Repr) when substituting in region
+
+#![feature(impl_trait_in_assoc_type)]
+
+use std::future::Future;
+
+trait Stream {}
+
+trait X {
+    type LineStream<'a, Repr>
+    where
+        Self: 'a;
+    type LineStreamFut<'a, Repr>
+    where
+        Self: 'a;
+}
+
+struct Y;
+
+impl X for Y {
+    type LineStream<'c, 'd> = impl Stream;
+    //~^ ERROR type `LineStream` has 0 type parameters but its trait declaration has 1 type parameter
+    type LineStreamFut<'a, Repr> = impl Future<Output = Self::LineStream<'a, Repr>>;
+    fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {}
+    //~^ ERROR `()` is not a future
+    //~^^ method `line_stream` is not a member of trait `X`
+}
+
+pub fn main() {}
diff --git a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.stderr b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.stderr
new file mode 100644
index 00000000000..28a0f7461e2
--- /dev/null
+++ b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.stderr
@@ -0,0 +1,31 @@
+error[E0407]: method `line_stream` is not a member of trait `X`
+  --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:25:5
+   |
+LL |     fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a member of trait `X`
+
+error[E0049]: type `LineStream` has 0 type parameters but its trait declaration has 1 type parameter
+  --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:22:21
+   |
+LL |     type LineStream<'a, Repr>
+   |                     --  ----
+   |                     |
+   |                     expected 1 type parameter
+...
+LL |     type LineStream<'c, 'd> = impl Stream;
+   |                     ^^  ^^
+   |                     |
+   |                     found 0 type parameters
+
+error[E0277]: `()` is not a future
+  --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:25:43
+   |
+LL |     fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {}
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future
+   |
+   = help: the trait `Future` is not implemented for `()`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0049, E0277, E0407.
+For more information about an error, try `rustc --explain E0049`.
diff --git a/tests/ui/impl-trait/impl-fn-hrtb-bounds.rs b/tests/ui/impl-trait/impl-fn-hrtb-bounds.rs
index a9ea657f10e..da7530b4e7a 100644
--- a/tests/ui/impl-trait/impl-fn-hrtb-bounds.rs
+++ b/tests/ui/impl-trait/impl-fn-hrtb-bounds.rs
@@ -4,19 +4,16 @@ use std::fmt::Debug;
 fn a() -> impl Fn(&u8) -> (impl Debug + '_) {
     //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
     |x| x
-    //~^ ERROR lifetime may not live long enough
 }
 
 fn b() -> impl for<'a> Fn(&'a u8) -> (impl Debug + 'a) {
     //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
     |x| x
-    //~^ ERROR lifetime may not live long enough
 }
 
 fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) {
     //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
     |x| x
-    //~^ ERROR lifetime may not live long enough
 }
 
 fn d() -> impl Fn() -> (impl Debug + '_) {
diff --git a/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr b/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr
index bdb099619b7..7d108b30b76 100644
--- a/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr
+++ b/tests/ui/impl-trait/impl-fn-hrtb-bounds.stderr
@@ -1,5 +1,5 @@
 error[E0106]: missing lifetime specifier
-  --> $DIR/impl-fn-hrtb-bounds.rs:22:38
+  --> $DIR/impl-fn-hrtb-bounds.rs:19:38
    |
 LL | fn d() -> impl Fn() -> (impl Debug + '_) {
    |                                      ^^ expected named lifetime parameter
@@ -22,58 +22,31 @@ note: lifetime declared here
 LL | fn a() -> impl Fn(&u8) -> (impl Debug + '_) {
    |                   ^
 
-error: lifetime may not live long enough
-  --> $DIR/impl-fn-hrtb-bounds.rs:6:9
-   |
-LL |     |x| x
-   |      -- ^ returning this value requires that `'1` must outlive `'2`
-   |      ||
-   |      |return type of closure is impl Debug + '2
-   |      has type `&'1 u8`
-
 error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
-  --> $DIR/impl-fn-hrtb-bounds.rs:10:52
+  --> $DIR/impl-fn-hrtb-bounds.rs:9:52
    |
 LL | fn b() -> impl for<'a> Fn(&'a u8) -> (impl Debug + 'a) {
    |                                                    ^^
    |
 note: lifetime declared here
-  --> $DIR/impl-fn-hrtb-bounds.rs:10:20
+  --> $DIR/impl-fn-hrtb-bounds.rs:9:20
    |
 LL | fn b() -> impl for<'a> Fn(&'a u8) -> (impl Debug + 'a) {
    |                    ^^
 
-error: lifetime may not live long enough
-  --> $DIR/impl-fn-hrtb-bounds.rs:12:9
-   |
-LL |     |x| x
-   |      -- ^ returning this value requires that `'1` must outlive `'2`
-   |      ||
-   |      |return type of closure is impl Debug + '2
-   |      has type `&'1 u8`
-
 error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
-  --> $DIR/impl-fn-hrtb-bounds.rs:16:52
+  --> $DIR/impl-fn-hrtb-bounds.rs:14:52
    |
 LL | fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) {
    |                                                    ^^
    |
 note: lifetime declared here
-  --> $DIR/impl-fn-hrtb-bounds.rs:16:20
+  --> $DIR/impl-fn-hrtb-bounds.rs:14:20
    |
 LL | fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) {
    |                    ^^
 
-error: lifetime may not live long enough
-  --> $DIR/impl-fn-hrtb-bounds.rs:18:9
-   |
-LL |     |x| x
-   |      -- ^ returning this value requires that `'1` must outlive `'2`
-   |      ||
-   |      |return type of closure is impl Debug + '2
-   |      has type `&'1 u8`
-
-error: aborting due to 7 previous errors
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0106, E0657.
 For more information about an error, try `rustc --explain E0106`.
diff --git a/tests/ui/impl-trait/impl-fn-parsing-ambiguities.rs b/tests/ui/impl-trait/impl-fn-parsing-ambiguities.rs
index ef9d8733509..7679b7ec478 100644
--- a/tests/ui/impl-trait/impl-fn-parsing-ambiguities.rs
+++ b/tests/ui/impl-trait/impl-fn-parsing-ambiguities.rs
@@ -5,7 +5,6 @@ fn a() -> impl Fn(&u8) -> impl Debug + '_ {
     //~^ ERROR ambiguous `+` in a type
     //~| ERROR cannot capture higher-ranked lifetime from outer `impl Trait`
     |x| x
-    //~^ ERROR lifetime may not live long enough
 }
 
 fn b() -> impl Fn() -> impl Debug + Send {
diff --git a/tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr b/tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr
index 3881b37a0cb..e0955faac7c 100644
--- a/tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr
+++ b/tests/ui/impl-trait/impl-fn-parsing-ambiguities.stderr
@@ -5,7 +5,7 @@ LL | fn a() -> impl Fn(&u8) -> impl Debug + '_ {
    |                           ^^^^^^^^^^^^^^^ help: use parentheses to disambiguate: `(impl Debug + '_)`
 
 error: ambiguous `+` in a type
-  --> $DIR/impl-fn-parsing-ambiguities.rs:11:24
+  --> $DIR/impl-fn-parsing-ambiguities.rs:10:24
    |
 LL | fn b() -> impl Fn() -> impl Debug + Send {
    |                        ^^^^^^^^^^^^^^^^^ help: use parentheses to disambiguate: `(impl Debug + Send)`
@@ -22,15 +22,6 @@ note: lifetime declared here
 LL | fn a() -> impl Fn(&u8) -> impl Debug + '_ {
    |                   ^
 
-error: lifetime may not live long enough
-  --> $DIR/impl-fn-parsing-ambiguities.rs:7:9
-   |
-LL |     |x| x
-   |      -- ^ returning this value requires that `'1` must outlive `'2`
-   |      ||
-   |      |return type of closure is impl Debug + '2
-   |      has type `&'1 u8`
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0657`.
diff --git a/tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.rs b/tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.rs
index 6f0dbd752b0..21e2fda1c3a 100644
--- a/tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.rs
+++ b/tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.rs
@@ -1,5 +1,4 @@
-struct Wrapper<'rom>(T);
-//~^ ERROR cannot find type `T` in this scope
+struct Wrapper<'rom>(&'rom ());
 
 trait Foo {
     fn bar() -> Wrapper<impl Sized>;
@@ -15,4 +14,18 @@ impl Foo for () {
     }
 }
 
+trait Bar {
+    fn foo() -> Wrapper<impl Sized>;
+    //~^ ERROR missing lifetime specifier
+    //~| ERROR struct takes 0 generic arguments but 1 generic argument was supplied
+}
+
+impl Bar for () {
+    fn foo() -> Wrapper<impl Sized> {
+        //~^ ERROR missing lifetime specifier
+        //~| ERROR struct takes 0 generic arguments but 1 generic argument was supplied
+        Wrapper(&())
+    }
+}
+
 fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.stderr b/tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.stderr
index d30557c8a7b..d7fc40fa342 100644
--- a/tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.stderr
+++ b/tests/ui/impl-trait/in-trait/opaque-and-lifetime-mismatch.stderr
@@ -1,5 +1,5 @@
 error[E0106]: missing lifetime specifier
-  --> $DIR/opaque-and-lifetime-mismatch.rs:5:24
+  --> $DIR/opaque-and-lifetime-mismatch.rs:4:24
    |
 LL |     fn bar() -> Wrapper<impl Sized>;
    |                        ^ expected named lifetime parameter
@@ -10,19 +10,32 @@ help: consider using the `'static` lifetime, but this is uncommon unless you're
 LL |     fn bar() -> Wrapper<'static, impl Sized>;
    |                         ++++++++
 
-error[E0412]: cannot find type `T` in this scope
-  --> $DIR/opaque-and-lifetime-mismatch.rs:1:22
+error[E0106]: missing lifetime specifier
+  --> $DIR/opaque-and-lifetime-mismatch.rs:18:24
+   |
+LL |     fn foo() -> Wrapper<impl Sized>;
+   |                        ^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values
+   |
+LL |     fn foo() -> Wrapper<'static, impl Sized>;
+   |                         ++++++++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/opaque-and-lifetime-mismatch.rs:24:24
    |
-LL | struct Wrapper<'rom>(T);
-   |                      ^ not found in this scope
+LL |     fn foo() -> Wrapper<impl Sized> {
+   |                        ^ expected named lifetime parameter
    |
-help: you might be missing a type parameter
+   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
+help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values
    |
-LL | struct Wrapper<'rom, T>(T);
-   |                    +++
+LL |     fn foo() -> Wrapper<'static, impl Sized> {
+   |                         ++++++++
 
 error[E0107]: struct takes 0 generic arguments but 1 generic argument was supplied
-  --> $DIR/opaque-and-lifetime-mismatch.rs:5:17
+  --> $DIR/opaque-and-lifetime-mismatch.rs:4:17
    |
 LL |     fn bar() -> Wrapper<impl Sized>;
    |                 ^^^^^^^ ---------- help: remove this generic argument
@@ -32,11 +45,25 @@ LL |     fn bar() -> Wrapper<impl Sized>;
 note: struct defined here, with 0 generic parameters
   --> $DIR/opaque-and-lifetime-mismatch.rs:1:8
    |
-LL | struct Wrapper<'rom>(T);
+LL | struct Wrapper<'rom>(&'rom ());
+   |        ^^^^^^^
+
+error[E0107]: struct takes 0 generic arguments but 1 generic argument was supplied
+  --> $DIR/opaque-and-lifetime-mismatch.rs:18:17
+   |
+LL |     fn foo() -> Wrapper<impl Sized>;
+   |                 ^^^^^^^ ---------- help: remove this generic argument
+   |                 |
+   |                 expected 0 generic arguments
+   |
+note: struct defined here, with 0 generic parameters
+  --> $DIR/opaque-and-lifetime-mismatch.rs:1:8
+   |
+LL | struct Wrapper<'rom>(&'rom ());
    |        ^^^^^^^
 
 error[E0053]: method `bar` has an incompatible return type for trait
-  --> $DIR/opaque-and-lifetime-mismatch.rs:11:17
+  --> $DIR/opaque-and-lifetime-mismatch.rs:10:17
    |
 LL |     fn bar() -> i32 {
    |                 ^^^
@@ -45,7 +72,7 @@ LL |     fn bar() -> i32 {
    |                 return type in trait
 
 error[E0053]: method `bar` has an incompatible type for trait
-  --> $DIR/opaque-and-lifetime-mismatch.rs:11:17
+  --> $DIR/opaque-and-lifetime-mismatch.rs:10:17
    |
 LL |     fn bar() -> i32 {
    |                 ^^^
@@ -54,14 +81,28 @@ LL |     fn bar() -> i32 {
    |                 help: change the output type to match the trait: `Wrapper<'static>`
    |
 note: type in trait
-  --> $DIR/opaque-and-lifetime-mismatch.rs:5:17
+  --> $DIR/opaque-and-lifetime-mismatch.rs:4:17
    |
 LL |     fn bar() -> Wrapper<impl Sized>;
    |                 ^^^^^^^^^^^^^^^^^^^
    = note: expected signature `fn() -> Wrapper<'static>`
               found signature `fn() -> i32`
 
-error: aborting due to 5 previous errors
+error[E0107]: struct takes 0 generic arguments but 1 generic argument was supplied
+  --> $DIR/opaque-and-lifetime-mismatch.rs:24:17
+   |
+LL |     fn foo() -> Wrapper<impl Sized> {
+   |                 ^^^^^^^ ---------- help: remove this generic argument
+   |                 |
+   |                 expected 0 generic arguments
+   |
+note: struct defined here, with 0 generic parameters
+  --> $DIR/opaque-and-lifetime-mismatch.rs:1:8
+   |
+LL | struct Wrapper<'rom>(&'rom ());
+   |        ^^^^^^^
+
+error: aborting due to 8 previous errors
 
-Some errors have detailed explanations: E0053, E0106, E0107, E0412.
+Some errors have detailed explanations: E0053, E0106, E0107.
 For more information about an error, try `rustc --explain E0053`.
diff --git a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs
index 10167ee9352..ab21dae7dc5 100644
--- a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs
+++ b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs
@@ -12,6 +12,7 @@ impl<'a, I: 'a + Iterable> Iterable for &'a I {
 
     fn iter(&self) -> impl for<'missing> Iterator<Item = Self::Item<'missing>> {}
     //~^ ERROR binding for associated type `Item` references lifetime `'missing`
+    //~| ERROR binding for associated type `Item` references lifetime `'missing`
     //~| ERROR `()` is not an iterator
 }
 
diff --git a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr
index 96c3644f893..d8a2eef94a1 100644
--- a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr
+++ b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr
@@ -4,6 +4,14 @@ error[E0582]: binding for associated type `Item` references lifetime `'missing`,
 LL |     fn iter(&self) -> impl for<'missing> Iterator<Item = Self::Item<'missing>> {}
    |                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error[E0582]: binding for associated type `Item` references lifetime `'missing`, which does not appear in the trait input types
+  --> $DIR/span-bug-issue-121457.rs:13:51
+   |
+LL |     fn iter(&self) -> impl for<'missing> Iterator<Item = Self::Item<'missing>> {}
+   |                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
 error[E0195]: lifetime parameters or bounds on type `Item` do not match the trait declaration
   --> $DIR/span-bug-issue-121457.rs:10:14
    |
@@ -24,7 +32,7 @@ LL |     fn iter(&self) -> impl for<'missing> Iterator<Item = Self::Item<'missin
    |
    = help: the trait `Iterator` is not implemented for `()`
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0195, E0277, E0582.
 For more information about an error, try `rustc --explain E0195`.
diff --git a/tests/ui/impl-trait/issues/issue-92305.rs b/tests/ui/impl-trait/issues/issue-92305.rs
index 5ecb6984cfe..be98ce807ec 100644
--- a/tests/ui/impl-trait/issues/issue-92305.rs
+++ b/tests/ui/impl-trait/issues/issue-92305.rs
@@ -4,6 +4,7 @@ use std::iter;
 
 fn f<T>(data: &[T]) -> impl Iterator<Item = Vec> {
     //~^ ERROR: missing generics for struct `Vec` [E0107]
+    //~| ERROR: missing generics for struct `Vec` [E0107]
     iter::empty()
 }
 
diff --git a/tests/ui/impl-trait/issues/issue-92305.stderr b/tests/ui/impl-trait/issues/issue-92305.stderr
index 88fb1fb2707..4591d2c53f7 100644
--- a/tests/ui/impl-trait/issues/issue-92305.stderr
+++ b/tests/ui/impl-trait/issues/issue-92305.stderr
@@ -9,6 +9,18 @@ help: add missing generic argument
 LL | fn f<T>(data: &[T]) -> impl Iterator<Item = Vec<T>> {
    |                                                +++
 
-error: aborting due to 1 previous error
+error[E0107]: missing generics for struct `Vec`
+  --> $DIR/issue-92305.rs:5:45
+   |
+LL | fn f<T>(data: &[T]) -> impl Iterator<Item = Vec> {
+   |                                             ^^^ expected at least 1 generic argument
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: add missing generic argument
+   |
+LL | fn f<T>(data: &[T]) -> impl Iterator<Item = Vec<T>> {
+   |                                                +++
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0107`.
diff --git a/tests/ui/impl-trait/nested-rpit-hrtb.rs b/tests/ui/impl-trait/nested-rpit-hrtb.rs
index c10bfbfe4dc..a696e1710f0 100644
--- a/tests/ui/impl-trait/nested-rpit-hrtb.rs
+++ b/tests/ui/impl-trait/nested-rpit-hrtb.rs
@@ -35,7 +35,6 @@ fn one_hrtb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'a> {}
 
 fn one_hrtb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl Qux<'a>> {}
 //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
-//~| ERROR: the trait bound `for<'a> &'a (): Qux<'_>` is not satisfied
 
 // This should resolve.
 fn one_hrtb_mention_fn_trait_param<'b>() -> impl for<'a> Foo<'a, Assoc = impl Qux<'b>> {}
@@ -45,7 +44,7 @@ fn one_hrtb_mention_fn_outlives<'b>() -> impl for<'a> Foo<'a, Assoc = impl Sized
 
 // This should resolve.
 fn one_hrtb_mention_fn_trait_param_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Qux<'b>> {}
-//~^ ERROR: the trait bound `for<'a> &'a (): Qux<'b>` is not satisfied
+//~^ ERROR type annotations needed: cannot satisfy `for<'a> &'a (): Qux<'b>`
 
 // This should resolve.
 fn one_hrtb_mention_fn_outlives_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'b> {}
diff --git a/tests/ui/impl-trait/nested-rpit-hrtb.stderr b/tests/ui/impl-trait/nested-rpit-hrtb.stderr
index 2779694a517..64f801ea685 100644
--- a/tests/ui/impl-trait/nested-rpit-hrtb.stderr
+++ b/tests/ui/impl-trait/nested-rpit-hrtb.stderr
@@ -1,5 +1,5 @@
 error[E0261]: use of undeclared lifetime name `'b`
-  --> $DIR/nested-rpit-hrtb.rs:58:77
+  --> $DIR/nested-rpit-hrtb.rs:57:77
    |
 LL | fn two_htrb_outlives() -> impl for<'a> Foo<'a, Assoc = impl for<'b> Sized + 'b> {}
    |                                                                             ^^ undeclared lifetime
@@ -15,7 +15,7 @@ LL | fn two_htrb_outlives<'b>() -> impl for<'a> Foo<'a, Assoc = impl for<'b> Siz
    |                     ++++
 
 error[E0261]: use of undeclared lifetime name `'b`
-  --> $DIR/nested-rpit-hrtb.rs:66:82
+  --> $DIR/nested-rpit-hrtb.rs:65:82
    |
 LL | fn two_htrb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Sized + 'b> {}
    |                                                                                  ^^ undeclared lifetime
@@ -86,26 +86,18 @@ note: lifetime declared here
 LL | fn one_hrtb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl Qux<'a>> {}
    |                                            ^^
 
-error[E0277]: the trait bound `for<'a> &'a (): Qux<'_>` is not satisfied
-  --> $DIR/nested-rpit-hrtb.rs:36:64
-   |
-LL | fn one_hrtb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl Qux<'a>> {}
-   |                                                                ^^^^^^^^^^^^ the trait `for<'a> Qux<'_>` is not implemented for `&'a ()`
-   |
-   = help: the trait `Qux<'_>` is implemented for `()`
-   = help: for that trait implementation, expected `()`, found `&'a ()`
-
-error[E0277]: the trait bound `for<'a> &'a (): Qux<'b>` is not satisfied
-  --> $DIR/nested-rpit-hrtb.rs:47:79
+error[E0283]: type annotations needed: cannot satisfy `for<'a> &'a (): Qux<'b>`
+  --> $DIR/nested-rpit-hrtb.rs:46:79
    |
 LL | fn one_hrtb_mention_fn_trait_param_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Qux<'b>> {}
-   |                                                                               ^^^^^^^^^^^^ the trait `for<'a> Qux<'b>` is not implemented for `&'a ()`
+   |                                                                               ^^^^^^^^^^^^
    |
+   = note: cannot satisfy `for<'a> &'a (): Qux<'b>`
    = help: the trait `Qux<'_>` is implemented for `()`
    = help: for that trait implementation, expected `()`, found `&'a ()`
 
 error: implementation of `Bar` is not general enough
-  --> $DIR/nested-rpit-hrtb.rs:51:93
+  --> $DIR/nested-rpit-hrtb.rs:50:93
    |
 LL | fn one_hrtb_mention_fn_outlives_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'b> {}
    |                                                                                             ^^ implementation of `Bar` is not general enough
@@ -114,7 +106,7 @@ LL | fn one_hrtb_mention_fn_outlives_uses<'b>() -> impl for<'a> Bar<'a, Assoc =
    = note: ...but it actually implements `Bar<'0>`, for some specific lifetime `'0`
 
 error[E0277]: the trait bound `for<'a, 'b> &'a (): Qux<'b>` is not satisfied
-  --> $DIR/nested-rpit-hrtb.rs:62:64
+  --> $DIR/nested-rpit-hrtb.rs:61:64
    |
 LL | fn two_htrb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Qux<'b>> {}
    |                                                                ^^^^^^^^^^^^^^^^^^^^ the trait `for<'a, 'b> Qux<'b>` is not implemented for `&'a ()`
@@ -123,7 +115,7 @@ LL | fn two_htrb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b>
    = help: for that trait implementation, expected `()`, found `&'a ()`
 
 error: implementation of `Bar` is not general enough
-  --> $DIR/nested-rpit-hrtb.rs:66:86
+  --> $DIR/nested-rpit-hrtb.rs:65:86
    |
 LL | fn two_htrb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Sized + 'b> {}
    |                                                                                      ^^ implementation of `Bar` is not general enough
@@ -131,7 +123,7 @@ LL | fn two_htrb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Si
    = note: `()` must implement `Bar<'a>`
    = note: ...but it actually implements `Bar<'0>`, for some specific lifetime `'0`
 
-error: aborting due to 12 previous errors
+error: aborting due to 11 previous errors
 
-Some errors have detailed explanations: E0261, E0277, E0657.
+Some errors have detailed explanations: E0261, E0277, E0283, E0657.
 For more information about an error, try `rustc --explain E0261`.
diff --git a/tests/ui/impl-trait/opaque-used-in-extraneous-argument.rs b/tests/ui/impl-trait/opaque-used-in-extraneous-argument.rs
index 529913479ef..8d4855c101c 100644
--- a/tests/ui/impl-trait/opaque-used-in-extraneous-argument.rs
+++ b/tests/ui/impl-trait/opaque-used-in-extraneous-argument.rs
@@ -7,6 +7,7 @@ fn frob() -> impl Fn<P, Output = T> + '_ {}
 //~| ERROR cannot find type `P`
 //~| ERROR cannot find type `T`
 //~| ERROR `Fn`-family traits' type parameters is subject to change
+//~| ERROR `Fn`-family traits' type parameters is subject to change
 
 fn open_parent<'path>() {
     todo!()
diff --git a/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr b/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr
index b54b9f908b2..6d417488533 100644
--- a/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr
+++ b/tests/ui/impl-trait/opaque-used-in-extraneous-argument.stderr
@@ -42,8 +42,19 @@ LL | fn frob() -> impl Fn<P, Output = T> + '_ {}
    = help: add `#![feature(unboxed_closures)]` 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]: the precise format of `Fn`-family traits' type parameters is subject to change
+  --> $DIR/opaque-used-in-extraneous-argument.rs:5:19
+   |
+LL | fn frob() -> impl Fn<P, Output = T> + '_ {}
+   |                   ^^^^^^^^^^^^^^^^^ help: use parenthetical notation instead: `Fn(P) -> T`
+   |
+   = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
+   = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
 error[E0061]: this function takes 0 arguments but 1 argument was supplied
-  --> $DIR/opaque-used-in-extraneous-argument.rs:16:20
+  --> $DIR/opaque-used-in-extraneous-argument.rs:17:20
    |
 LL |     let old_path = frob("hello");
    |                    ^^^^ -------
@@ -58,7 +69,7 @@ LL | fn frob() -> impl Fn<P, Output = T> + '_ {}
    |    ^^^^
 
 error[E0061]: this function takes 0 arguments but 1 argument was supplied
-  --> $DIR/opaque-used-in-extraneous-argument.rs:19:5
+  --> $DIR/opaque-used-in-extraneous-argument.rs:20:5
    |
 LL |     open_parent(&old_path)
    |     ^^^^^^^^^^^ ---------
@@ -67,12 +78,12 @@ LL |     open_parent(&old_path)
    |                 help: remove the extra argument
    |
 note: function defined here
-  --> $DIR/opaque-used-in-extraneous-argument.rs:11:4
+  --> $DIR/opaque-used-in-extraneous-argument.rs:12:4
    |
 LL | fn open_parent<'path>() {
    |    ^^^^^^^^^^^
 
-error: aborting due to 6 previous errors
+error: aborting due to 7 previous errors
 
 Some errors have detailed explanations: E0061, E0106, E0412, E0658.
 For more information about an error, try `rustc --explain E0061`.
diff --git a/tests/ui/impl-trait/recursive-ice-101862.rs b/tests/ui/impl-trait/recursive-ice-101862.rs
new file mode 100644
index 00000000000..02f95fe5604
--- /dev/null
+++ b/tests/ui/impl-trait/recursive-ice-101862.rs
@@ -0,0 +1,12 @@
+// issue: rust-lang/rust#101852
+// ICE opaque type with non-universal region substs
+
+pub fn ice(x: impl AsRef<str>) -> impl IntoIterator<Item = ()> {
+//~^ WARN function cannot return without recursing
+    vec![].append(&mut ice(x.as_ref()));
+    //~^ ERROR expected generic type parameter, found `&str`
+
+    Vec::new()
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/recursive-ice-101862.stderr b/tests/ui/impl-trait/recursive-ice-101862.stderr
new file mode 100644
index 00000000000..f4148720c33
--- /dev/null
+++ b/tests/ui/impl-trait/recursive-ice-101862.stderr
@@ -0,0 +1,24 @@
+warning: function cannot return without recursing
+  --> $DIR/recursive-ice-101862.rs:4:1
+   |
+LL | pub fn ice(x: impl AsRef<str>) -> impl IntoIterator<Item = ()> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL |
+LL |     vec![].append(&mut ice(x.as_ref()));
+   |                        --------------- recursive call site
+   |
+   = help: a `loop` may express intention better if this is on purpose
+   = note: `#[warn(unconditional_recursion)]` on by default
+
+error[E0792]: expected generic type parameter, found `&str`
+  --> $DIR/recursive-ice-101862.rs:6:5
+   |
+LL | pub fn ice(x: impl AsRef<str>) -> impl IntoIterator<Item = ()> {
+   |               --------------- this generic parameter must be used with a generic type parameter
+LL |
+LL |     vec![].append(&mut ice(x.as_ref()));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0792`.
diff --git a/tests/ui/impl-trait/stranded-opaque.rs b/tests/ui/impl-trait/stranded-opaque.rs
index c7ab390e1fd..6ce5cbd3b55 100644
--- a/tests/ui/impl-trait/stranded-opaque.rs
+++ b/tests/ui/impl-trait/stranded-opaque.rs
@@ -7,6 +7,7 @@ impl Trait for i32 {}
 // ICE in this case.
 fn produce<T>() -> impl Trait<Assoc = impl Trait> {
     //~^ ERROR associated type `Assoc` not found for `Trait`
+    //~| ERROR associated type `Assoc` not found for `Trait`
     16
 }
 
diff --git a/tests/ui/impl-trait/stranded-opaque.stderr b/tests/ui/impl-trait/stranded-opaque.stderr
index 75f5480bc8b..5bea3e2af6b 100644
--- a/tests/ui/impl-trait/stranded-opaque.stderr
+++ b/tests/ui/impl-trait/stranded-opaque.stderr
@@ -4,6 +4,14 @@ error[E0220]: associated type `Assoc` not found for `Trait`
 LL | fn produce<T>() -> impl Trait<Assoc = impl Trait> {
    |                               ^^^^^ associated type `Assoc` not found
 
-error: aborting due to 1 previous error
+error[E0220]: associated type `Assoc` not found for `Trait`
+  --> $DIR/stranded-opaque.rs:8:31
+   |
+LL | fn produce<T>() -> impl Trait<Assoc = impl Trait> {
+   |                               ^^^^^ associated type `Assoc` not found
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0220`.
diff --git a/tests/ui/inference/ice-cannot-relate-region-109178.rs b/tests/ui/inference/ice-cannot-relate-region-109178.rs
new file mode 100644
index 00000000000..3282f95a992
--- /dev/null
+++ b/tests/ui/inference/ice-cannot-relate-region-109178.rs
@@ -0,0 +1,14 @@
+// test for ice #109178  cannot relate region: LUB(ReErased, ReError)
+
+#![allow(incomplete_features)]
+#![crate_type = "lib"]
+#![feature(adt_const_params, generic_const_exprs)]
+
+struct Changes<const CHANGES: &[&'static str]>
+//~^ ERROR `&` without an explicit lifetime name cannot be used here
+where
+    [(); CHANGES.len()]:, {}
+
+impl<const CHANGES: &[&str]> Changes<CHANGES> where [(); CHANGES.len()]: {}
+//~^ ERROR `&` without an explicit lifetime name cannot be used here
+//~^^ ERROR `&` without an explicit lifetime name cannot be used here
diff --git a/tests/ui/inference/ice-cannot-relate-region-109178.stderr b/tests/ui/inference/ice-cannot-relate-region-109178.stderr
new file mode 100644
index 00000000000..0ac924452c0
--- /dev/null
+++ b/tests/ui/inference/ice-cannot-relate-region-109178.stderr
@@ -0,0 +1,21 @@
+error[E0637]: `&` without an explicit lifetime name cannot be used here
+  --> $DIR/ice-cannot-relate-region-109178.rs:7:31
+   |
+LL | struct Changes<const CHANGES: &[&'static str]>
+   |                               ^ explicit lifetime name needed here
+
+error[E0637]: `&` without an explicit lifetime name cannot be used here
+  --> $DIR/ice-cannot-relate-region-109178.rs:12:21
+   |
+LL | impl<const CHANGES: &[&str]> Changes<CHANGES> where [(); CHANGES.len()]: {}
+   |                     ^ explicit lifetime name needed here
+
+error[E0637]: `&` without an explicit lifetime name cannot be used here
+  --> $DIR/ice-cannot-relate-region-109178.rs:12:23
+   |
+LL | impl<const CHANGES: &[&str]> Changes<CHANGES> where [(); CHANGES.len()]: {}
+   |                       ^ explicit lifetime name needed here
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0637`.
diff --git a/tests/ui/inference/ice-ifer-var-leaked-out-of-rollback-122098.rs b/tests/ui/inference/ice-ifer-var-leaked-out-of-rollback-122098.rs
new file mode 100644
index 00000000000..3c2aa176c0f
--- /dev/null
+++ b/tests/ui/inference/ice-ifer-var-leaked-out-of-rollback-122098.rs
@@ -0,0 +1,25 @@
+// test for #122098 ICE snapshot_vec.rs: index out of bounds: the len is 4 but the index is 4
+
+trait LendingIterator {
+    type Item<'q>: 'a;
+    //~^ ERROR use of undeclared lifetime name `'a`
+
+    fn for_each(mut self, mut f: Box<dyn FnMut(Self::Item<'_>) + 'static>) {}
+    //~^ ERROR the size for values of type `Self` cannot be known at compilation time
+}
+
+struct Query<'q> {}
+//~^ ERROR lifetime parameter `'q` is never used
+
+impl<'static> Query<'q> {
+//~^ ERROR invalid lifetime parameter name: `'static`
+//~^^ ERROR use of undeclared lifetime name `'q`
+    pub fn new() -> Self {}
+}
+
+fn data() {
+    LendingIterator::for_each(Query::new(&data), Box::new);
+    //~^ ERROR this function takes 0 arguments but 1 argument was supplied
+}
+
+pub fn main() {}
diff --git a/tests/ui/inference/ice-ifer-var-leaked-out-of-rollback-122098.stderr b/tests/ui/inference/ice-ifer-var-leaked-out-of-rollback-122098.stderr
new file mode 100644
index 00000000000..e2ddf474c4a
--- /dev/null
+++ b/tests/ui/inference/ice-ifer-var-leaked-out-of-rollback-122098.stderr
@@ -0,0 +1,72 @@
+error[E0261]: use of undeclared lifetime name `'a`
+  --> $DIR/ice-ifer-var-leaked-out-of-rollback-122098.rs:4:20
+   |
+LL |     type Item<'q>: 'a;
+   |                    ^^ undeclared lifetime
+   |
+help: consider introducing lifetime `'a` here
+   |
+LL |     type Item<'a, 'q>: 'a;
+   |               +++
+help: consider introducing lifetime `'a` here
+   |
+LL | trait LendingIterator<'a> {
+   |                      ++++
+
+error[E0262]: invalid lifetime parameter name: `'static`
+  --> $DIR/ice-ifer-var-leaked-out-of-rollback-122098.rs:14:6
+   |
+LL | impl<'static> Query<'q> {
+   |      ^^^^^^^ 'static is a reserved lifetime name
+
+error[E0261]: use of undeclared lifetime name `'q`
+  --> $DIR/ice-ifer-var-leaked-out-of-rollback-122098.rs:14:21
+   |
+LL | impl<'static> Query<'q> {
+   |      -              ^^ undeclared lifetime
+   |      |
+   |      help: consider introducing lifetime `'q` here: `'q,`
+
+error[E0392]: lifetime parameter `'q` is never used
+  --> $DIR/ice-ifer-var-leaked-out-of-rollback-122098.rs:11:14
+   |
+LL | struct Query<'q> {}
+   |              ^^ unused lifetime parameter
+   |
+   = help: consider removing `'q`, referring to it in a field, or using a marker such as `PhantomData`
+
+error[E0277]: the size for values of type `Self` cannot be known at compilation time
+  --> $DIR/ice-ifer-var-leaked-out-of-rollback-122098.rs:7:17
+   |
+LL |     fn for_each(mut self, mut f: Box<dyn FnMut(Self::Item<'_>) + 'static>) {}
+   |                 ^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: unsized fn params are gated as an unstable feature
+help: consider further restricting `Self`
+   |
+LL |     fn for_each(mut self, mut f: Box<dyn FnMut(Self::Item<'_>) + 'static>) where Self: Sized {}
+   |                                                                            +++++++++++++++++
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL |     fn for_each(mut &self, mut f: Box<dyn FnMut(Self::Item<'_>) + 'static>) {}
+   |                     +
+
+error[E0061]: this function takes 0 arguments but 1 argument was supplied
+  --> $DIR/ice-ifer-var-leaked-out-of-rollback-122098.rs:21:31
+   |
+LL |     LendingIterator::for_each(Query::new(&data), Box::new);
+   |                               ^^^^^^^^^^ -----
+   |                                          |
+   |                                          unexpected argument of type `&fn() {data}`
+   |                                          help: remove the extra argument
+   |
+note: associated function defined here
+  --> $DIR/ice-ifer-var-leaked-out-of-rollback-122098.rs:17:12
+   |
+LL |     pub fn new() -> Self {}
+   |            ^^^
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0061, E0261, E0262, E0277, E0392.
+For more information about an error, try `rustc --explain E0061`.
diff --git a/tests/ui/inference/issue-107090.rs b/tests/ui/inference/issue-107090.rs
index d1c86fb03d7..799c3641833 100644
--- a/tests/ui/inference/issue-107090.rs
+++ b/tests/ui/inference/issue-107090.rs
@@ -19,7 +19,7 @@ impl<'long: 'short, 'short, T> Convert<'long, 'b> for Foo<'short, 'out, T> {
 
 fn badboi<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ Foo<'short, 'out, T>) -> &'out T {
     //~^ ERROR use of undeclared lifetime name
-    sadness.cast() //~ ERROR: mismatched types
+    sadness.cast()
 }
 
 fn main() {}
diff --git a/tests/ui/inference/issue-107090.stderr b/tests/ui/inference/issue-107090.stderr
index 55825f7765b..e509e262fb1 100644
--- a/tests/ui/inference/issue-107090.stderr
+++ b/tests/ui/inference/issue-107090.stderr
@@ -66,19 +66,6 @@ LL | fn badboi<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ Foo<'short,
    |           |
    |           help: consider introducing lifetime `'short` here: `'short,`
 
-error[E0308]: mismatched types
-  --> $DIR/issue-107090.rs:22:5
-   |
-LL | fn badboi<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ Foo<'short, 'out, T>) -> &'out T {
-   |                       - expected this type parameter                                    ------- expected `&'out T` because of return type
-LL |
-LL |     sadness.cast()
-   |     ^^^^^^^^^^^^^^ expected `&T`, found `&Foo<'_, '_, T>`
-   |
-   = note: expected reference `&'out T`
-              found reference `&Foo<'_, '_, T>`
-
-error: aborting due to 7 previous errors
+error: aborting due to 6 previous errors
 
-Some errors have detailed explanations: E0261, E0308.
-For more information about an error, try `rustc --explain E0261`.
+For more information about this error, try `rustc --explain E0261`.
diff --git a/tests/ui/inference/str-as-char.stderr b/tests/ui/inference/str-as-char.stderr
index 216f4cda698..4ca71c5f067 100644
--- a/tests/ui/inference/str-as-char.stderr
+++ b/tests/ui/inference/str-as-char.stderr
@@ -4,7 +4,7 @@ error: character literal may only contain one codepoint
 LL |     let _: &str = '"""';
    |                   ^^^^^
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     let _: &str = "\"\"\"";
    |                   ~~~~~~~~
@@ -15,10 +15,10 @@ error: character literal may only contain one codepoint
 LL |     let _: &str = '\"\"\"';
    |                   ^^^^^^^^
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     let _: &str = "\"\"\"";
-   |                   ~~~~~~~~
+   |                   ~      ~
 
 error: character literal may only contain one codepoint
   --> $DIR/str-as-char.rs:10:19
@@ -26,7 +26,7 @@ error: character literal may only contain one codepoint
 LL |     let _: &str = '"\"\"\\"\\"';
    |                   ^^^^^^^^^^^^^^^^^
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     let _: &str = "\"\"\\"\\"\\\"";
    |                   ~~~~~~~~~~~~~~~~~~~~
@@ -39,10 +39,10 @@ LL |     let _: &str = 'a';
    |            |
    |            expected due to this
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     let _: &str = "a";
-   |                   ~~~
+   |                   ~ ~
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/issues/issue-10412.rs b/tests/ui/issues/issue-10412.rs
index 0de170161b5..68ce0c2ea3c 100644
--- a/tests/ui/issues/issue-10412.rs
+++ b/tests/ui/issues/issue-10412.rs
@@ -8,7 +8,6 @@ impl<'self> Serializable<str> for &'self str {
     //~^ ERROR lifetimes cannot use keyword names
     //~| ERROR lifetimes cannot use keyword names
     //~| ERROR implicit elided lifetime not allowed here
-    //~| ERROR the size for values of type `str` cannot be known at compilation time [E0277]
     fn serialize(val: &'self str) -> Vec<u8> {
         //~^ ERROR lifetimes cannot use keyword names
         vec![1]
diff --git a/tests/ui/issues/issue-10412.stderr b/tests/ui/issues/issue-10412.stderr
index 02a26034f9a..c74ba1306cc 100644
--- a/tests/ui/issues/issue-10412.stderr
+++ b/tests/ui/issues/issue-10412.stderr
@@ -29,13 +29,13 @@ LL | impl<'self> Serializable<str> for &'self str {
    |                                    ^^^^^
 
 error: lifetimes cannot use keyword names
-  --> $DIR/issue-10412.rs:12:24
+  --> $DIR/issue-10412.rs:11:24
    |
 LL |     fn serialize(val: &'self str) -> Vec<u8> {
    |                        ^^^^^
 
 error: lifetimes cannot use keyword names
-  --> $DIR/issue-10412.rs:16:37
+  --> $DIR/issue-10412.rs:15:37
    |
 LL |     fn deserialize(repr: &[u8]) -> &'self str {
    |                                     ^^^^^
@@ -51,24 +51,6 @@ help: indicate the anonymous lifetime
 LL | impl<'self> Serializable<'_, str> for &'self str {
    |                          +++
 
-error[E0277]: the size for values of type `str` cannot be known at compilation time
-  --> $DIR/issue-10412.rs:7:13
-   |
-LL | impl<'self> Serializable<str> for &'self str {
-   |             ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
-   |
-   = help: the trait `Sized` is not implemented for `str`
-note: required by an implicit `Sized` bound in `Serializable`
-  --> $DIR/issue-10412.rs:1:27
-   |
-LL | trait Serializable<'self, T> {
-   |                           ^ required by the implicit `Sized` requirement on this type parameter in `Serializable`
-help: consider relaxing the implicit `Sized` restriction
-   |
-LL | trait Serializable<'self, T: ?Sized> {
-   |                            ++++++++
-
-error: aborting due to 9 previous errors
+error: aborting due to 8 previous errors
 
-Some errors have detailed explanations: E0277, E0726.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0726`.
diff --git a/tests/ui/issues/issue-17361.rs b/tests/ui/issues/issue-17361.rs
index 8e85f0791d6..1b1eeb5a252 100644
--- a/tests/ui/issues/issue-17361.rs
+++ b/tests/ui/issues/issue-17361.rs
@@ -1,5 +1,5 @@
 //@ run-pass
-// Test that astconv doesn't forget about mutability of &mut str
+// Test that HIR ty lowering doesn't forget about mutability of `&mut str`.
 
 //@ pretty-expanded FIXME #23616
 
diff --git a/tests/ui/issues/issue-23589.stderr b/tests/ui/issues/issue-23589.stderr
index 1a91f5e04db..21d383b0e8c 100644
--- a/tests/ui/issues/issue-23589.stderr
+++ b/tests/ui/issues/issue-23589.stderr
@@ -15,10 +15,10 @@ error[E0308]: mismatched types
 LL |     let v: Vec(&str) = vec!['1', '2'];
    |                             ^^^ expected `&str`, found `char`
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     let v: Vec(&str) = vec!["1", '2'];
-   |                             ~~~
+   |                             ~ ~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/issues/issue-27942.stderr b/tests/ui/issues/issue-27942.stderr
index 7ea9345a668..8ea46bae26d 100644
--- a/tests/ui/issues/issue-27942.stderr
+++ b/tests/ui/issues/issue-27942.stderr
@@ -6,16 +6,16 @@ LL |     fn select(&self) -> BufferViewHandle<R>;
    |
    = note: expected trait `Resources<'_>`
               found trait `Resources<'a>`
-note: the anonymous lifetime defined here...
-  --> $DIR/issue-27942.rs:5:15
-   |
-LL |     fn select(&self) -> BufferViewHandle<R>;
-   |               ^^^^^
-note: ...does not necessarily outlive the lifetime `'a` as defined here
+note: the lifetime `'a` as defined here...
   --> $DIR/issue-27942.rs:3:18
    |
 LL | pub trait Buffer<'a, R: Resources<'a>> {
    |                  ^^
+note: ...does not necessarily outlive the anonymous lifetime defined here
+  --> $DIR/issue-27942.rs:5:15
+   |
+LL |     fn select(&self) -> BufferViewHandle<R>;
+   |               ^^^^^
 
 error[E0308]: mismatched types
   --> $DIR/issue-27942.rs:5:25
@@ -25,16 +25,16 @@ LL |     fn select(&self) -> BufferViewHandle<R>;
    |
    = note: expected trait `Resources<'_>`
               found trait `Resources<'a>`
-note: the lifetime `'a` as defined here...
-  --> $DIR/issue-27942.rs:3:18
-   |
-LL | pub trait Buffer<'a, R: Resources<'a>> {
-   |                  ^^
-note: ...does not necessarily outlive the anonymous lifetime defined here
+note: the anonymous lifetime defined here...
   --> $DIR/issue-27942.rs:5:15
    |
 LL |     fn select(&self) -> BufferViewHandle<R>;
    |               ^^^^^
+note: ...does not necessarily outlive the lifetime `'a` as defined here
+  --> $DIR/issue-27942.rs:3:18
+   |
+LL | pub trait Buffer<'a, R: Resources<'a>> {
+   |                  ^^
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/issues/issue-87199.rs b/tests/ui/issues/issue-87199.rs
index 081c45d6151..34879c5a7ca 100644
--- a/tests/ui/issues/issue-87199.rs
+++ b/tests/ui/issues/issue-87199.rs
@@ -11,6 +11,7 @@ fn ref_arg<T: ?Send>(_: &T) {}
 //~^ warning: relaxing a default bound only does something for `?Sized`
 fn ret() -> impl Iterator<Item = ()> + ?Send { std::iter::empty() }
 //~^ warning: relaxing a default bound only does something for `?Sized`
+//~| warning: relaxing a default bound only does something for `?Sized`
 
 // Check that there's no `?Sized` relaxation!
 fn main() {
diff --git a/tests/ui/issues/issue-87199.stderr b/tests/ui/issues/issue-87199.stderr
index 34433eef5c7..a0ed2946fb4 100644
--- a/tests/ui/issues/issue-87199.stderr
+++ b/tests/ui/issues/issue-87199.stderr
@@ -16,8 +16,16 @@ warning: relaxing a default bound only does something for `?Sized`; all other tr
 LL | fn ret() -> impl Iterator<Item = ()> + ?Send { std::iter::empty() }
    |                                        ^^^^^
 
+warning: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+  --> $DIR/issue-87199.rs:12:40
+   |
+LL | fn ret() -> impl Iterator<Item = ()> + ?Send { std::iter::empty() }
+   |                                        ^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
 error[E0277]: the size for values of type `[i32]` cannot be known at compilation time
-  --> $DIR/issue-87199.rs:18:15
+  --> $DIR/issue-87199.rs:19:15
    |
 LL |     ref_arg::<[i32]>(&[5]);
    |               ^^^^^ doesn't have a size known at compile-time
@@ -33,6 +41,6 @@ help: consider relaxing the implicit `Sized` restriction
 LL | fn ref_arg<T: ?Send + ?Sized>(_: &T) {}
    |                     ++++++++
 
-error: aborting due to 1 previous error; 3 warnings emitted
+error: aborting due to 1 previous error; 4 warnings emitted
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/lexer/lex-bad-char-literals-2.stderr b/tests/ui/lexer/lex-bad-char-literals-2.stderr
index 1518a37ab53..76cde00404a 100644
--- a/tests/ui/lexer/lex-bad-char-literals-2.stderr
+++ b/tests/ui/lexer/lex-bad-char-literals-2.stderr
@@ -4,10 +4,10 @@ error: character literal may only contain one codepoint
 LL |     'nope'
    |     ^^^^^^
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     "nope"
-   |     ~~~~~~
+   |     ~    ~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lexer/lex-bad-char-literals-3.stderr b/tests/ui/lexer/lex-bad-char-literals-3.stderr
index 62a5e424cb4..3f339b2ef7d 100644
--- a/tests/ui/lexer/lex-bad-char-literals-3.stderr
+++ b/tests/ui/lexer/lex-bad-char-literals-3.stderr
@@ -4,10 +4,10 @@ error: character literal may only contain one codepoint
 LL | static c: char = '●●';
    |                  ^^^^
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL | static c: char = "●●";
-   |                  ~~~~
+   |                  ~  ~
 
 error: character literal may only contain one codepoint
   --> $DIR/lex-bad-char-literals-3.rs:5:20
@@ -15,10 +15,10 @@ error: character literal may only contain one codepoint
 LL |     let ch: &str = '●●';
    |                    ^^^^
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     let ch: &str = "●●";
-   |                    ~~~~
+   |                    ~  ~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/lexer/lex-bad-char-literals-5.stderr b/tests/ui/lexer/lex-bad-char-literals-5.stderr
index 184817a6579..8004157e87f 100644
--- a/tests/ui/lexer/lex-bad-char-literals-5.stderr
+++ b/tests/ui/lexer/lex-bad-char-literals-5.stderr
@@ -4,10 +4,10 @@ error: character literal may only contain one codepoint
 LL | static c: char = '\x10\x10';
    |                  ^^^^^^^^^^
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL | static c: char = "\x10\x10";
-   |                  ~~~~~~~~~~
+   |                  ~        ~
 
 error: character literal may only contain one codepoint
   --> $DIR/lex-bad-char-literals-5.rs:5:20
@@ -15,10 +15,10 @@ error: character literal may only contain one codepoint
 LL |     let ch: &str = '\x10\x10';
    |                    ^^^^^^^^^^
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     let ch: &str = "\x10\x10";
-   |                    ~~~~~~~~~~
+   |                    ~        ~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/lexer/lex-bad-char-literals-6.stderr b/tests/ui/lexer/lex-bad-char-literals-6.stderr
index 2fe30304a50..96d409d59bb 100644
--- a/tests/ui/lexer/lex-bad-char-literals-6.stderr
+++ b/tests/ui/lexer/lex-bad-char-literals-6.stderr
@@ -4,10 +4,10 @@ error: character literal may only contain one codepoint
 LL |     let x: &str = 'ab';
    |                   ^^^^
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     let x: &str = "ab";
-   |                   ~~~~
+   |                   ~  ~
 
 error: character literal may only contain one codepoint
   --> $DIR/lex-bad-char-literals-6.rs:4:19
@@ -15,10 +15,10 @@ error: character literal may only contain one codepoint
 LL |     let y: char = 'cd';
    |                   ^^^^
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     let y: char = "cd";
-   |                   ~~~~
+   |                   ~  ~
 
 error: character literal may only contain one codepoint
   --> $DIR/lex-bad-char-literals-6.rs:6:13
@@ -26,10 +26,10 @@ error: character literal may only contain one codepoint
 LL |     let z = 'ef';
    |             ^^^^
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     let z = "ef";
-   |             ~~~~
+   |             ~  ~
 
 error[E0308]: mismatched types
   --> $DIR/lex-bad-char-literals-6.rs:13:20
diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-1.fixed b/tests/ui/lexer/lex-bad-str-literal-as-char-1.fixed
new file mode 100644
index 00000000000..b12139b0b40
--- /dev/null
+++ b/tests/ui/lexer/lex-bad-str-literal-as-char-1.fixed
@@ -0,0 +1,6 @@
+//@ run-rustfix
+fn main() {
+    println!("1 + 1");
+    //~^ ERROR unterminated character literal
+    //~| ERROR lifetimes cannot start with a number
+}
diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-1.rs b/tests/ui/lexer/lex-bad-str-literal-as-char-1.rs
new file mode 100644
index 00000000000..6548792f33b
--- /dev/null
+++ b/tests/ui/lexer/lex-bad-str-literal-as-char-1.rs
@@ -0,0 +1,6 @@
+//@ run-rustfix
+fn main() {
+    println!('1 + 1');
+    //~^ ERROR unterminated character literal
+    //~| ERROR lifetimes cannot start with a number
+}
diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr
new file mode 100644
index 00000000000..57c5f82704e
--- /dev/null
+++ b/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr
@@ -0,0 +1,20 @@
+error[E0762]: unterminated character literal
+  --> $DIR/lex-bad-str-literal-as-char-1.rs:3:20
+   |
+LL |     println!('1 + 1');
+   |                    ^^^
+   |
+help: if you meant to write a string literal, use double quotes
+   |
+LL |     println!("1 + 1");
+   |              ~     ~
+
+error: lifetimes cannot start with a number
+  --> $DIR/lex-bad-str-literal-as-char-1.rs:3:14
+   |
+LL |     println!('1 + 1');
+   |              ^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0762`.
diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-2.fixed b/tests/ui/lexer/lex-bad-str-literal-as-char-2.fixed
new file mode 100644
index 00000000000..3ccec537c6c
--- /dev/null
+++ b/tests/ui/lexer/lex-bad-str-literal-as-char-2.fixed
@@ -0,0 +1,4 @@
+//@ run-rustfix
+fn main() {
+    println!(" 1 + 1"); //~ ERROR character literal may only contain one codepoint
+}
diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-2.rs b/tests/ui/lexer/lex-bad-str-literal-as-char-2.rs
new file mode 100644
index 00000000000..8af72e47dbb
--- /dev/null
+++ b/tests/ui/lexer/lex-bad-str-literal-as-char-2.rs
@@ -0,0 +1,4 @@
+//@ run-rustfix
+fn main() {
+    println!(' 1 + 1'); //~ ERROR character literal may only contain one codepoint
+}
diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr
new file mode 100644
index 00000000000..f64761af641
--- /dev/null
+++ b/tests/ui/lexer/lex-bad-str-literal-as-char-2.stderr
@@ -0,0 +1,13 @@
+error: character literal may only contain one codepoint
+  --> $DIR/lex-bad-str-literal-as-char-2.rs:3:14
+   |
+LL |     println!(' 1 + 1');
+   |              ^^^^^^^^
+   |
+help: if you meant to write a string literal, use double quotes
+   |
+LL |     println!(" 1 + 1");
+   |              ~      ~
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs
new file mode 100644
index 00000000000..0ae227da5f1
--- /dev/null
+++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs
@@ -0,0 +1,7 @@
+//@ revisions: rust2015 rust2018 rust2021
+//@[rust2018] edition:2018
+//@[rust2021] edition:2021
+fn main() {
+    println!('hello world');
+    //[rust2015,rust2018,rust2021]~^ ERROR unterminated character literal
+}
diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2015.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2015.stderr
new file mode 100644
index 00000000000..06f12742667
--- /dev/null
+++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2015.stderr
@@ -0,0 +1,14 @@
+error[E0762]: unterminated character literal
+  --> $DIR/lex-bad-str-literal-as-char-3.rs:5:26
+   |
+LL |     println!('hello world');
+   |                          ^^^
+   |
+help: if you meant to write a string literal, use double quotes
+   |
+LL |     println!("hello world");
+   |              ~           ~
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0762`.
diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2018.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2018.stderr
new file mode 100644
index 00000000000..06f12742667
--- /dev/null
+++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2018.stderr
@@ -0,0 +1,14 @@
+error[E0762]: unterminated character literal
+  --> $DIR/lex-bad-str-literal-as-char-3.rs:5:26
+   |
+LL |     println!('hello world');
+   |                          ^^^
+   |
+help: if you meant to write a string literal, use double quotes
+   |
+LL |     println!("hello world");
+   |              ~           ~
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0762`.
diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr
new file mode 100644
index 00000000000..06f12742667
--- /dev/null
+++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr
@@ -0,0 +1,14 @@
+error[E0762]: unterminated character literal
+  --> $DIR/lex-bad-str-literal-as-char-3.rs:5:26
+   |
+LL |     println!('hello world');
+   |                          ^^^
+   |
+help: if you meant to write a string literal, use double quotes
+   |
+LL |     println!("hello world");
+   |              ~           ~
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0762`.
diff --git a/tests/ui/lifetimes/could-not-resolve-issue-121503.rs b/tests/ui/lifetimes/could-not-resolve-issue-121503.rs
index 6bc70a907d9..363162370f2 100644
--- a/tests/ui/lifetimes/could-not-resolve-issue-121503.rs
+++ b/tests/ui/lifetimes/could-not-resolve-issue-121503.rs
@@ -4,8 +4,7 @@
 struct Struct;
 impl Struct {
     async fn box_ref_Struct(self: Box<Self, impl FnMut(&mut Self)>) -> &u32 {
-    //~^ ERROR the trait bound `impl FnMut(&mut Self): Allocator` is not satisfied
-    //~| ERROR Box<Struct, impl FnMut(&mut Self)>` cannot be used as the type of `self` without
+    //~^ ERROR Box<Struct, impl FnMut(&mut Self)>` cannot be used as the type of `self` without
         &1
     }
 }
diff --git a/tests/ui/lifetimes/could-not-resolve-issue-121503.stderr b/tests/ui/lifetimes/could-not-resolve-issue-121503.stderr
index a5d8239a2df..3babf63347c 100644
--- a/tests/ui/lifetimes/could-not-resolve-issue-121503.stderr
+++ b/tests/ui/lifetimes/could-not-resolve-issue-121503.stderr
@@ -1,16 +1,3 @@
-error[E0277]: the trait bound `impl FnMut(&mut Self): Allocator` is not satisfied
-  --> $DIR/could-not-resolve-issue-121503.rs:6:5
-   |
-LL |     async fn box_ref_Struct(self: Box<Self, impl FnMut(&mut Self)>) -> &u32 {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Allocator` is not implemented for `impl FnMut(&mut Self)`
-   |
-note: required by a bound in `Box`
-  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
-help: consider further restricting this bound
-   |
-LL |     async fn box_ref_Struct(self: Box<Self, impl FnMut(&mut Self) + std::alloc::Allocator>) -> &u32 {
-   |                                                                   +++++++++++++++++++++++
-
 error[E0658]: `Box<Struct, impl FnMut(&mut Self)>` cannot be used as the type of `self` without the `arbitrary_self_types` feature
   --> $DIR/could-not-resolve-issue-121503.rs:6:35
    |
@@ -22,7 +9,6 @@ LL |     async fn box_ref_Struct(self: Box<Self, impl FnMut(&mut Self)>) -> &u32
    = 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 2 previous errors
+error: aborting due to 1 previous error
 
-Some errors have detailed explanations: E0277, E0658.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/lifetimes/issue-26638.rs b/tests/ui/lifetimes/issue-26638.rs
index 4bec3b3415b..11c730165f2 100644
--- a/tests/ui/lifetimes/issue-26638.rs
+++ b/tests/ui/lifetimes/issue-26638.rs
@@ -1,6 +1,5 @@
 fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.next() }
 //~^ ERROR missing lifetime specifier [E0106]
-//~| ERROR mismatched types
 
 fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
 //~^ ERROR missing lifetime specifier [E0106]
diff --git a/tests/ui/lifetimes/issue-26638.stderr b/tests/ui/lifetimes/issue-26638.stderr
index ee958686259..403a8c67ccb 100644
--- a/tests/ui/lifetimes/issue-26638.stderr
+++ b/tests/ui/lifetimes/issue-26638.stderr
@@ -11,7 +11,7 @@ LL | fn parse_type<'a>(iter: Box<dyn Iterator<Item=&'a str>+'static>) -> &'a str
    |              ++++                              ++                    ++
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/issue-26638.rs:5:40
+  --> $DIR/issue-26638.rs:4:40
    |
 LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
    |                                        ^ expected named lifetime parameter
@@ -31,7 +31,7 @@ LL | fn parse_type_2(iter: fn(&u8)->&u8) -> String { iter() }
    |                                        ~~~~~~
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/issue-26638.rs:10:22
+  --> $DIR/issue-26638.rs:9:22
    |
 LL | fn parse_type_3() -> &str { unimplemented!() }
    |                      ^ expected named lifetime parameter
@@ -46,23 +46,8 @@ help: instead, you are more likely to want to return an owned value
 LL | fn parse_type_3() -> String { unimplemented!() }
    |                      ~~~~~~
 
-error[E0308]: mismatched types
-  --> $DIR/issue-26638.rs:1:69
-   |
-LL | fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.next() }
-   |                                                              ----   ^^^^^^^^^^^ expected `&str`, found `Option<&str>`
-   |                                                              |
-   |                                                              expected `&str` because of return type
-   |
-   = note: expected reference `&str`
-                   found enum `Option<&str>`
-help: consider using `Option::expect` to unwrap the `Option<&str>` value, panicking if the value is an `Option::None`
-   |
-LL | fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.next().expect("REASON") }
-   |                                                                                +++++++++++++++++
-
 error[E0061]: this function takes 1 argument but 0 arguments were supplied
-  --> $DIR/issue-26638.rs:5:47
+  --> $DIR/issue-26638.rs:4:47
    |
 LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
    |                                               ^^^^-- an argument of type `&u8` is missing
@@ -73,7 +58,7 @@ LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter(/* &u8 */) }
    |                                                   ~~~~~~~~~~~
 
 error[E0308]: mismatched types
-  --> $DIR/issue-26638.rs:5:47
+  --> $DIR/issue-26638.rs:4:47
    |
 LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
    |                                        ----   ^^^^^^ expected `&str`, found `&u8`
@@ -83,7 +68,7 @@ LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
    = note: expected reference `&'static str`
               found reference `&u8`
 
-error: aborting due to 6 previous errors
+error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0061, E0106, E0308.
 For more information about an error, try `rustc --explain E0061`.
diff --git a/tests/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.rs b/tests/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.rs
index 56f89b70410..d6c918843c7 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.rs
+++ b/tests/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.rs
@@ -1,7 +1,5 @@
 fn foo(x: &i32, y: &i32) -> &i32 { //~ ERROR missing lifetime
     if x > y { x } else { y }
-    //~^ ERROR: lifetime may not live long enough
-    //~| ERROR: lifetime may not live long enough
 }
 
 fn main() {}
diff --git a/tests/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr b/tests/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr
index db5b039d1c2..62b0a8a04bf 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex1b-return-no-names-if-else.stderr
@@ -10,22 +10,6 @@ help: consider introducing a named lifetime parameter
 LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
    |       ++++     ++          ++          ++
 
-error: lifetime may not live long enough
-  --> $DIR/ex1b-return-no-names-if-else.rs:2:16
-   |
-LL | fn foo(x: &i32, y: &i32) -> &i32 {
-   |           - let's call the lifetime of this reference `'1`
-LL |     if x > y { x } else { y }
-   |                ^ returning this value requires that `'1` must outlive `'static`
-
-error: lifetime may not live long enough
-  --> $DIR/ex1b-return-no-names-if-else.rs:2:27
-   |
-LL | fn foo(x: &i32, y: &i32) -> &i32 {
-   |                    - let's call the lifetime of this reference `'2`
-LL |     if x > y { x } else { y }
-   |                           ^ returning this value requires that `'2` must outlive `'static`
-
-error: aborting due to 3 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0106`.
diff --git a/tests/ui/lint/dead-code/pub-field-in-priv-mod.rs b/tests/ui/lint/dead-code/pub-field-in-priv-mod.rs
new file mode 100644
index 00000000000..e49a164e940
--- /dev/null
+++ b/tests/ui/lint/dead-code/pub-field-in-priv-mod.rs
@@ -0,0 +1,11 @@
+#![deny(dead_code)]
+
+fn main() {
+    let _ = foo::S{f: false};
+}
+
+mod foo {
+    pub struct S {
+        pub f: bool, //~ ERROR field `f` is never read
+    }
+}
diff --git a/tests/ui/lint/dead-code/pub-field-in-priv-mod.stderr b/tests/ui/lint/dead-code/pub-field-in-priv-mod.stderr
new file mode 100644
index 00000000000..11dd387315f
--- /dev/null
+++ b/tests/ui/lint/dead-code/pub-field-in-priv-mod.stderr
@@ -0,0 +1,16 @@
+error: field `f` is never read
+  --> $DIR/pub-field-in-priv-mod.rs:9:13
+   |
+LL |     pub struct S {
+   |                - field in this struct
+LL |         pub f: bool,
+   |             ^
+   |
+note: the lint level is defined here
+  --> $DIR/pub-field-in-priv-mod.rs:1:9
+   |
+LL | #![deny(dead_code)]
+   |         ^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/lint/lint-qualification.fixed b/tests/ui/lint/lint-qualification.fixed
index 2070bbcef52..7c8fd5236e6 100644
--- a/tests/ui/lint/lint-qualification.fixed
+++ b/tests/ui/lint/lint-qualification.fixed
@@ -35,6 +35,7 @@ fn main() {
         foo::bar();
         foo::$b(); // issue #96698
         $a::bar();
+        $a::$b();
     } }
     m!(foo, bar);
 }
diff --git a/tests/ui/lint/lint-qualification.rs b/tests/ui/lint/lint-qualification.rs
index 41b7e17c6ed..009b3080d5c 100644
--- a/tests/ui/lint/lint-qualification.rs
+++ b/tests/ui/lint/lint-qualification.rs
@@ -35,6 +35,7 @@ fn main() {
         foo::bar();
         foo::$b(); // issue #96698
         $a::bar();
+        $a::$b();
     } }
     m!(foo, bar);
 }
diff --git a/tests/ui/lint/unused/unused-associated-item.rs b/tests/ui/lint/unused/unused-associated-item.rs
new file mode 100644
index 00000000000..27cb4e979f1
--- /dev/null
+++ b/tests/ui/lint/unused/unused-associated-item.rs
@@ -0,0 +1,21 @@
+//@ check-pass
+
+#![deny(unused_must_use)]
+
+use std::future::Future;
+use std::pin::Pin;
+
+trait Factory {
+    type Output;
+}
+
+impl Factory for () {
+    type Output = Pin<Box<dyn Future<Output = ()> + 'static>>;
+}
+
+// Make sure we don't get an `unused_must_use` error on the *associated type bound*.
+fn f() -> impl Factory<Output: Future> {}
+
+fn main() {
+    f();
+}
diff --git a/tests/ui/match/postfix-match/pf-match-chain.rs b/tests/ui/match/postfix-match/pf-match-chain.rs
new file mode 100644
index 00000000000..80546e1963b
--- /dev/null
+++ b/tests/ui/match/postfix-match/pf-match-chain.rs
@@ -0,0 +1,16 @@
+//@ run-pass
+
+#![feature(postfix_match)]
+
+fn main() {
+    1.match {
+        2 => Some(0),
+        _ => None,
+    }.match {
+        None => Ok(true),
+        Some(_) => Err("nope")
+    }.match {
+        Ok(_) => (),
+        Err(_) => panic!()
+    }
+}
diff --git a/tests/ui/match/postfix-match/pf-match-exhaustiveness.rs b/tests/ui/match/postfix-match/pf-match-exhaustiveness.rs
new file mode 100644
index 00000000000..f4cac46f7cd
--- /dev/null
+++ b/tests/ui/match/postfix-match/pf-match-exhaustiveness.rs
@@ -0,0 +1,7 @@
+#![feature(postfix_match)]
+
+fn main() {
+    Some(1).match { //~ non-exhaustive patterns
+        None => {},
+    }
+}
diff --git a/tests/ui/match/postfix-match/pf-match-exhaustiveness.stderr b/tests/ui/match/postfix-match/pf-match-exhaustiveness.stderr
new file mode 100644
index 00000000000..f458218bb5d
--- /dev/null
+++ b/tests/ui/match/postfix-match/pf-match-exhaustiveness.stderr
@@ -0,0 +1,21 @@
+error[E0004]: non-exhaustive patterns: `Some(_)` not covered
+  --> $DIR/pf-match-exhaustiveness.rs:4:5
+   |
+LL |     Some(1).match {
+   |     ^^^^^^^ pattern `Some(_)` not covered
+   |
+note: `Option<i32>` defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+  ::: $SRC_DIR/core/src/option.rs:LL:COL
+   |
+   = note: not covered
+   = note: the matched value is of type `Option<i32>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         None => {},
+LL ~         Some(_) => todo!(),
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/match/postfix-match/pf-match-types.rs b/tests/ui/match/postfix-match/pf-match-types.rs
new file mode 100644
index 00000000000..af205926fb6
--- /dev/null
+++ b/tests/ui/match/postfix-match/pf-match-types.rs
@@ -0,0 +1,15 @@
+#![feature(postfix_match)]
+
+fn main() {
+    Some(10).match {
+    //~^ NOTE `match` arms have incompatible types
+        Some(5) => false,
+        //~^ NOTE this is found to be of type `bool`
+        Some(2) => true,
+        //~^ NOTE this is found to be of type `bool`
+        None    => (),
+        //~^ ERROR `match` arms have incompatible types
+        //~| NOTE expected `bool`, found `()`
+        _       => true
+    }
+}
diff --git a/tests/ui/match/postfix-match/pf-match-types.stderr b/tests/ui/match/postfix-match/pf-match-types.stderr
new file mode 100644
index 00000000000..0cfc1363d5f
--- /dev/null
+++ b/tests/ui/match/postfix-match/pf-match-types.stderr
@@ -0,0 +1,21 @@
+error[E0308]: `match` arms have incompatible types
+  --> $DIR/pf-match-types.rs:10:20
+   |
+LL | /     Some(10).match {
+LL | |
+LL | |         Some(5) => false,
+   | |                    ----- this is found to be of type `bool`
+LL | |
+LL | |         Some(2) => true,
+   | |                    ---- this is found to be of type `bool`
+LL | |
+LL | |         None    => (),
+   | |                    ^^ expected `bool`, found `()`
+...  |
+LL | |         _       => true
+LL | |     }
+   | |_____- `match` arms have incompatible types
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/match/postfix-match/postfix-match.rs b/tests/ui/match/postfix-match/postfix-match.rs
new file mode 100644
index 00000000000..03c4e8ab545
--- /dev/null
+++ b/tests/ui/match/postfix-match/postfix-match.rs
@@ -0,0 +1,62 @@
+//@ run-pass
+
+#![feature(postfix_match)]
+
+struct Bar {
+    foo: u8,
+    baz: u8,
+}
+
+pub fn main() {
+    let thing = Some("thing");
+
+    thing.match {
+        Some("nothing") => {},
+        Some(text) if text.eq_ignore_ascii_case("tapir")  => {},
+        Some("true") | Some("false") => {},
+        Some("thing") => {},
+        Some(_) => {},
+        None => {}
+    };
+
+    let num = 2u8;
+
+    num.match {
+        0 => {},
+        1..=5 => {},
+        _ => {},
+    };
+
+    let slic = &[1, 2, 3, 4][..];
+
+    slic.match {
+        [1] => {},
+        [2, _tail @ ..] => {},
+        [1, _] => {},
+        _ => {},
+    };
+
+    slic[0].match {
+        1 => 0,
+        i => i,
+    };
+
+    let out = (1, 2).match {
+        (1, 3) => 0,
+        (_, 1) => 0,
+        (1, i) => i,
+        _ => 3,
+    };
+    assert!(out == 2);
+
+    let strct = Bar {
+        foo: 3,
+        baz: 4
+    };
+
+    strct.match {
+        Bar { foo: 1, .. } => {},
+        Bar { baz: 2, .. } => {},
+        _ => (),
+    };
+}
diff --git a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
index 9feb2a7320d..d7933a39eaa 100644
--- a/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
+++ b/tests/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
@@ -53,17 +53,16 @@ LL | fn case2() {
 error[E0597]: `a` does not live long enough
   --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:30:26
    |
-LL |       let a = 0;
-   |           - binding `a` declared here
-LL |       let cell = Cell::new(&a);
-   |                            ^^ borrowed value does not live long enough
+LL |     let a = 0;
+   |         - binding `a` declared here
+LL |     let cell = Cell::new(&a);
+   |                ----------^^-
+   |                |         |
+   |                |         borrowed value does not live long enough
+   |                argument requires that `a` is borrowed for `'static`
 ...
-LL | /     foo(cell, |cell_a, cell_x| {
-LL | |         cell_x.set(cell_a.get()); // forces 'a: 'x, implies 'a = 'static -> borrow error
-LL | |     })
-   | |______- argument requires that `a` is borrowed for `'static`
-LL |   }
-   |   - `a` dropped here while still borrowed
+LL | }
+   | - `a` dropped here while still borrowed
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/nll/ice-106874.rs b/tests/ui/nll/ice-106874.rs
new file mode 100644
index 00000000000..9337eee961b
--- /dev/null
+++ b/tests/ui/nll/ice-106874.rs
@@ -0,0 +1,48 @@
+// issue: rust-lang/rust#106874
+// ICE BoundUniversalRegionError
+
+use std::marker::PhantomData;
+use std::rc::Rc;
+
+pub fn func<V, F: Fn(&mut V)>(f: F) -> A<impl X> {
+    A(B(C::new(D::new(move |st| f(st)))))
+    //~^ ERROR implementation of `FnOnce` is not general enough
+    //~| ERROR implementation of `Fn` is not general enough
+    //~| ERROR implementation of `FnOnce` is not general enough
+    //~| ERROR implementation of `FnOnce` is not general enough
+    //~| ERROR implementation of `Fn` is not general enough
+    //~| ERROR implementation of `FnOnce` is not general enough
+    //~| ERROR implementation of `Fn` is not general enough
+    //~| ERROR implementation of `FnOnce` is not general enough
+    //~| ERROR higher-ranked subtype error
+    //~| ERROR higher-ranked subtype error
+}
+
+trait X {}
+trait Y {
+    type V;
+}
+
+struct A<T>(T);
+
+struct B<T>(Rc<T>);
+impl<T> X for B<T> {}
+
+struct C<T: Y>(T::V);
+impl<T: Y> C<T> {
+    fn new(_: T) -> Rc<Self> {
+        todo!()
+    }
+}
+struct D<V, F>(F, PhantomData<fn(&mut V)>);
+
+impl<V, F> D<V, F> {
+    fn new(_: F) -> Self {
+        todo!()
+    }
+}
+impl<V, F: Fn(&mut V)> Y for D<V, F> {
+    type V = V;
+}
+
+pub fn main() {}
diff --git a/tests/ui/nll/ice-106874.stderr b/tests/ui/nll/ice-106874.stderr
new file mode 100644
index 00000000000..ead4d490a62
--- /dev/null
+++ b/tests/ui/nll/ice-106874.stderr
@@ -0,0 +1,90 @@
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/ice-106874.rs:8:5
+   |
+LL |     A(B(C::new(D::new(move |st| f(st)))))
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
+   |
+   = note: closure with signature `fn(&'0 mut V)` must implement `FnOnce<(&mut V,)>`, for some specific lifetime `'0`...
+   = note: ...but it actually implements `FnOnce<(&'1 mut V,)>`, for some specific lifetime `'1`
+
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/ice-106874.rs:8:5
+   |
+LL |     A(B(C::new(D::new(move |st| f(st)))))
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
+   |
+   = note: closure with signature `fn(&'0 mut V)` must implement `FnOnce<(&mut V,)>`, for some specific lifetime `'0`...
+   = note: ...but it actually implements `FnOnce<(&'1 mut V,)>`, for some specific lifetime `'1`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: implementation of `Fn` is not general enough
+  --> $DIR/ice-106874.rs:8:7
+   |
+LL |     A(B(C::new(D::new(move |st| f(st)))))
+   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Fn` is not general enough
+   |
+   = note: closure with signature `fn(&'2 mut V)` must implement `Fn<(&'1 mut V,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `Fn<(&'2 mut V,)>`, for some specific lifetime `'2`
+
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/ice-106874.rs:8:7
+   |
+LL |     A(B(C::new(D::new(move |st| f(st)))))
+   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
+   |
+   = note: closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&'2 mut V,)>`, for some specific lifetime `'2`
+
+error: implementation of `Fn` is not general enough
+  --> $DIR/ice-106874.rs:8:7
+   |
+LL |     A(B(C::new(D::new(move |st| f(st)))))
+   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Fn` is not general enough
+   |
+   = note: closure with signature `fn(&'2 mut V)` must implement `Fn<(&'1 mut V,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `Fn<(&'2 mut V,)>`, for some specific lifetime `'2`
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/ice-106874.rs:8:9
+   |
+LL |     A(B(C::new(D::new(move |st| f(st)))))
+   |         ^^^^^^ implementation of `FnOnce` is not general enough
+   |
+   = note: closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&'2 mut V,)>`, for some specific lifetime `'2`
+
+error: implementation of `Fn` is not general enough
+  --> $DIR/ice-106874.rs:8:9
+   |
+LL |     A(B(C::new(D::new(move |st| f(st)))))
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Fn` is not general enough
+   |
+   = note: closure with signature `fn(&'2 mut V)` must implement `Fn<(&'1 mut V,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `Fn<(&'2 mut V,)>`, for some specific lifetime `'2`
+
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/ice-106874.rs:8:9
+   |
+LL |     A(B(C::new(D::new(move |st| f(st)))))
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
+   |
+   = note: closure with signature `fn(&'2 mut V)` must implement `FnOnce<(&'1 mut V,)>`, for any lifetime `'1`...
+   = note: ...but it actually implements `FnOnce<(&'2 mut V,)>`, for some specific lifetime `'2`
+
+error: higher-ranked subtype error
+  --> $DIR/ice-106874.rs:8:41
+   |
+LL |     A(B(C::new(D::new(move |st| f(st)))))
+   |                                         ^
+
+error: higher-ranked subtype error
+  --> $DIR/ice-106874.rs:8:41
+   |
+LL |     A(B(C::new(D::new(move |st| f(st)))))
+   |                                         ^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 10 previous errors
+
diff --git a/tests/ui/nll/issue-54189.rs b/tests/ui/nll/issue-54189.rs
index 70aecc384ef..2339a722a7b 100644
--- a/tests/ui/nll/issue-54189.rs
+++ b/tests/ui/nll/issue-54189.rs
@@ -1,5 +1,6 @@
 fn bug() -> impl for <'r> Fn() -> &'r () { || { &() } }
 //~^ ERROR binding for associated type `Output` references lifetime `'r`
+//~| ERROR binding for associated type `Output` references lifetime `'r`
 
 fn main() {
     let f = bug();
diff --git a/tests/ui/nll/issue-54189.stderr b/tests/ui/nll/issue-54189.stderr
index 14ed2bb222d..ce756a91f56 100644
--- a/tests/ui/nll/issue-54189.stderr
+++ b/tests/ui/nll/issue-54189.stderr
@@ -4,6 +4,14 @@ error[E0582]: binding for associated type `Output` references lifetime `'r`, whi
 LL | fn bug() -> impl for <'r> Fn() -> &'r () { || { &() } }
    |                                   ^^^^^^
 
-error: aborting due to 1 previous error
+error[E0582]: binding for associated type `Output` references lifetime `'r`, which does not appear in the trait input types
+  --> $DIR/issue-54189.rs:1:35
+   |
+LL | fn bug() -> impl for <'r> Fn() -> &'r () { || { &() } }
+   |                                   ^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0582`.
diff --git a/tests/ui/nll/user-annotations/adt-nullary-enums.stderr b/tests/ui/nll/user-annotations/adt-nullary-enums.stderr
index 5b385feeedc..644fc94f730 100644
--- a/tests/ui/nll/user-annotations/adt-nullary-enums.stderr
+++ b/tests/ui/nll/user-annotations/adt-nullary-enums.stderr
@@ -1,16 +1,17 @@
 error[E0597]: `c` does not live long enough
   --> $DIR/adt-nullary-enums.rs:33:41
    |
-LL |       let c = 66;
-   |           - binding `c` declared here
-LL | /     combine(
-LL | |         SomeEnum::SomeVariant(Cell::new(&c)),
-   | |                                         ^^ borrowed value does not live long enough
-LL | |         SomeEnum::SomeOtherVariant::<Cell<&'static u32>>,
-LL | |     );
-   | |_____- argument requires that `c` is borrowed for `'static`
-LL |   }
-   |   - `c` dropped here while still borrowed
+LL |     let c = 66;
+   |         - binding `c` declared here
+LL |     combine(
+LL |         SomeEnum::SomeVariant(Cell::new(&c)),
+   |                               ----------^^-
+   |                               |         |
+   |                               |         borrowed value does not live long enough
+   |                               argument requires that `c` is borrowed for `'static`
+...
+LL | }
+   | - `c` dropped here while still borrowed
 
 error[E0597]: `c` does not live long enough
   --> $DIR/adt-nullary-enums.rs:41:41
diff --git a/tests/ui/nll/user-annotations/region-error-ice-109072.rs b/tests/ui/nll/user-annotations/region-error-ice-109072.rs
index 3f2ad3ccbf5..bcdc6651cf5 100644
--- a/tests/ui/nll/user-annotations/region-error-ice-109072.rs
+++ b/tests/ui/nll/user-annotations/region-error-ice-109072.rs
@@ -11,4 +11,5 @@ impl Lt<'missing> for () { //~ ERROR undeclared lifetime
 
 fn main() {
     let _: <() as Lt<'_>>::T = &();
+    //~^ ERROR the trait bound `(): Lt<'_>` is not satisfied
 }
diff --git a/tests/ui/nll/user-annotations/region-error-ice-109072.stderr b/tests/ui/nll/user-annotations/region-error-ice-109072.stderr
index d90971bed25..c187c17d98c 100644
--- a/tests/ui/nll/user-annotations/region-error-ice-109072.stderr
+++ b/tests/ui/nll/user-annotations/region-error-ice-109072.stderr
@@ -21,6 +21,13 @@ help: consider introducing lifetime `'missing` here
 LL | impl<'missing> Lt<'missing> for () {
    |     ++++++++++
 
-error: aborting due to 2 previous errors
+error[E0277]: the trait bound `(): Lt<'_>` is not satisfied
+  --> $DIR/region-error-ice-109072.rs:13:13
+   |
+LL |     let _: <() as Lt<'_>>::T = &();
+   |             ^^ the trait `Lt<'_>` is not implemented for `()`
+
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0261`.
+Some errors have detailed explanations: E0261, E0277.
+For more information about an error, try `rustc --explain E0261`.
diff --git a/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.rs b/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.rs
index 345c8a25f79..51be999a632 100644
--- a/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.rs
+++ b/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.rs
@@ -15,7 +15,6 @@ fn is_static<T>(_: T) where T: 'static { }
 // code forces us into a conservative, hacky path.
 fn bar(x: &str) -> &dyn Foo<Item = dyn Bar> { &() }
 //~^ ERROR please supply an explicit bound
-//~| ERROR `(): Foo<'_>` is not satisfied
 
 fn main() {
     let s = format!("foo");
diff --git a/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.stderr b/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.stderr
index d227c8778fe..688f8af0822 100644
--- a/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.stderr
+++ b/tests/ui/object-lifetime/object-lifetime-default-dyn-binding-nonstatic3.stderr
@@ -4,20 +4,6 @@ error[E0228]: the lifetime bound for this object type cannot be deduced from con
 LL | fn bar(x: &str) -> &dyn Foo<Item = dyn Bar> { &() }
    |                                    ^^^^^^^
 
-error[E0277]: the trait bound `(): Foo<'_>` is not satisfied
-  --> $DIR/object-lifetime-default-dyn-binding-nonstatic3.rs:16:47
-   |
-LL | fn bar(x: &str) -> &dyn Foo<Item = dyn Bar> { &() }
-   |                                               ^^^ the trait `Foo<'_>` is not implemented for `()`
-   |
-help: this trait has no implementations, consider adding one
-  --> $DIR/object-lifetime-default-dyn-binding-nonstatic3.rs:4:1
-   |
-LL | trait Foo<'a> {
-   | ^^^^^^^^^^^^^
-   = note: required for the cast from `&()` to `&dyn Foo<'_, Item = dyn Bar>`
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
-Some errors have detailed explanations: E0228, E0277.
-For more information about an error, try `rustc --explain E0228`.
+For more information about this error, try `rustc --explain E0228`.
diff --git a/tests/ui/panics/panic-in-message-fmt.rs b/tests/ui/panics/panic-in-message-fmt.rs
new file mode 100644
index 00000000000..e5bedf96b35
--- /dev/null
+++ b/tests/ui/panics/panic-in-message-fmt.rs
@@ -0,0 +1,25 @@
+// Checks what happens when formatting the panic message panics.
+
+//@ run-fail
+//@ exec-env:RUST_BACKTRACE=0
+//@ check-run-results
+//@ error-pattern: panicked while processing panic
+//@ normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> ""
+//@ normalize-stderr-test: "\n +at [^\n]+" -> ""
+//@ normalize-stderr-test: "(core/src/panicking\.rs):[0-9]+:[0-9]+" -> "$1:$$LINE:$$COL"
+//@ ignore-emscripten "RuntimeError" junk in output
+
+use std::fmt::{Display, self};
+
+struct MyStruct;
+
+impl Display for MyStruct {
+    fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
+        todo!()
+    }
+}
+
+fn main() {
+    let instance = MyStruct;
+    panic!("this is wrong: {}", instance);
+}
diff --git a/tests/ui/panics/panic-in-message-fmt.run.stderr b/tests/ui/panics/panic-in-message-fmt.run.stderr
new file mode 100644
index 00000000000..c3a5733c8ae
--- /dev/null
+++ b/tests/ui/panics/panic-in-message-fmt.run.stderr
@@ -0,0 +1,2 @@
+panicked at $DIR/panic-in-message-fmt.rs:18:9:
+thread panicked while processing panic. aborting.
diff --git a/tests/ui/parser/attribute/attr-bad-meta-4.rs b/tests/ui/parser/attribute/attr-bad-meta-4.rs
new file mode 100644
index 00000000000..cedbd1d6686
--- /dev/null
+++ b/tests/ui/parser/attribute/attr-bad-meta-4.rs
@@ -0,0 +1,12 @@
+macro_rules! mac {
+    ($attr_item: meta) => {
+        #[cfg($attr_item)]
+        //~^ ERROR expected unsuffixed literal or identifier, found `an(arbitrary token stream)`
+        //~| ERROR expected unsuffixed literal or identifier, found `an(arbitrary token stream)`
+        struct S;
+    }
+}
+
+mac!(an(arbitrary token stream));
+
+fn main() {}
diff --git a/tests/ui/parser/attribute/attr-bad-meta-4.stderr b/tests/ui/parser/attribute/attr-bad-meta-4.stderr
new file mode 100644
index 00000000000..a543bcb692e
--- /dev/null
+++ b/tests/ui/parser/attribute/attr-bad-meta-4.stderr
@@ -0,0 +1,25 @@
+error: expected unsuffixed literal or identifier, found `an(arbitrary token stream)`
+  --> $DIR/attr-bad-meta-4.rs:3:15
+   |
+LL |         #[cfg($attr_item)]
+   |               ^^^^^^^^^^
+...
+LL | mac!(an(arbitrary token stream));
+   | -------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected unsuffixed literal or identifier, found `an(arbitrary token stream)`
+  --> $DIR/attr-bad-meta-4.rs:3:15
+   |
+LL |         #[cfg($attr_item)]
+   |               ^^^^^^^^^^
+...
+LL | mac!(an(arbitrary token stream));
+   | -------------------------------- in this macro invocation
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+   = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/parser/issues/issue-64732.rs b/tests/ui/parser/issues/issue-64732.rs
index 2db51ea6042..ff0f97ea211 100644
--- a/tests/ui/parser/issues/issue-64732.rs
+++ b/tests/ui/parser/issues/issue-64732.rs
@@ -5,5 +5,5 @@ fn main() {
     //~| HELP if you meant to write a byte string literal, use double quotes
     let _bar = 'hello';
     //~^ ERROR character literal may only contain one codepoint
-    //~| HELP if you meant to write a `str` literal, use double quotes
+    //~| HELP if you meant to write a string literal, use double quotes
 }
diff --git a/tests/ui/parser/issues/issue-64732.stderr b/tests/ui/parser/issues/issue-64732.stderr
index 80462549377..7ec2df6d3bf 100644
--- a/tests/ui/parser/issues/issue-64732.stderr
+++ b/tests/ui/parser/issues/issue-64732.stderr
@@ -7,7 +7,7 @@ LL |     let _foo = b'hello\0';
 help: if you meant to write a byte string literal, use double quotes
    |
 LL |     let _foo = b"hello\0";
-   |                ~~~~~~~~~~
+   |                ~~       ~
 
 error: character literal may only contain one codepoint
   --> $DIR/issue-64732.rs:6:16
@@ -15,10 +15,10 @@ error: character literal may only contain one codepoint
 LL |     let _bar = 'hello';
    |                ^^^^^^^
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     let _bar = "hello";
-   |                ~~~~~~~
+   |                ~     ~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/parser/parser-ice-ed2021-await-105210.rs b/tests/ui/parser/parser-ice-ed2021-await-105210.rs
new file mode 100644
index 00000000000..95383cc81c2
--- /dev/null
+++ b/tests/ui/parser/parser-ice-ed2021-await-105210.rs
@@ -0,0 +1,10 @@
+// ICE #105210 self.lines.iter().all(|r| !r.iter().any(|sc| sc.chr == \'\\t\'))
+// ignore-tidy-tab
+//@ edition:2021
+pub fn main() {}
+
+fn box () {
+ (( h (const {( default ( await ( await (	(move {await((((}}
+ //~^ ERROR mismatched closing delimiter: `}`
+ //~^^ ERROR mismatched closing delimiter: `}`
+//~ ERROR this file contains an unclosed delimiter
diff --git a/tests/ui/parser/parser-ice-ed2021-await-105210.stderr b/tests/ui/parser/parser-ice-ed2021-await-105210.stderr
new file mode 100644
index 00000000000..fc54476c220
--- /dev/null
+++ b/tests/ui/parser/parser-ice-ed2021-await-105210.stderr
@@ -0,0 +1,34 @@
+error: mismatched closing delimiter: `}`
+  --> $DIR/parser-ice-ed2021-await-105210.rs:7:58
+   |
+LL |  (( h (const {( default ( await ( await (    (move {await((((}}
+   |                                                    -        ^^ mismatched closing delimiter
+   |                                                    |        |
+   |                                                    |        unclosed delimiter
+   |                                                    closing delimiter possibly meant for this
+
+error: mismatched closing delimiter: `}`
+  --> $DIR/parser-ice-ed2021-await-105210.rs:7:43
+   |
+LL |  (( h (const {( default ( await ( await (    (move {await((((}}
+   |              -                               ^                ^ mismatched closing delimiter
+   |              |                               |
+   |              |                               unclosed delimiter
+   |              closing delimiter possibly meant for this
+
+error: this file contains an unclosed delimiter
+  --> $DIR/parser-ice-ed2021-await-105210.rs:10:52
+   |
+LL | fn box () {
+   |           - unclosed delimiter
+LL |  (( h (const {( default ( await ( await (    (move {await((((}}
+   |  --   - unclosed delimiter
+   |  ||
+   |  |unclosed delimiter
+   |  unclosed delimiter
+...
+LL |
+   |                                                    ^
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/parser/unicode-character-literal.fixed b/tests/ui/parser/unicode-character-literal.fixed
index 9e31890151c..e401ecaf5da 100644
--- a/tests/ui/parser/unicode-character-literal.fixed
+++ b/tests/ui/parser/unicode-character-literal.fixed
@@ -7,12 +7,12 @@ fn main() {
     let _spade = "♠️";
     //~^ ERROR: character literal may only contain one codepoint
     //~| NOTE: this `♠` is followed by the combining mark `\u{fe0f}`
-    //~| HELP: if you meant to write a `str` literal, use double quotes
+    //~| HELP: if you meant to write a string literal, use double quotes
 
     let _s = "ṩ̂̊";
     //~^ ERROR: character literal may only contain one codepoint
     //~| NOTE: this `s` is followed by the combining marks `\u{323}\u{307}\u{302}\u{30a}`
-    //~| HELP: if you meant to write a `str` literal, use double quotes
+    //~| HELP: if you meant to write a string literal, use double quotes
 
     let _a = 'Å';
     //~^ ERROR: character literal may only contain one codepoint
diff --git a/tests/ui/parser/unicode-character-literal.rs b/tests/ui/parser/unicode-character-literal.rs
index d886e5b26a5..428e4e1ac5a 100644
--- a/tests/ui/parser/unicode-character-literal.rs
+++ b/tests/ui/parser/unicode-character-literal.rs
@@ -7,12 +7,12 @@ fn main() {
     let _spade = '♠️';
     //~^ ERROR: character literal may only contain one codepoint
     //~| NOTE: this `♠` is followed by the combining mark `\u{fe0f}`
-    //~| HELP: if you meant to write a `str` literal, use double quotes
+    //~| HELP: if you meant to write a string literal, use double quotes
 
     let _s = 'ṩ̂̊';
     //~^ ERROR: character literal may only contain one codepoint
     //~| NOTE: this `s` is followed by the combining marks `\u{323}\u{307}\u{302}\u{30a}`
-    //~| HELP: if you meant to write a `str` literal, use double quotes
+    //~| HELP: if you meant to write a string literal, use double quotes
 
     let _a = 'Å';
     //~^ ERROR: character literal may only contain one codepoint
diff --git a/tests/ui/parser/unicode-character-literal.stderr b/tests/ui/parser/unicode-character-literal.stderr
index 5cd3bd0fe69..726cde2b413 100644
--- a/tests/ui/parser/unicode-character-literal.stderr
+++ b/tests/ui/parser/unicode-character-literal.stderr
@@ -9,10 +9,10 @@ note: this `♠` is followed by the combining mark `\u{fe0f}`
    |
 LL |     let _spade = '♠️';
    |                   ^
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     let _spade = "♠️";
-   |                  ~~~
+   |                  ~ ~
 
 error: character literal may only contain one codepoint
   --> $DIR/unicode-character-literal.rs:12:14
@@ -25,10 +25,10 @@ note: this `s` is followed by the combining marks `\u{323}\u{307}\u{302}\u{30a}`
    |
 LL |     let _s = 'ṩ̂̊';
    |               ^
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     let _s = "ṩ̂̊";
-   |              ~~~
+   |              ~ ~
 
 error: character literal may only contain one codepoint
   --> $DIR/unicode-character-literal.rs:17:14
diff --git a/tests/ui/pattern/deref-patterns/typeck.rs b/tests/ui/pattern/deref-patterns/typeck.rs
new file mode 100644
index 00000000000..ead6dcdbaf0
--- /dev/null
+++ b/tests/ui/pattern/deref-patterns/typeck.rs
@@ -0,0 +1,31 @@
+//@ check-pass
+#![feature(deref_patterns)]
+#![allow(incomplete_features)]
+
+use std::rc::Rc;
+
+fn main() {
+    let vec: Vec<u32> = Vec::new();
+    match vec {
+        deref!([..]) => {}
+        _ => {}
+    }
+    match Box::new(true) {
+        deref!(true) => {}
+        _ => {}
+    }
+    match &Box::new(true) {
+        deref!(true) => {}
+        _ => {}
+    }
+    match &Rc::new(0) {
+        deref!(1..) => {}
+        _ => {}
+    }
+    // FIXME(deref_patterns): fails to typecheck because `"foo"` has type &str but deref creates a
+    // place of type `str`.
+    // match "foo".to_string() {
+    //     box "foo" => {}
+    //     _ => {}
+    // }
+}
diff --git a/tests/ui/print_type_sizes/async.stdout b/tests/ui/print_type_sizes/async.stdout
index e1be98f85d8..1df4d85d09e 100644
--- a/tests/ui/print_type_sizes/async.stdout
+++ b/tests/ui/print_type_sizes/async.stdout
@@ -5,7 +5,7 @@ print-type-size         upvar `.arg`: 8192 bytes
 print-type-size     variant `Suspend0`: 16385 bytes
 print-type-size         upvar `.arg`: 8192 bytes
 print-type-size         local `.arg`: 8192 bytes
-print-type-size         local `.__awaitee`: 1 bytes
+print-type-size         local `.__awaitee`: 1 bytes, type: {async fn body@$DIR/async.rs:8:17: 8:19}
 print-type-size     variant `Returned`: 8192 bytes
 print-type-size         upvar `.arg`: 8192 bytes
 print-type-size     variant `Panicked`: 8192 bytes
diff --git a/tests/ui/privacy/suggest-making-field-public.fixed b/tests/ui/privacy/suggest-making-field-public.fixed
index 29dcde88ab4..8a5686aa5e1 100644
--- a/tests/ui/privacy/suggest-making-field-public.fixed
+++ b/tests/ui/privacy/suggest-making-field-public.fixed
@@ -1,5 +1,5 @@
 //@ run-rustfix
-mod a {
+pub mod a {
     pub struct A(pub String);
 }
 
diff --git a/tests/ui/privacy/suggest-making-field-public.rs b/tests/ui/privacy/suggest-making-field-public.rs
index c9f04757b2f..63fdb0bce6a 100644
--- a/tests/ui/privacy/suggest-making-field-public.rs
+++ b/tests/ui/privacy/suggest-making-field-public.rs
@@ -1,5 +1,5 @@
 //@ run-rustfix
-mod a {
+pub mod a {
     pub struct A(pub(self)String);
 }
 
diff --git a/tests/ui/raw-ref-op/const-eval-compare-ice-105047.rs b/tests/ui/raw-ref-op/const-eval-compare-ice-105047.rs
new file mode 100644
index 00000000000..87ce4f1e14d
--- /dev/null
+++ b/tests/ui/raw-ref-op/const-eval-compare-ice-105047.rs
@@ -0,0 +1,15 @@
+// issue: rust-lang/rust#105047
+// ICE raw ptr comparison should already be caught in the trait systems
+
+#![feature(raw_ref_op)]
+
+const RCZ: *const i32 = &raw const *&0;
+
+const fn f() {
+    if let RCZ = &raw const *&0 { }
+    //~^ WARN function pointers and raw pointers not derived from integers in patterns
+    //~| ERROR pointers cannot be reliably compared during const eval
+    //~| WARN this was previously accepted by the compiler but is being phased out
+}
+
+fn main() {}
diff --git a/tests/ui/raw-ref-op/const-eval-compare-ice-105047.stderr b/tests/ui/raw-ref-op/const-eval-compare-ice-105047.stderr
new file mode 100644
index 00000000000..9c472cda244
--- /dev/null
+++ b/tests/ui/raw-ref-op/const-eval-compare-ice-105047.stderr
@@ -0,0 +1,31 @@
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/const-eval-compare-ice-105047.rs:9:12
+   |
+LL |     if let RCZ = &raw const *&0 { }
+   |            ^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
+error: pointers cannot be reliably compared during const eval
+  --> $DIR/const-eval-compare-ice-105047.rs:9:12
+   |
+LL |     if let RCZ = &raw const *&0 { }
+   |            ^^^
+   |
+   = note: see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+Future incompatibility report: Future breakage diagnostic:
+warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+  --> $DIR/const-eval-compare-ice-105047.rs:9:12
+   |
+LL |     if let RCZ = &raw const *&0 { }
+   |            ^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
+   = note: `#[warn(pointer_structural_match)]` on by default
+
diff --git a/tests/ui/raw-ref-op/raw-ref-temp.stderr b/tests/ui/raw-ref-op/raw-ref-temp.stderr
index b9666162517..1f6d85e4a7e 100644
--- a/tests/ui/raw-ref-op/raw-ref-temp.stderr
+++ b/tests/ui/raw-ref-op/raw-ref-temp.stderr
@@ -75,24 +75,32 @@ error[E0745]: cannot take address of a temporary
    |
 LL |     let ref_ascribe = &raw const type_ascribe!(2, i32);
    |                                  ^^^^^^^^^^^^^^^^^^^^^ temporary value
+   |
+   = note: this error originates in the macro `type_ascribe` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0745]: cannot take address of a temporary
   --> $DIR/raw-ref-temp.rs:27:36
    |
 LL |     let mut_ref_ascribe = &raw mut type_ascribe!(3, i32);
    |                                    ^^^^^^^^^^^^^^^^^^^^^ temporary value
+   |
+   = note: this error originates in the macro `type_ascribe` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0745]: cannot take address of a temporary
   --> $DIR/raw-ref-temp.rs:29:40
    |
 LL |     let ascribe_field_ref = &raw const type_ascribe!(PAIR.0, i32);
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value
+   |
+   = note: this error originates in the macro `type_ascribe` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0745]: cannot take address of a temporary
   --> $DIR/raw-ref-temp.rs:30:38
    |
 LL |     let ascribe_index_ref = &raw mut type_ascribe!(ARRAY[0], i32);
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value
+   |
+   = note: this error originates in the macro `type_ascribe` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 16 previous errors
 
diff --git a/tests/ui/reachable/expr_type.stderr b/tests/ui/reachable/expr_type.stderr
index 70536326fd8..008b867e230 100644
--- a/tests/ui/reachable/expr_type.stderr
+++ b/tests/ui/reachable/expr_type.stderr
@@ -12,6 +12,7 @@ note: the lint level is defined here
    |
 LL | #![deny(unreachable_code)]
    |         ^^^^^^^^^^^^^^^^
+   = note: this error originates in the macro `type_ascribe` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/return/return-impl-trait-bad.stderr b/tests/ui/return/return-impl-trait-bad.stderr
index a015b9f53af..6277c5feb20 100644
--- a/tests/ui/return/return-impl-trait-bad.stderr
+++ b/tests/ui/return/return-impl-trait-bad.stderr
@@ -10,6 +10,7 @@ LL |     "this should not suggest impl Trait"
    |
    = note: expected type parameter `T`
                    found reference `&'static str`
+   = note: the caller chooses a type for `T` which can be different from `&'static str`
 
 error[E0308]: mismatched types
   --> $DIR/return-impl-trait-bad.rs:9:5
@@ -23,6 +24,7 @@ LL |     "this will not suggest it, because that would probably be wrong"
    |
    = note: expected type parameter `T`
                    found reference `&'static str`
+   = note: the caller chooses a type for `T` which can be different from `&'static str`
 
 error[E0308]: mismatched types
   --> $DIR/return-impl-trait-bad.rs:17:5
@@ -37,6 +39,7 @@ LL |     "don't suggest this, because Option<T> places additional constraints"
    |
    = note: expected type parameter `T`
                    found reference `&'static str`
+   = note: the caller chooses a type for `T` which can be different from `&'static str`
 
 error[E0308]: mismatched types
   --> $DIR/return-impl-trait-bad.rs:28:5
@@ -53,6 +56,7 @@ LL |     "don't suggest this, because the generic param is used in the bound."
    |
    = note: expected type parameter `T`
                    found reference `&'static str`
+   = note: the caller chooses a type for `T` which can be different from `&'static str`
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/return/return-impl-trait.stderr b/tests/ui/return/return-impl-trait.stderr
index 707f014a16f..114ae0c2445 100644
--- a/tests/ui/return/return-impl-trait.stderr
+++ b/tests/ui/return/return-impl-trait.stderr
@@ -12,6 +12,7 @@ LL |     ()
    |
    = note: expected type parameter `T`
                    found unit type `()`
+   = note: the caller chooses a type for `T` which can be different from `()`
 
 error[E0308]: mismatched types
   --> $DIR/return-impl-trait.rs:23:5
@@ -28,6 +29,7 @@ LL |     ()
    |
    = note: expected type parameter `T`
                    found unit type `()`
+   = note: the caller chooses a type for `T` which can be different from `()`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/return/return-ty-mismatch-note.rs b/tests/ui/return/return-ty-mismatch-note.rs
new file mode 100644
index 00000000000..352bc2a1637
--- /dev/null
+++ b/tests/ui/return/return-ty-mismatch-note.rs
@@ -0,0 +1,21 @@
+// Checks existence of a note for "a caller chooses ty for ty param" upon return ty mismatch.
+
+fn f<T>() -> (T,) {
+    (0,) //~ ERROR mismatched types
+}
+
+fn g<U, V>() -> (U, V) {
+    (0, "foo")
+    //~^ ERROR mismatched types
+    //~| ERROR mismatched types
+}
+
+fn h() -> u8 {
+    0u8
+}
+
+fn main() {
+    f::<()>();
+    g::<(), ()>;
+    let _ = h();
+}
diff --git a/tests/ui/return/return-ty-mismatch-note.stderr b/tests/ui/return/return-ty-mismatch-note.stderr
new file mode 100644
index 00000000000..135903da5c2
--- /dev/null
+++ b/tests/ui/return/return-ty-mismatch-note.stderr
@@ -0,0 +1,36 @@
+error[E0308]: mismatched types
+  --> $DIR/return-ty-mismatch-note.rs:4:6
+   |
+LL | fn f<T>() -> (T,) {
+   |      - expected this type parameter
+LL |     (0,)
+   |      ^ expected type parameter `T`, found integer
+   |
+   = note: expected type parameter `T`
+                        found type `{integer}`
+
+error[E0308]: mismatched types
+  --> $DIR/return-ty-mismatch-note.rs:8:6
+   |
+LL | fn g<U, V>() -> (U, V) {
+   |      - expected this type parameter
+LL |     (0, "foo")
+   |      ^ expected type parameter `U`, found integer
+   |
+   = note: expected type parameter `U`
+                        found type `{integer}`
+
+error[E0308]: mismatched types
+  --> $DIR/return-ty-mismatch-note.rs:8:9
+   |
+LL | fn g<U, V>() -> (U, V) {
+   |         - expected this type parameter
+LL |     (0, "foo")
+   |         ^^^^^ expected type parameter `V`, found `&str`
+   |
+   = note: expected type parameter `V`
+                   found reference `&'static str`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.stderr
index ace2e7e46c4..12cc79f5961 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.stderr
@@ -4,5 +4,13 @@ error: `~const` can only be applied to `#[const_trait]` traits
 LL | const fn test() -> impl ~const Fn() {
    |                                ^^^^
 
-error: aborting due to 1 previous error
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-closure-parse-not-item.rs:7:32
+   |
+LL | const fn test() -> impl ~const Fn() {
+   |                                ^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.rs
index 7d817d09c7f..21197fcaa27 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.rs
@@ -1,7 +1,9 @@
 #![feature(const_trait_impl, effects)]
 
-const fn test() -> impl ~const Fn() { //~ ERROR `~const` can only be applied to `#[const_trait]` traits
-    //~^ ERROR cycle detected
+const fn test() -> impl ~const Fn() {
+    //~^ ERROR `~const` can only be applied to `#[const_trait]` traits
+    //~| ERROR `~const` can only be applied to `#[const_trait]` traits
+    //~| ERROR cycle detected
     const move || { //~ ERROR const closures are experimental
         let sl: &[u8] = b"foo";
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.stderr
index 0f6240cc03b..2f805110917 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.stderr
@@ -1,5 +1,5 @@
 error[E0658]: const closures are experimental
-  --> $DIR/ice-112822-expected-type-for-param.rs:5:5
+  --> $DIR/ice-112822-expected-type-for-param.rs:7:5
    |
 LL |     const move || {
    |     ^^^^^
@@ -14,8 +14,16 @@ error: `~const` can only be applied to `#[const_trait]` traits
 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
+   |
+LL | const fn test() -> impl ~const Fn() {
+   |                                ^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
 error[E0277]: can't compare `&u8` with `&u8`
-  --> $DIR/ice-112822-expected-type-for-param.rs:10:17
+  --> $DIR/ice-112822-expected-type-for-param.rs:12:17
    |
 LL |                 assert_eq!(first, &b'f');
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `&u8 == &u8`
@@ -54,7 +62,7 @@ LL | const fn test() -> impl ~const Fn() {
    |                    ^^^^^^^^^^^^^^^^
    = 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 4 previous errors
+error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0277, E0391, E0658.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs b/tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs
new file mode 100644
index 00000000000..a46a3afd734
--- /dev/null
+++ b/tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs
@@ -0,0 +1,18 @@
+// Tests that converting a closure to a function pointer works
+// The notable thing being tested here is that when the closure does not capture anything,
+// the call method from its Fn trait takes a ZST representing its environment. The compiler then
+// uses the assumption that the ZST is non-passed to reify this into a function pointer.
+//
+// This checks that the reified function pointer will have the expected alias set at its call-site.
+
+//@ needs-sanitizer-cfi
+// FIXME(#122848) Remove only-linux once OSX CFI binaries work
+//@ only-linux
+//@ compile-flags: --crate-type=bin -Cprefer-dynamic=off -Clto -Zsanitizer=cfi
+//@ compile-flags: -C target-feature=-crt-static -C codegen-units=1 -C opt-level=0
+//@ run-pass
+
+pub fn main() {
+    let f: &fn() = &((|| ()) as _);
+    f();
+}
diff --git a/tests/ui/specialization/broken-mir-drop-glue-107228.rs b/tests/ui/specialization/broken-mir-drop-glue-107228.rs
new file mode 100644
index 00000000000..5a6dbf9ffc7
--- /dev/null
+++ b/tests/ui/specialization/broken-mir-drop-glue-107228.rs
@@ -0,0 +1,28 @@
+// issue: rust-lang/rust#107228
+// ICE broken MIR in DropGlue
+//@ compile-flags: -Zvalidate-mir
+//@ check-pass
+
+#![feature(specialization)]
+#![crate_type="lib"]
+#![allow(incomplete_features)]
+
+pub(crate) trait SpecTrait {
+    type Assoc;
+}
+
+impl<C> SpecTrait for C {
+    default type Assoc = Vec<Self>;
+}
+
+pub(crate) struct AssocWrap<C: SpecTrait> {
+    _assoc: C::Assoc,
+}
+
+fn instantiate<C: SpecTrait>() -> AssocWrap<C> {
+    loop {}
+}
+
+pub fn main() {
+    instantiate::<()>();
+}
diff --git a/tests/ui/stable-mir-print/basic_function.rs b/tests/ui/stable-mir-print/basic_function.rs
index 9b27a56dab1..deefef63bdb 100644
--- a/tests/ui/stable-mir-print/basic_function.rs
+++ b/tests/ui/stable-mir-print/basic_function.rs
@@ -2,7 +2,7 @@
 //@ check-pass
 //@ only-x86_64
 
-fn foo(i:i32) -> i32 {
+fn foo(i: i32) -> i32 {
     i + 1
 }
 
@@ -12,4 +12,13 @@ fn bar(vec: &mut Vec<i32>) -> Vec<i32> {
     new_vec
 }
 
-fn main(){}
+pub fn demux(input: u8) -> u8 {
+    match input {
+        0 => 10,
+        1 => 6,
+        2 => 8,
+        _ => 0,
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/stable-mir-print/basic_function.stdout b/tests/ui/stable-mir-print/basic_function.stdout
index d9b33a4257c..3926c1048f5 100644
--- a/tests/ui/stable-mir-print/basic_function.stdout
+++ b/tests/ui/stable-mir-print/basic_function.stdout
@@ -1,234 +1,74 @@
 // WARNING: This is highly experimental output it's intended for stable-mir developers only.
 // If you find a bug or want to improve the output open a issue at https://github.com/rust-lang/project-stable-mir.
-fn foo(_0: i32) -> i32 {
-    let mut _0: (i32, bool);
+fn foo(_1: i32) -> i32 {
+    let mut _0: i32;
+    let mut _2: (i32, bool);
+    debug i => _1;
+    bb0: {
+        _2 = CheckedAdd(_1, 1_i32);
+        assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", _1, 1_i32) -> [success: bb1, unwind continue];
+    }
+    bb1: {
+        _0 = move (_2.0: i32);
+        return;
+    }
 }
+fn bar(_1: &mut Vec<i32>) -> Vec<i32> {
+    let mut _0: Vec<i32>;
+    let mut _2: Vec<i32>;
+    let mut _3: &Vec<i32>;
+    let  _4: ();
+    let mut _5: &mut Vec<i32>;
+    debug vec => _1;
+    debug new_vec => _2;
     bb0: {
-        _2 = 1 Add const 1_i32
-        assert(!move _2 bool),"attempt to compute `{} + {}`, which would overflow", 1, const 1_i32) -> [success: bb1, unwind continue]
+        _3 = &(*_1);
+        _2 = <Vec<i32> as Clone>::clone(move _3) -> [return: bb1, unwind continue];
     }
     bb1: {
-        _0 = move _2
-        return
+        _5 = &mut _2;
+        _4 = Vec::<i32>::push(move _5, 1_i32) -> [return: bb2, unwind: bb3];
+    }
+    bb2: {
+        _0 = move _2;
+        return;
+    }
+    bb3: {
+        drop(_2) -> [return: bb4, unwind terminate];
+    }
+    bb4: {
+        resume;
     }
-fn bar(_0: &mut Ty {
-    id: 10,
-    kind: RigidTy(
-        Adt(
-            AdtDef(
-                DefId {
-                    id: 3,
-                    name: "std::vec::Vec",
-                },
-            ),
-            GenericArgs(
-                [
-                    Type(
-                        Ty {
-                            id: 11,
-                            kind: Param(
-                                ParamTy {
-                                    index: 0,
-                                    name: "T",
-                                },
-                            ),
-                        },
-                    ),
-                    Type(
-                        Ty {
-                            id: 12,
-                            kind: Param(
-                                ParamTy {
-                                    index: 1,
-                                    name: "A",
-                                },
-                            ),
-                        },
-                    ),
-                ],
-            ),
-        ),
-    ),
-}) -> Ty {
-    id: 10,
-    kind: RigidTy(
-        Adt(
-            AdtDef(
-                DefId {
-                    id: 3,
-                    name: "std::vec::Vec",
-                },
-            ),
-            GenericArgs(
-                [
-                    Type(
-                        Ty {
-                            id: 11,
-                            kind: Param(
-                                ParamTy {
-                                    index: 0,
-                                    name: "T",
-                                },
-                            ),
-                        },
-                    ),
-                    Type(
-                        Ty {
-                            id: 12,
-                            kind: Param(
-                                ParamTy {
-                                    index: 1,
-                                    name: "A",
-                                },
-                            ),
-                        },
-                    ),
-                ],
-            ),
-        ),
-    ),
-} {
-    let mut _0: Ty {
-    id: 10,
-    kind: RigidTy(
-        Adt(
-            AdtDef(
-                DefId {
-                    id: 3,
-                    name: "std::vec::Vec",
-                },
-            ),
-            GenericArgs(
-                [
-                    Type(
-                        Ty {
-                            id: 11,
-                            kind: Param(
-                                ParamTy {
-                                    index: 0,
-                                    name: "T",
-                                },
-                            ),
-                        },
-                    ),
-                    Type(
-                        Ty {
-                            id: 12,
-                            kind: Param(
-                                ParamTy {
-                                    index: 1,
-                                    name: "A",
-                                },
-                            ),
-                        },
-                    ),
-                ],
-            ),
-        ),
-    ),
-};
-    let mut _1: &Ty {
-    id: 10,
-    kind: RigidTy(
-        Adt(
-            AdtDef(
-                DefId {
-                    id: 3,
-                    name: "std::vec::Vec",
-                },
-            ),
-            GenericArgs(
-                [
-                    Type(
-                        Ty {
-                            id: 11,
-                            kind: Param(
-                                ParamTy {
-                                    index: 0,
-                                    name: "T",
-                                },
-                            ),
-                        },
-                    ),
-                    Type(
-                        Ty {
-                            id: 12,
-                            kind: Param(
-                                ParamTy {
-                                    index: 1,
-                                    name: "A",
-                                },
-                            ),
-                        },
-                    ),
-                ],
-            ),
-        ),
-    ),
-};
-    let _2: ();
-    let mut _3: &mut Ty {
-    id: 10,
-    kind: RigidTy(
-        Adt(
-            AdtDef(
-                DefId {
-                    id: 3,
-                    name: "std::vec::Vec",
-                },
-            ),
-            GenericArgs(
-                [
-                    Type(
-                        Ty {
-                            id: 11,
-                            kind: Param(
-                                ParamTy {
-                                    index: 0,
-                                    name: "T",
-                                },
-                            ),
-                        },
-                    ),
-                    Type(
-                        Ty {
-                            id: 12,
-                            kind: Param(
-                                ParamTy {
-                                    index: 1,
-                                    name: "A",
-                                },
-                            ),
-                        },
-                    ),
-                ],
-            ),
-        ),
-    ),
-};
 }
+fn demux(_1: u8) -> u8 {
+    let mut _0: u8;
+    debug input => _1;
     bb0: {
-        _3 = refShared1
-        _2 = const <Vec<i32> as Clone>::clone(move _3) -> [return: bb1, unwind continue]
+        switchInt(_1) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb1];
     }
     bb1: {
-        _5 = refMut {
-    kind: TwoPhaseBorrow,
-}2
-        _4 = const Vec::<i32>::push(move _5, const 1_i32) -> [return: bb2, unwind: bb3]
+        _0 = 0_u8;
+        goto -> bb5;
     }
     bb2: {
-        _0 = move _2
-        return
+        _0 = 10_u8;
+        goto -> bb5;
     }
     bb3: {
-        drop(_2) -> [return: bb4, unwind terminate]
+        _0 = 6_u8;
+        goto -> bb5;
     }
     bb4: {
-        resume
+        _0 = 8_u8;
+        goto -> bb5;
+    }
+    bb5: {
+        return;
     }
-fn main() -> () {
 }
+fn main() -> () {
+    let mut _0: ();
     bb0: {
-        return
+        return;
     }
+}
diff --git a/tests/ui/str/str-as-char.stderr b/tests/ui/str/str-as-char.stderr
index 44ec079e929..0638d371c17 100644
--- a/tests/ui/str/str-as-char.stderr
+++ b/tests/ui/str/str-as-char.stderr
@@ -4,10 +4,10 @@ error: character literal may only contain one codepoint
 LL |     println!('●●');
    |              ^^^^
    |
-help: if you meant to write a `str` literal, use double quotes
+help: if you meant to write a string literal, use double quotes
    |
 LL |     println!("●●");
-   |              ~~~~
+   |              ~  ~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/suggestions/clone-on-unconstrained-borrowed-type-param.stderr b/tests/ui/suggestions/clone-on-unconstrained-borrowed-type-param.stderr
index afbb9c32d51..2c4be26a82b 100644
--- a/tests/ui/suggestions/clone-on-unconstrained-borrowed-type-param.stderr
+++ b/tests/ui/suggestions/clone-on-unconstrained-borrowed-type-param.stderr
@@ -10,6 +10,7 @@ LL |     t.clone()
    |
    = note: expected type parameter `_`
                    found reference `&_`
+   = note: the caller chooses a type for `T` which can be different from `&T`
 note: `T` does not implement `Clone`, so `&T` was cloned instead
   --> $DIR/clone-on-unconstrained-borrowed-type-param.rs:3:5
    |
diff --git a/tests/ui/suggestions/issue-85347.rs b/tests/ui/suggestions/issue-85347.rs
index 04d4c47d8e5..d14cf07d915 100644
--- a/tests/ui/suggestions/issue-85347.rs
+++ b/tests/ui/suggestions/issue-85347.rs
@@ -4,6 +4,9 @@ trait Foo {
     //~^ ERROR associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
     //~| ERROR associated type bindings are not allowed here
     //~| HELP add missing
+    //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
+    //~| ERROR associated type bindings are not allowed here
+    //~| HELP add missing
 }
 
 fn main() {}
diff --git a/tests/ui/suggestions/issue-85347.stderr b/tests/ui/suggestions/issue-85347.stderr
index f330b3c1fad..45f87e539b4 100644
--- a/tests/ui/suggestions/issue-85347.stderr
+++ b/tests/ui/suggestions/issue-85347.stderr
@@ -20,7 +20,32 @@ error[E0229]: associated type bindings are not allowed here
 LL |     type Bar<'a>: Deref<Target = <Self>::Bar<Target = Self>>;
    |                                              ^^^^^^^^^^^^^ associated type not allowed here
 
-error: aborting due to 2 previous errors
+error[E0107]: associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
+  --> $DIR/issue-85347.rs:3:42
+   |
+LL |     type Bar<'a>: Deref<Target = <Self>::Bar<Target = Self>>;
+   |                                          ^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-85347.rs:3:10
+   |
+LL |     type Bar<'a>: Deref<Target = <Self>::Bar<Target = Self>>;
+   |          ^^^ --
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: add missing lifetime argument
+   |
+LL |     type Bar<'a>: Deref<Target = <Self>::Bar<'a, Target = Self>>;
+   |                                              +++
+
+error[E0229]: associated type bindings are not allowed here
+  --> $DIR/issue-85347.rs:3:46
+   |
+LL |     type Bar<'a>: Deref<Target = <Self>::Bar<Target = Self>>;
+   |                                              ^^^^^^^^^^^^^ associated type not allowed here
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0107, E0229.
 For more information about an error, try `rustc --explain E0107`.
diff --git a/tests/ui/suggestions/issue-86667.rs b/tests/ui/suggestions/issue-86667.rs
index 8c18a879238..1f37e9a5f6d 100644
--- a/tests/ui/suggestions/issue-86667.rs
+++ b/tests/ui/suggestions/issue-86667.rs
@@ -6,13 +6,11 @@
 async fn a(s1: &str, s2: &str) -> &str {
     //~^ ERROR: missing lifetime specifier [E0106]
     s1
-    //~^ ERROR: lifetime may not live long enough
 }
 
 fn b(s1: &str, s2: &str) -> &str {
     //~^ ERROR: missing lifetime specifier [E0106]
     s1
-    //~^ ERROR lifetime may not live long enough
 }
 
 fn main() {}
diff --git a/tests/ui/suggestions/issue-86667.stderr b/tests/ui/suggestions/issue-86667.stderr
index e3d673ff233..14dbbfffb0e 100644
--- a/tests/ui/suggestions/issue-86667.stderr
+++ b/tests/ui/suggestions/issue-86667.stderr
@@ -11,7 +11,7 @@ LL | async fn a<'a>(s1: &'a str, s2: &'a str) -> &'a str {
    |           ++++      ++           ++          ++
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/issue-86667.rs:12:29
+  --> $DIR/issue-86667.rs:11:29
    |
 LL | fn b(s1: &str, s2: &str) -> &str {
    |          ----      ----     ^ expected named lifetime parameter
@@ -22,24 +22,6 @@ help: consider introducing a named lifetime parameter
 LL | fn b<'a>(s1: &'a str, s2: &'a str) -> &'a str {
    |     ++++      ++           ++          ++
 
-error: lifetime may not live long enough
-  --> $DIR/issue-86667.rs:8:5
-   |
-LL | async fn a(s1: &str, s2: &str) -> &str {
-   |                - let's call the lifetime of this reference `'1`
-LL |
-LL |     s1
-   |     ^^ returning this value requires that `'1` must outlive `'static`
-
-error: lifetime may not live long enough
-  --> $DIR/issue-86667.rs:14:5
-   |
-LL | fn b(s1: &str, s2: &str) -> &str {
-   |          - let's call the lifetime of this reference `'1`
-LL |
-LL |     s1
-   |     ^^ returning this value requires that `'1` must outlive `'static`
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0106`.
diff --git a/tests/ui/suggestions/lifetimes/explicit-lifetime-suggestion-in-proper-span-issue-121267.rs b/tests/ui/suggestions/lifetimes/explicit-lifetime-suggestion-in-proper-span-issue-121267.rs
new file mode 100644
index 00000000000..34afd363129
--- /dev/null
+++ b/tests/ui/suggestions/lifetimes/explicit-lifetime-suggestion-in-proper-span-issue-121267.rs
@@ -0,0 +1,12 @@
+fn main() {}
+
+fn foo(_src: &crate::Foo) -> Option<i32> {
+    todo!()
+}
+fn bar(src: &crate::Foo) -> impl Iterator<Item = i32> {
+    [0].into_iter()
+ //~^ ERROR hidden type for `impl Iterator<Item = i32>` captures lifetime that does not appear in bounds
+        .filter_map(|_| foo(src))
+}
+
+struct Foo<'a>(&'a str);
diff --git a/tests/ui/suggestions/lifetimes/explicit-lifetime-suggestion-in-proper-span-issue-121267.stderr b/tests/ui/suggestions/lifetimes/explicit-lifetime-suggestion-in-proper-span-issue-121267.stderr
new file mode 100644
index 00000000000..aeeec3aca34
--- /dev/null
+++ b/tests/ui/suggestions/lifetimes/explicit-lifetime-suggestion-in-proper-span-issue-121267.stderr
@@ -0,0 +1,20 @@
+error[E0700]: hidden type for `impl Iterator<Item = i32>` captures lifetime that does not appear in bounds
+  --> $DIR/explicit-lifetime-suggestion-in-proper-span-issue-121267.rs:7:5
+   |
+LL |   fn bar(src: &crate::Foo) -> impl Iterator<Item = i32> {
+   |                ----------     ------------------------- opaque type defined here
+   |                |
+   |                hidden type `FilterMap<std::slice::Iter<'static, i32>, {closure@$DIR/explicit-lifetime-suggestion-in-proper-span-issue-121267.rs:9:21: 9:24}>` captures the anonymous lifetime defined here
+LL | /     [0].into_iter()
+LL | |
+LL | |         .filter_map(|_| foo(src))
+   | |_________________________________^
+   |
+help: to declare that `impl Iterator<Item = i32>` captures `'_`, you can introduce a named lifetime parameter `'a`
+   |
+LL | fn bar<'a>(src: &'a crate::Foo<'a>) -> impl Iterator<Item = i32> + 'a  {
+   |       ++++       ++           ++++                               ++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0700`.
diff --git a/tests/ui/suggestions/missing-lifetime-specifier.rs b/tests/ui/suggestions/missing-lifetime-specifier.rs
index 3fa7f75f862..cd7fa0c1d85 100644
--- a/tests/ui/suggestions/missing-lifetime-specifier.rs
+++ b/tests/ui/suggestions/missing-lifetime-specifier.rs
@@ -20,31 +20,21 @@ pub union Qux<'t, 'k, I> {
 trait Tar<'t, 'k, I> {}
 
 thread_local! {
-    //~^ ERROR lifetime may not live long enough
-    //~| ERROR lifetime may not live long enough
     static a: RefCell<HashMap<i32, Vec<Vec<Foo>>>> = RefCell::new(HashMap::new());
       //~^ ERROR missing lifetime specifiers
       //~| ERROR missing lifetime specifiers
 }
 thread_local! {
-    //~^ ERROR lifetime may not live long enough
-    //~| ERROR lifetime may not live long enough
-    //~| ERROR lifetime may not live long enough
     static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
       //~^ ERROR missing lifetime specifiers
       //~| ERROR missing lifetime specifiers
 }
 thread_local! {
-    //~^ ERROR lifetime may not live long enough
-    //~| ERROR lifetime may not live long enough
     static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new());
     //~^ ERROR missing lifetime specifiers
     //~| ERROR missing lifetime specifiers
 }
 thread_local! {
-    //~^ ERROR lifetime may not live long enough
-    //~| ERROR lifetime may not live long enough
-    //~| ERROR lifetime may not live long enough
     static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
     //~^ ERROR missing lifetime specifiers
     //~| ERROR missing lifetime specifiers
diff --git a/tests/ui/suggestions/missing-lifetime-specifier.stderr b/tests/ui/suggestions/missing-lifetime-specifier.stderr
index 62eca162148..2b85cfde7b6 100644
--- a/tests/ui/suggestions/missing-lifetime-specifier.stderr
+++ b/tests/ui/suggestions/missing-lifetime-specifier.stderr
@@ -1,5 +1,5 @@
 error[E0106]: missing lifetime specifiers
-  --> $DIR/missing-lifetime-specifier.rs:25:44
+  --> $DIR/missing-lifetime-specifier.rs:23:44
    |
 LL |     static a: RefCell<HashMap<i32, Vec<Vec<Foo>>>> = RefCell::new(HashMap::new());
    |                                            ^^^ expected 2 lifetime parameters
@@ -11,11 +11,9 @@ LL |     static a: RefCell<HashMap<i32, Vec<Vec<Foo<'static, 'static>>>>> = RefC
    |                                               ++++++++++++++++++
 
 error[E0106]: missing lifetime specifiers
-  --> $DIR/missing-lifetime-specifier.rs:25:44
+  --> $DIR/missing-lifetime-specifier.rs:23:44
    |
 LL | / thread_local! {
-LL | |
-LL | |
 LL | |     static a: RefCell<HashMap<i32, Vec<Vec<Foo>>>> = RefCell::new(HashMap::new());
    | |                                            ^^^ expected 2 lifetime parameters
 LL | |
@@ -26,7 +24,7 @@ LL | | }
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from
 
 error[E0106]: missing lifetime specifiers
-  --> $DIR/missing-lifetime-specifier.rs:33:44
+  --> $DIR/missing-lifetime-specifier.rs:28:44
    |
 LL |     static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
    |                                            ^^^^ expected 2 lifetime parameters
@@ -40,12 +38,9 @@ LL |     static b: RefCell<HashMap<i32, Vec<Vec<&'static Bar<'static, 'static>>>
    |                                             +++++++    ++++++++++++++++++
 
 error[E0106]: missing lifetime specifiers
-  --> $DIR/missing-lifetime-specifier.rs:33:44
+  --> $DIR/missing-lifetime-specifier.rs:28:44
    |
 LL | / thread_local! {
-LL | |
-LL | |
-LL | |
 LL | |     static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
    | |                                            ^^^^ expected 2 lifetime parameters
    | |                                            |
@@ -58,7 +53,7 @@ LL | | }
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from
 
 error[E0106]: missing lifetime specifiers
-  --> $DIR/missing-lifetime-specifier.rs:40:47
+  --> $DIR/missing-lifetime-specifier.rs:33:47
    |
 LL |     static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new());
    |                                               ^ expected 2 lifetime parameters
@@ -70,11 +65,9 @@ LL |     static c: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> =
    |                                                +++++++++++++++++
 
 error[E0106]: missing lifetime specifiers
-  --> $DIR/missing-lifetime-specifier.rs:40:47
+  --> $DIR/missing-lifetime-specifier.rs:33:47
    |
 LL | / thread_local! {
-LL | |
-LL | |
 LL | |     static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new());
    | |                                               ^ expected 2 lifetime parameters
 LL | |
@@ -85,7 +78,7 @@ LL | | }
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from
 
 error[E0106]: missing lifetime specifiers
-  --> $DIR/missing-lifetime-specifier.rs:48:44
+  --> $DIR/missing-lifetime-specifier.rs:38:44
    |
 LL |     static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
    |                                            ^   ^ expected 2 lifetime parameters
@@ -99,12 +92,9 @@ LL |     static d: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, 'static, i
    |                                             +++++++     +++++++++++++++++
 
 error[E0106]: missing lifetime specifiers
-  --> $DIR/missing-lifetime-specifier.rs:48:44
+  --> $DIR/missing-lifetime-specifier.rs:38:44
    |
 LL | / thread_local! {
-LL | |
-LL | |
-LL | |
 LL | |     static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
    | |                                            ^   ^ expected 2 lifetime parameters
    | |                                            |
@@ -117,7 +107,7 @@ LL | | }
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/missing-lifetime-specifier.rs:58:44
+  --> $DIR/missing-lifetime-specifier.rs:48:44
    |
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                            ^ expected named lifetime parameter
@@ -129,7 +119,7 @@ LL |     static f: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, i32>>>>> =
    |                                             +++++++
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/missing-lifetime-specifier.rs:58:44
+  --> $DIR/missing-lifetime-specifier.rs:48:44
    |
 LL | / thread_local! {
 LL | |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
@@ -143,7 +133,7 @@ LL | | }
    = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from
 
 error[E0107]: union takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/missing-lifetime-specifier.rs:54:44
+  --> $DIR/missing-lifetime-specifier.rs:44:44
    |
 LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                            ^^^ ------- supplied 1 lifetime argument
@@ -161,7 +151,7 @@ LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> =
    |                                                       +++++++++
 
 error[E0107]: trait takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/missing-lifetime-specifier.rs:58:45
+  --> $DIR/missing-lifetime-specifier.rs:48:45
    |
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                             ^^^ ------- supplied 1 lifetime argument
@@ -178,199 +168,7 @@ help: add missing lifetime argument
 LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                                        +++++++++
 
-error: lifetime may not live long enough
-  --> $DIR/missing-lifetime-specifier.rs:22:1
-   |
-LL | / thread_local! {
-LL | |
-LL | |
-LL | |     static a: RefCell<HashMap<i32, Vec<Vec<Foo>>>> = RefCell::new(HashMap::new());
-LL | |
-LL | |
-LL | | }
-   | | ^
-   | | |
-   | |_has type `Option<&mut Option<RefCell<HashMap<i32, Vec<Vec<Foo<'1, '_>>>>>>>`
-   |   returning this value requires that `'1` must outlive `'static`
-   |
-   = note: this error originates in the macro `$crate::thread::local_impl::thread_local_inner` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: lifetime may not live long enough
-  --> $DIR/missing-lifetime-specifier.rs:22:1
-   |
-LL | / thread_local! {
-LL | |
-LL | |
-LL | |     static a: RefCell<HashMap<i32, Vec<Vec<Foo>>>> = RefCell::new(HashMap::new());
-LL | |
-LL | |
-LL | | }
-   | | ^
-   | | |
-   | |_has type `Option<&mut Option<RefCell<HashMap<i32, Vec<Vec<Foo<'_, '2>>>>>>>`
-   |   returning this value requires that `'2` must outlive `'static`
-   |
-   = note: this error originates in the macro `$crate::thread::local_impl::thread_local_inner` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: lifetime may not live long enough
-  --> $DIR/missing-lifetime-specifier.rs:29:1
-   |
-LL | / thread_local! {
-LL | |
-LL | |
-LL | |
-LL | |     static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
-   | |                                            - let's call the lifetime of this reference `'1`
-LL | |
-LL | |
-LL | | }
-   | |_^ returning this value requires that `'1` must outlive `'static`
-   |
-   = note: this error originates in the macro `$crate::thread::local_impl::thread_local_inner` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: to declare that the trait object captures data from argument `init`, you can add an explicit `'_` lifetime bound
-   |
-LL |     static b: RefCell<HashMap<i32, Vec<Vec<&Bar + '_>>>> = RefCell::new(HashMap::new());
-   |                                                 ++++
-
-error: lifetime may not live long enough
-  --> $DIR/missing-lifetime-specifier.rs:29:1
-   |
-LL | / thread_local! {
-LL | |
-LL | |
-LL | |
-...  |
-LL | |
-LL | | }
-   | | ^
-   | | |
-   | |_has type `Option<&mut Option<RefCell<HashMap<i32, Vec<Vec<&dyn Bar<'2, '_>>>>>>>`
-   |   returning this value requires that `'2` must outlive `'static`
-   |
-   = note: this error originates in the macro `$crate::thread::local_impl::thread_local_inner` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: to declare that the trait object captures data from argument `init`, you can add an explicit `'_` lifetime bound
-   |
-LL |     static b: RefCell<HashMap<i32, Vec<Vec<&Bar + '_>>>> = RefCell::new(HashMap::new());
-   |                                                 ++++
-
-error: lifetime may not live long enough
-  --> $DIR/missing-lifetime-specifier.rs:29:1
-   |
-LL | / thread_local! {
-LL | |
-LL | |
-LL | |
-...  |
-LL | |
-LL | | }
-   | | ^
-   | | |
-   | |_has type `Option<&mut Option<RefCell<HashMap<i32, Vec<Vec<&dyn Bar<'_, '3>>>>>>>`
-   |   returning this value requires that `'3` must outlive `'static`
-   |
-   = note: this error originates in the macro `$crate::thread::local_impl::thread_local_inner` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: to declare that the trait object captures data from argument `init`, you can add an explicit `'_` lifetime bound
-   |
-LL |     static b: RefCell<HashMap<i32, Vec<Vec<&Bar + '_>>>> = RefCell::new(HashMap::new());
-   |                                                 ++++
-
-error: lifetime may not live long enough
-  --> $DIR/missing-lifetime-specifier.rs:37:1
-   |
-LL | / thread_local! {
-LL | |
-LL | |
-LL | |     static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new());
-LL | |
-LL | |
-LL | | }
-   | | ^
-   | | |
-   | |_has type `Option<&mut Option<RefCell<HashMap<i32, Vec<Vec<Qux<'1, '_, i32>>>>>>>`
-   |   returning this value requires that `'1` must outlive `'static`
-   |
-   = note: this error originates in the macro `$crate::thread::local_impl::thread_local_inner` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: lifetime may not live long enough
-  --> $DIR/missing-lifetime-specifier.rs:37:1
-   |
-LL | / thread_local! {
-LL | |
-LL | |
-LL | |     static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new());
-LL | |
-LL | |
-LL | | }
-   | | ^
-   | | |
-   | |_has type `Option<&mut Option<RefCell<HashMap<i32, Vec<Vec<Qux<'_, '2, i32>>>>>>>`
-   |   returning this value requires that `'2` must outlive `'static`
-   |
-   = note: this error originates in the macro `$crate::thread::local_impl::thread_local_inner` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: lifetime may not live long enough
-  --> $DIR/missing-lifetime-specifier.rs:44:1
-   |
-LL | / thread_local! {
-LL | |
-LL | |
-LL | |
-LL | |     static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
-   | |                                            - let's call the lifetime of this reference `'1`
-LL | |
-LL | |
-LL | | }
-   | |_^ returning this value requires that `'1` must outlive `'static`
-   |
-   = note: this error originates in the macro `$crate::thread::local_impl::thread_local_inner` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: to declare that the trait object captures data from argument `init`, you can add an explicit `'_` lifetime bound
-   |
-LL |     static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32> + '_>>>> = RefCell::new(HashMap::new());
-   |                                                      ++++
-
-error: lifetime may not live long enough
-  --> $DIR/missing-lifetime-specifier.rs:44:1
-   |
-LL | / thread_local! {
-LL | |
-LL | |
-LL | |
-...  |
-LL | |
-LL | | }
-   | | ^
-   | | |
-   | |_has type `Option<&mut Option<RefCell<HashMap<i32, Vec<Vec<&dyn Tar<'2, '_, i32>>>>>>>`
-   |   returning this value requires that `'2` must outlive `'static`
-   |
-   = note: this error originates in the macro `$crate::thread::local_impl::thread_local_inner` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: to declare that the trait object captures data from argument `init`, you can add an explicit `'_` lifetime bound
-   |
-LL |     static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32> + '_>>>> = RefCell::new(HashMap::new());
-   |                                                      ++++
-
-error: lifetime may not live long enough
-  --> $DIR/missing-lifetime-specifier.rs:44:1
-   |
-LL | / thread_local! {
-LL | |
-LL | |
-LL | |
-...  |
-LL | |
-LL | | }
-   | | ^
-   | | |
-   | |_has type `Option<&mut Option<RefCell<HashMap<i32, Vec<Vec<&dyn Tar<'_, '3, i32>>>>>>>`
-   |   returning this value requires that `'3` must outlive `'static`
-   |
-   = note: this error originates in the macro `$crate::thread::local_impl::thread_local_inner` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: to declare that the trait object captures data from argument `init`, you can add an explicit `'_` lifetime bound
-   |
-LL |     static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32> + '_>>>> = RefCell::new(HashMap::new());
-   |                                                      ++++
-
-error: aborting due to 22 previous errors
+error: aborting due to 12 previous errors
 
 Some errors have detailed explanations: E0106, E0107.
 For more information about an error, try `rustc --explain E0106`.
diff --git a/tests/ui/suggestions/types/into-inference-needs-type.rs b/tests/ui/suggestions/types/into-inference-needs-type.rs
new file mode 100644
index 00000000000..4c8b6ec2113
--- /dev/null
+++ b/tests/ui/suggestions/types/into-inference-needs-type.rs
@@ -0,0 +1,15 @@
+#[derive(Debug)]
+enum MyError {
+    MainError
+}
+
+fn main() -> Result<(), MyError> {
+    let vec = vec!["one", "two", "three"];
+    let list = vec
+        .iter()
+        .map(|s| s.strip_prefix("t"))
+        .filter_map(Option::Some)
+        .into()?; //~ ERROR type annotations needed
+
+    return Ok(());
+}
diff --git a/tests/ui/suggestions/types/into-inference-needs-type.stderr b/tests/ui/suggestions/types/into-inference-needs-type.stderr
new file mode 100644
index 00000000000..dd688f90289
--- /dev/null
+++ b/tests/ui/suggestions/types/into-inference-needs-type.stderr
@@ -0,0 +1,19 @@
+error[E0283]: type annotations needed
+  --> $DIR/into-inference-needs-type.rs:12:10
+   |
+LL |         .into()?;
+   |          ^^^^
+   |
+   = note: cannot satisfy `_: From<FilterMap<Map<std::slice::Iter<'_, &str>, {closure@$DIR/into-inference-needs-type.rs:10:14: 10:17}>, fn(Option<&str>) -> Option<Option<&str>> {Option::<Option<&str>>::Some}>>`
+   = note: required for `FilterMap<Map<std::slice::Iter<'_, &str>, {closure@$DIR/into-inference-needs-type.rs:10:14: 10:17}>, fn(Option<&str>) -> Option<Option<&str>> {Option::<Option<&str>>::Some}>` to implement `Into<_>`
+help: try using a fully qualified path to specify the expected types
+   |
+LL ~     let list = <FilterMap<Map<std::slice::Iter<'_, &str>, _>, _> as Into<T>>::into(vec
+LL |         .iter()
+LL |         .map(|s| s.strip_prefix("t"))
+LL ~         .filter_map(Option::Some))?;
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/trait-bounds/restrict-assoc-type-of-generic-bound.stderr b/tests/ui/trait-bounds/restrict-assoc-type-of-generic-bound.stderr
index 5024ad21892..7aa32557af2 100644
--- a/tests/ui/trait-bounds/restrict-assoc-type-of-generic-bound.stderr
+++ b/tests/ui/trait-bounds/restrict-assoc-type-of-generic-bound.stderr
@@ -10,6 +10,7 @@ LL |     return a.bar();
    |
    = note: expected type parameter `B`
              found associated type `<A as MyTrait>::T`
+   = note: the caller chooses a type for `B` which can be different from `<A as MyTrait>::T`
 help: consider further restricting this bound
    |
 LL | pub fn foo<A: MyTrait<T = B>, B>(a: A) -> B {
diff --git a/tests/ui/traits/alias/self-in-generics.rs b/tests/ui/traits/alias/self-in-generics.rs
index dcb33b7a90a..433b741532d 100644
--- a/tests/ui/traits/alias/self-in-generics.rs
+++ b/tests/ui/traits/alias/self-in-generics.rs
@@ -1,4 +1,4 @@
-// astconv uses `FreshTy(0)` as a dummy `Self` type when instanciating trait objects.
+// HIR ty lowering uses `FreshTy(0)` as a dummy `Self` type when instanciating trait objects.
 // This `FreshTy(0)` can leak into substs, causing ICEs in several places.
 
 #![feature(trait_alias)]
diff --git a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs
index 7d71fcdd158..cab484a120c 100644
--- a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs
+++ b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs
@@ -20,6 +20,7 @@ impl<T, S> Trait<T, S> for () {}
 fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), i32> {
 //~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied
 //~| ERROR trait takes 1 generic argument but 2 generic arguments were supplied
+//~| ERROR trait takes 1 generic argument but 2 generic arguments were supplied
 //~| ERROR type annotations needed
     3
 }
diff --git a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr
index f4ede4190fc..99e81a9039e 100644
--- a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr
+++ b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr
@@ -54,6 +54,23 @@ help: replace the generic bound with the associated type
 LL | fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), Assoc = i32> {
    |                                                        +++++++
 
+error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:20:46
+   |
+LL | fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), i32> {
+   |                                              ^^^^^ expected 1 generic argument
+   |
+note: trait defined here, with 1 generic parameter: `T`
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11
+   |
+LL | pub trait Trait<T> {
+   |           ^^^^^ -
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: replace the generic bound with the associated type
+   |
+LL | fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), Assoc = i32> {
+   |                                                        +++++++
+
 error[E0282]: type annotations needed
   --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:20:41
    |
@@ -61,7 +78,7 @@ LL | fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), i32> {
    |                                         ^^^^^^^^^^^^^^^^^^^ cannot infer type
 
 error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
-  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:27:18
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:28:18
    |
 LL | struct Struct<T: Trait<u32, String>> {
    |                  ^^^^^ expected 1 generic argument
@@ -77,7 +94,7 @@ LL | struct Struct<T: Trait<u32, Assoc = String>> {
    |                             +++++++
 
 error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
-  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:32:23
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:33:23
    |
 LL | trait AnotherTrait<T: Trait<T, i32>> {}
    |                       ^^^^^ expected 1 generic argument
@@ -93,7 +110,7 @@ LL | trait AnotherTrait<T: Trait<T, Assoc = i32>> {}
    |                                +++++++
 
 error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied
-  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:35:9
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:36:9
    |
 LL | impl<T: Trait<u32, String>> Struct<T> {}
    |         ^^^^^ expected 1 generic argument
@@ -109,7 +126,7 @@ LL | impl<T: Trait<u32, Assoc = String>> Struct<T> {}
    |                    +++++++
 
 error[E0107]: struct takes 1 generic argument but 2 generic arguments were supplied
-  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:41:58
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:42:58
    |
 LL | impl<T: Trait<u32, Assoc=String>, U> YetAnotherTrait for Struct<T, U> {}
    |                                                          ^^^^^^    - help: remove this generic argument
@@ -117,12 +134,12 @@ LL | impl<T: Trait<u32, Assoc=String>, U> YetAnotherTrait for Struct<T, U> {}
    |                                                          expected 1 generic argument
    |
 note: struct defined here, with 1 generic parameter: `T`
-  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:27:8
+  --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:28:8
    |
 LL | struct Struct<T: Trait<u32, String>> {
    |        ^^^^^^ -
 
-error: aborting due to 10 previous errors
+error: aborting due to 11 previous errors
 
 Some errors have detailed explanations: E0107, E0207, E0282.
 For more information about an error, try `rustc --explain E0107`.
diff --git a/tests/ui/traits/impl-of-supertrait-has-wrong-lifetime-parameters.stderr b/tests/ui/traits/impl-of-supertrait-has-wrong-lifetime-parameters.stderr
index 092776edea7..8bf8536c74e 100644
--- a/tests/ui/traits/impl-of-supertrait-has-wrong-lifetime-parameters.stderr
+++ b/tests/ui/traits/impl-of-supertrait-has-wrong-lifetime-parameters.stderr
@@ -4,16 +4,16 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'b` d
 LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> {
    |                            ^^^^^^^^^
    |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
-  --> $DIR/impl-of-supertrait-has-wrong-lifetime-parameters.rs:24:6
-   |
-LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> {
-   |      ^^
-note: ...but the lifetime must also be valid for the lifetime `'b` as defined here...
+note: first, the lifetime cannot outlive the lifetime `'b` as defined here...
   --> $DIR/impl-of-supertrait-has-wrong-lifetime-parameters.rs:24:9
    |
 LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> {
    |         ^^
+note: ...but the lifetime must also be valid for the lifetime `'a` as defined here...
+  --> $DIR/impl-of-supertrait-has-wrong-lifetime-parameters.rs:24:6
+   |
+LL | impl<'a,'b> T2<'a, 'b> for S<'a, 'b> {
+   |      ^^
 note: ...so that the types are compatible
   --> $DIR/impl-of-supertrait-has-wrong-lifetime-parameters.rs:24:28
    |
diff --git a/tests/ui/traits/matching-lifetimes.stderr b/tests/ui/traits/matching-lifetimes.stderr
index f8119ed415d..8a802d57f5c 100644
--- a/tests/ui/traits/matching-lifetimes.stderr
+++ b/tests/ui/traits/matching-lifetimes.stderr
@@ -6,16 +6,16 @@ LL |     fn foo(x: Foo<'b,'a>) {
    |
    = note: expected signature `fn(Foo<'a, 'b>)`
               found signature `fn(Foo<'b, 'a>)`
-note: the lifetime `'b` as defined here...
-  --> $DIR/matching-lifetimes.rs:13:9
-   |
-LL | impl<'a,'b> Tr for Foo<'a,'b> {
-   |         ^^
-note: ...does not necessarily outlive the lifetime `'a` as defined here
+note: the lifetime `'a` as defined here...
   --> $DIR/matching-lifetimes.rs:13:6
    |
 LL | impl<'a,'b> Tr for Foo<'a,'b> {
    |      ^^
+note: ...does not necessarily outlive the lifetime `'b` as defined here
+  --> $DIR/matching-lifetimes.rs:13:9
+   |
+LL | impl<'a,'b> Tr for Foo<'a,'b> {
+   |         ^^
 
 error[E0308]: method not compatible with trait
   --> $DIR/matching-lifetimes.rs:14:5
@@ -25,16 +25,16 @@ LL |     fn foo(x: Foo<'b,'a>) {
    |
    = note: expected signature `fn(Foo<'a, 'b>)`
               found signature `fn(Foo<'b, 'a>)`
-note: the lifetime `'a` as defined here...
-  --> $DIR/matching-lifetimes.rs:13:6
-   |
-LL | impl<'a,'b> Tr for Foo<'a,'b> {
-   |      ^^
-note: ...does not necessarily outlive the lifetime `'b` as defined here
+note: the lifetime `'b` as defined here...
   --> $DIR/matching-lifetimes.rs:13:9
    |
 LL | impl<'a,'b> Tr for Foo<'a,'b> {
    |         ^^
+note: ...does not necessarily outlive the lifetime `'a` as defined here
+  --> $DIR/matching-lifetimes.rs:13:6
+   |
+LL | impl<'a,'b> Tr for Foo<'a,'b> {
+   |      ^^
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/traits/next-solver/dont-canonicalize-re-error.rs b/tests/ui/traits/next-solver/dont-canonicalize-re-error.rs
new file mode 100644
index 00000000000..57f814bc81e
--- /dev/null
+++ b/tests/ui/traits/next-solver/dont-canonicalize-re-error.rs
@@ -0,0 +1,28 @@
+//@ compile-flags: -Znext-solver
+
+trait Tr<'a> {}
+
+// Fulfillment in the new solver relies on an invariant to hold: Either
+// `has_changed` is true, or computing a goal's certainty is idempotent.
+// This isn't true for `ReError`, which we used to pass through in the
+// canonicalizer even on input mode, which can cause a goal to go from
+// ambig => pass, but we don't consider `has_changed` when the response
+// only contains region constraints (since we usually uniquify regions).
+//
+//   In this test:
+// Implicit negative coherence tries to prove `W<?0>: Constrain<'?1>`,
+// which will then match with the impl below. This constrains `'?1` to
+// `ReError`, but still bails w/ ambiguity bc we can't prove `?0: Sized`.
+// Then, when we recompute the goal `W<?0>: Constrain<'error>`, when
+// collecting ambiguities and overflows, we end up assembling a default
+// error candidate w/o ambiguity, which causes the goal to pass, and ICE.
+impl<'a, A: ?Sized> Tr<'a> for W<A> {}
+struct W<A: ?Sized>(A);
+impl<'a, A: ?Sized> Tr<'a> for A where A: Constrain<'a> {}
+//~^ ERROR conflicting implementations of trait `Tr<'_>` for type `W<_>`
+
+trait Constrain<'a> {}
+impl<A: Sized> Constrain<'missing> for W<A> {}
+//~^ ERROR use of undeclared lifetime name `'missing`
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/dont-canonicalize-re-error.stderr b/tests/ui/traits/next-solver/dont-canonicalize-re-error.stderr
new file mode 100644
index 00000000000..cf85c52fb42
--- /dev/null
+++ b/tests/ui/traits/next-solver/dont-canonicalize-re-error.stderr
@@ -0,0 +1,21 @@
+error[E0261]: use of undeclared lifetime name `'missing`
+  --> $DIR/dont-canonicalize-re-error.rs:25:26
+   |
+LL | impl<A: Sized> Constrain<'missing> for W<A> {}
+   |      -                   ^^^^^^^^ undeclared lifetime
+   |      |
+   |      help: consider introducing lifetime `'missing` here: `'missing,`
+
+error[E0119]: conflicting implementations of trait `Tr<'_>` for type `W<_>`
+  --> $DIR/dont-canonicalize-re-error.rs:21:1
+   |
+LL | impl<'a, A: ?Sized> Tr<'a> for W<A> {}
+   | ----------------------------------- first implementation here
+LL | struct W<A: ?Sized>(A);
+LL | impl<'a, A: ?Sized> Tr<'a> for A where A: Constrain<'a> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<_>`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0119, E0261.
+For more information about an error, try `rustc --explain E0119`.
diff --git a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs
new file mode 100644
index 00000000000..3af299e5b11
--- /dev/null
+++ b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs
@@ -0,0 +1,15 @@
+trait FromResidual<R = <Self as Try>::Residual> {
+    fn from_residual(residual: R) -> Self;
+}
+
+trait Try {
+    type Residual;
+}
+
+fn w<'a, T: 'a, F: Fn(&'a T)>() {
+    let b: &dyn FromResidual = &();
+    //~^ ERROR: the trait `FromResidual` cannot be made into an object
+    //~| ERROR: the trait `FromResidual` cannot be made into an object
+}
+
+fn main() {}
diff --git a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr
new file mode 100644
index 00000000000..d5e9b1be63b
--- /dev/null
+++ b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr
@@ -0,0 +1,33 @@
+error[E0038]: the trait `FromResidual` cannot be made into an object
+  --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:10:17
+   |
+LL |     let b: &dyn FromResidual = &();
+   |                 ^^^^^^^^^^^^
+   |
+   = note: it cannot use `Self` as a type parameter in a supertrait or `where`-clause
+
+error[E0038]: the trait `FromResidual` cannot be made into an object
+  --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:10:12
+   |
+LL |     let b: &dyn FromResidual = &();
+   |            ^^^^^^^^^^^^^^^^^ `FromResidual` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:2:8
+   |
+LL | trait FromResidual<R = <Self as Try>::Residual> {
+   |       ------------ this trait cannot be made into an object...
+LL |     fn from_residual(residual: R) -> Self;
+   |        ^^^^^^^^^^^^^ ...because associated function `from_residual` has no `self` parameter
+help: consider turning `from_residual` into a method by giving it a `&self` argument
+   |
+LL |     fn from_residual(&self, residual: R) -> Self;
+   |                      ++++++
+help: alternatively, consider constraining `from_residual` so it does not apply to trait objects
+   |
+LL |     fn from_residual(residual: R) -> Self where Self: Sized;
+   |                                           +++++++++++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/traits/span-bug-issue-121414.rs b/tests/ui/traits/span-bug-issue-121414.rs
index 6fbe2c179c6..ec38d8c2de6 100644
--- a/tests/ui/traits/span-bug-issue-121414.rs
+++ b/tests/ui/traits/span-bug-issue-121414.rs
@@ -6,7 +6,8 @@ impl<'a> Bar for Foo<'f> { //~ ERROR undeclared lifetime
     type Type = u32;
 }
 
-fn test() //~ ERROR implementation of `Bar` is not general enough
+fn test() //~ ERROR the trait bound `for<'a> Foo<'a>: Bar` is not satisfied
+          //~| ERROR the trait bound `for<'a> Foo<'a>: Bar` is not satisfied
 where
     for<'a> <Foo<'a> as Bar>::Type: Sized,
 {
diff --git a/tests/ui/traits/span-bug-issue-121414.stderr b/tests/ui/traits/span-bug-issue-121414.stderr
index 3c97f64e781..e2ef6672cd5 100644
--- a/tests/ui/traits/span-bug-issue-121414.stderr
+++ b/tests/ui/traits/span-bug-issue-121414.stderr
@@ -6,15 +6,22 @@ LL | impl<'a> Bar for Foo<'f> {
    |      |
    |      help: consider introducing lifetime `'f` here: `'f,`
 
-error: implementation of `Bar` is not general enough
+error[E0277]: the trait bound `for<'a> Foo<'a>: Bar` is not satisfied
+  --> $DIR/span-bug-issue-121414.rs:9:1
+   |
+LL | / fn test()
+LL | |
+LL | | where
+LL | |     for<'a> <Foo<'a> as Bar>::Type: Sized,
+   | |__________________________________________^ the trait `for<'a> Bar` is not implemented for `Foo<'a>`
+
+error[E0277]: the trait bound `for<'a> Foo<'a>: Bar` is not satisfied
   --> $DIR/span-bug-issue-121414.rs:9:4
    |
 LL | fn test()
-   |    ^^^^ implementation of `Bar` is not general enough
-   |
-   = note: `Bar` would have to be implemented for the type `Foo<'0>`, for any lifetime `'0`...
-   = note: ...but `Bar` is actually implemented for the type `Foo<'1>`, for some specific lifetime `'1`
+   |    ^^^^ the trait `for<'a> Bar` is not implemented for `Foo<'a>`
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0261`.
+Some errors have detailed explanations: E0261, E0277.
+For more information about an error, try `rustc --explain E0261`.
diff --git a/tests/ui/traits/suggest-fully-qualified-closure.rs b/tests/ui/traits/suggest-fully-qualified-closure.rs
index f401a3012da..3d28a4e6bf5 100644
--- a/tests/ui/traits/suggest-fully-qualified-closure.rs
+++ b/tests/ui/traits/suggest-fully-qualified-closure.rs
@@ -1,7 +1,5 @@
 //@ check-fail
 //@ known-bug: #103705
-//@ normalize-stderr-test "\{closure@.*\}" -> "{closure@}"
-//@ normalize-stderr-test "\+* ~" -> "+++ ~"
 
 // The output of this currently suggests writing a closure in the qualified path.
 
diff --git a/tests/ui/traits/suggest-fully-qualified-closure.stderr b/tests/ui/traits/suggest-fully-qualified-closure.stderr
index e077bd7ac2a..a2c1115e673 100644
--- a/tests/ui/traits/suggest-fully-qualified-closure.stderr
+++ b/tests/ui/traits/suggest-fully-qualified-closure.stderr
@@ -1,11 +1,11 @@
 error[E0283]: type annotations needed
-  --> $DIR/suggest-fully-qualified-closure.rs:23:7
+  --> $DIR/suggest-fully-qualified-closure.rs:21:7
    |
 LL |     q.lol(||());
    |       ^^^
    |
 note: multiple `impl`s satisfying `Qqq: MyTrait<_>` found
-  --> $DIR/suggest-fully-qualified-closure.rs:14:1
+  --> $DIR/suggest-fully-qualified-closure.rs:12:1
    |
 LL | impl MyTrait<u32> for Qqq{
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -14,8 +14,8 @@ LL | impl MyTrait<u64> for Qqq{
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 help: try using a fully qualified path to specify the expected types
    |
-LL |     <Qqq as MyTrait<T>>::lol::<{closure@}>(&q, ||());
-   |     +++ ~
+LL |     <Qqq as MyTrait<T>>::lol::<_>(&q, ||());
+   |     +++++++++++++++++++++++++++++++ ~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/transmute/transmute-zst-generics.rs b/tests/ui/transmute/transmute-zst-generics.rs
new file mode 100644
index 00000000000..9aeb21923ea
--- /dev/null
+++ b/tests/ui/transmute/transmute-zst-generics.rs
@@ -0,0 +1,34 @@
+//@ run-pass
+
+// Transmuting to/from ZSTs that contain generics.
+
+#![feature(transmute_generic_consts)]
+
+// Verify non-generic ZST -> generic ZST transmute
+unsafe fn cast_zst0<T>(from: ()) -> [T; 0] {
+    ::std::mem::transmute::<(), [T; 0]>(from)
+}
+
+// Verify generic ZST -> non-generic ZST transmute
+unsafe fn cast_zst1<T>(from: [T; 0]) -> () {
+    ::std::mem::transmute::<[T; 0], ()>(from)
+}
+
+// Verify transmute with generic compound types
+unsafe fn cast_zst2<T>(from: ()) -> [(T, T); 0] {
+    ::std::mem::transmute::<(), [(T, T); 0]>(from)
+}
+
+// Verify transmute with ZST propagation through arrays
+unsafe fn cast_zst3<T>(from: ()) -> [[T; 0]; 8] {
+    ::std::mem::transmute::<(), [[T; 0]; 8]>(from)
+}
+
+pub fn main() {
+    unsafe {
+        let _: [u32; 0] = cast_zst0(());
+        let _ = cast_zst1::<u32>([]);
+        let _: [(u32, u32); 0] = cast_zst2(());
+        let _: [[u32; 0]; 8] = cast_zst3(());
+    };
+}
diff --git a/tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.rs b/tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.rs
new file mode 100644
index 00000000000..023991c29d0
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.rs
@@ -0,0 +1,36 @@
+// issue: rust-lang/rust#99945
+// ICE Failed to normalize
+
+#![feature(type_alias_impl_trait)]
+
+trait Widget<E> {
+    type State;
+
+    fn make_state(&self) -> Self::State;
+}
+
+impl<E> Widget<E> for () {
+    type State = ();
+
+    fn make_state(&self) -> Self::State {}
+}
+
+struct StatefulWidget<F>(F);
+
+type StateWidget<'a> = impl Widget<&'a ()>;
+
+impl<F: for<'a> Fn(&'a ()) -> StateWidget<'a>> Widget<()> for StatefulWidget<F> {
+    type State = ();
+
+    fn make_state(&self) -> Self::State {}
+}
+
+fn new_stateful_widget<F: for<'a> Fn(&'a ()) -> StateWidget<'a>>(build: F) -> impl Widget<()> {
+    StatefulWidget(build)
+    //~^ ERROR expected generic lifetime parameter, found `'a`
+}
+
+fn main() {
+    new_stateful_widget(|_| ()).make_state();
+    //~^ ERROR mismatched types
+}
diff --git a/tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.stderr b/tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.stderr
new file mode 100644
index 00000000000..0c76feae198
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/failed-to-normalize-ice-99945.stderr
@@ -0,0 +1,25 @@
+error[E0308]: mismatched types
+  --> $DIR/failed-to-normalize-ice-99945.rs:34:29
+   |
+LL | type StateWidget<'a> = impl Widget<&'a ()>;
+   |                        ------------------- the expected opaque type
+...
+LL |     new_stateful_widget(|_| ()).make_state();
+   |                             ^^ expected opaque type, found `()`
+   |
+   = note: expected opaque type `StateWidget<'_>`
+                found unit type `()`
+
+error[E0792]: expected generic lifetime parameter, found `'a`
+  --> $DIR/failed-to-normalize-ice-99945.rs:29:5
+   |
+LL | type StateWidget<'a> = impl Widget<&'a ()>;
+   |                  -- this generic parameter must be used with a generic lifetime parameter
+...
+LL |     StatefulWidget(build)
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0308, E0792.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/type-alias-impl-trait/hkl_forbidden4.rs b/tests/ui/type-alias-impl-trait/hkl_forbidden4.rs
new file mode 100644
index 00000000000..ef9fe604ea7
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/hkl_forbidden4.rs
@@ -0,0 +1,25 @@
+//! This test used to ICE because, while an error was emitted,
+//! we still tried to remap generic params used in the hidden type
+//! to the ones of the opaque type definition.
+
+//@ edition: 2021
+
+#![feature(type_alias_impl_trait)]
+use std::future::Future;
+
+type FutNothing<'a> = impl 'a + Future<Output = ()>;
+//~^ ERROR: unconstrained opaque type
+
+async fn operation(_: &mut ()) -> () {
+    //~^ ERROR: concrete type differs from previous
+    call(operation).await
+}
+
+async fn call<F>(_f: F)
+where
+    for<'any> F: FnMut(&'any mut ()) -> FutNothing<'any>,
+{
+    //~^ ERROR: expected generic lifetime parameter, found `'any`
+}
+
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr b/tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr
new file mode 100644
index 00000000000..d7a0452727e
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr
@@ -0,0 +1,34 @@
+error: unconstrained opaque type
+  --> $DIR/hkl_forbidden4.rs:10:23
+   |
+LL | type FutNothing<'a> = impl 'a + Future<Output = ()>;
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `FutNothing` must be used in combination with a concrete type within the same module
+
+error: concrete type differs from previous defining opaque type use
+  --> $DIR/hkl_forbidden4.rs:13:1
+   |
+LL | async fn operation(_: &mut ()) -> () {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `FutNothing<'_>`, got `{async fn body@$DIR/hkl_forbidden4.rs:13:38: 16:2}`
+   |
+note: previous use here
+  --> $DIR/hkl_forbidden4.rs:15:5
+   |
+LL |     call(operation).await
+   |     ^^^^^^^^^^^^^^^
+
+error[E0792]: expected generic lifetime parameter, found `'any`
+  --> $DIR/hkl_forbidden4.rs:21:1
+   |
+LL |   type FutNothing<'a> = impl 'a + Future<Output = ()>;
+   |                   -- this generic parameter must be used with a generic lifetime parameter
+...
+LL | / {
+LL | |
+LL | | }
+   | |_^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0792`.
diff --git a/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.rs b/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.rs
new file mode 100644
index 00000000000..fc71d0d61ff
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.rs
@@ -0,0 +1,52 @@
+// test for #110696
+// failed to resolve instance for <Scope<()> as MyIndex<()>>::my_index
+// ignore-tidy-linelength
+
+#![feature(type_alias_impl_trait)]
+
+use std::marker::PhantomData;
+
+
+trait MyIndex<T> {
+    type O;
+    fn my_index(self) -> Self::O;
+}
+trait MyFrom<T>: Sized {
+    type Error;
+    fn my_from(value: T) -> Result<Self, Self::Error>;
+}
+
+
+trait F {}
+impl F for () {}
+type DummyT<T> = impl F;
+fn _dummy_t<T>() -> DummyT<T> {}
+
+struct Phantom1<T>(PhantomData<T>);
+struct Phantom2<T>(PhantomData<T>);
+struct Scope<T>(Phantom2<DummyT<T>>);
+
+impl<T> Scope<T> {
+    fn new() -> Self {
+        unimplemented!()
+    }
+}
+
+impl<T> MyFrom<Phantom2<T>> for Phantom1<T> {
+    type Error = ();
+    fn my_from(_: Phantom2<T>) -> Result<Self, Self::Error> {
+        unimplemented!()
+    }
+}
+
+impl<T: MyFrom<Phantom2<DummyT<U>>>, U> MyIndex<DummyT<T>> for Scope<U> {
+    //~^ ERROR the type parameter `T` is not constrained by the impl
+    type O = T;
+    fn my_index(self) -> Self::O {
+        MyFrom::my_from(self.0).ok().unwrap()
+    }
+}
+
+fn main() {
+    let _pos: Phantom1<DummyT<()>> = Scope::new().my_index();
+}
diff --git a/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr b/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr
new file mode 100644
index 00000000000..a39f77ce17f
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr
@@ -0,0 +1,9 @@
+error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/ice-failed-to-resolve-instance-for-110696.rs:42:6
+   |
+LL | impl<T: MyFrom<Phantom2<DummyT<U>>>, U> MyIndex<DummyT<T>> for Scope<U> {
+   |      ^ unconstrained type parameter
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0207`.
diff --git a/tests/ui/type-alias-impl-trait/not_well_formed.fixed b/tests/ui/type-alias-impl-trait/not_well_formed.fixed
deleted file mode 100644
index bd45d8cddae..00000000000
--- a/tests/ui/type-alias-impl-trait/not_well_formed.fixed
+++ /dev/null
@@ -1,19 +0,0 @@
-//@ run-rustfix
-#![feature(type_alias_impl_trait)]
-#![allow(dead_code)]
-
-fn main() {}
-
-trait TraitWithAssoc {
-    type Assoc;
-}
-
-type Foo<V: TraitWithAssoc> = impl Trait<V::Assoc>; //~ associated type `Assoc` not found for `V`
-
-trait Trait<U> {}
-
-impl<W> Trait<W> for () {}
-
-fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T> {
-    ()
-}
diff --git a/tests/ui/type-alias-impl-trait/not_well_formed.rs b/tests/ui/type-alias-impl-trait/not_well_formed.rs
index 7b5444ae0d3..0cf8d41c7fd 100644
--- a/tests/ui/type-alias-impl-trait/not_well_formed.rs
+++ b/tests/ui/type-alias-impl-trait/not_well_formed.rs
@@ -1,4 +1,4 @@
-//@ run-rustfix
+// Can't rustfix because we apply the suggestion twice :^(
 #![feature(type_alias_impl_trait)]
 #![allow(dead_code)]
 
@@ -8,7 +8,9 @@ trait TraitWithAssoc {
     type Assoc;
 }
 
-type Foo<V> = impl Trait<V::Assoc>; //~ associated type `Assoc` not found for `V`
+type Foo<V> = impl Trait<V::Assoc>;
+//~^ associated type `Assoc` not found for `V`
+//~| associated type `Assoc` not found for `V`
 
 trait Trait<U> {}
 
diff --git a/tests/ui/type-alias-impl-trait/not_well_formed.stderr b/tests/ui/type-alias-impl-trait/not_well_formed.stderr
index dbd80ffa4f6..a2944a1acb9 100644
--- a/tests/ui/type-alias-impl-trait/not_well_formed.stderr
+++ b/tests/ui/type-alias-impl-trait/not_well_formed.stderr
@@ -9,6 +9,18 @@ help: consider restricting type parameter `V`
 LL | type Foo<V: TraitWithAssoc> = impl Trait<V::Assoc>;
    |           ++++++++++++++++
 
-error: aborting due to 1 previous error
+error[E0220]: associated type `Assoc` not found for `V`
+  --> $DIR/not_well_formed.rs:11:29
+   |
+LL | type Foo<V> = impl Trait<V::Assoc>;
+   |                             ^^^^^ there is an associated type `Assoc` in the trait `TraitWithAssoc`
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: consider restricting type parameter `V`
+   |
+LL | type Foo<V: TraitWithAssoc> = impl Trait<V::Assoc>;
+   |           ++++++++++++++++
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0220`.
diff --git a/tests/ui/type-alias-impl-trait/underef-index-out-of-bounds-121472.rs b/tests/ui/type-alias-impl-trait/underef-index-out-of-bounds-121472.rs
new file mode 100644
index 00000000000..37e0d89efc7
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/underef-index-out-of-bounds-121472.rs
@@ -0,0 +1,16 @@
+// test for ICE #121472 index out of bounds un_derefer.rs
+#![feature(type_alias_impl_trait)]
+
+trait T {}
+
+type Alias<'a> = impl T;
+
+struct S;
+impl<'a> T for &'a S {}
+
+fn with_positive(fun: impl Fn(Alias<'_>)) {}
+
+fn main() {
+    with_positive(|&n| ());
+    //~^ ERROR mismatched types
+}
diff --git a/tests/ui/type-alias-impl-trait/underef-index-out-of-bounds-121472.stderr b/tests/ui/type-alias-impl-trait/underef-index-out-of-bounds-121472.stderr
new file mode 100644
index 00000000000..a224bab0705
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/underef-index-out-of-bounds-121472.stderr
@@ -0,0 +1,23 @@
+error[E0308]: mismatched types
+  --> $DIR/underef-index-out-of-bounds-121472.rs:14:20
+   |
+LL | type Alias<'a> = impl T;
+   |                  ------ the expected opaque type
+...
+LL |     with_positive(|&n| ());
+   |                    ^^
+   |                    |
+   |                    expected opaque type, found `&_`
+   |                    expected due to this
+   |
+   = note: expected opaque type `Alias<'_>`
+                found reference `&_`
+help: consider removing `&` from the pattern
+   |
+LL -     with_positive(|&n| ());
+LL +     with_positive(|n| ());
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/type/type-parameter-names.stderr b/tests/ui/type/type-parameter-names.stderr
index 8e3e2388c6c..be9000a99e4 100644
--- a/tests/ui/type/type-parameter-names.stderr
+++ b/tests/ui/type/type-parameter-names.stderr
@@ -13,6 +13,7 @@ LL |     x
               found type parameter `Foo`
    = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
    = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
+   = note: the caller chooses a type for `Bar` which can be different from `Foo`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/type/type-params-in-different-spaces-3.stderr b/tests/ui/type/type-params-in-different-spaces-3.stderr
index 58783fe1ff0..3c0c022f112 100644
--- a/tests/ui/type/type-params-in-different-spaces-3.stderr
+++ b/tests/ui/type/type-params-in-different-spaces-3.stderr
@@ -14,6 +14,7 @@ LL |         u
               found type parameter `X`
    = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
    = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
+   = note: the caller chooses a type for `Self` which can be different from `X`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/typeck/escaping_bound_vars.rs b/tests/ui/typeck/escaping_bound_vars.rs
index f886388bfbd..985a3fdbccf 100644
--- a/tests/ui/typeck/escaping_bound_vars.rs
+++ b/tests/ui/typeck/escaping_bound_vars.rs
@@ -11,9 +11,6 @@ where
     (): Test<{ 1 + (<() as Elide(&())>::call) }>,
     //~^ ERROR cannot capture late-bound lifetime in constant
     //~| ERROR associated type bindings are not allowed here
-    //~| ERROR the trait bound `(): Elide<(&(),)>` is not satisfied
-    //~| ERROR the trait bound `(): Elide<(&(),)>` is not satisfied
-    //~| ERROR cannot add
 {
 }
 
diff --git a/tests/ui/typeck/escaping_bound_vars.stderr b/tests/ui/typeck/escaping_bound_vars.stderr
index 8c7dcdb7f16..bd9c95fab97 100644
--- a/tests/ui/typeck/escaping_bound_vars.stderr
+++ b/tests/ui/typeck/escaping_bound_vars.stderr
@@ -12,49 +12,6 @@ error[E0229]: associated type bindings are not allowed here
 LL |     (): Test<{ 1 + (<() as Elide(&())>::call) }>,
    |                            ^^^^^^^^^^ associated type not allowed here
 
-error[E0277]: the trait bound `(): Elide<(&(),)>` is not satisfied
-  --> $DIR/escaping_bound_vars.rs:11:22
-   |
-LL |     (): Test<{ 1 + (<() as Elide(&())>::call) }>,
-   |                      ^^ the trait `Elide<(&(),)>` is not implemented for `()`
-   |
-help: this trait has no implementations, consider adding one
-  --> $DIR/escaping_bound_vars.rs:5:1
-   |
-LL | trait Elide<T> {
-   | ^^^^^^^^^^^^^^
-
-error[E0277]: cannot add `fn() {<() as Elide<(&(),)>>::call}` to `{integer}`
-  --> $DIR/escaping_bound_vars.rs:11:18
-   |
-LL |     (): Test<{ 1 + (<() as Elide(&())>::call) }>,
-   |                  ^ no implementation for `{integer} + fn() {<() as Elide<(&(),)>>::call}`
-   |
-   = help: the trait `Add<fn() {<() as Elide<(&(),)>>::call}>` is not implemented for `{integer}`
-   = help: the following other types implement trait `Add<Rhs>`:
-             <isize as Add>
-             <isize as Add<&isize>>
-             <i8 as Add>
-             <i8 as Add<&i8>>
-             <i16 as Add>
-             <i16 as Add<&i16>>
-             <i32 as Add>
-             <i32 as Add<&i32>>
-           and 48 others
-
-error[E0277]: the trait bound `(): Elide<(&(),)>` is not satisfied
-  --> $DIR/escaping_bound_vars.rs:11:18
-   |
-LL |     (): Test<{ 1 + (<() as Elide(&())>::call) }>,
-   |                  ^ the trait `Elide<(&(),)>` is not implemented for `()`
-   |
-help: this trait has no implementations, consider adding one
-  --> $DIR/escaping_bound_vars.rs:5:1
-   |
-LL | trait Elide<T> {
-   | ^^^^^^^^^^^^^^
-
-error: aborting due to 5 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0229, E0277.
-For more information about an error, try `rustc --explain E0229`.
+For more information about this error, try `rustc --explain E0229`.
diff --git a/tests/ui/typeck/issue-13853.stderr b/tests/ui/typeck/issue-13853.stderr
index 0683c782933..45363c87d29 100644
--- a/tests/ui/typeck/issue-13853.stderr
+++ b/tests/ui/typeck/issue-13853.stderr
@@ -9,6 +9,7 @@ LL |         self.iter()
    |
    = note: expected type parameter `I`
                       found struct `std::slice::Iter<'_, N>`
+   = note: the caller chooses a type for `I` which can be different from `std::slice::Iter<'_, N>`
 
 error[E0599]: no method named `iter` found for reference `&G` in the current scope
   --> $DIR/issue-13853.rs:27:23
diff --git a/tests/ui/typeck/issue-91267.stderr b/tests/ui/typeck/issue-91267.stderr
index 7e48b251980..399309d0ec4 100644
--- a/tests/ui/typeck/issue-91267.stderr
+++ b/tests/ui/typeck/issue-91267.stderr
@@ -17,6 +17,8 @@ LL | fn main() {
    |          - expected `()` because of default return type
 LL |     type_ascribe!(0, u8<e<5>=e>)
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `u8`
+   |
+   = note: this error originates in the macro `type_ascribe` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-region.rs b/tests/ui/unboxed-closures/unboxed-closure-sugar-region.rs
index 8537eb71774..ea73b8b3c4a 100644
--- a/tests/ui/unboxed-closures/unboxed-closure-sugar-region.rs
+++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-region.rs
@@ -33,7 +33,6 @@ fn test2(x: &dyn Foo<(isize,),Output=()>, y: &dyn Foo(isize)) {
     //~^ ERROR trait takes 1 lifetime argument but 0 lifetime arguments were supplied
     // Here, the omitted lifetimes are expanded to distinct things.
     same_type(x, y)
-    //~^ ERROR borrowed data escapes outside of function
 }
 
 fn main() { }
diff --git a/tests/ui/unboxed-closures/unboxed-closure-sugar-region.stderr b/tests/ui/unboxed-closures/unboxed-closure-sugar-region.stderr
index 6e6c649ca3d..d73aef851fd 100644
--- a/tests/ui/unboxed-closures/unboxed-closure-sugar-region.stderr
+++ b/tests/ui/unboxed-closures/unboxed-closure-sugar-region.stderr
@@ -34,22 +34,6 @@ note: trait defined here, with 1 lifetime parameter: `'a`
 LL | trait Foo<'a,T> {
    |       ^^^ --
 
-error[E0521]: borrowed data escapes outside of function
-  --> $DIR/unboxed-closure-sugar-region.rs:35:5
-   |
-LL | fn test2(x: &dyn Foo<(isize,),Output=()>, y: &dyn Foo(isize)) {
-   |          -                                - `y` declared here, outside of the function body
-   |          |
-   |          `x` is a reference that is only valid in the function body
-   |          has type `&dyn Foo<'1, (isize,), Output = ()>`
-...
-LL |     same_type(x, y)
-   |     ^^^^^^^^^^^^^^^
-   |     |
-   |     `x` escapes the function body here
-   |     argument requires that `'1` must outlive `'static`
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0107, E0521.
-For more information about an error, try `rustc --explain E0107`.
+For more information about this error, try `rustc --explain E0107`.
diff --git a/tests/ui/unboxed-closures/unboxed-closures-type-mismatch-closure-from-another-scope.stderr b/tests/ui/unboxed-closures/unboxed-closures-type-mismatch-closure-from-another-scope.stderr
index 1470c32d7de..5f22c781345 100644
--- a/tests/ui/unboxed-closures/unboxed-closures-type-mismatch-closure-from-another-scope.stderr
+++ b/tests/ui/unboxed-closures/unboxed-closures-type-mismatch-closure-from-another-scope.stderr
@@ -26,11 +26,11 @@ note: closure parameter defined here
 LL |         let mut closure = expect_sig(|p, y| *p = y);
    |                                       ^
 
-error[E0425]: cannot find function `deref` in this scope
+error[E0423]: expected function, found macro `deref`
   --> $DIR/unboxed-closures-type-mismatch-closure-from-another-scope.rs:13:5
    |
 LL |     deref(p);
-   |     ^^^^^ not found in this scope
+   |     ^^^^^ not a function
    |
 help: use the `.` operator to call the method `Deref::deref` on `&&()`
    |
@@ -40,5 +40,5 @@ LL +     p.deref();
 
 error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0308, E0425.
+Some errors have detailed explanations: E0308, E0423, E0425.
 For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/underscore-lifetime/underscore-lifetime-binders.rs b/tests/ui/underscore-lifetime/underscore-lifetime-binders.rs
index ebc38798544..3d049cc5639 100644
--- a/tests/ui/underscore-lifetime/underscore-lifetime-binders.rs
+++ b/tests/ui/underscore-lifetime/underscore-lifetime-binders.rs
@@ -14,7 +14,6 @@ fn meh() -> Box<dyn for<'_> Meh<'_>> //~ ERROR cannot be used here
 }
 
 fn foo2(_: &'_ u8, y: &'_ u8) -> &'_ u8 { y } //~ ERROR missing lifetime specifier
-//~^ ERROR lifetime may not live long enough
 
 fn main() {
     let x = 5;
diff --git a/tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr b/tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr
index 5d2954d1d71..cd74d27dcb5 100644
--- a/tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr
+++ b/tests/ui/underscore-lifetime/underscore-lifetime-binders.stderr
@@ -45,15 +45,7 @@ help: consider introducing a named lifetime parameter
 LL | fn foo2<'a>(_: &'a u8, y: &'a u8) -> &'a u8 { y }
    |        ++++     ~~         ~~         ~~
 
-error: lifetime may not live long enough
-  --> $DIR/underscore-lifetime-binders.rs:16:43
-   |
-LL | fn foo2(_: &'_ u8, y: &'_ u8) -> &'_ u8 { y }
-   |                       -                   ^ returning this value requires that `'1` must outlive `'static`
-   |                       |
-   |                       let's call the lifetime of this reference `'1`
-
-error: aborting due to 6 previous errors
+error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0106, E0637.
 For more information about an error, try `rustc --explain E0106`.
diff --git a/tests/ui/union/union-macro.rs b/tests/ui/union/union-macro.rs
index 01cba85deb3..729f56de7a0 100644
--- a/tests/ui/union/union-macro.rs
+++ b/tests/ui/union/union-macro.rs
@@ -15,6 +15,7 @@ macro_rules! duplicate {
 
 duplicate! {
     pub union U {
+        #[allow(dead_code)]
         pub a: u8
     }
 }
diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs
new file mode 100644
index 00000000000..db155f4fa3c
--- /dev/null
+++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs
@@ -0,0 +1,31 @@
+trait Trait<const N: Trait = bar> {
+    //~^ ERROR cannot find value `bar` in this scope
+    //~| ERROR cycle detected when computing type of `Trait::N`
+    //~| ERROR cycle detected when computing type of `Trait::N`
+    //~| ERROR the trait `Trait` cannot be made into an object
+    //~| ERROR the trait `Trait` cannot be made into an object
+    //~| ERROR the trait `Trait` cannot be made into an object
+    //~| ERROR `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter
+    //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
+    //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+    //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
+    //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+    fn fnc<const N: Trait = u32>(&self) -> Trait {
+    //~^ ERROR the name `N` is already used for a generic parameter in this item's generic parameters
+    //~| ERROR expected value, found builtin type `u32`
+    //~| ERROR defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
+    //~| ERROR associated item referring to unboxed trait object for its own trait
+    //~| ERROR the trait `Trait` cannot be made into an object
+    //~| ERROR `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter
+    //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
+    //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+    //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
+    //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+    //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
+    //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+        bar
+    //~^ ERROR cannot find value `bar` in this scope
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr
new file mode 100644
index 00000000000..cf985d9d1fd
--- /dev/null
+++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr
@@ -0,0 +1,228 @@
+error[E0403]: the name `N` is already used for a generic parameter in this item's generic parameters
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:18
+   |
+LL | trait Trait<const N: Trait = bar> {
+   |                   - first use of `N`
+...
+LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
+   |                  ^ already used
+
+error[E0425]: cannot find value `bar` in this scope
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:30
+   |
+LL | trait Trait<const N: Trait = bar> {
+   |                              ^^^ not found in this scope
+
+error[E0423]: expected value, found builtin type `u32`
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:29
+   |
+LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
+   |                             ^^^ not a value
+
+error[E0425]: cannot find value `bar` in this scope
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:26:9
+   |
+LL |         bar
+   |         ^^^ not found in this scope
+
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:22
+   |
+LL | trait Trait<const N: Trait = bar> {
+   |                      ^^^^^
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+   = note: `#[warn(bare_trait_objects)]` on by default
+help: if this is an object-safe trait, use `dyn`
+   |
+LL | trait Trait<const N: dyn Trait = bar> {
+   |                      +++
+
+error[E0391]: cycle detected when computing type of `Trait::N`
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:22
+   |
+LL | trait Trait<const N: Trait = bar> {
+   |                      ^^^^^
+   |
+   = note: ...which immediately requires computing type of `Trait::N` again
+note: cycle used when computing explicit predicates of trait `Trait`
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:1
+   |
+LL | trait Trait<const N: Trait = bar> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = 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[E0391]: cycle detected when computing type of `Trait::N`
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:13
+   |
+LL | trait Trait<const N: Trait = bar> {
+   |             ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: ...which immediately requires computing type of `Trait::N` again
+note: cycle used when computing explicit predicates of trait `Trait`
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:1
+   |
+LL | trait Trait<const N: Trait = bar> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = 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: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:12
+   |
+LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
+   |            ^^^^^^^^^^^^^^^^^^^^
+
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:21
+   |
+LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
+   |                     ^^^^^
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: if this is an object-safe trait, use `dyn`
+   |
+LL |     fn fnc<const N: dyn Trait = u32>(&self) -> Trait {
+   |                     +++
+
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:44
+   |
+LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
+   |                                            ^^^^^
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: if this is an object-safe trait, use `dyn`
+   |
+LL |     fn fnc<const N: Trait = u32>(&self) -> dyn Trait {
+   |                                            +++
+
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:22
+   |
+LL | trait Trait<const N: Trait = bar> {
+   |                      ^^^^^
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: if this is an object-safe trait, use `dyn`
+   |
+LL | trait Trait<const N: dyn Trait = bar> {
+   |                      +++
+
+error[E0038]: the trait `Trait` cannot be made into an object
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:22
+   |
+LL | trait Trait<const N: Trait = bar> {
+   |                      ^^^^^ `Trait` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:8
+   |
+LL | trait Trait<const N: Trait = bar> {
+   |       ----- this trait cannot be made into an object...
+...
+LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
+   |        ^^^ ...because method `fnc` has generic type parameters
+   = help: consider moving `fnc` to another trait
+
+error[E0038]: the trait `Trait` cannot be made into an object
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:13
+   |
+LL | trait Trait<const N: Trait = bar> {
+   |             ^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:8
+   |
+LL | trait Trait<const N: Trait = bar> {
+   |       ----- this trait cannot be made into an object...
+...
+LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
+   |        ^^^ ...because method `fnc` has generic type parameters
+   = help: consider moving `fnc` to another trait
+
+error: `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:22
+   |
+LL | trait Trait<const N: Trait = bar> {
+   |                      ^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+
+error: associated item referring to unboxed trait object for its own trait
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:44
+   |
+LL | trait Trait<const N: Trait = bar> {
+   |       ----- in this trait
+...
+LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
+   |                                            ^^^^^
+   |
+help: you might have meant to use `Self` to refer to the implementing type
+   |
+LL |     fn fnc<const N: Trait = u32>(&self) -> Self {
+   |                                            ~~~~
+
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:21
+   |
+LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
+   |                     ^^^^^
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: if this is an object-safe trait, use `dyn`
+   |
+LL |     fn fnc<const N: dyn Trait = u32>(&self) -> Trait {
+   |                     +++
+
+error[E0038]: the trait `Trait` cannot be made into an object
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:21
+   |
+LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
+   |                     ^^^^^ `Trait` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:8
+   |
+LL | trait Trait<const N: Trait = bar> {
+   |       ----- this trait cannot be made into an object...
+...
+LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
+   |        ^^^ ...because method `fnc` has generic type parameters
+   = help: consider moving `fnc` to another trait
+
+error[E0038]: the trait `Trait` cannot be made into an object
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:13
+   |
+LL | trait Trait<const N: Trait = bar> {
+   |             ^^^^^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:8
+   |
+LL | trait Trait<const N: Trait = bar> {
+   |       ----- this trait cannot be made into an object...
+...
+LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
+   |        ^^^ ...because method `fnc` has generic type parameters
+   = help: consider moving `fnc` to another trait
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:21
+   |
+LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
+   |                     ^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+
+error: aborting due to 14 previous errors; 5 warnings emitted
+
+Some errors have detailed explanations: E0038, E0391, E0403, E0423, E0425.
+For more information about an error, try `rustc --explain E0038`.
diff --git a/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.rs b/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.rs
index 0be5127dcc4..e6d4e2ee01a 100644
--- a/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.rs
+++ b/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.rs
@@ -14,4 +14,5 @@ impl Trait for Ref {} //~ ERROR:  implicit elided lifetime not allowed here
 
 extern "C" {
     pub fn repro(_: Wrapper<Ref>);
+    //~^ ERROR the trait bound `Ref<'_>: Trait` is not satisfied
 }
diff --git a/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr b/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr
index 0af4ab022e1..59b55b2732d 100644
--- a/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr
+++ b/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr
@@ -9,6 +9,19 @@ help: indicate the anonymous lifetime
 LL | impl Trait for Ref<'_> {}
    |                   ++++
 
-error: aborting due to 1 previous error
+error[E0277]: the trait bound `Ref<'_>: Trait` is not satisfied
+  --> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:16:21
+   |
+LL |     pub fn repro(_: Wrapper<Ref>);
+   |                     ^^^^^^^^^^^^ the trait `Trait` is not implemented for `Ref<'_>`
+   |
+note: required by a bound in `Wrapper`
+  --> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:8:23
+   |
+LL | pub struct Wrapper<T: Trait>(T);
+   |                       ^^^^^ required by this bound in `Wrapper`
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0726`.
+Some errors have detailed explanations: E0277, E0726.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/triagebot.toml b/triagebot.toml
index 0a36eab7b87..2bcc77ae433 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -499,6 +499,10 @@ of `ObligationCtxt`.
 """
 cc = ["@lcnr", "@compiler-errors"]
 
+[mentions."compiler/rustc_hir_analysis/src/hir_ty_lowering"]
+message = "HIR ty lowering was modified"
+cc = ["@fmease"]
+
 [mentions."compiler/rustc_error_codes/src/lib.rs"]
 message = "Some changes occurred in diagnostic error codes"
 cc = ["@GuillaumeGomez"]
@@ -619,7 +623,7 @@ cc = ["@davidtwco", "@compiler-errors", "@TaKO8Ki"]
 
 [mentions."compiler/stable_mir"]
 message = "This PR changes Stable MIR"
-cc = ["@oli-obk", "@celinval", "@spastorino", "@ouz-a"]
+cc = ["@oli-obk", "@celinval", "@ouz-a"]
 
 [mentions."compiler/rustc_target/src/spec"]
 message = """
@@ -829,6 +833,7 @@ parser = [
     "@estebank",
     "@nnethercote",
     "@petrochenkov",
+    "@spastorino",
 ]
 lexer = [
     "@nnethercote",
@@ -837,6 +842,7 @@ lexer = [
 ]
 arena = [
     "@nnethercote",
+    "@spastorino",
 ]
 mir = [
     "@davidtwco",