about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock9
-rw-r--r--compiler/rustc_ast/src/ast.rs80
-rw-r--r--compiler/rustc_ast/src/attr/mod.rs2
-rw-r--r--compiler/rustc_ast/src/token.rs24
-rw-r--r--compiler/rustc_ast_lowering/src/asm.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/block.rs7
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs128
-rw-r--r--compiler/rustc_ast_lowering/src/index.rs4
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs123
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs303
-rw-r--r--compiler/rustc_ast_lowering/src/pat.rs57
-rw-r--r--compiler/rustc_ast_lowering/src/path.rs26
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs4
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs26
-rw-r--r--compiler/rustc_attr/src/builtin.rs29
-rw-r--r--compiler/rustc_attr/src/session_diagnostics.rs17
-rw-r--r--compiler/rustc_borrowck/src/dataflow.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs23
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs7
-rw-r--r--compiler/rustc_borrowck/src/invalidation.rs26
-rw-r--r--compiler/rustc_borrowck/src/lib.rs28
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs1
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs13
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs28
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs39
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs8
-rw-r--r--compiler/rustc_codegen_cranelift/src/discriminant.rs11
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs3
-rw-r--r--compiler/rustc_codegen_gcc/src/common.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/abi.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/common.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs18
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs76
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs42
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs52
-rw-r--r--compiler/rustc_codegen_ssa/src/lib.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/intrinsic.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/operand.rs9
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/place.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/statement.rs14
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/consts.rs1
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs36
-rw-r--r--compiler/rustc_const_eval/src/interpret/machine.rs10
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs20
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs10
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs8
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs13
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs2
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs53
-rw-r--r--compiler/rustc_data_structures/src/obligation_forest/mod.rs4
-rw-r--r--compiler/rustc_error_messages/locales/en-US/infer.ftl62
-rw-r--r--compiler/rustc_error_messages/locales/en-US/middle.ftl17
-rw-r--r--compiler/rustc_error_messages/locales/en-US/parser.ftl6
-rw-r--r--compiler/rustc_error_messages/locales/en-US/session.ftl42
-rw-r--r--compiler/rustc_error_messages/src/lib.rs1
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs7
-rw-r--r--compiler/rustc_errors/src/lib.rs45
-rw-r--r--compiler/rustc_expand/src/build.rs10
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs8
-rw-r--r--compiler/rustc_feature/src/lib.rs4
-rw-r--r--compiler/rustc_hir/src/def.rs8
-rw-r--r--compiler/rustc_hir/src/hir.rs121
-rw-r--r--compiler/rustc_hir/src/hir_id.rs3
-rw-r--r--compiler/rustc_hir/src/intravisit.rs5
-rw-r--r--compiler/rustc_hir/src/pat_util.rs19
-rw-r--r--compiler/rustc_hir/src/weak_lang_items.rs6
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs82
-rw-r--r--compiler/rustc_infer/src/errors.rs254
-rw-r--r--compiler/rustc_infer/src/errors/mod.rs499
-rw-r--r--compiler/rustc_infer/src/errors/note_and_explain.rs179
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs20
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs75
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs42
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs147
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs51
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs15
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs9
-rw-r--r--compiler/rustc_infer/src/infer/outlives/verify.rs6
-rw-r--r--compiler/rustc_interface/src/passes.rs17
-rw-r--r--compiler/rustc_lexer/src/lib.rs2
-rw-r--r--compiler/rustc_lint/src/array_into_iter.rs3
-rw-r--r--compiler/rustc_lint/src/builtin.rs17
-rw-r--r--compiler/rustc_lint/src/context.rs28
-rw-r--r--compiler/rustc_lint/src/errors.rs8
-rw-r--r--compiler/rustc_lint/src/internal.rs5
-rw-r--r--compiler/rustc_lint/src/late.rs15
-rw-r--r--compiler/rustc_lint/src/lib.rs43
-rw-r--r--compiler/rustc_lint/src/methods.rs18
-rw-r--r--compiler/rustc_lint/src/noop_method_call.rs3
-rw-r--r--compiler/rustc_lint/src/passes.rs2
-rw-r--r--compiler/rustc_lint/src/types.rs10
-rw-r--r--compiler/rustc_lint/src/unused.rs6
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp23
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic.rs2
-rw-r--r--compiler/rustc_metadata/src/errors.rs12
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs15
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs6
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs7
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs2
-rw-r--r--compiler/rustc_middle/src/error.rs50
-rw-r--r--compiler/rustc_middle/src/lib.rs2
-rw-r--r--compiler/rustc_middle/src/metadata.rs3
-rw-r--r--compiler/rustc_middle/src/middle/limits.rs8
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs34
-rw-r--r--compiler/rustc_middle/src/mir/spanview.rs2
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs47
-rw-r--r--compiler/rustc_middle/src/mir/terminator.rs2
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs17
-rw-r--r--compiler/rustc_middle/src/query/mod.rs2
-rw-r--r--compiler/rustc_middle/src/thir.rs50
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs4
-rw-r--r--compiler/rustc_middle/src/traits/query.rs12
-rw-r--r--compiler/rustc_middle/src/ty/assoc.rs2
-rw-r--r--compiler/rustc_middle/src/ty/binding.rs14
-rw-r--r--compiler/rustc_middle/src/ty/consts/kind.rs1
-rw-r--r--compiler/rustc_middle/src/ty/context.rs8
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs14
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs14
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs1
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs318
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs241
-rw-r--r--compiler/rustc_middle/src/ty/parameterized.rs4
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs20
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs14
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs13
-rw-r--r--compiler/rustc_middle/src/ty/visit.rs2
-rw-r--r--compiler/rustc_middle/src/ty/walk.rs6
-rw-r--r--compiler/rustc_middle/src/values.rs (renamed from compiler/rustc_query_impl/src/values.rs)33
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs10
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs9
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/liveness.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs2
-rw-r--r--compiler/rustc_mir_transform/src/check_unsafety.rs3
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans.rs2
-rw-r--r--compiler/rustc_mir_transform/src/dead_store_elimination.rs2
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs2
-rw-r--r--compiler/rustc_mir_transform/src/generator.rs2
-rw-r--r--compiler/rustc_mir_transform/src/lower_intrinsics.rs31
-rw-r--r--compiler/rustc_mir_transform/src/pass_manager.rs4
-rw-r--r--compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs2
-rw-r--r--compiler/rustc_mir_transform/src/separate_const_switch.rs4
-rw-r--r--compiler/rustc_mir_transform/src/simplify.rs2
-rw-r--r--compiler/rustc_monomorphize/src/errors.rs5
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs34
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs8
-rw-r--r--compiler/rustc_parse/src/parser/item.rs15
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs51
-rw-r--r--compiler/rustc_passes/src/check_attr.rs1
-rw-r--r--compiler/rustc_passes/src/dead.rs11
-rw-r--r--compiler/rustc_passes/src/hir_id_validator.rs2
-rw-r--r--compiler/rustc_passes/src/hir_stats.rs5
-rw-r--r--compiler/rustc_passes/src/liveness.rs5
-rw-r--r--compiler/rustc_passes/src/naked_functions.rs2
-rw-r--r--compiler/rustc_passes/src/stability.rs2
-rw-r--r--compiler/rustc_privacy/src/lib.rs76
-rw-r--r--compiler/rustc_query_impl/src/lib.rs3
-rw-r--r--compiler/rustc_query_impl/src/plumbing.rs24
-rw-r--r--compiler/rustc_query_system/Cargo.toml1
-rw-r--r--compiler/rustc_query_system/src/error.rs7
-rw-r--r--compiler/rustc_query_system/src/ich/impls_syntax.rs2
-rw-r--r--compiler/rustc_query_system/src/lib.rs4
-rw-r--r--compiler/rustc_query_system/src/query/config.rs5
-rw-r--r--compiler/rustc_query_system/src/query/job.rs2
-rw-r--r--compiler/rustc_query_system/src/query/plumbing.rs38
-rw-r--r--compiler/rustc_query_system/src/values.rs14
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs46
-rw-r--r--compiler/rustc_resolve/src/ident.rs13
-rw-r--r--compiler/rustc_resolve/src/imports.rs4
-rw-r--r--compiler/rustc_resolve/src/late.rs14
-rw-r--r--compiler/rustc_resolve/src/late/lifetimes.rs3
-rw-r--r--compiler/rustc_resolve/src/lib.rs47
-rw-r--r--compiler/rustc_save_analysis/src/dump_visitor.rs11
-rw-r--r--compiler/rustc_save_analysis/src/lib.rs26
-rw-r--r--compiler/rustc_session/src/config.rs2
-rw-r--r--compiler/rustc_session/src/errors.rs131
-rw-r--r--compiler/rustc_session/src/parse.rs6
-rw-r--r--compiler/rustc_session/src/session.rs92
-rw-r--r--compiler/rustc_span/src/def_id.rs6
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs12
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs6
-rw-r--r--compiler/rustc_target/src/abi/mod.rs67
-rw-r--r--compiler/rustc_trait_selection/src/errors.rs8
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs17
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs28
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs50
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs19
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs9
-rw-r--r--compiler/rustc_type_ir/src/lib.rs49
-rw-r--r--compiler/rustc_type_ir/src/sty.rs6
-rw-r--r--compiler/rustc_typeck/src/astconv/errors.rs1
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs50
-rw-r--r--compiler/rustc_typeck/src/check/callee.rs25
-rw-r--r--compiler/rustc_typeck/src/check/cast.rs13
-rw-r--r--compiler/rustc_typeck/src/check/check.rs9
-rw-r--r--compiler/rustc_typeck/src/check/demand.rs21
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs27
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs13
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/checks.rs38
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs9
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs3
-rw-r--r--compiler/rustc_typeck/src/check/intrinsicck.rs4
-rw-r--r--compiler/rustc_typeck/src/check/method/mod.rs26
-rw-r--r--compiler/rustc_typeck/src/check/method/prelude2021.rs1
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs13
-rw-r--r--compiler/rustc_typeck/src/check/op.rs352
-rw-r--r--compiler/rustc_typeck/src/check/pat.rs16
-rw-r--r--compiler/rustc_typeck/src/check/region.rs8
-rw-r--r--compiler/rustc_typeck/src/check/wfcheck.rs2
-rw-r--r--compiler/rustc_typeck/src/collect.rs21
-rw-r--r--compiler/rustc_typeck/src/collect/item_bounds.rs3
-rw-r--r--compiler/rustc_typeck/src/collect/type_of.rs8
-rw-r--r--compiler/rustc_typeck/src/errors.rs18
-rw-r--r--compiler/rustc_typeck/src/expr_use_visitor.rs3
-rw-r--r--compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs149
-rw-r--r--compiler/rustc_typeck/src/variance/constraints.rs6
-rw-r--r--library/core/src/bool.rs6
-rw-r--r--library/core/src/convert/mod.rs1
-rw-r--r--library/core/src/num/int_macros.rs78
-rw-r--r--library/core/src/slice/iter/macros.rs18
-rw-r--r--library/core/src/slice/sort.rs8
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--library/core/tests/num/int_macros.rs26
-rw-r--r--library/core/tests/num/uint_macros.rs22
-rw-r--r--library/portable-simd/crates/std_float/src/lib.rs6
-rw-r--r--library/std/src/io/stdio.rs28
-rw-r--r--library/std/src/macros.rs12
-rw-r--r--library/std/src/os/fd/owned.rs3
-rw-r--r--library/std/src/sys/hermit/fs.rs12
-rw-r--r--library/std/src/sys/hermit/mutex.rs1
-rw-r--r--library/std/src/sys/hermit/net.rs2
-rw-r--r--library/std/src/sys/hermit/rwlock.rs1
-rw-r--r--library/std/src/sys/windows/c.rs14
-rw-r--r--library/std/src/sys/windows/fs.rs2
-rw-r--r--library/std/src/sys/windows/rand.rs94
-rw-r--r--src/bootstrap/Cargo.toml1
-rw-r--r--src/bootstrap/util.rs10
-rw-r--r--src/doc/rustc/src/platform-support/fuchsia.md1
-rw-r--r--src/etc/check_missing_items.py14
-rw-r--r--src/librustdoc/clean/mod.rs18
-rw-r--r--src/librustdoc/clean/types.rs3
-rw-r--r--src/librustdoc/html/render/span_map.rs34
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css36
-rw-r--r--src/librustdoc/json/conversions.rs68
-rw-r--r--src/librustdoc/scrape_examples.rs2
-rw-r--r--src/rustdoc-json-types/lib.rs73
-rw-r--r--src/rustdoc-json-types/tests.rs4
-rw-r--r--src/test/codegen/issue-98294-get-mut-copy-from-slice-opt.rs19
-rw-r--r--src/test/debuginfo/msvc-pretty-enums.rs6
-rw-r--r--src/test/incremental/issue-100521-change-struct-name-assocty.rs65
-rw-r--r--src/test/mir-opt/array-index-is-temporary.rs2
-rw-r--r--src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir64
-rw-r--r--src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir (renamed from src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir)0
-rw-r--r--src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir16
-rw-r--r--src/test/mir-opt/inline/inline-into-box-place.rs2
-rw-r--r--src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff82
-rw-r--r--src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff (renamed from src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff)0
-rw-r--r--src/test/mir-opt/issue-41697.rs2
-rw-r--r--src/test/mir-opt/issue-72181.rs4
-rw-r--r--src/test/mir-opt/issue-73223.rs2
-rw-r--r--src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir20
-rw-r--r--src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.mir (renamed from src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.32bit.mir)0
-rw-r--r--src/test/mir-opt/issue_72181.bar.mir_map.0.64bit.mir17
-rw-r--r--src/test/mir-opt/issue_72181.bar.mir_map.0.mir (renamed from src/test/mir-opt/issue_72181.bar.mir_map.0.32bit.mir)0
-rw-r--r--src/test/mir-opt/issue_72181.foo.mir_map.0.64bit.mir27
-rw-r--r--src/test/mir-opt/issue_72181.foo.mir_map.0.mir (renamed from src/test/mir-opt/issue_72181.foo.mir_map.0.32bit.mir)0
-rw-r--r--src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir62
-rw-r--r--src/test/mir-opt/issue_72181.main.mir_map.0.mir (renamed from src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir)0
-rw-r--r--src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff161
-rw-r--r--src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff (renamed from src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff)0
-rw-r--r--src/test/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff26
-rw-r--r--src/test/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff72
-rw-r--r--src/test/mir-opt/lower_intrinsics.rs23
-rw-r--r--src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff88
-rw-r--r--src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff (renamed from src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff)0
-rw-r--r--src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff55
-rw-r--r--src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff (renamed from src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff)0
-rw-r--r--src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff113
-rw-r--r--src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.diff (renamed from src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff)0
-rw-r--r--src/test/mir-opt/matches_reduce_branches.rs2
-rw-r--r--src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.64bit.diff32
-rw-r--r--src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff (renamed from src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.32bit.diff)0
-rw-r--r--src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.64bit.diff32
-rw-r--r--src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff (renamed from src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.32bit.diff)0
-rw-r--r--src/test/mir-opt/matches_u8.rs2
-rw-r--r--src/test/mir-opt/packed-struct-drop-aligned.rs2
-rw-r--r--src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.64bit.mir60
-rw-r--r--src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir (renamed from src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.32bit.mir)0
-rw-r--r--src/test/mir-opt/separate_const_switch.identity.ConstProp.diff146
-rw-r--r--src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir124
-rw-r--r--src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff103
-rw-r--r--src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir73
-rw-r--r--src/test/mir-opt/simple-match.rs2
-rw-r--r--src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir29
-rw-r--r--src/test/mir-opt/simple_match.match_bool.mir_map.0.mir (renamed from src/test/mir-opt/simple_match.match_bool.mir_map.0.32bit.mir)0
-rw-r--r--src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs1
-rw-r--r--src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff52
-rw-r--r--src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff (renamed from src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff)0
-rw-r--r--src/test/mir-opt/slice-drop-shim.rs2
-rw-r--r--src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.64bit.mir101
-rw-r--r--src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir (renamed from src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.32bit.mir)0
-rw-r--r--src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir8
-rw-r--r--src/test/mir-opt/unusual-item-types.rs2
-rw-r--r--src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.64bit.mir10
-rw-r--r--src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.mir (renamed from src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.32bit.mir)0
-rw-r--r--src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir12
-rw-r--r--src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.mir (renamed from src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir)0
-rw-r--r--src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir39
-rw-r--r--src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir (renamed from src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir)0
-rw-r--r--src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir10
-rw-r--r--src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.mir (renamed from src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir)0
-rw-r--r--src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.64bit.diff55
-rw-r--r--src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff (renamed from src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.32bit.diff)0
-rw-r--r--src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir17
-rw-r--r--src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir (renamed from src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.32bit.mir)0
-rw-r--r--src/test/mir-opt/while_let_loops.rs1
-rw-r--r--src/test/run-make/issue-71519/Makefile1
-rw-r--r--src/test/run-make/track-pgo-dep-info/Makefile26
-rw-r--r--src/test/run-make/track-pgo-dep-info/main.rs1
-rw-r--r--src/test/rustdoc-json/enums/field_hidden.rs (renamed from src/test/rustdoc-json/enum_variant_hidden.rs)2
-rw-r--r--src/test/rustdoc-json/enums/kind.rs37
-rw-r--r--src/test/rustdoc-json/enums/struct_field_hidden.rs17
-rw-r--r--src/test/rustdoc-json/enums/tuple_fields_hidden.rs94
-rw-r--r--src/test/rustdoc-json/nested.rs2
-rw-r--r--src/test/rustdoc-json/structs/plain_all_pub.rs11
-rw-r--r--src/test/rustdoc-json/structs/plain_doc_hidden.rs11
-rw-r--r--src/test/rustdoc-json/structs/plain_empty.rs9
-rw-r--r--src/test/rustdoc-json/structs/plain_pub_priv.rs9
-rw-r--r--src/test/rustdoc-json/structs/tuple.rs7
-rw-r--r--src/test/rustdoc-json/structs/tuple_empty.rs2
-rw-r--r--src/test/rustdoc-json/structs/tuple_pub_priv.rs13
-rw-r--r--src/test/rustdoc-json/structs/unit.rs7
-rw-r--r--src/test/rustdoc-json/structs/with_generics.rs16
-rw-r--r--src/test/rustdoc-json/structs/with_primitives.rs12
-rw-r--r--src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs2
-rw-r--r--src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs6
-rw-r--r--src/test/ui-fulldeps/auxiliary/lint-for-crate.rs2
-rw-r--r--src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs2
-rw-r--r--src/test/ui-fulldeps/internal-lints/diagnostics.rs24
-rw-r--r--src/test/ui-fulldeps/internal-lints/diagnostics.stderr26
-rw-r--r--src/test/ui/asm/aarch64/type-check-3.stderr40
-rw-r--r--src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr4
-rw-r--r--src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr4
-rw-r--r--src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr4
-rw-r--r--src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr4
-rw-r--r--src/test/ui/asm/x86_64/type-check-3.stderr16
-rw-r--r--src/test/ui/associated-types/issue-62200.rs3
-rw-r--r--src/test/ui/associated-types/issue-62200.stderr3
-rw-r--r--src/test/ui/attributes/issue-100631.rs8
-rw-r--r--src/test/ui/attributes/issue-100631.stderr12
-rw-r--r--src/test/ui/binop/binary-op-on-double-ref.stderr2
-rw-r--r--src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr30
-rw-r--r--src/test/ui/borrowck/borrowck-describe-lvalue.stderr8
-rw-r--r--src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr6
-rw-r--r--src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr6
-rw-r--r--src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr10
-rw-r--r--src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr6
-rw-r--r--src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr20
-rw-r--r--src/test/ui/borrowck/borrowck-move-out-from-array.stderr16
-rw-r--r--src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr8
-rw-r--r--src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr8
-rw-r--r--src/test/ui/borrowck/borrowck-vec-pattern-move-tail.stderr2
-rw-r--r--src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr2
-rw-r--r--src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.rs2
-rw-r--r--src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr8
-rw-r--r--src/test/ui/closures/issue-52437.rs1
-rw-r--r--src/test/ui/closures/issue-52437.stderr13
-rw-r--r--src/test/ui/empty/empty-never-array.rs2
-rw-r--r--src/test/ui/empty/empty-never-array.stderr4
-rw-r--r--src/test/ui/error-codes/E0004.stderr6
-rw-r--r--src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs2
-rw-r--r--src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr6
-rw-r--r--src/test/ui/generic-associated-types/missing-bounds.fixed2
-rw-r--r--src/test/ui/generic-associated-types/missing-bounds.stderr4
-rw-r--r--src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2015.stderr9
-rw-r--r--src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr22
-rw-r--r--src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs12
-rw-r--r--src/test/ui/issue-94866.stderr6
-rw-r--r--src/test/ui/issues/issue-41139.stderr4
-rw-r--r--src/test/ui/issues/issue-43988.stderr4
-rw-r--r--src/test/ui/issues/issue-47511.stderr3
-rw-r--r--src/test/ui/issues/issue-66706.rs3
-rw-r--r--src/test/ui/issues/issue-66706.stderr35
-rw-r--r--src/test/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr4
-rw-r--r--src/test/ui/layout/zero-sized-array-enum-niche.stderr2
-rw-r--r--src/test/ui/let-else/let-else-drop-order.rs270
-rw-r--r--src/test/ui/let-else/let-else-drop-order.run.stdout51
-rw-r--r--src/test/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.rs9
-rw-r--r--src/test/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.stderr23
-rw-r--r--src/test/ui/match/match_non_exhaustive.rs2
-rw-r--r--src/test/ui/match/match_non_exhaustive.stderr8
-rw-r--r--src/test/ui/moves/move-out-of-array-ref.stderr4
-rw-r--r--src/test/ui/moves/move-out-of-slice-2.stderr8
-rw-r--r--src/test/ui/nll/issue-51244.stderr2
-rw-r--r--src/test/ui/parser/do-not-suggest-semicolon-before-array.rs (renamed from src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.rs)0
-rw-r--r--src/test/ui/parser/do-not-suggest-semicolon-before-array.stderr (renamed from src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.stderr)2
-rw-r--r--src/test/ui/parser/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.rs3
-rw-r--r--src/test/ui/parser/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.stderr8
-rw-r--r--src/test/ui/parser/issue-101477-enum.fixed10
-rw-r--r--src/test/ui/parser/issue-101477-enum.rs10
-rw-r--r--src/test/ui/parser/issue-101477-enum.stderr14
-rw-r--r--src/test/ui/parser/issue-101477-let.fixed6
-rw-r--r--src/test/ui/parser/issue-101477-let.rs6
-rw-r--r--src/test/ui/parser/issue-101477-let.stderr8
-rw-r--r--src/test/ui/parser/recover-field-semi.rs16
-rw-r--r--src/test/ui/parser/recover-field-semi.stderr29
-rw-r--r--src/test/ui/parser/removed-syntax-field-semicolon.rs2
-rw-r--r--src/test/ui/parser/removed-syntax-field-semicolon.stderr4
-rw-r--r--src/test/ui/parser/suggest-semicolon-before-array.fixed (renamed from src/test/ui/parser/suggest-suggest-semicolon-before-array.fixed)0
-rw-r--r--src/test/ui/parser/suggest-semicolon-before-array.rs (renamed from src/test/ui/parser/suggest-suggest-semicolon-before-array.rs)0
-rw-r--r--src/test/ui/parser/suggest-semicolon-before-array.stderr (renamed from src/test/ui/parser/suggest-suggest-semicolon-before-array.stderr)2
-rw-r--r--src/test/ui/parser/unnecessary-let.rs11
-rw-r--r--src/test/ui/parser/unnecessary-let.stderr20
-rw-r--r--src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr10
-rw-r--r--src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr5
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr34
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr30
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr40
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr49
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr42
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr32
-rw-r--r--src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr5
-rw-r--r--src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr2
-rw-r--r--src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr2
-rw-r--r--src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr6
-rw-r--r--src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs8
-rw-r--r--src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr24
-rw-r--r--src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr28
-rw-r--r--src/test/ui/pattern/usefulness/empty-match.normal.stderr28
-rw-r--r--src/test/ui/pattern/usefulness/empty-match.rs12
-rw-r--r--src/test/ui/pattern/usefulness/issue-15129.rs2
-rw-r--r--src/test/ui/pattern/usefulness/issue-15129.stderr6
-rw-r--r--src/test/ui/pattern/usefulness/issue-31561.rs2
-rw-r--r--src/test/ui/pattern/usefulness/issue-31561.stderr4
-rw-r--r--src/test/ui/pattern/usefulness/issue-35609.stderr32
-rw-r--r--src/test/ui/pattern/usefulness/issue-39362.stderr4
-rw-r--r--src/test/ui/pattern/usefulness/issue-40221.stderr6
-rw-r--r--src/test/ui/pattern/usefulness/issue-50900.rs2
-rw-r--r--src/test/ui/pattern/usefulness/issue-50900.stderr6
-rw-r--r--src/test/ui/pattern/usefulness/issue-56379.rs2
-rw-r--r--src/test/ui/pattern/usefulness/issue-56379.stderr6
-rw-r--r--src/test/ui/pattern/usefulness/issue-72377.rs2
-rw-r--r--src/test/ui/pattern/usefulness/issue-72377.stderr4
-rw-r--r--src/test/ui/pattern/usefulness/match-arm-statics-2.rs4
-rw-r--r--src/test/ui/pattern/usefulness/match-arm-statics-2.stderr12
-rw-r--r--src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs32
-rw-r--r--src/test/ui/pattern/usefulness/non-exhaustive-defined-here.stderr40
-rw-r--r--src/test/ui/pattern/usefulness/non-exhaustive-match-nested.rs2
-rw-r--r--src/test/ui/pattern/usefulness/non-exhaustive-match-nested.stderr6
-rw-r--r--src/test/ui/pattern/usefulness/non-exhaustive-match.rs6
-rw-r--r--src/test/ui/pattern/usefulness/non-exhaustive-match.stderr20
-rw-r--r--src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.rs10
-rw-r--r--src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr28
-rw-r--r--src/test/ui/pattern/usefulness/stable-gated-patterns.rs2
-rw-r--r--src/test/ui/pattern/usefulness/stable-gated-patterns.stderr6
-rw-r--r--src/test/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr6
-rw-r--r--src/test/ui/pattern/usefulness/unstable-gated-patterns.rs2
-rw-r--r--src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr6
-rw-r--r--src/test/ui/repr/invalid_repr_list_help.rs17
-rw-r--r--src/test/ui/repr/invalid_repr_list_help.stderr35
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.rs4
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr12
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr16
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr2
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr6
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr6
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr6
-rw-r--r--src/test/ui/sanitize/memory-eager.rs38
-rw-r--r--src/test/ui/sanitize/memory.rs11
-rw-r--r--src/test/ui/stats/hir-stats.rs1
-rw-r--r--src/test/ui/stats/hir-stats.stderr105
-rw-r--r--src/test/ui/structs-enums/type-sizes.rs79
-rw-r--r--src/test/ui/suggestions/issue-101421.rs12
-rw-r--r--src/test/ui/suggestions/issue-101421.stderr17
-rw-r--r--src/test/ui/suggestions/issue-97677.fixed2
-rw-r--r--src/test/ui/suggestions/issue-97677.stderr4
-rw-r--r--src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr4
-rw-r--r--src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr18
-rw-r--r--src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.rs18
-rw-r--r--src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr24
-rw-r--r--src/test/ui/suggestions/restrict-type-not-param.rs12
-rw-r--r--src/test/ui/suggestions/restrict-type-not-param.stderr26
-rw-r--r--src/test/ui/traits/resolution-in-overloaded-op.stderr4
-rw-r--r--src/test/ui/type-alias-impl-trait/constrain_inputs.rs24
-rw-r--r--src/test/ui/type-alias-impl-trait/constrain_inputs.stderr58
-rw-r--r--src/test/ui/type-alias-impl-trait/constrain_inputs_unsound.rs31
-rw-r--r--src/test/ui/type-alias-impl-trait/constrain_inputs_unsound.stderr9
-rw-r--r--src/test/ui/typeck/assign-non-lval-derefmut.stderr4
-rw-r--r--src/test/ui/typeck/assign-non-lval-mut-ref.stderr4
-rw-r--r--src/test/ui/typeck/point-at-type-param-in-path-expr.rs6
-rw-r--r--src/test/ui/typeck/point-at-type-param-in-path-expr.stderr17
-rw-r--r--src/test/ui/uninhabited/uninhabited-irrefutable.rs2
-rw-r--r--src/test/ui/uninhabited/uninhabited-irrefutable.stderr4
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/book/src/development/common_tools_writing_lints.md2
-rw-r--r--src/tools/clippy/clippy_dev/src/new_lint.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/booleans.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/default.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs87
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/doc.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/entry.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/equatable_if_let.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/explicit_write.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/fallible_impl_from.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs79
-rw-r--r--src/tools/clippy/clippy_lints/src/format_args.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/format_impl.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/format_push_string.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/must_use.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/if_let_mutex.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/index_refutable_slice.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/infinite_iter.rs108
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/let_if_seq.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs414
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_find.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/needless_collect.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/never_loop.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/same_item_push.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_bits.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_retain.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_string_new.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_strip.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/map_unit_fn.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/match_result_ok.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_map.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/needless_match.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/single_match.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bytecount.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_clone.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs102
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/open_options.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/single_char_add_str.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs58
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/str_splitn.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/utils.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/minmax.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/misc.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/redundant_pattern.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_reference.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_for_each.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_late_init.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/float_cmp.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/op_ref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/option_if_let_else.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/ref_option_ref.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/strings.rs28
-rw-r--r--src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/to_digit_is_some.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/trait_bounds.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/uninit_vec.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs39
-rw-r--r--src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_io_amount.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_peekable.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap_in_result.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/useless_conversion.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/vec_init_then_push.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/check_proc_macro.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/diagnostics.rs8
-rw-r--r--src/tools/clippy/clippy_utils/src/eager_or_lazy.rs18
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs26
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs31
-rw-r--r--src/tools/clippy/clippy_utils/src/ptr.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs11
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs24
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs8
-rw-r--r--src/tools/clippy/tests/ui/author.stdout2
-rw-r--r--src/tools/clippy/tests/ui/author/blocks.stdout6
-rw-r--r--src/tools/clippy/tests/ui/author/loop.stdout4
-rw-r--r--src/tools/clippy/tests/ui/author/matches.stdout4
-rw-r--r--src/tools/clippy/tests/ui/author/struct.stdout6
-rw-r--r--src/tools/compiletest/src/header.rs18
-rw-r--r--src/tools/lld-wrapper/src/main.rs12
m---------src/tools/miri14
-rw-r--r--src/tools/rust-analyzer/.github/workflows/ci.yaml156
-rw-r--r--src/tools/rust-analyzer/.github/workflows/release.yaml4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body.rs19
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs135
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs34
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs24
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/resolver.rs253
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/name.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/usefulness.rs29
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs33
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs187
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs173
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lib.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower.rs57
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs92
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/diagnostics.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs294
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs115
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_or_with_or_else.rs364
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs160
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs293
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/lib.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs86
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs24
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs38
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs120
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs44
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs130
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rast43
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs1
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs12
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs4
-rw-r--r--src/tools/rust-analyzer/crates/syntax/rust.ungram1
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs415
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/make.rs263
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs21
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs27
-rw-r--r--src/tools/rust-analyzer/lib/la-arena/src/lib.rs37
-rw-r--r--src/tools/rustfmt/src/patterns.rs12
-rw-r--r--src/tools/tidy/src/features.rs3
-rw-r--r--triagebot.toml3
706 files changed, 10176 insertions, 6897 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 0f1f16cbce2..90bcc2e4be4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -577,9 +577,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "3.2.5"
+version = "3.2.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d53da17d37dba964b9b3ecb5c5a1f193a2762c700e6829201e645b9381c99dc7"
+checksum = "23b71c3ce99b7611011217b366d923f1d0a7e07a92bb2dbf1e84508c673ca3bd"
 dependencies = [
  "atty",
  "bitflags",
@@ -603,9 +603,9 @@ dependencies = [
 
 [[package]]
 name = "clap_derive"
-version = "3.2.5"
+version = "3.2.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c11d40217d16aee8508cc8e5fde8b4ff24639758608e5374e731b53f85749fb9"
+checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65"
 dependencies = [
  "heck",
  "proc-macro-error",
@@ -3958,6 +3958,7 @@ dependencies = [
  "rustc_session",
  "rustc_span",
  "rustc_target",
+ "rustc_type_ir",
  "smallvec",
  "thin-vec",
  "tracing",
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 097a59d027b..e38572f609b 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -594,7 +594,7 @@ impl Pat {
             // In a type expression `_` is an inference variable.
             PatKind::Wild => TyKind::Infer,
             // An IDENT pattern with no binding mode would be valid as path to a type. E.g. `u32`.
-            PatKind::Ident(BindingMode::ByValue(Mutability::Not), ident, None) => {
+            PatKind::Ident(BindingAnnotation::NONE, ident, None) => {
                 TyKind::Path(None, Path::from_ident(*ident))
             }
             PatKind::Path(qself, path) => TyKind::Path(qself.clone(), path.clone()),
@@ -681,10 +681,43 @@ pub struct PatField {
     pub is_placeholder: bool,
 }
 
-#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy)]
-pub enum BindingMode {
-    ByRef(Mutability),
-    ByValue(Mutability),
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+#[derive(Encodable, Decodable, HashStable_Generic)]
+pub enum ByRef {
+    Yes,
+    No,
+}
+
+impl From<bool> for ByRef {
+    fn from(b: bool) -> ByRef {
+        match b {
+            false => ByRef::No,
+            true => ByRef::Yes,
+        }
+    }
+}
+
+/// Explicit binding annotations given in the HIR for a binding. Note
+/// that this is not the final binding *mode* that we infer after type
+/// inference.
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+#[derive(Encodable, Decodable, HashStable_Generic)]
+pub struct BindingAnnotation(pub ByRef, pub Mutability);
+
+impl BindingAnnotation {
+    pub const NONE: Self = Self(ByRef::No, Mutability::Not);
+    pub const REF: Self = Self(ByRef::Yes, Mutability::Not);
+    pub const MUT: Self = Self(ByRef::No, Mutability::Mut);
+    pub const REF_MUT: Self = Self(ByRef::Yes, Mutability::Mut);
+
+    pub fn prefix_str(self) -> &'static str {
+        match self {
+            Self::NONE => "",
+            Self::REF => "ref ",
+            Self::MUT => "mut ",
+            Self::REF_MUT => "ref mut ",
+        }
+    }
 }
 
 #[derive(Clone, Encodable, Decodable, Debug)]
@@ -713,7 +746,7 @@ pub enum PatKind {
     /// or a unit struct/variant pattern, or a const pattern (in the last two cases the third
     /// field must be `None`). Disambiguation cannot be done with parser alone, so it happens
     /// during name resolution.
-    Ident(BindingMode, Ident, Option<P<Pat>>),
+    Ident(BindingAnnotation, Ident, Option<P<Pat>>),
 
     /// A struct or struct variant pattern (e.g., `Variant {x, y, ..}`).
     /// The `bool` is `true` in the presence of a `..`.
@@ -2228,7 +2261,7 @@ pub type ExplicitSelf = Spanned<SelfKind>;
 impl Param {
     /// Attempts to cast parameter to `ExplicitSelf`.
     pub fn to_self(&self) -> Option<ExplicitSelf> {
-        if let PatKind::Ident(BindingMode::ByValue(mutbl), ident, _) = self.pat.kind {
+        if let PatKind::Ident(BindingAnnotation(ByRef::No, mutbl), ident, _) = self.pat.kind {
             if ident.name == kw::SelfLower {
                 return match self.ty.kind {
                     TyKind::ImplicitSelf => Some(respan(self.pat.span, SelfKind::Value(mutbl))),
@@ -2258,11 +2291,24 @@ impl Param {
     pub fn from_self(attrs: AttrVec, eself: ExplicitSelf, eself_ident: Ident) -> Param {
         let span = eself.span.to(eself_ident.span);
         let infer_ty = P(Ty { id: DUMMY_NODE_ID, kind: TyKind::ImplicitSelf, span, tokens: None });
-        let param = |mutbl, ty| Param {
+        let (mutbl, ty) = match eself.node {
+            SelfKind::Explicit(ty, mutbl) => (mutbl, ty),
+            SelfKind::Value(mutbl) => (mutbl, infer_ty),
+            SelfKind::Region(lt, mutbl) => (
+                Mutability::Not,
+                P(Ty {
+                    id: DUMMY_NODE_ID,
+                    kind: TyKind::Rptr(lt, MutTy { ty: infer_ty, mutbl }),
+                    span,
+                    tokens: None,
+                }),
+            ),
+        };
+        Param {
             attrs,
             pat: P(Pat {
                 id: DUMMY_NODE_ID,
-                kind: PatKind::Ident(BindingMode::ByValue(mutbl), eself_ident, None),
+                kind: PatKind::Ident(BindingAnnotation(ByRef::No, mutbl), eself_ident, None),
                 span,
                 tokens: None,
             }),
@@ -2270,19 +2316,6 @@ impl Param {
             ty,
             id: DUMMY_NODE_ID,
             is_placeholder: false,
-        };
-        match eself.node {
-            SelfKind::Explicit(ty, mutbl) => param(mutbl, ty),
-            SelfKind::Value(mutbl) => param(mutbl, infer_ty),
-            SelfKind::Region(lt, mutbl) => param(
-                Mutability::Not,
-                P(Ty {
-                    id: DUMMY_NODE_ID,
-                    kind: TyKind::Rptr(lt, MutTy { ty: infer_ty, mutbl }),
-                    span,
-                    tokens: None,
-                }),
-            ),
         }
     }
 }
@@ -3042,7 +3075,8 @@ mod size_asserts {
     static_assert_size!(Block, 48);
     static_assert_size!(Expr, 104);
     static_assert_size!(ExprKind, 72);
-    static_assert_size!(Fn, 192);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(Fn, 184);
     static_assert_size!(ForeignItem, 96);
     static_assert_size!(ForeignItemKind, 24);
     static_assert_size!(GenericArg, 24);
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 5b72ec2b601..6b0dac7c2f0 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -232,6 +232,8 @@ impl AttrItem {
 }
 
 impl Attribute {
+    /// Returns `true` if it is a sugared doc comment (`///` or `//!` for example).
+    /// So `#[doc = "doc"]` will return `false`.
     pub fn is_doc_comment(&self) -> bool {
         match self.kind {
             AttrKind::Normal(..) => false,
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index dd98946b4cc..bfc4db32d37 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -398,6 +398,30 @@ impl Token {
         }
     }
 
+    /// Returns `true` if the token can appear at the start of an pattern.
+    ///
+    /// Shamelessly borrowed from `can_begin_expr`, only used for diagnostics right now.
+    pub fn can_begin_pattern(&self) -> bool {
+        match self.uninterpolate().kind {
+            Ident(name, is_raw)              =>
+                ident_can_begin_expr(name, self.span, is_raw), // value name or keyword
+            | OpenDelim(Delimiter::Bracket | Delimiter::Parenthesis)  // tuple or array
+            | Literal(..)                        // literal
+            | BinOp(Minus)                       // unary minus
+            | BinOp(And)                         // reference
+            | AndAnd                             // double reference
+            // DotDotDot is no longer supported
+            | DotDot | DotDotDot | DotDotEq      // ranges
+            | Lt | BinOp(Shl)                    // associated path
+            | ModSep                    => true, // global path
+            Interpolated(ref nt) => matches!(**nt, NtLiteral(..) |
+                NtPat(..)     |
+                NtBlock(..)   |
+                NtPath(..)),
+            _ => false,
+        }
+    }
+
     /// Returns `true` if the token can appear at the start of a type.
     pub fn can_begin_type(&self) -> bool {
         match self.uninterpolate().kind {
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs
index b0e9fe0469c..90bb01aa216 100644
--- a/compiler/rustc_ast_lowering/src/asm.rs
+++ b/compiler/rustc_ast_lowering/src/asm.rs
@@ -220,7 +220,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                                 &sym.qself,
                                 &sym.path,
                                 ParamMode::Optional,
-                                ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                                &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                             );
                             hir::InlineAsmOperand::SymStatic { path, def_id }
                         } else {
diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs
index 7cbfe143b4d..7465706d1a9 100644
--- a/compiler/rustc_ast_lowering/src/block.rs
+++ b/compiler/rustc_ast_lowering/src/block.rs
@@ -84,10 +84,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     }
 
     fn lower_local(&mut self, l: &Local) -> &'hir hir::Local<'hir> {
-        let ty = l
-            .ty
-            .as_ref()
-            .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Variable)));
+        let ty = l.ty.as_ref().map(|t| {
+            self.lower_ty(t, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Variable))
+        });
         let init = l.kind.init().map(|init| self.lower_expr(init));
         let hir_id = self.lower_node_id(l.id);
         let pat = self.lower_pat(&l.pat);
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 7df3520422c..5346f1ced82 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -66,12 +66,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         seg,
                         ParamMode::Optional,
                         ParenthesizedGenericArgs::Err,
-                        ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                        &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                     ));
-                    let args = self.arena.alloc_from_iter(
-                        [&*receiver].into_iter().chain(args.iter()).map(|x| self.lower_expr_mut(x)),
-                    );
-                    hir::ExprKind::MethodCall(hir_seg, args, self.lower_span(span))
+                    let receiver = self.lower_expr(receiver);
+                    let args =
+                        self.arena.alloc_from_iter(args.iter().map(|x| self.lower_expr_mut(x)));
+                    hir::ExprKind::MethodCall(hir_seg, receiver, args, self.lower_span(span))
                 }
                 ExprKind::Binary(binop, ref lhs, ref rhs) => {
                     let binop = self.lower_binop(binop);
@@ -89,14 +89,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 }
                 ExprKind::Cast(ref expr, ref ty) => {
                     let expr = self.lower_expr(expr);
-                    let ty =
-                        self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+                    let ty = self
+                        .lower_ty(ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type));
                     hir::ExprKind::Cast(expr, ty)
                 }
                 ExprKind::Type(ref expr, ref ty) => {
                     let expr = self.lower_expr(expr);
-                    let ty =
-                        self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+                    let ty = self
+                        .lower_ty(ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type));
                     hir::ExprKind::Type(expr, ty)
                 }
                 ExprKind::AddrOf(k, m, ref ohs) => {
@@ -219,7 +219,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         qself,
                         path,
                         ParamMode::Optional,
-                        ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                        &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                     );
                     hir::ExprKind::Path(qpath)
                 }
@@ -253,7 +253,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                             &se.qself,
                             &se.path,
                             ParamMode::Optional,
-                            ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                            &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                         )),
                         self.arena
                             .alloc_from_iter(se.fields.iter().map(|x| self.lower_expr_field(x))),
@@ -550,12 +550,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
         async_gen_kind: hir::AsyncGeneratorKind,
         body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
     ) -> hir::ExprKind<'hir> {
-        let output = match ret_ty {
-            Some(ty) => hir::FnRetTy::Return(
-                self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock)),
-            ),
-            None => hir::FnRetTy::DefaultReturn(self.lower_span(span)),
-        };
+        let output =
+            match ret_ty {
+                Some(ty) => hir::FnRetTy::Return(self.lower_ty(
+                    &ty,
+                    &mut ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock),
+                )),
+                None => hir::FnRetTy::DefaultReturn(self.lower_span(span)),
+            };
 
         // Resume argument type. We let the compiler infer this to simplify the lowering. It is
         // fully constrained by `future::from_generator`.
@@ -577,7 +579,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let (pat, task_context_hid) = self.pat_ident_binding_mode(
             span,
             Ident::with_dummy_span(sym::_task_context),
-            hir::BindingAnnotation::Mutable,
+            hir::BindingAnnotation::MUT,
         );
         let param = hir::Param {
             hir_id: self.next_id(),
@@ -671,7 +673,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         // this name to identify what is being awaited by a suspended async functions.
         let awaitee_ident = Ident::with_dummy_span(sym::__awaitee);
         let (awaitee_pat, awaitee_pat_hid) =
-            self.pat_ident_binding_mode(span, awaitee_ident, hir::BindingAnnotation::Mutable);
+            self.pat_ident_binding_mode(span, awaitee_ident, hir::BindingAnnotation::MUT);
 
         let task_context_ident = Ident::with_dummy_span(sym::_task_context);
 
@@ -847,21 +849,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
             (body_id, generator_option)
         });
 
-        let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
-        // Lower outside new scope to preserve `is_in_loop_condition`.
-        let fn_decl = self.lower_fn_decl(decl, None, FnDeclKind::Closure, None);
-
-        let c = self.arena.alloc(hir::Closure {
-            binder: binder_clause,
-            capture_clause,
-            bound_generic_params,
-            fn_decl,
-            body: body_id,
-            fn_decl_span: self.lower_span(fn_decl_span),
-            movability: generator_option,
-        });
+        self.lower_lifetime_binder(closure_id, generic_params, |lctx, bound_generic_params| {
+            // Lower outside new scope to preserve `is_in_loop_condition`.
+            let fn_decl = lctx.lower_fn_decl(decl, None, FnDeclKind::Closure, None);
 
-        hir::ExprKind::Closure(c)
+            let c = lctx.arena.alloc(hir::Closure {
+                binder: binder_clause,
+                capture_clause,
+                bound_generic_params,
+                fn_decl,
+                body: body_id,
+                fn_decl_span: lctx.lower_span(fn_decl_span),
+                movability: generator_option,
+            });
+
+            hir::ExprKind::Closure(c)
+        })
     }
 
     fn generator_movability_for_fn(
@@ -948,23 +951,23 @@ impl<'hir> LoweringContext<'_, 'hir> {
             body_id
         });
 
-        let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
-
-        // We need to lower the declaration outside the new scope, because we
-        // have to conserve the state of being inside a loop condition for the
-        // closure argument types.
-        let fn_decl = self.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None);
-
-        let c = self.arena.alloc(hir::Closure {
-            binder: binder_clause,
-            capture_clause,
-            bound_generic_params,
-            fn_decl,
-            body,
-            fn_decl_span: self.lower_span(fn_decl_span),
-            movability: None,
-        });
-        hir::ExprKind::Closure(c)
+        self.lower_lifetime_binder(closure_id, generic_params, |lctx, bound_generic_params| {
+            // We need to lower the declaration outside the new scope, because we
+            // have to conserve the state of being inside a loop condition for the
+            // closure argument types.
+            let fn_decl = lctx.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None);
+
+            let c = lctx.arena.alloc(hir::Closure {
+                binder: binder_clause,
+                capture_clause,
+                bound_generic_params,
+                fn_decl,
+                body,
+                fn_decl_span: lctx.lower_span(fn_decl_span),
+                movability: None,
+            });
+            hir::ExprKind::Closure(c)
+        })
     }
 
     /// Destructure the LHS of complex assignments.
@@ -1123,11 +1126,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         qself,
                         path,
                         ParamMode::Optional,
-                        ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                        &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                     );
                     // Destructure like a tuple struct.
-                    let tuple_struct_pat =
-                        hir::PatKind::TupleStruct(qpath, pats, rest.map(|r| r.0));
+                    let tuple_struct_pat = hir::PatKind::TupleStruct(
+                        qpath,
+                        pats,
+                        hir::DotDotPos::new(rest.map(|r| r.0)),
+                    );
                     return self.pat_without_dbm(lhs.span, tuple_struct_pat);
                 }
             }
@@ -1139,7 +1145,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         qself,
                         path,
                         ParamMode::Optional,
-                        ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                        &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                     );
                     // Destructure like a unit struct.
                     let unit_struct_pat = hir::PatKind::Path(qpath);
@@ -1163,7 +1169,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     &se.qself,
                     &se.path,
                     ParamMode::Optional,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                    &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                 );
                 let fields_omitted = match &se.rest {
                     StructRest::Base(e) => {
@@ -1182,13 +1188,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
             ExprKind::Tup(elements) => {
                 let (pats, rest) =
                     self.destructure_sequence(elements, "tuple", eq_sign_span, assignments);
-                let tuple_pat = hir::PatKind::Tuple(pats, rest.map(|r| r.0));
+                let tuple_pat = hir::PatKind::Tuple(pats, hir::DotDotPos::new(rest.map(|r| r.0)));
                 return self.pat_without_dbm(lhs.span, tuple_pat);
             }
             ExprKind::Paren(e) => {
                 // We special-case `(..)` for consistency with patterns.
                 if let ExprKind::Range(None, None, RangeLimits::HalfOpen) = e.kind {
-                    let tuple_pat = hir::PatKind::Tuple(&[], Some(0));
+                    let tuple_pat = hir::PatKind::Tuple(&[], hir::DotDotPos::new(Some(0)));
                     return self.pat_without_dbm(lhs.span, tuple_pat);
                 } else {
                     return self.destructure_assign_mut(e, eq_sign_span, assignments);
@@ -1433,7 +1439,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         // `mut iter`
         let iter = Ident::with_dummy_span(sym::iter);
         let (iter_pat, iter_pat_nid) =
-            self.pat_ident_binding_mode(head_span, iter, hir::BindingAnnotation::Mutable);
+            self.pat_ident_binding_mode(head_span, iter, hir::BindingAnnotation::MUT);
 
         // `match Iterator::next(&mut iter) { ... }`
         let match_expr = {
@@ -1776,12 +1782,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
         binding: hir::HirId,
         attrs: AttrVec,
     ) -> hir::Expr<'hir> {
+        let hir_id = self.next_id();
+        let res = Res::Local(binding);
         let expr_path = hir::ExprKind::Path(hir::QPath::Resolved(
             None,
             self.arena.alloc(hir::Path {
                 span: self.lower_span(span),
-                res: Res::Local(binding),
-                segments: arena_vec![self; hir::PathSegment::from_ident(ident)],
+                res,
+                segments: arena_vec![self; hir::PathSegment::new(ident, hir_id, res)],
             }),
         ));
 
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index 219e1b81d1e..61470d93bdb 100644
--- a/compiler/rustc_ast_lowering/src/index.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -246,9 +246,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
     }
 
     fn visit_path_segment(&mut self, path_span: Span, path_segment: &'hir PathSegment<'hir>) {
-        if let Some(hir_id) = path_segment.hir_id {
-            self.insert(path_span, hir_id, Node::PathSegment(path_segment));
-        }
+        self.insert(path_span, path_segment.hir_id, Node::PathSegment(path_segment));
         intravisit::walk_path_segment(self, path_span, path_segment);
     }
 
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 269091c89e9..9e05fbbdc19 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1,6 +1,6 @@
 use super::errors::{InvalidAbi, MisplacedRelaxTraitBound};
 use super::ResolverAstLoweringExt;
-use super::{AstOwner, ImplTraitContext, ImplTraitPosition};
+use super::{Arena, AstOwner, ImplTraitContext, ImplTraitPosition};
 use super::{FnDeclKind, LoweringContext, ParamMode};
 
 use rustc_ast::ptr::P;
@@ -25,6 +25,7 @@ use std::iter;
 pub(super) struct ItemLowerer<'a, 'hir> {
     pub(super) tcx: TyCtxt<'hir>,
     pub(super) resolver: &'a mut ResolverAstLowering,
+    pub(super) ast_arena: &'a Arena<'static>,
     pub(super) ast_index: &'a IndexVec<LocalDefId, AstOwner<'a>>,
     pub(super) owners: &'a mut IndexVec<LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>>,
 }
@@ -60,6 +61,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
             tcx: self.tcx,
             resolver: self.resolver,
             arena: self.tcx.hir_arena,
+            ast_arena: self.ast_arena,
 
             // HirId handling.
             bodies: Vec::new(),
@@ -85,6 +87,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
             allow_try_trait: Some([sym::try_trait_v2, sym::yeet_desugar_details][..].into()),
             allow_gen_future: Some([sym::gen_future][..].into()),
             allow_into_future: Some([sym::into_future][..].into()),
+            generics_def_id_map: Default::default(),
         };
         lctx.with_hir_id_owner(owner, |lctx| f(lctx));
 
@@ -263,8 +266,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     let body_id =
                         this.lower_maybe_async_body(span, &decl, asyncness, body.as_deref());
 
-                    let itctx = ImplTraitContext::Universal;
-                    let (generics, decl) = this.lower_generics(generics, id, itctx, |this| {
+                    let mut itctx = ImplTraitContext::Universal;
+                    let (generics, decl) = this.lower_generics(generics, id, &mut itctx, |this| {
                         let ret_id = asyncness.opt_return_id();
                         this.lower_fn_decl(&decl, Some(id), FnDeclKind::Fn, ret_id)
                     });
@@ -310,8 +313,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 let (generics, ty) = self.lower_generics(
                     &generics,
                     id,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
-                    |this| this.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy),
+                    &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    |this| this.lower_ty(ty, &mut ImplTraitContext::TypeAliasesOpaqueTy),
                 );
                 hir::ItemKind::TyAlias(ty, generics)
             }
@@ -323,7 +326,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 let (generics, ty) = self.lower_generics(
                     &generics,
                     id,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| this.arena.alloc(this.ty(span, hir::TyKind::Err)),
                 );
                 hir::ItemKind::TyAlias(ty, generics)
@@ -332,7 +335,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 let (generics, variants) = self.lower_generics(
                     generics,
                     id,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| {
                         this.arena.alloc_from_iter(
                             enum_definition.variants.iter().map(|x| this.lower_variant(x)),
@@ -345,7 +348,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 let (generics, struct_def) = self.lower_generics(
                     generics,
                     id,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| this.lower_variant_data(hir_id, struct_def),
                 );
                 hir::ItemKind::Struct(struct_def, generics)
@@ -354,7 +357,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 let (generics, vdata) = self.lower_generics(
                     generics,
                     id,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| this.lower_variant_data(hir_id, vdata),
                 );
                 hir::ItemKind::Union(vdata, generics)
@@ -382,18 +385,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 // method, it will not be considered an in-band
                 // lifetime to be added, but rather a reference to a
                 // parent lifetime.
-                let itctx = ImplTraitContext::Universal;
+                let mut itctx = ImplTraitContext::Universal;
                 let (generics, (trait_ref, lowered_ty)) =
-                    self.lower_generics(ast_generics, id, itctx, |this| {
+                    self.lower_generics(ast_generics, id, &mut itctx, |this| {
                         let trait_ref = trait_ref.as_ref().map(|trait_ref| {
                             this.lower_trait_ref(
                                 trait_ref,
-                                ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
+                                &mut ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
                             )
                         });
 
-                        let lowered_ty = this
-                            .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+                        let lowered_ty = this.lower_ty(
+                            ty,
+                            &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type),
+                        );
 
                         (trait_ref, lowered_ty)
                     });
@@ -432,11 +437,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 let (generics, (unsafety, items, bounds)) = self.lower_generics(
                     generics,
                     id,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| {
                         let bounds = this.lower_param_bounds(
                             bounds,
-                            ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+                            &mut ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
                         );
                         let items = this.arena.alloc_from_iter(
                             items.iter().map(|item| this.lower_trait_item_ref(item)),
@@ -451,11 +456,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 let (generics, bounds) = self.lower_generics(
                     generics,
                     id,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| {
                         this.lower_param_bounds(
                             bounds,
-                            ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+                            &mut ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
                         )
                     },
                 );
@@ -478,7 +483,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         span: Span,
         body: Option<&Expr>,
     ) -> (&'hir hir::Ty<'hir>, hir::BodyId) {
-        let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+        let ty = self.lower_ty(ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type));
         (ty, self.lower_const_body(span, body))
     }
 
@@ -651,9 +656,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
             kind: match i.kind {
                 ForeignItemKind::Fn(box Fn { ref sig, ref generics, .. }) => {
                     let fdec = &sig.decl;
-                    let itctx = ImplTraitContext::Universal;
+                    let mut itctx = ImplTraitContext::Universal;
                     let (generics, (fn_dec, fn_args)) =
-                        self.lower_generics(generics, i.id, itctx, |this| {
+                        self.lower_generics(generics, i.id, &mut itctx, |this| {
                             (
                                 // Disallow `impl Trait` in foreign items.
                                 this.lower_fn_decl(fdec, None, FnDeclKind::ExternFn, None),
@@ -664,8 +669,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     hir::ForeignItemKind::Fn(fn_dec, fn_args, generics)
                 }
                 ForeignItemKind::Static(ref t, m, _) => {
-                    let ty =
-                        self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+                    let ty = self
+                        .lower_ty(t, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type));
                     hir::ForeignItemKind::Static(ty, m)
                 }
                 ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type,
@@ -733,11 +738,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 qself,
                 path,
                 ParamMode::ExplicitNamed, // no `'_` in declarations (Issue #61124)
-                ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
             );
             self.arena.alloc(t)
         } else {
-            self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
+            self.lower_ty(&f.ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type))
         };
         let hir_id = self.lower_node_id(f.id);
         self.lower_attrs(hir_id, &f.attrs);
@@ -760,7 +765,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
         let (generics, kind, has_default) = match i.kind {
             AssocItemKind::Const(_, ref ty, ref default) => {
-                let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+                let ty =
+                    self.lower_ty(ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type));
                 let body = default.as_ref().map(|x| self.lower_const_body(i.span, Some(x)));
                 (hir::Generics::empty(), hir::TraitItemKind::Const(ty, body), body.is_some())
             }
@@ -795,15 +801,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 let (generics, kind) = self.lower_generics(
                     &generics,
                     i.id,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| {
                         let ty = ty.as_ref().map(|x| {
-                            this.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
+                            this.lower_ty(
+                                x,
+                                &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type),
+                            )
                         });
                         hir::TraitItemKind::Type(
                             this.lower_param_bounds(
                                 bounds,
-                                ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                                &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                             ),
                             ty,
                         )
@@ -856,7 +865,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
         let (generics, kind) = match &i.kind {
             AssocItemKind::Const(_, ty, expr) => {
-                let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+                let ty =
+                    self.lower_ty(ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type));
                 (
                     hir::Generics::empty(),
                     hir::ImplItemKind::Const(ty, self.lower_const_body(i.span, expr.as_deref())),
@@ -883,14 +893,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 self.lower_generics(
                     &generics,
                     i.id,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
+                    &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| match ty {
                         None => {
                             let ty = this.arena.alloc(this.ty(i.span, hir::TyKind::Err));
                             hir::ImplItemKind::TyAlias(ty)
                         }
                         Some(ty) => {
-                            let ty = this.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy);
+                            let ty = this.lower_ty(ty, &mut ImplTraitContext::TypeAliasesOpaqueTy);
                             hir::ImplItemKind::TyAlias(ty)
                         }
                     },
@@ -1082,12 +1092,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 // Check if this is a binding pattern, if so, we can optimize and avoid adding a
                 // `let <pat> = __argN;` statement. In this case, we do not rename the parameter.
                 let (ident, is_simple_parameter) = match parameter.pat.kind {
-                    hir::PatKind::Binding(
-                        hir::BindingAnnotation::Unannotated | hir::BindingAnnotation::Mutable,
-                        _,
-                        ident,
-                        _,
-                    ) => (ident, true),
+                    hir::PatKind::Binding(hir::BindingAnnotation(ByRef::No, _), _, ident, _) => {
+                        (ident, true)
+                    }
                     // For `ref mut` or wildcard arguments, we can't reuse the binding, but
                     // we can keep the same name for the parameter.
                     // This lets rustdoc render it correctly in documentation.
@@ -1152,7 +1159,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     let (move_pat, move_id) = this.pat_ident_binding_mode(
                         desugared_span,
                         ident,
-                        hir::BindingAnnotation::Mutable,
+                        hir::BindingAnnotation::MUT,
                     );
                     let move_expr = this.expr_ident(desugared_span, ident, new_parameter_id);
                     let move_stmt = this.stmt_let_pat(
@@ -1236,8 +1243,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
         is_async: Option<NodeId>,
     ) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
         let header = self.lower_fn_header(sig.header);
-        let itctx = ImplTraitContext::Universal;
-        let (generics, decl) = self.lower_generics(generics, id, itctx, |this| {
+        let mut itctx = ImplTraitContext::Universal;
+        let (generics, decl) = self.lower_generics(generics, id, &mut itctx, |this| {
             this.lower_fn_decl(&sig.decl, Some(id), kind, is_async)
         });
         (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
@@ -1303,7 +1310,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         &mut self,
         generics: &Generics,
         parent_node_id: NodeId,
-        itctx: ImplTraitContext,
+        itctx: &mut ImplTraitContext,
         f: impl FnOnce(&mut Self) -> T,
     ) -> (&'hir hir::Generics<'hir>, T) {
         debug_assert!(self.impl_trait_defs.is_empty());
@@ -1408,7 +1415,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         id: NodeId,
         kind: &GenericParamKind,
         bounds: &[GenericBound],
-        itctx: ImplTraitContext,
+        itctx: &mut ImplTraitContext,
         origin: PredicateOrigin,
     ) -> Option<hir::WherePredicate<'hir>> {
         // Do not create a clause if we do not have anything inside it.
@@ -1439,10 +1446,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
             GenericParamKind::Const { .. } => None,
             GenericParamKind::Type { .. } => {
                 let def_id = self.local_def_id(id).to_def_id();
+                let hir_id = self.next_id();
+                let res = Res::Def(DefKind::TyParam, def_id);
                 let ty_path = self.arena.alloc(hir::Path {
                     span: param_span,
-                    res: Res::Def(DefKind::TyParam, def_id),
-                    segments: self.arena.alloc_from_iter([hir::PathSegment::from_ident(ident)]),
+                    res,
+                    segments: self
+                        .arena
+                        .alloc_from_iter([hir::PathSegment::new(ident, hir_id, res)]),
                 });
                 let ty_id = self.next_id();
                 let bounded_ty =
@@ -1479,12 +1490,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 span,
             }) => hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
                 bound_generic_params: self.lower_generic_params(bound_generic_params),
-                bounded_ty: self
-                    .lower_ty(bounded_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
+                bounded_ty: self.lower_ty(
+                    bounded_ty,
+                    &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type),
+                ),
                 bounds: self.arena.alloc_from_iter(bounds.iter().map(|bound| {
                     self.lower_param_bound(
                         bound,
-                        ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+                        &mut ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
                     )
                 })),
                 span: self.lower_span(span),
@@ -1499,16 +1512,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 lifetime: self.lower_lifetime(lifetime),
                 bounds: self.lower_param_bounds(
                     bounds,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
+                    &mut ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
                 ),
                 in_where_clause: true,
             }),
             WherePredicate::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty, span }) => {
                 hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
-                    lhs_ty: self
-                        .lower_ty(lhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
-                    rhs_ty: self
-                        .lower_ty(rhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
+                    lhs_ty: self.lower_ty(
+                        lhs_ty,
+                        &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type),
+                    ),
+                    rhs_ty: self.lower_ty(
+                        rhs_ty,
+                        &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type),
+                    ),
                     span: self.lower_span(span),
                 })
             }
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 55f117ef01b..f57c92fd70c 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -44,6 +44,7 @@ extern crate tracing;
 
 use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait};
 
+use rustc_arena::declare_arena;
 use rustc_ast::ptr::P;
 use rustc_ast::visit;
 use rustc_ast::{self as ast, *};
@@ -95,6 +96,13 @@ struct LoweringContext<'a, 'hir> {
     /// Used to allocate HIR nodes.
     arena: &'hir hir::Arena<'hir>,
 
+    /// Used to allocate temporary AST nodes for use during lowering.
+    /// This allows us to create "fake" AST -- these nodes can sometimes
+    /// be allocated on the stack, but other times we need them to live longer
+    /// than the current stack frame, so they can be collected into vectors
+    /// and things like that.
+    ast_arena: &'a Arena<'static>,
+
     /// Bodies inside the owner being lowered.
     bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>,
     /// Attributes inside the owner being lowered.
@@ -132,8 +140,23 @@ struct LoweringContext<'a, 'hir> {
     allow_try_trait: Option<Lrc<[Symbol]>>,
     allow_gen_future: Option<Lrc<[Symbol]>>,
     allow_into_future: Option<Lrc<[Symbol]>>,
+
+    /// Mapping from generics `def_id`s to TAIT generics `def_id`s.
+    /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic
+    /// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this
+    /// field from the original parameter 'a to the new parameter 'a1.
+    generics_def_id_map: Vec<FxHashMap<LocalDefId, LocalDefId>>,
 }
 
+declare_arena!([
+    [] tys: rustc_ast::Ty,
+    [] aba: rustc_ast::AngleBracketedArgs,
+    [] ptr: rustc_ast::PolyTraitRef,
+    // This _marker field is needed because `declare_arena` creates `Arena<'tcx>` and we need to
+    // use `'tcx`. If we don't have this we get a compile error.
+    [] _marker: std::marker::PhantomData<&'tcx ()>,
+]);
+
 trait ResolverAstLoweringExt {
     fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>>;
     fn get_partial_res(&self, id: NodeId) -> Option<PartialRes>;
@@ -142,12 +165,6 @@ trait ResolverAstLoweringExt {
     fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes>;
     fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)>;
     fn decl_macro_kind(&self, def_id: LocalDefId) -> MacroKind;
-    /// Record the map from `from` local def id to `to` local def id, on `generics_def_id_map`
-    /// field.
-    fn record_def_id_remap(&mut self, from: LocalDefId, to: LocalDefId);
-    /// Get the previously recorded `to` local def id given the `from` local def id, obtained using
-    /// `generics_def_id_map` field.
-    fn get_remapped_def_id(&self, local_def_id: LocalDefId) -> LocalDefId;
 }
 
 impl ResolverAstLoweringExt for ResolverAstLowering {
@@ -215,41 +232,6 @@ impl ResolverAstLoweringExt for ResolverAstLowering {
     fn decl_macro_kind(&self, def_id: LocalDefId) -> MacroKind {
         self.builtin_macro_kinds.get(&def_id).copied().unwrap_or(MacroKind::Bang)
     }
-
-    /// Push a remapping into the top-most map.
-    /// Panics if no map has been pushed.
-    /// Remapping is used when creating lowering `-> impl Trait` return
-    /// types to create the resulting opaque type.
-    #[instrument(level = "debug", skip(self))]
-    fn record_def_id_remap(&mut self, from: LocalDefId, to: LocalDefId) {
-        self.generics_def_id_map.last_mut().expect("no map pushed").insert(from, to);
-    }
-
-    fn get_remapped_def_id(&self, mut local_def_id: LocalDefId) -> LocalDefId {
-        // `generics_def_id_map` is a stack of mappings. As we go deeper in impl traits nesting we
-        // push new mappings so we need to try first the latest mappings, hence `iter().rev()`.
-        //
-        // Consider:
-        //
-        // `fn test<'a, 'b>() -> impl Trait<&'a u8, Ty = impl Sized + 'b> {}`
-        //
-        // We would end with a generics_def_id_map like:
-        //
-        // `[[fn#'b -> impl_trait#'b], [fn#'b -> impl_sized#'b]]`
-        //
-        // for the opaque type generated on `impl Sized + 'b`, We want the result to be:
-        // impl_sized#'b, so iterating forward is the wrong thing to do.
-        for map in self.generics_def_id_map.iter().rev() {
-            if let Some(r) = map.get(&local_def_id) {
-                debug!("def_id_remapper: remapping from `{local_def_id:?}` to `{r:?}`");
-                local_def_id = *r;
-            } else {
-                debug!("def_id_remapper: no remapping for `{local_def_id:?}` found in map");
-            }
-        }
-
-        local_def_id
-    }
 }
 
 /// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
@@ -436,10 +418,13 @@ pub fn lower_to_hir<'hir>(tcx: TyCtxt<'hir>, (): ()) -> hir::Crate<'hir> {
         tcx.definitions_untracked().def_index_count(),
     );
 
+    let ast_arena = Arena::default();
+
     for def_id in ast_index.indices() {
         item::ItemLowerer {
             tcx,
             resolver: &mut resolver,
+            ast_arena: &ast_arena,
             ast_index: &ast_index,
             owners: &mut owners,
         }
@@ -522,13 +507,41 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         self.resolver
             .node_id_to_def_id
             .get(&node)
-            .map(|local_def_id| self.resolver.get_remapped_def_id(*local_def_id))
+            .map(|local_def_id| self.get_remapped_def_id(*local_def_id))
     }
 
     fn local_def_id(&self, node: NodeId) -> LocalDefId {
         self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node))
     }
 
+    /// Get the previously recorded `to` local def id given the `from` local def id, obtained using
+    /// `generics_def_id_map` field.
+    fn get_remapped_def_id(&self, mut local_def_id: LocalDefId) -> LocalDefId {
+        // `generics_def_id_map` is a stack of mappings. As we go deeper in impl traits nesting we
+        // push new mappings so we need to try first the latest mappings, hence `iter().rev()`.
+        //
+        // Consider:
+        //
+        // `fn test<'a, 'b>() -> impl Trait<&'a u8, Ty = impl Sized + 'b> {}`
+        //
+        // We would end with a generics_def_id_map like:
+        //
+        // `[[fn#'b -> impl_trait#'b], [fn#'b -> impl_sized#'b]]`
+        //
+        // for the opaque type generated on `impl Sized + 'b`, We want the result to be:
+        // impl_sized#'b, so iterating forward is the wrong thing to do.
+        for map in self.generics_def_id_map.iter().rev() {
+            if let Some(r) = map.get(&local_def_id) {
+                debug!("def_id_remapper: remapping from `{local_def_id:?}` to `{r:?}`");
+                local_def_id = *r;
+            } else {
+                debug!("def_id_remapper: no remapping for `{local_def_id:?}` found in map");
+            }
+        }
+
+        local_def_id
+    }
+
     /// Freshen the `LoweringContext` and ready it to lower a nested item.
     /// The lowered item is registered into `self.children`.
     ///
@@ -597,9 +610,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         remap: FxHashMap<LocalDefId, LocalDefId>,
         f: impl FnOnce(&mut Self) -> R,
     ) -> R {
-        self.resolver.generics_def_id_map.push(remap);
+        self.generics_def_id_map.push(remap);
         let res = f(self);
-        self.resolver.generics_def_id_map.pop();
+        self.generics_def_id_map.pop();
         res
     }
 
@@ -667,6 +680,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     /// actually used in the HIR, as that would trigger an assertion in the
     /// `HirIdValidator` later on, which makes sure that all `NodeId`s got mapped
     /// properly. Calling the method twice with the same `NodeId` is fine though.
+    #[instrument(level = "debug", skip(self), ret)]
     fn lower_node_id(&mut self, ast_node_id: NodeId) -> hir::HirId {
         assert_ne!(ast_node_id, DUMMY_NODE_ID);
 
@@ -700,6 +714,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     }
 
     /// Generate a new `HirId` without a backing `NodeId`.
+    #[instrument(level = "debug", skip(self), ret)]
     fn next_id(&mut self) -> hir::HirId {
         let owner = self.current_hir_id_owner;
         let local_id = self.item_local_id_counter;
@@ -815,23 +830,31 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     /// name resolver owing to lifetime elision; this also populates the resolver's node-id->def-id
     /// map, so that later calls to `opt_node_id_to_def_id` that refer to these extra lifetime
     /// parameters will be successful.
-    #[instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self, in_binder))]
     #[inline]
-    fn lower_lifetime_binder(
+    fn lower_lifetime_binder<R>(
         &mut self,
         binder: NodeId,
         generic_params: &[GenericParam],
-    ) -> &'hir [hir::GenericParam<'hir>] {
-        let mut generic_params: Vec<_> = self.lower_generic_params_mut(generic_params).collect();
+        in_binder: impl FnOnce(&mut Self, &'hir [hir::GenericParam<'hir>]) -> R,
+    ) -> R {
         let extra_lifetimes = self.resolver.take_extra_lifetime_params(binder);
         debug!(?extra_lifetimes);
-        generic_params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| {
-            self.lifetime_res_to_generic_param(ident, node_id, res)
-        }));
+        let extra_lifetimes: Vec<_> = extra_lifetimes
+            .into_iter()
+            .filter_map(|(ident, node_id, res)| {
+                self.lifetime_res_to_generic_param(ident, node_id, res)
+            })
+            .collect();
+
+        let generic_params: Vec<_> = self
+            .lower_generic_params_mut(generic_params)
+            .chain(extra_lifetimes.into_iter())
+            .collect();
         let generic_params = self.arena.alloc_from_iter(generic_params);
         debug!(?generic_params);
 
-        generic_params
+        in_binder(self, generic_params)
     }
 
     fn with_dyn_type_scope<T>(&mut self, in_scope: bool, f: impl FnOnce(&mut Self) -> T) -> T {
@@ -960,7 +983,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_assoc_ty_constraint(
         &mut self,
         constraint: &AssocConstraint,
-        itctx: ImplTraitContext,
+        itctx: &mut ImplTraitContext,
     ) -> hir::TypeBinding<'hir> {
         debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
         // lower generic arguments of identifier in constraint
@@ -971,18 +994,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 }
                 GenericArgs::Parenthesized(ref data) => {
                     self.emit_bad_parenthesized_trait_in_assoc_ty(data);
-                    self.lower_angle_bracketed_parameter_data(
-                        &data.as_angle_bracketed_args(),
-                        ParamMode::Explicit,
-                        itctx,
-                    )
-                    .0
+                    let aba = self.ast_arena.aba.alloc(data.as_angle_bracketed_args());
+                    self.lower_angle_bracketed_parameter_data(aba, ParamMode::Explicit, itctx).0
                 }
             };
             gen_args_ctor.into_generic_args(self)
         } else {
             self.arena.alloc(hir::GenericArgs::none())
         };
+        let mut itctx_tait = ImplTraitContext::TypeAliasesOpaqueTy;
 
         let kind = match constraint.kind {
             AssocConstraintKind::Equality { ref term } => {
@@ -1021,7 +1041,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     //
                     // FIXME: this is only needed until `impl Trait` is allowed in type aliases.
                     ImplTraitContext::Disallowed(_) if self.is_in_dyn_type => {
-                        (true, ImplTraitContext::TypeAliasesOpaqueTy)
+                        (true, &mut itctx_tait)
                     }
 
                     // We are in the parameter position, but not within a dyn type:
@@ -1044,15 +1064,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
                     self.with_dyn_type_scope(false, |this| {
                         let node_id = this.next_node_id();
-                        let ty = this.lower_ty(
-                            &Ty {
-                                id: node_id,
-                                kind: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()),
-                                span: this.lower_span(constraint.span),
-                                tokens: None,
-                            },
-                            itctx,
-                        );
+                        let ty = this.ast_arena.tys.alloc(Ty {
+                            id: node_id,
+                            kind: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()),
+                            span: this.lower_span(constraint.span),
+                            tokens: None,
+                        });
+                        let ty = this.lower_ty(ty, itctx);
 
                         hir::TypeBindingKind::Equality { term: ty.into() }
                     })
@@ -1103,7 +1121,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_generic_arg(
         &mut self,
         arg: &ast::GenericArg,
-        itctx: ImplTraitContext,
+        itctx: &mut ImplTraitContext,
     ) -> hir::GenericArg<'hir> {
         match arg {
             ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(&lt)),
@@ -1165,7 +1183,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     }
 
     #[instrument(level = "debug", skip(self))]
-    fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> &'hir hir::Ty<'hir> {
+    fn lower_ty(&mut self, t: &Ty, itctx: &mut ImplTraitContext) -> &'hir hir::Ty<'hir> {
         self.arena.alloc(self.lower_ty_direct(t, itctx))
     }
 
@@ -1175,7 +1193,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         qself: &Option<QSelf>,
         path: &Path,
         param_mode: ParamMode,
-        itctx: ImplTraitContext,
+        itctx: &mut ImplTraitContext,
     ) -> hir::Ty<'hir> {
         // Check whether we should interpret this as a bare trait object.
         // This check mirrors the one in late resolution.  We only introduce this special case in
@@ -1188,19 +1206,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             && let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = partial_res.base_res()
         {
             let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| {
+                let poly_trait_ref = this.ast_arena.ptr.alloc(PolyTraitRef {
+                    bound_generic_params: vec![],
+                    trait_ref: TraitRef { path: path.clone(), ref_id: t.id },
+                    span: t.span
+                });
                 let bound = this.lower_poly_trait_ref(
-                    &PolyTraitRef {
-                        bound_generic_params: vec![],
-                        trait_ref: TraitRef { path: path.clone(), ref_id: t.id },
-                        span: t.span
-                    },
+                    poly_trait_ref,
                     itctx,
                 );
                 let bounds = this.arena.alloc_from_iter([bound]);
                 let lifetime_bound = this.elided_dyn_bound(t.span);
                 (bounds, lifetime_bound)
             });
-            let kind = hir::TyKind::TraitObject(bounds, lifetime_bound, TraitObjectSyntax::None);
+            let kind = hir::TyKind::TraitObject(bounds, &lifetime_bound, TraitObjectSyntax::None);
             return hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.next_id() };
         }
 
@@ -1217,7 +1236,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         self.ty(span, hir::TyKind::Tup(tys))
     }
 
-    fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> {
+    fn lower_ty_direct(&mut self, t: &Ty, itctx: &mut ImplTraitContext) -> hir::Ty<'hir> {
         let kind = match t.kind {
             TyKind::Infer => hir::TyKind::Infer,
             TyKind::Err => hir::TyKind::Err,
@@ -1240,14 +1259,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 hir::TyKind::Rptr(lifetime, self.lower_mt(mt, itctx))
             }
             TyKind::BareFn(ref f) => {
-                let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params);
-                hir::TyKind::BareFn(self.arena.alloc(hir::BareFnTy {
-                    generic_params,
-                    unsafety: self.lower_unsafety(f.unsafety),
-                    abi: self.lower_extern(f.ext),
-                    decl: self.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None),
-                    param_names: self.lower_fn_params_to_names(&f.decl),
-                }))
+                self.lower_lifetime_binder(t.id, &f.generic_params, |lctx, generic_params| {
+                    hir::TyKind::BareFn(lctx.arena.alloc(hir::BareFnTy {
+                        generic_params,
+                        unsafety: lctx.lower_unsafety(f.unsafety),
+                        abi: lctx.lower_extern(f.ext),
+                        decl: lctx.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None),
+                        param_names: lctx.lower_fn_params_to_names(&f.decl),
+                    }))
+                })
             }
             TyKind::Never => hir::TyKind::Never,
             TyKind::Tup(ref tys) => hir::TyKind::Tup(
@@ -1260,14 +1280,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 return self.lower_path_ty(t, qself, path, ParamMode::Explicit, itctx);
             }
             TyKind::ImplicitSelf => {
+                let hir_id = self.lower_node_id(t.id);
                 let res = self.expect_full_res(t.id);
                 let res = self.lower_res(res);
                 hir::TyKind::Path(hir::QPath::Resolved(
                     None,
                     self.arena.alloc(hir::Path {
                         res,
-                        segments: arena_vec![self; hir::PathSegment::from_ident(
-                            Ident::with_dummy_span(kw::SelfUpper)
+                        segments: arena_vec![self; hir::PathSegment::new(
+                            Ident::with_dummy_span(kw::SelfUpper),
+                            hir_id,
+                            res
                         )],
                         span: self.lower_span(t.span),
                     }),
@@ -1311,16 +1334,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 let span = t.span;
                 match itctx {
                     ImplTraitContext::ReturnPositionOpaqueTy { origin } => {
-                        self.lower_opaque_impl_trait(span, origin, def_node_id, bounds, itctx)
+                        self.lower_opaque_impl_trait(span, *origin, def_node_id, bounds, itctx)
                     }
                     ImplTraitContext::TypeAliasesOpaqueTy => {
-                        let nested_itctx = ImplTraitContext::TypeAliasesOpaqueTy;
+                        let mut nested_itctx = ImplTraitContext::TypeAliasesOpaqueTy;
                         self.lower_opaque_impl_trait(
                             span,
                             hir::OpaqueTyOrigin::TyAlias,
                             def_node_id,
                             bounds,
-                            nested_itctx,
+                            &mut nested_itctx,
                         )
                     }
                     ImplTraitContext::Universal => {
@@ -1385,14 +1408,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     /// added explicitly in the HIR). But this includes all the lifetimes, and we only want to
     /// capture the lifetimes that are referenced in the bounds. Therefore, we add *extra* lifetime parameters
     /// for the lifetimes that get captured (`'x`, in our example above) and reference those.
-    #[instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self), ret)]
     fn lower_opaque_impl_trait(
         &mut self,
         span: Span,
         origin: hir::OpaqueTyOrigin,
         opaque_ty_node_id: NodeId,
         bounds: &GenericBounds,
-        itctx: ImplTraitContext,
+        itctx: &mut ImplTraitContext,
     ) -> hir::TyKind<'hir> {
         // Make sure we know that some funky desugaring has been going on here.
         // This is a first: there is code in other places like for loop
@@ -1565,8 +1588,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
                 LifetimeRes::Fresh { param, binder: _ } => {
                     debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
-                    let old_def_id = self.local_def_id(param);
-                    if remapping.get(&old_def_id).is_none() {
+                    if let Some(old_def_id) = self.opt_local_def_id(param) && remapping.get(&old_def_id).is_none() {
                         let node_id = self.next_node_id();
 
                         let new_def_id = self.create_def(
@@ -1640,11 +1662,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         }
         let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| {
             if fn_node_id.is_some() {
-                self.lower_ty_direct(&param.ty, ImplTraitContext::Universal)
+                self.lower_ty_direct(&param.ty, &mut ImplTraitContext::Universal)
             } else {
                 self.lower_ty_direct(
                     &param.ty,
-                    ImplTraitContext::Disallowed(match kind {
+                    &mut ImplTraitContext::Disallowed(match kind {
                         FnDeclKind::Fn | FnDeclKind::Inherent => {
                             unreachable!("fn should allow in-band lifetimes")
                         }
@@ -1667,7 +1689,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         } else {
             match decl.output {
                 FnRetTy::Ty(ref ty) => {
-                    let context = match fn_node_id {
+                    let mut context = match fn_node_id {
                         Some(fn_node_id) if kind.impl_trait_return_allowed() => {
                             let fn_def_id = self.local_def_id(fn_node_id);
                             ImplTraitContext::ReturnPositionOpaqueTy {
@@ -1685,7 +1707,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                             FnDeclKind::Impl => ImplTraitPosition::ImplReturn,
                         }),
                     };
-                    hir::FnRetTy::Return(self.lower_ty(ty, context))
+                    hir::FnRetTy::Return(self.lower_ty(ty, &mut context))
                 }
                 FnRetTy::Default(span) => hir::FnRetTy::DefaultReturn(self.lower_span(span)),
             }
@@ -1696,10 +1718,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             output,
             c_variadic,
             implicit_self: decl.inputs.get(0).map_or(hir::ImplicitSelfKind::None, |arg| {
-                use BindingMode::{ByRef, ByValue};
                 let is_mutable_pat = matches!(
                     arg.pat.kind,
-                    PatKind::Ident(ByValue(Mutability::Mut) | ByRef(Mutability::Mut), ..)
+                    PatKind::Ident(hir::BindingAnnotation(_, Mutability::Mut), ..)
                 );
 
                 match arg.ty.kind {
@@ -1937,8 +1958,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 let res = res.unwrap_or(
                     self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error),
                 );
-                let l = self.new_named_lifetime_with_res(id, span, ident, res);
-                hir::GenericArg::Lifetime(l)
+                hir::GenericArg::Lifetime(self.new_named_lifetime_with_res(id, span, ident, res))
             },
         ));
 
@@ -1965,10 +1985,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 // Not `OpaqueTyOrigin::AsyncFn`: that's only used for the
                 // `impl Future` opaque type that `async fn` implicitly
                 // generates.
-                let context = ImplTraitContext::ReturnPositionOpaqueTy {
+                let mut context = ImplTraitContext::ReturnPositionOpaqueTy {
                     origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
                 };
-                self.lower_ty(ty, context)
+                self.lower_ty(ty, &mut context)
             }
             FnRetTy::Default(ret_ty_span) => self.arena.alloc(self.ty_tup(*ret_ty_span, &[])),
         };
@@ -1994,7 +2014,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_param_bound(
         &mut self,
         tpb: &GenericBound,
-        itctx: ImplTraitContext,
+        itctx: &mut ImplTraitContext,
     ) -> hir::GenericBound<'hir> {
         match tpb {
             GenericBound::Trait(p, modifier) => hir::GenericBound::Trait(
@@ -2007,7 +2027,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         }
     }
 
-    fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime {
+    fn lower_lifetime(&mut self, l: &Lifetime) -> &'hir hir::Lifetime {
         let span = self.lower_span(l.ident.span);
         let ident = self.lower_ident(l.ident);
         self.new_named_lifetime(l.id, l.id, span, ident)
@@ -2020,11 +2040,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         span: Span,
         ident: Ident,
         res: LifetimeRes,
-    ) -> hir::Lifetime {
+    ) -> &'hir hir::Lifetime {
         let name = match res {
             LifetimeRes::Param { param, .. } => {
                 let p_name = ParamName::Plain(ident);
-                let param = self.resolver.get_remapped_def_id(param);
+                let param = self.get_remapped_def_id(param);
 
                 hir::LifetimeName::Param(param, p_name)
             }
@@ -2041,7 +2061,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         };
 
         debug!(?name);
-        hir::Lifetime { hir_id: self.lower_node_id(id), span: self.lower_span(span), name }
+        self.arena.alloc(hir::Lifetime {
+            hir_id: self.lower_node_id(id),
+            span: self.lower_span(span),
+            name,
+        })
     }
 
     #[instrument(level = "debug", skip(self))]
@@ -2051,7 +2075,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         new_id: NodeId,
         span: Span,
         ident: Ident,
-    ) -> hir::Lifetime {
+    ) -> &'hir hir::Lifetime {
         let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error);
         self.new_named_lifetime_with_res(new_id, span, ident, res)
     }
@@ -2106,7 +2130,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             GenericParamKind::Type { ref default, .. } => {
                 let kind = hir::GenericParamKind::Type {
                     default: default.as_ref().map(|x| {
-                        self.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Type))
+                        self.lower_ty(x, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type))
                     }),
                     synthetic: false,
                 };
@@ -2114,7 +2138,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 (hir::ParamName::Plain(self.lower_ident(param.ident)), kind)
             }
             GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
-                let ty = self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
+                let ty =
+                    self.lower_ty(&ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type));
                 let default = default.as_ref().map(|def| self.lower_anon_const(def));
                 (
                     hir::ParamName::Plain(self.lower_ident(param.ident)),
@@ -2124,7 +2149,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         }
     }
 
-    fn lower_trait_ref(&mut self, p: &TraitRef, itctx: ImplTraitContext) -> hir::TraitRef<'hir> {
+    fn lower_trait_ref(
+        &mut self,
+        p: &TraitRef,
+        itctx: &mut ImplTraitContext,
+    ) -> hir::TraitRef<'hir> {
         let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit, itctx) {
             hir::QPath::Resolved(None, path) => path,
             qpath => panic!("lower_trait_ref: unexpected QPath `{:?}`", qpath),
@@ -2136,34 +2165,41 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_poly_trait_ref(
         &mut self,
         p: &PolyTraitRef,
-        itctx: ImplTraitContext,
+        itctx: &mut ImplTraitContext,
     ) -> hir::PolyTraitRef<'hir> {
-        let bound_generic_params =
-            self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params);
-        let trait_ref = self.lower_trait_ref(&p.trait_ref, itctx);
-        hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) }
+        self.lower_lifetime_binder(
+            p.trait_ref.ref_id,
+            &p.bound_generic_params,
+            |lctx, bound_generic_params| {
+                let trait_ref = lctx.lower_trait_ref(&p.trait_ref, itctx);
+                hir::PolyTraitRef { bound_generic_params, trait_ref, span: lctx.lower_span(p.span) }
+            },
+        )
     }
 
-    fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> {
+    fn lower_mt(&mut self, mt: &MutTy, itctx: &mut ImplTraitContext) -> hir::MutTy<'hir> {
         hir::MutTy { ty: self.lower_ty(&mt.ty, itctx), mutbl: mt.mutbl }
     }
 
+    #[instrument(level = "debug", skip(self), ret)]
     fn lower_param_bounds(
         &mut self,
         bounds: &[GenericBound],
-        itctx: ImplTraitContext,
+        itctx: &mut ImplTraitContext,
     ) -> hir::GenericBounds<'hir> {
         self.arena.alloc_from_iter(self.lower_param_bounds_mut(bounds, itctx))
     }
 
-    fn lower_param_bounds_mut<'s>(
+    fn lower_param_bounds_mut<'s, 'b>(
         &'s mut self,
         bounds: &'s [GenericBound],
-        itctx: ImplTraitContext,
-    ) -> impl Iterator<Item = hir::GenericBound<'hir>> + Captures<'s> + Captures<'a> {
+        itctx: &'b mut ImplTraitContext,
+    ) -> impl Iterator<Item = hir::GenericBound<'hir>> + Captures<'s> + Captures<'a> + Captures<'b>
+    {
         bounds.iter().map(move |bound| self.lower_param_bound(bound, itctx))
     }
 
+    #[instrument(level = "debug", skip(self), ret)]
     fn lower_generic_and_bounds(
         &mut self,
         node_id: NodeId,
@@ -2189,16 +2225,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             node_id,
             &GenericParamKind::Type { default: None },
             bounds,
-            ImplTraitContext::Universal,
+            &mut ImplTraitContext::Universal,
             hir::PredicateOrigin::ImplTrait,
         );
 
+        let hir_id = self.next_id();
+        let res = Res::Def(DefKind::TyParam, def_id.to_def_id());
         let ty = hir::TyKind::Path(hir::QPath::Resolved(
             None,
             self.arena.alloc(hir::Path {
                 span: self.lower_span(span),
-                res: Res::Def(DefKind::TyParam, def_id.to_def_id()),
-                segments: arena_vec![self; hir::PathSegment::from_ident(self.lower_ident(ident))],
+                res,
+                segments:
+                    arena_vec![self; hir::PathSegment::new(self.lower_ident(ident), hir_id, res)],
             }),
         ));
 
@@ -2361,11 +2400,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     }
 
     fn pat_ident(&mut self, span: Span, ident: Ident) -> (&'hir hir::Pat<'hir>, hir::HirId) {
-        self.pat_ident_binding_mode(span, ident, hir::BindingAnnotation::Unannotated)
+        self.pat_ident_binding_mode(span, ident, hir::BindingAnnotation::NONE)
     }
 
     fn pat_ident_mut(&mut self, span: Span, ident: Ident) -> (hir::Pat<'hir>, hir::HirId) {
-        self.pat_ident_binding_mode_mut(span, ident, hir::BindingAnnotation::Unannotated)
+        self.pat_ident_binding_mode_mut(span, ident, hir::BindingAnnotation::NONE)
     }
 
     fn pat_ident_binding_mode(
@@ -2454,14 +2493,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     /// bound, like the bound in `Box<dyn Debug>`. This method is not invoked
     /// when the bound is written, even if it is written with `'_` like in
     /// `Box<dyn Debug + '_>`. In those cases, `lower_lifetime` is invoked.
-    fn elided_dyn_bound(&mut self, span: Span) -> hir::Lifetime {
+    fn elided_dyn_bound(&mut self, span: Span) -> &'hir hir::Lifetime {
         let r = hir::Lifetime {
             hir_id: self.next_id(),
             span: self.lower_span(span),
             name: hir::LifetimeName::ImplicitObjectLifetimeDefault,
         };
         debug!("elided_dyn_bound: r={:?}", r);
-        r
+        self.arena.alloc(r)
     }
 }
 
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index 1efa19a3a82..1ea76fdbfcb 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -24,7 +24,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             let node = loop {
                 match pattern.kind {
                     PatKind::Wild => break hir::PatKind::Wild,
-                    PatKind::Ident(ref binding_mode, ident, ref sub) => {
+                    PatKind::Ident(binding_mode, ident, ref sub) => {
                         let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(&*s));
                         break self.lower_pat_ident(pattern, binding_mode, ident, lower_sub);
                     }
@@ -37,7 +37,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                             qself,
                             path,
                             ParamMode::Optional,
-                            ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                            &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                         );
                         let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct");
                         break hir::PatKind::TupleStruct(qpath, pats, ddpos);
@@ -53,7 +53,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                             qself,
                             path,
                             ParamMode::Optional,
-                            ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                            &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                         );
                         break hir::PatKind::Path(qpath);
                     }
@@ -63,7 +63,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                             qself,
                             path,
                             ParamMode::Optional,
-                            ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                            &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                         );
 
                         let fs = self.arena.alloc_from_iter(fields.iter().map(|f| {
@@ -116,7 +116,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         &mut self,
         pats: &[P<Pat>],
         ctx: &str,
-    ) -> (&'hir [hir::Pat<'hir>], Option<usize>) {
+    ) -> (&'hir [hir::Pat<'hir>], hir::DotDotPos) {
         let mut elems = Vec::with_capacity(pats.len());
         let mut rest = None;
 
@@ -160,7 +160,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             }
         }
 
-        (self.arena.alloc_from_iter(elems), rest.map(|(ddpos, _)| ddpos))
+        (self.arena.alloc_from_iter(elems), hir::DotDotPos::new(rest.map(|(ddpos, _)| ddpos)))
     }
 
     /// Lower a slice pattern of form `[pat_0, ..., pat_n]` into
@@ -176,9 +176,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let mut prev_rest_span = None;
 
         // Lowers `$bm $ident @ ..` to `$bm $ident @ _`.
-        let lower_rest_sub = |this: &mut Self, pat, bm, ident, sub| {
+        let lower_rest_sub = |this: &mut Self, pat, ann, ident, sub| {
             let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub));
-            let node = this.lower_pat_ident(pat, bm, ident, lower_sub);
+            let node = this.lower_pat_ident(pat, ann, ident, lower_sub);
             this.pat_with_node_id_of(pat, node)
         };
 
@@ -194,9 +194,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 }
                 // Found a sub-slice pattern `$binding_mode $ident @ ..`.
                 // Record, lower it to `$binding_mode $ident @ _`, and stop here.
-                PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
+                PatKind::Ident(ann, ident, Some(ref sub)) if sub.is_rest() => {
                     prev_rest_span = Some(sub.span);
-                    slice = Some(self.arena.alloc(lower_rest_sub(self, pat, bm, ident, sub)));
+                    slice = Some(self.arena.alloc(lower_rest_sub(self, pat, ann, ident, sub)));
                     break;
                 }
                 // It was not a subslice pattern so lower it normally.
@@ -209,9 +209,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             // There was a previous subslice pattern; make sure we don't allow more.
             let rest_span = match pat.kind {
                 PatKind::Rest => Some(pat.span),
-                PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
+                PatKind::Ident(ann, ident, Some(ref sub)) if sub.is_rest() => {
                     // #69103: Lower into `binding @ _` as above to avoid ICEs.
-                    after.push(lower_rest_sub(self, pat, bm, ident, sub));
+                    after.push(lower_rest_sub(self, pat, ann, ident, sub));
                     Some(sub.span)
                 }
                 _ => None,
@@ -235,7 +235,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_pat_ident(
         &mut self,
         p: &Pat,
-        binding_mode: &BindingMode,
+        annotation: BindingAnnotation,
         ident: Ident,
         lower_sub: impl FnOnce(&mut Self) -> Option<&'hir hir::Pat<'hir>>,
     ) -> hir::PatKind<'hir> {
@@ -248,29 +248,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 };
 
                 hir::PatKind::Binding(
-                    self.lower_binding_mode(binding_mode),
+                    annotation,
                     self.lower_node_id(canonical_id),
                     self.lower_ident(ident),
                     lower_sub(self),
                 )
             }
-            Some(res) => hir::PatKind::Path(hir::QPath::Resolved(
-                None,
-                self.arena.alloc(hir::Path {
-                    span: self.lower_span(ident.span),
-                    res: self.lower_res(res),
-                    segments: arena_vec![self; hir::PathSegment::from_ident(self.lower_ident(ident))],
-                }),
-            )),
-        }
-    }
-
-    fn lower_binding_mode(&mut self, b: &BindingMode) -> hir::BindingAnnotation {
-        match *b {
-            BindingMode::ByValue(Mutability::Not) => hir::BindingAnnotation::Unannotated,
-            BindingMode::ByRef(Mutability::Not) => hir::BindingAnnotation::Ref,
-            BindingMode::ByValue(Mutability::Mut) => hir::BindingAnnotation::Mutable,
-            BindingMode::ByRef(Mutability::Mut) => hir::BindingAnnotation::RefMut,
+            Some(res) => {
+                let hir_id = self.next_id();
+                let res = self.lower_res(res);
+                hir::PatKind::Path(hir::QPath::Resolved(
+                    None,
+                    self.arena.alloc(hir::Path {
+                        span: self.lower_span(ident.span),
+                        res,
+                        segments: arena_vec![self; hir::PathSegment::new(self.lower_ident(ident), hir_id, res)],
+                    }),
+            ))
+            }
         }
     }
 
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index f071012d01e..a3d864023a9 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -22,7 +22,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         qself: &Option<QSelf>,
         p: &Path,
         param_mode: ParamMode,
-        itctx: ImplTraitContext,
+        itctx: &mut ImplTraitContext,
     ) -> hir::QPath<'hir> {
         let qself_position = qself.as_ref().map(|q| q.position);
         let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
@@ -156,7 +156,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     segment,
                     param_mode,
                     ParenthesizedGenericArgs::Err,
-                    ImplTraitContext::Disallowed(ImplTraitPosition::Path),
+                    &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                 )
             })),
             span: self.lower_span(p.span),
@@ -180,7 +180,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         segment: &PathSegment,
         param_mode: ParamMode,
         parenthesized_generic_args: ParenthesizedGenericArgs,
-        itctx: ImplTraitContext,
+        itctx: &mut ImplTraitContext,
     ) -> hir::PathSegment<'hir> {
         debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment,);
         let (mut generic_args, infer_args) = if let Some(ref generic_args) = segment.args {
@@ -250,16 +250,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         }
 
         let res = self.expect_full_res(segment.id);
-        let id = self.lower_node_id(segment.id);
+        let hir_id = self.lower_node_id(segment.id);
         debug!(
             "lower_path_segment: ident={:?} original-id={:?} new-id={:?}",
-            segment.ident, segment.id, id,
+            segment.ident, segment.id, hir_id,
         );
 
         hir::PathSegment {
             ident: self.lower_ident(segment.ident),
-            hir_id: Some(id),
-            res: Some(self.lower_res(res)),
+            hir_id,
+            res: self.lower_res(res),
             infer_args,
             args: if generic_args.is_empty() && generic_args.span.is_empty() {
                 None
@@ -316,7 +316,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         &mut self,
         data: &AngleBracketedArgs,
         param_mode: ParamMode,
-        itctx: ImplTraitContext,
+        itctx: &mut ImplTraitContext,
     ) -> (GenericArgsCtor<'hir>, bool) {
         let has_non_lt_args = data.args.iter().any(|arg| match arg {
             AngleBracketedArg::Arg(ast::GenericArg::Lifetime(_))
@@ -350,12 +350,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         // we generally don't permit such things (see #51008).
         let ParenthesizedArgs { span, inputs, inputs_span, output } = data;
         let inputs = self.arena.alloc_from_iter(inputs.iter().map(|ty| {
-            self.lower_ty_direct(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam))
+            self.lower_ty_direct(
+                ty,
+                &mut ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam),
+            )
         }));
         let output_ty = match output {
-            FnRetTy::Ty(ty) => {
-                self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn))
-            }
+            FnRetTy::Ty(ty) => self
+                .lower_ty(&ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)),
             FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])),
         };
         let args = smallvec![GenericArg::Type(self.arena.alloc(self.ty_tup(*inputs_span, inputs)))];
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 23464bf0a5a..d6d8881a53a 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -281,8 +281,8 @@ impl<'a> AstValidator<'a> {
     fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
         for Param { pat, .. } in &decl.inputs {
             match pat.kind {
-                PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None) | PatKind::Wild => {}
-                PatKind::Ident(BindingMode::ByValue(Mutability::Mut), ident, None) => {
+                PatKind::Ident(BindingAnnotation::NONE, _, None) | PatKind::Wild => {}
+                PatKind::Ident(BindingAnnotation::MUT, ident, None) => {
                     report_err(pat.span, Some(ident), true)
                 }
                 _ => report_err(pat.span, None, false),
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 8749a13c5dd..ed5e7dace4b 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -11,8 +11,8 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_ast::util::classify;
 use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle};
 use rustc_ast::util::parser;
-use rustc_ast::{self as ast, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
-use rustc_ast::{attr, Term};
+use rustc_ast::{self as ast, BlockCheckMode, Mutability, PatKind, RangeEnd, RangeSyntax};
+use rustc_ast::{attr, BindingAnnotation, ByRef, Term};
 use rustc_ast::{GenericArg, MacArgs, MacArgsEq};
 use rustc_ast::{GenericBound, SelfKind, TraitBoundModifier};
 use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
@@ -1399,16 +1399,12 @@ impl<'a> State<'a> {
         is that it doesn't matter */
         match pat.kind {
             PatKind::Wild => self.word("_"),
-            PatKind::Ident(binding_mode, ident, ref sub) => {
-                match binding_mode {
-                    ast::BindingMode::ByRef(mutbl) => {
-                        self.word_nbsp("ref");
-                        self.print_mutability(mutbl, false);
-                    }
-                    ast::BindingMode::ByValue(ast::Mutability::Not) => {}
-                    ast::BindingMode::ByValue(ast::Mutability::Mut) => {
-                        self.word_nbsp("mut");
-                    }
+            PatKind::Ident(BindingAnnotation(by_ref, mutbl), ident, ref sub) => {
+                if by_ref == ByRef::Yes {
+                    self.word_nbsp("ref");
+                }
+                if mutbl == Mutability::Mut {
+                    self.word_nbsp("mut");
                 }
                 self.print_ident(ident);
                 if let Some(ref p) = *sub {
@@ -1487,12 +1483,10 @@ impl<'a> State<'a> {
             }
             PatKind::Ref(ref inner, mutbl) => {
                 self.word("&");
-                if mutbl == ast::Mutability::Mut {
+                if mutbl == Mutability::Mut {
                     self.word("mut ");
                 }
-                if let PatKind::Ident(ast::BindingMode::ByValue(ast::Mutability::Mut), ..) =
-                    inner.kind
-                {
+                if let PatKind::Ident(ast::BindingAnnotation::MUT, ..) = inner.kind {
                     self.popen();
                     self.print_pat(inner);
                     self.pclose();
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index a8ed510866d..bb972a18acb 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -63,7 +63,12 @@ fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) {
             sess.emit_err(session_diagnostics::MultipleStabilityLevels { span });
         }
         AttrError::UnsupportedLiteral(reason, is_bytestr) => {
-            sess.emit_err(session_diagnostics::UnsupportedLiteral { span, reason, is_bytestr });
+            sess.emit_err(session_diagnostics::UnsupportedLiteral {
+                span,
+                reason,
+                is_bytestr,
+                start_point_span: sess.source_map().start_point(span),
+            });
         }
     }
 }
@@ -1040,18 +1045,16 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
                                 &name,
                             ),
                         });
-                    } else {
-                        if matches!(
-                            meta_item.name_or_empty(),
-                            sym::C | sym::simd | sym::transparent
-                        ) || int_type_of_word(meta_item.name_or_empty()).is_some()
-                        {
-                            recognised = true;
-                            sess.emit_err(session_diagnostics::InvalidReprHintNoValue {
-                                span: meta_item.span,
-                                name: meta_item.name_or_empty().to_ident_string(),
-                            });
-                        }
+                    } else if matches!(
+                        meta_item.name_or_empty(),
+                        sym::C | sym::simd | sym::transparent
+                    ) || int_type_of_word(meta_item.name_or_empty()).is_some()
+                    {
+                        recognised = true;
+                        sess.emit_err(session_diagnostics::InvalidReprHintNoValue {
+                            span: meta_item.span,
+                            name: meta_item.name_or_empty().to_ident_string(),
+                        });
                     }
                 } else if let MetaItemKind::List(_) = meta_item.kind {
                     if meta_item.has_name(sym::align) {
diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs
index 25cd960dbf1..085175d4bed 100644
--- a/compiler/rustc_attr/src/session_diagnostics.rs
+++ b/compiler/rustc_attr/src/session_diagnostics.rs
@@ -1,9 +1,11 @@
 use std::num::IntErrorKind;
 
 use rustc_ast as ast;
-use rustc_errors::{error_code, fluent, Applicability, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_errors::{
+    error_code, fluent, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler,
+};
 use rustc_macros::SessionDiagnostic;
-use rustc_session::{parse::ParseSess, SessionDiagnostic};
+use rustc_session::SessionDiagnostic;
 use rustc_span::{Span, Symbol};
 
 use crate::UnsupportedLiteralReason;
@@ -49,9 +51,9 @@ pub(crate) struct UnknownMetaItem<'a> {
 
 // Manual implementation to be able to format `expected` items correctly.
 impl<'a> SessionDiagnostic<'a> for UnknownMetaItem<'_> {
-    fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
+    fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
         let expected = self.expected.iter().map(|name| format!("`{}`", name)).collect::<Vec<_>>();
-        let mut diag = sess.span_diagnostic.struct_span_err_with_code(
+        let mut diag = handler.struct_span_err_with_code(
             self.span,
             fluent::attr::unknown_meta_item,
             error_code!(E0541),
@@ -204,11 +206,12 @@ pub(crate) struct UnsupportedLiteral {
     pub span: Span,
     pub reason: UnsupportedLiteralReason,
     pub is_bytestr: bool,
+    pub start_point_span: Span,
 }
 
 impl<'a> SessionDiagnostic<'a> for UnsupportedLiteral {
-    fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
-        let mut diag = sess.span_diagnostic.struct_span_err_with_code(
+    fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
+        let mut diag = handler.struct_span_err_with_code(
             self.span,
             match self.reason {
                 UnsupportedLiteralReason::Generic => fluent::attr::unsupported_literal_generic,
@@ -224,7 +227,7 @@ impl<'a> SessionDiagnostic<'a> for UnsupportedLiteral {
         );
         if self.is_bytestr {
             diag.span_suggestion(
-                sess.source_map().start_point(self.span),
+                self.start_point_span,
                 fluent::attr::unsupported_literal_suggestion,
                 "",
                 Applicability::MaybeIncorrect,
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index 816288eb50b..9f7a4d49989 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -391,7 +391,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
             | mir::StatementKind::Retag { .. }
             | mir::StatementKind::AscribeUserType(..)
             | mir::StatementKind::Coverage(..)
-            | mir::StatementKind::CopyNonOverlapping(..)
+            | mir::StatementKind::Intrinsic(..)
             | mir::StatementKind::Nop => {}
         }
     }
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index dd9590016b9..2c6c461267a 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -367,7 +367,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
                 if let Some(Node::Pat(pat)) = self.infcx.tcx.hir().find(upvar_hir_id)
                     && let hir::PatKind::Binding(
-                        hir::BindingAnnotation::Unannotated,
+                        hir::BindingAnnotation::NONE,
                         _,
                         upvar_ident,
                         _,
@@ -711,8 +711,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                             Applicability::MachineApplicable,
                         );
                         self.suggested = true;
-                    } else if let hir::ExprKind::MethodCall(_path, args @ [_, ..], sp) = expr.kind
-                        && let hir::ExprKind::Index(val, index) = args[0].kind
+                    } else if let hir::ExprKind::MethodCall(_path, receiver, _, sp) = expr.kind
+                        && let hir::ExprKind::Index(val, index) = receiver.kind
                         && expr.span == self.assign_span
                     {
                         // val[index].path(args..);
@@ -724,7 +724,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                                     ".get_mut(".to_string(),
                                 ),
                                 (
-                                    index.span.shrink_to_hi().with_hi(args[0].span.hi()),
+                                    index.span.shrink_to_hi().with_hi(receiver.span.hi()),
                                     ").map(|val| val".to_string(),
                                 ),
                                 (sp.shrink_to_hi(), ")".to_string()),
@@ -911,11 +911,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                                                         [
                                                             Expr {
                                                                 kind:
-                                                                    MethodCall(
-                                                                        path_segment,
-                                                                        _args,
-                                                                        span,
-                                                                    ),
+                                                                    MethodCall(path_segment, _, _, span),
                                                                 hir_id,
                                                                 ..
                                                             },
@@ -935,10 +931,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 _,
             ) = hir_map.body(fn_body_id).value.kind
             {
-                let opt_suggestions = path_segment
-                    .hir_id
-                    .map(|path_hir_id| self.infcx.tcx.typeck(path_hir_id.owner))
-                    .and_then(|typeck| typeck.type_dependent_def_id(*hir_id))
+                let opt_suggestions = self
+                    .infcx
+                    .tcx
+                    .typeck(path_segment.hir_id.owner)
+                    .type_dependent_def_id(*hir_id)
                     .and_then(|def_id| self.infcx.tcx.impl_of_method(def_id))
                     .map(|def_id| self.infcx.tcx.associated_items(def_id))
                     .map(|assoc_items| {
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 082dd869023..9615025fa57 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -900,14 +900,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         let mut closure_span = None::<rustc_span::Span>;
         match expr.kind {
             hir::ExprKind::MethodCall(.., args, _) => {
-                // only the first closre parameter of the method. args[0] is MethodCall PathSegment
-                for i in 1..args.len() {
+                for arg in args {
                     if let hir::ExprKind::Closure(hir::Closure {
                         capture_clause: hir::CaptureBy::Ref,
                         ..
-                    }) = args[i].kind
+                    }) = arg.kind
                     {
-                        closure_span = Some(args[i].span.shrink_to_lo());
+                        closure_span = Some(arg.span.shrink_to_lo());
                         break;
                     }
                 }
diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs
index ec521b1cf0a..3157f861d93 100644
--- a/compiler/rustc_borrowck/src/invalidation.rs
+++ b/compiler/rustc_borrowck/src/invalidation.rs
@@ -1,6 +1,6 @@
 use rustc_data_structures::graph::dominators::Dominators;
 use rustc_middle::mir::visit::Visitor;
-use rustc_middle::mir::{BasicBlock, Body, Location, Place, Rvalue};
+use rustc_middle::mir::{self, BasicBlock, Body, Location, NonDivergingIntrinsic, Place, Rvalue};
 use rustc_middle::mir::{BorrowKind, Mutability, Operand};
 use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
 use rustc_middle::mir::{Statement, StatementKind};
@@ -63,23 +63,24 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
             StatementKind::FakeRead(box (_, _)) => {
                 // Only relevant for initialized/liveness/safety checks.
             }
-            StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
+            StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => {
+                self.consume_operand(location, op);
+            }
+            StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping {
                 ref src,
                 ref dst,
                 ref count,
-            }) => {
+            })) => {
                 self.consume_operand(location, src);
                 self.consume_operand(location, dst);
                 self.consume_operand(location, count);
             }
-            StatementKind::Nop
+            // Only relevant for mir typeck
+            StatementKind::AscribeUserType(..)
+            // Doesn't have any language semantics
             | StatementKind::Coverage(..)
-            | StatementKind::AscribeUserType(..)
-            | StatementKind::Retag { .. }
-            | StatementKind::StorageLive(..) => {
-                // `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant
-                // to borrow check.
-            }
+            // Does not actually affect borrowck
+            | StatementKind::StorageLive(..) => {}
             StatementKind::StorageDead(local) => {
                 self.access_place(
                     location,
@@ -88,7 +89,10 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
                     LocalMutationIsAllowed::Yes,
                 );
             }
-            StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
+            StatementKind::Nop
+            | StatementKind::Retag { .. }
+            | StatementKind::Deinit(..)
+            | StatementKind::SetDiscriminant { .. } => {
                 bug!("Statement not allowed in this MIR phase")
             }
         }
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 20c22575bd1..ec652f85217 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -26,8 +26,8 @@ use rustc_index::bit_set::ChunkedBitSet;
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt};
 use rustc_middle::mir::{
-    traversal, Body, ClearCrossCrate, Local, Location, Mutability, Operand, Place, PlaceElem,
-    PlaceRef, VarDebugInfoContents,
+    traversal, Body, ClearCrossCrate, Local, Location, Mutability, NonDivergingIntrinsic, Operand,
+    Place, PlaceElem, PlaceRef, VarDebugInfoContents,
 };
 use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
 use rustc_middle::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
@@ -591,22 +591,19 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
                     flow_state,
                 );
             }
-            StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
-                ..
-            }) => {
-                span_bug!(
+            StatementKind::Intrinsic(box ref kind) => match kind {
+                NonDivergingIntrinsic::Assume(op) => self.consume_operand(location, (op, span), flow_state),
+                NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!(
                     span,
                     "Unexpected CopyNonOverlapping, should only appear after lower_intrinsics",
                 )
             }
-            StatementKind::Nop
+            // Only relevant for mir typeck
+            StatementKind::AscribeUserType(..)
+            // Doesn't have any language semantics
             | StatementKind::Coverage(..)
-            | StatementKind::AscribeUserType(..)
-            | StatementKind::Retag { .. }
-            | StatementKind::StorageLive(..) => {
-                // `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant
-                // to borrow check.
-            }
+            // Does not actually affect borrowck
+            | StatementKind::StorageLive(..) => {}
             StatementKind::StorageDead(local) => {
                 self.access_place(
                     location,
@@ -616,7 +613,10 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
                     flow_state,
                 );
             }
-            StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
+            StatementKind::Nop
+            | StatementKind::Retag { .. }
+            | StatementKind::Deinit(..)
+            | StatementKind::SetDiscriminant { .. } => {
                 bug!("Statement not allowed in this MIR phase")
             }
         }
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 8dc9368a0b9..de70b17e44c 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -135,7 +135,6 @@ pub struct RegionInferenceContext<'tcx> {
 /// adds a new lower bound to the SCC it is analyzing: so you wind up
 /// with `'R: 'O` where `'R` is the pick-region and `'O` is the
 /// minimal viable option.
-#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
 pub(crate) struct AppliedMemberConstraint {
     /// The SCC that was affected. (The "member region".)
     ///
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index a620c987052..fc0e95f30c9 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -1302,12 +1302,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     );
                 }
             }
-            StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
-                ..
-            }) => span_bug!(
-                stmt.source_info.span,
-                "Unexpected StatementKind::CopyNonOverlapping, should only appear after lowering_intrinsics",
-            ),
+            StatementKind::Intrinsic(box ref kind) => match kind {
+                NonDivergingIntrinsic::Assume(op) => self.check_operand(op, location),
+                NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!(
+                    stmt.source_info.span,
+                    "Unexpected NonDivergingIntrinsic::CopyNonOverlapping, should only appear after lowering_intrinsics",
+                ),
+            },
             StatementKind::FakeRead(..)
             | StatementKind::StorageLive(..)
             | StatementKind::StorageDead(..)
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index adffebd3fd2..3cc160adb53 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -164,7 +164,9 @@ pub use SubstructureFields::*;
 
 use crate::deriving;
 use rustc_ast::ptr::P;
-use rustc_ast::{self as ast, EnumDef, Expr, Generics, PatKind};
+use rustc_ast::{
+    self as ast, BindingAnnotation, ByRef, EnumDef, Expr, Generics, Mutability, PatKind,
+};
 use rustc_ast::{GenericArg, GenericParamKind, VariantData};
 use rustc_attr as attr;
 use rustc_expand::base::{Annotatable, ExtCtxt};
@@ -1063,9 +1065,9 @@ impl<'a> MethodDef<'a> {
             let mut body = mk_body(cx, selflike_fields);
 
             let struct_path = cx.path(span, vec![Ident::new(kw::SelfUpper, type_ident.span)]);
-            let use_ref_pat = is_packed && !always_copy;
+            let by_ref = ByRef::from(is_packed && !always_copy);
             let patterns =
-                trait_.create_struct_patterns(cx, struct_path, struct_def, &prefixes, use_ref_pat);
+                trait_.create_struct_patterns(cx, struct_path, struct_def, &prefixes, by_ref);
 
             // Do the let-destructuring.
             let mut stmts: Vec<_> = iter::zip(selflike_args, patterns)
@@ -1247,13 +1249,13 @@ impl<'a> MethodDef<'a> {
 
                 let sp = variant.span.with_ctxt(trait_.span.ctxt());
                 let variant_path = cx.path(sp, vec![type_ident, variant.ident]);
-                let use_ref_pat = false; // because enums can't be repr(packed)
+                let by_ref = ByRef::No; // because enums can't be repr(packed)
                 let mut subpats: Vec<_> = trait_.create_struct_patterns(
                     cx,
                     variant_path,
                     &variant.data,
                     &prefixes,
-                    use_ref_pat,
+                    by_ref,
                 );
 
                 // `(VariantK, VariantK, ...)` or just `VariantK`.
@@ -1414,7 +1416,7 @@ impl<'a> TraitDef<'a> {
         struct_path: ast::Path,
         struct_def: &'a VariantData,
         prefixes: &[String],
-        use_ref_pat: bool,
+        by_ref: ByRef,
     ) -> Vec<P<ast::Pat>> {
         prefixes
             .iter()
@@ -1422,17 +1424,19 @@ impl<'a> TraitDef<'a> {
                 let pieces_iter =
                     struct_def.fields().iter().enumerate().map(|(i, struct_field)| {
                         let sp = struct_field.span.with_ctxt(self.span.ctxt());
-                        let binding_mode = if use_ref_pat {
-                            ast::BindingMode::ByRef(ast::Mutability::Not)
-                        } else {
-                            ast::BindingMode::ByValue(ast::Mutability::Not)
-                        };
                         let ident = self.mk_pattern_ident(prefix, i);
                         let path = ident.with_span_pos(sp);
                         (
                             sp,
                             struct_field.ident,
-                            cx.pat(path.span, PatKind::Ident(binding_mode, path, None)),
+                            cx.pat(
+                                path.span,
+                                PatKind::Ident(
+                                    BindingAnnotation(by_ref, Mutability::Not),
+                                    path,
+                                    None,
+                                ),
+                            ),
                         )
                     });
 
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index c412e451a03..2aa11ac2eea 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -794,20 +794,31 @@ fn codegen_stmt<'tcx>(
         | StatementKind::AscribeUserType(..) => {}
 
         StatementKind::Coverage { .. } => fx.tcx.sess.fatal("-Zcoverage is unimplemented"),
-        StatementKind::CopyNonOverlapping(inner) => {
-            let dst = codegen_operand(fx, &inner.dst);
-            let pointee = dst
-                .layout()
-                .pointee_info_at(fx, rustc_target::abi::Size::ZERO)
-                .expect("Expected pointer");
-            let dst = dst.load_scalar(fx);
-            let src = codegen_operand(fx, &inner.src).load_scalar(fx);
-            let count = codegen_operand(fx, &inner.count).load_scalar(fx);
-            let elem_size: u64 = pointee.size.bytes();
-            let bytes =
-                if elem_size != 1 { fx.bcx.ins().imul_imm(count, elem_size as i64) } else { count };
-            fx.bcx.call_memcpy(fx.target_config, dst, src, bytes);
-        }
+        StatementKind::Intrinsic(ref intrinsic) => match &**intrinsic {
+            // We ignore `assume` intrinsics, they are only useful for optimizations
+            NonDivergingIntrinsic::Assume(_) => {}
+            NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping {
+                src,
+                dst,
+                count,
+            }) => {
+                let dst = codegen_operand(fx, dst);
+                let pointee = dst
+                    .layout()
+                    .pointee_info_at(fx, rustc_target::abi::Size::ZERO)
+                    .expect("Expected pointer");
+                let dst = dst.load_scalar(fx);
+                let src = codegen_operand(fx, src).load_scalar(fx);
+                let count = codegen_operand(fx, count).load_scalar(fx);
+                let elem_size: u64 = pointee.size.bytes();
+                let bytes = if elem_size != 1 {
+                    fx.bcx.ins().imul_imm(count, elem_size as i64)
+                } else {
+                    count
+                };
+                fx.bcx.call_memcpy(fx.target_config, dst, src, bytes);
+            }
+        },
     }
 }
 
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index 9224f499339..0305341da78 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -536,9 +536,11 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
                         {
                             return None;
                         }
-                        StatementKind::CopyNonOverlapping(_) => {
-                            return None;
-                        } // conservative handling
+                        StatementKind::Intrinsic(ref intrinsic) => match **intrinsic {
+                            NonDivergingIntrinsic::CopyNonOverlapping(..) => return None,
+                            NonDivergingIntrinsic::Assume(..) => {}
+                        },
+                        // conservative handling
                         StatementKind::Assign(_)
                         | StatementKind::FakeRead(_)
                         | StatementKind::SetDiscriminant { .. }
diff --git a/compiler/rustc_codegen_cranelift/src/discriminant.rs b/compiler/rustc_codegen_cranelift/src/discriminant.rs
index e41ae1fbdba..97b395bcd05 100644
--- a/compiler/rustc_codegen_cranelift/src/discriminant.rs
+++ b/compiler/rustc_codegen_cranelift/src/discriminant.rs
@@ -42,10 +42,10 @@ pub(crate) fn codegen_set_discriminant<'tcx>(
         Variants::Multiple {
             tag: _,
             tag_field,
-            tag_encoding: TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start },
+            tag_encoding: TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start },
             variants: _,
         } => {
-            if variant_index != dataful_variant {
+            if variant_index != untagged_variant {
                 let niche = place.place_field(fx, mir::Field::new(tag_field));
                 let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
                 let niche_value = ty::ScalarInt::try_from_uint(
@@ -113,7 +113,7 @@ pub(crate) fn codegen_get_discriminant<'tcx>(
             let res = CValue::by_val(val, dest_layout);
             dest.write_cvalue(fx, res);
         }
-        TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => {
+        TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => {
             // Rebase from niche values to discriminants, and check
             // whether the result is in range for the niche variants.
 
@@ -169,8 +169,9 @@ pub(crate) fn codegen_get_discriminant<'tcx>(
                 fx.bcx.ins().iadd_imm(relative_discr, i64::from(niche_variants.start().as_u32()))
             };
 
-            let dataful_variant = fx.bcx.ins().iconst(cast_to, i64::from(dataful_variant.as_u32()));
-            let discr = fx.bcx.ins().select(is_niche, niche_discr, dataful_variant);
+            let untagged_variant =
+                fx.bcx.ins().iconst(cast_to, i64::from(untagged_variant.as_u32()));
+            let discr = fx.bcx.ins().select(is_niche, niche_discr, untagged_variant);
             let res = CValue::by_val(discr, dest_layout);
             dest.write_cvalue(fx, res);
         }
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 39e9e784a47..0cd9332a58b 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -357,9 +357,6 @@ fn codegen_regular_intrinsic_call<'tcx>(
     let usize_layout = fx.layout_of(fx.tcx.types.usize);
 
     match intrinsic {
-        sym::assume => {
-            intrinsic_args!(fx, args => (_a); intrinsic);
-        }
         sym::likely | sym::unlikely => {
             intrinsic_args!(fx, args => (a); intrinsic);
 
diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs
index ccb6cbbc2c8..aa1c271c31c 100644
--- a/compiler/rustc_codegen_gcc/src/common.rs
+++ b/compiler/rustc_codegen_gcc/src/common.rs
@@ -158,10 +158,6 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         None
     }
 
-    fn zst_to_backend(&self, _ty: Type<'gcc>) -> RValue<'gcc> {
-        self.const_undef(self.type_ix(0))
-    }
-
     fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) -> RValue<'gcc> {
         let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() };
         match cv {
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index 0ce161d7e75..26f5225f6b4 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -19,6 +19,7 @@ use rustc_target::abi::call::ArgAbi;
 pub use rustc_target::abi::call::*;
 use rustc_target::abi::{self, HasDataLayout, Int};
 pub use rustc_target::spec::abi::Abi;
+use rustc_target::spec::SanitizerSet;
 
 use libc::c_uint;
 use smallvec::SmallVec;
@@ -90,6 +91,13 @@ fn get_attrs<'ll>(this: &ArgAttributes, cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'
         if regular.contains(ArgAttribute::NoAliasMutRef) && should_use_mutable_noalias(cx) {
             attrs.push(llvm::AttributeKind::NoAlias.create_attr(cx.llcx));
         }
+    } else if cx.tcx.sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::MEMORY) {
+        // If we're not optimising, *but* memory sanitizer is on, emit noundef, since it affects
+        // memory sanitizer's behavior.
+
+        if regular.contains(ArgAttribute::NoUndef) {
+            attrs.push(llvm::AttributeKind::NoUndef.create_attr(cx.llcx));
+        }
     }
 
     attrs
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index aabbe8ac276..b38684a63e4 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -386,7 +386,8 @@ pub fn from_fn_attrs<'ll, 'tcx>(
     ) {
         let span = cx
             .tcx
-            .get_attr(instance.def_id(), sym::target_feature)
+            .get_attrs(instance.def_id(), sym::target_feature)
+            .next()
             .map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span);
         let msg = format!(
             "the target features {} must all be either enabled or disabled together",
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index 13e437cfbf7..488ea72c3b7 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -226,10 +226,6 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         })
     }
 
-    fn zst_to_backend(&self, _llty: &'ll Type) -> &'ll Value {
-        self.const_undef(self.type_ix(0))
-    }
-
     fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: &'ll Type) -> &'ll Value {
         let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() };
         match cv {
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
index daec9303b2c..129e336c7e4 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
@@ -99,7 +99,7 @@ const SINGLE_VARIANT_VIRTUAL_DISR: u64 = 0;
 /// compiler versions.
 ///
 /// Niche-tag enums have one special variant, usually called the
-/// "dataful variant". This variant has a field that
+/// "untagged variant". This variant has a field that
 /// doubles as the tag of the enum. The variant is active when the value of
 /// that field is within a pre-defined range. Therefore the variant struct
 /// has a `DISCR_BEGIN` and `DISCR_END` field instead of `DISCR_EXACT` in
@@ -249,7 +249,7 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
                     None,
                 ),
                 Variants::Multiple {
-                    tag_encoding: TagEncoding::Niche { dataful_variant, .. },
+                    tag_encoding: TagEncoding::Niche { untagged_variant, .. },
                     ref variants,
                     tag_field,
                     ..
@@ -260,7 +260,7 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
                     enum_type_di_node,
                     variants.indices(),
                     tag_field,
-                    Some(dataful_variant),
+                    Some(untagged_variant),
                 ),
             }
         },
@@ -391,7 +391,7 @@ fn build_union_fields_for_enum<'ll, 'tcx>(
     enum_type_di_node: &'ll DIType,
     variant_indices: impl Iterator<Item = VariantIdx> + Clone,
     tag_field: usize,
-    dataful_variant_index: Option<VariantIdx>,
+    untagged_variant_index: Option<VariantIdx>,
 ) -> SmallVec<&'ll DIType> {
     let tag_base_type = super::tag_base_type(cx, enum_type_and_layout);
 
@@ -436,7 +436,7 @@ fn build_union_fields_for_enum<'ll, 'tcx>(
         variant_names_type_di_node,
         tag_base_type,
         tag_field,
-        dataful_variant_index,
+        untagged_variant_index,
     )
 }
 
@@ -472,7 +472,7 @@ fn build_variant_struct_wrapper_type_di_node<'ll, 'tcx>(
     enum_or_generator_type_and_layout: TyAndLayout<'tcx>,
     enum_or_generator_type_di_node: &'ll DIType,
     variant_index: VariantIdx,
-    dataful_variant_index: Option<VariantIdx>,
+    untagged_variant_index: Option<VariantIdx>,
     variant_struct_type_di_node: &'ll DIType,
     variant_names_type_di_node: &'ll DIType,
     tag_base_type_di_node: &'ll DIType,
@@ -517,7 +517,7 @@ fn build_variant_struct_wrapper_type_di_node<'ll, 'tcx>(
                     }
                 }
                 DiscrResult::Range(min, max) => {
-                    assert_eq!(Some(variant_index), dataful_variant_index);
+                    assert_eq!(Some(variant_index), untagged_variant_index);
                     if is_128_bits {
                         DiscrKind::Range128(min, max)
                     } else {
@@ -757,7 +757,7 @@ fn build_union_fields_for_direct_tag_enum_or_generator<'ll, 'tcx>(
     discr_type_di_node: &'ll DIType,
     tag_base_type: Ty<'tcx>,
     tag_field: usize,
-    dataful_variant_index: Option<VariantIdx>,
+    untagged_variant_index: Option<VariantIdx>,
 ) -> SmallVec<&'ll DIType> {
     let tag_base_type_di_node = type_di_node(cx, tag_base_type);
     let mut unions_fields = SmallVec::with_capacity(variant_field_infos.len() + 1);
@@ -776,7 +776,7 @@ fn build_union_fields_for_direct_tag_enum_or_generator<'ll, 'tcx>(
             enum_type_and_layout,
             enum_type_di_node,
             variant_member_info.variant_index,
-            dataful_variant_index,
+            untagged_variant_index,
             variant_member_info.variant_struct_type_di_node,
             discr_type_di_node,
             tag_base_type_di_node,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
index 9b3d080bfd6..14044d0f99b 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
@@ -417,7 +417,7 @@ impl DiscrResult {
 /// Returns the discriminant value corresponding to the variant index.
 ///
 /// Will return `None` if there is less than two variants (because then the enum won't have)
-/// a tag, and if this is the dataful variant of a niche-layout enum (because then there is no
+/// a tag, and if this is the untagged variant of a niche-layout enum (because then there is no
 /// single discriminant value).
 fn compute_discriminant_value<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
@@ -430,11 +430,11 @@ fn compute_discriminant_value<'ll, 'tcx>(
             enum_type_and_layout.ty.discriminant_for_variant(cx.tcx, variant_index).unwrap().val,
         ),
         &Variants::Multiple {
-            tag_encoding: TagEncoding::Niche { ref niche_variants, niche_start, dataful_variant },
+            tag_encoding: TagEncoding::Niche { ref niche_variants, niche_start, untagged_variant },
             tag,
             ..
         } => {
-            if variant_index == dataful_variant {
+            if variant_index == untagged_variant {
                 let valid_range = enum_type_and_layout
                     .for_variant(cx, variant_index)
                     .largest_niche
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs
index dae90a43f26..becbccc434d 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs
@@ -378,7 +378,7 @@ fn build_discr_member_di_node<'ll, 'tcx>(
 ///
 /// The DW_AT_discr_value is optional, and is omitted if
 ///   - This is the only variant of a univariant enum (i.e. their is no discriminant)
-///   - This is the "dataful" variant of a niche-layout enum
+///   - This is the "untagged" variant of a niche-layout enum
 ///     (where only the other variants are identified by a single value)
 ///
 /// There is only ever a single member, the type of which is a struct that describes the
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index e9171823c24..a3fed88cc4b 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -1,6 +1,6 @@
 use rustc_arena::TypedArena;
 use rustc_ast::CRATE_NODE_ID;
-use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_errors::{ErrorGuaranteed, Handler};
@@ -1714,6 +1714,13 @@ fn add_post_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor
 /// that are necessary for the linking. They are only present in symbol table but not actually
 /// used in any sections, so the linker will therefore pick relevant rlibs for linking, but
 /// unused `#[no_mangle]` or `#[used]` can still be discard by GC sections.
+///
+/// There's a few internal crates in the standard library (aka libcore and
+/// libstd) which actually have a circular dependence upon one another. This
+/// currently arises through "weak lang items" where libcore requires things
+/// like `rust_begin_unwind` but libstd ends up defining it. To get this
+/// circular dependence to work correctly we declare some of these things
+/// in this synthetic object.
 fn add_linked_symbol_object(
     cmd: &mut dyn Linker,
     sess: &Session,
@@ -2333,65 +2340,10 @@ fn add_upstream_rust_crates<'a>(
     // crates.
     let deps = &codegen_results.crate_info.used_crates;
 
-    // There's a few internal crates in the standard library (aka libcore and
-    // libstd) which actually have a circular dependence upon one another. This
-    // currently arises through "weak lang items" where libcore requires things
-    // like `rust_begin_unwind` but libstd ends up defining it. To get this
-    // circular dependence to work correctly in all situations we'll need to be
-    // sure to correctly apply the `--start-group` and `--end-group` options to
-    // GNU linkers, otherwise if we don't use any other symbol from the standard
-    // library it'll get discarded and the whole application won't link.
-    //
-    // In this loop we're calculating the `group_end`, after which crate to
-    // pass `--end-group` and `group_start`, before which crate to pass
-    // `--start-group`. We currently do this by passing `--end-group` after
-    // the first crate (when iterating backwards) that requires a lang item
-    // defined somewhere else. Once that's set then when we've defined all the
-    // necessary lang items we'll pass `--start-group`.
-    //
-    // Note that this isn't amazing logic for now but it should do the trick
-    // for the current implementation of the standard library.
-    let mut group_end = None;
-    let mut group_start = None;
-    // Crates available for linking thus far.
-    let mut available = FxHashSet::default();
-    // Crates required to satisfy dependencies discovered so far.
-    let mut required = FxHashSet::default();
-
-    let info = &codegen_results.crate_info;
-    for &cnum in deps.iter().rev() {
-        if let Some(missing) = info.missing_lang_items.get(&cnum) {
-            let missing_crates = missing.iter().map(|i| info.lang_item_to_crate.get(i).copied());
-            required.extend(missing_crates);
-        }
-
-        required.insert(Some(cnum));
-        available.insert(Some(cnum));
-
-        if required.len() > available.len() && group_end.is_none() {
-            group_end = Some(cnum);
-        }
-        if required.len() == available.len() && group_end.is_some() {
-            group_start = Some(cnum);
-            break;
-        }
-    }
-
-    // If we didn't end up filling in all lang items from upstream crates then
-    // we'll be filling it in with our crate. This probably means we're the
-    // standard library itself, so skip this for now.
-    if group_end.is_some() && group_start.is_none() {
-        group_end = None;
-    }
-
     let mut compiler_builtins = None;
     let search_path = OnceCell::new();
 
     for &cnum in deps.iter() {
-        if group_start == Some(cnum) {
-            cmd.group_start();
-        }
-
         // We may not pass all crates through to the linker. Some crates may
         // appear statically in an existing dylib, meaning we'll pick up all the
         // symbols from the dylib.
@@ -2451,6 +2403,14 @@ fn add_upstream_rust_crates<'a>(
                                 bundle: Some(false),
                                 whole_archive: Some(false) | None,
                             } => {
+                                // HACK/FIXME: Fixup a circular dependency between libgcc and libc
+                                // with glibc. This logic should be moved to the libc crate.
+                                if sess.target.os == "linux"
+                                    && sess.target.env == "gnu"
+                                    && name == "c"
+                                {
+                                    cmd.link_staticlib("gcc", false);
+                                }
                                 cmd.link_staticlib(name, lib.verbatim.unwrap_or(false));
                             }
                             NativeLibKind::LinkArg => {
@@ -2470,10 +2430,6 @@ fn add_upstream_rust_crates<'a>(
             }
             Linkage::Dynamic => add_dynamic_crate(cmd, sess, &src.dylib.as_ref().unwrap().0),
         }
-
-        if group_end == Some(cnum) {
-            cmd.group_end();
-        }
     }
 
     // compiler-builtins are always placed last to ensure that they're
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 8c6f526b054..949a356fce1 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -183,8 +183,6 @@ pub trait Linker {
     fn no_default_libraries(&mut self);
     fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]);
     fn subsystem(&mut self, subsystem: &str);
-    fn group_start(&mut self);
-    fn group_end(&mut self);
     fn linker_plugin_lto(&mut self);
     fn add_eh_frame_header(&mut self) {}
     fn add_no_exec(&mut self) {}
@@ -730,18 +728,6 @@ impl<'a> Linker for GccLinker<'a> {
         self.hint_dynamic(); // Reset to default before returning the composed command line.
     }
 
-    fn group_start(&mut self) {
-        if self.takes_hints() {
-            self.linker_arg("--start-group");
-        }
-    }
-
-    fn group_end(&mut self) {
-        if self.takes_hints() {
-            self.linker_arg("--end-group");
-        }
-    }
-
     fn linker_plugin_lto(&mut self) {
         match self.sess.opts.cg.linker_plugin_lto {
             LinkerPluginLto::Disabled => {
@@ -1019,10 +1005,6 @@ impl<'a> Linker for MsvcLinker<'a> {
         }
     }
 
-    // MSVC doesn't need group indicators
-    fn group_start(&mut self) {}
-    fn group_end(&mut self) {}
-
     fn linker_plugin_lto(&mut self) {
         // Do nothing
     }
@@ -1165,10 +1147,6 @@ impl<'a> Linker for EmLinker<'a> {
         // noop
     }
 
-    // Appears not necessary on Emscripten
-    fn group_start(&mut self) {}
-    fn group_end(&mut self) {}
-
     fn linker_plugin_lto(&mut self) {
         // Do nothing
     }
@@ -1344,10 +1322,6 @@ impl<'a> Linker for WasmLd<'a> {
 
     fn subsystem(&mut self, _subsystem: &str) {}
 
-    // Not needed for now with LLD
-    fn group_start(&mut self) {}
-    fn group_end(&mut self) {}
-
     fn linker_plugin_lto(&mut self) {
         // Do nothing for now
     }
@@ -1476,14 +1450,6 @@ impl<'a> Linker for L4Bender<'a> {
         self.hint_static(); // Reset to default before returning the composed command line.
     }
 
-    fn group_start(&mut self) {
-        self.cmd.arg("--start-group");
-    }
-
-    fn group_end(&mut self) {
-        self.cmd.arg("--end-group");
-    }
-
     fn linker_plugin_lto(&mut self) {}
 
     fn control_flow_guard(&mut self) {}
@@ -1664,10 +1630,6 @@ impl<'a> Linker for PtxLinker<'a> {
 
     fn subsystem(&mut self, _subsystem: &str) {}
 
-    fn group_start(&mut self) {}
-
-    fn group_end(&mut self) {}
-
     fn linker_plugin_lto(&mut self) {}
 }
 
@@ -1777,9 +1739,5 @@ impl<'a> Linker for BpfLinker<'a> {
 
     fn subsystem(&mut self, _subsystem: &str) {}
 
-    fn group_start(&mut self) {}
-
-    fn group_end(&mut self) {}
-
     fn linker_plugin_lto(&mut self) {}
 }
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 6e482062383..5f140d709d8 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -12,7 +12,7 @@ use crate::traits::*;
 use crate::{CachedModuleCodegen, CompiledModule, CrateInfo, MemFlags, ModuleCodegen, ModuleKind};
 
 use rustc_attr as attr;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
 
 use rustc_data_structures::sync::par_iter;
@@ -21,10 +21,12 @@ use rustc_data_structures::sync::ParallelIterator;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::lang_items::LangItem;
+use rustc_hir::weak_lang_items::WEAK_ITEMS_SYMBOLS;
 use rustc_index::vec::Idx;
 use rustc_metadata::EncodedMetadata;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
 use rustc_middle::middle::exported_symbols;
+use rustc_middle::middle::exported_symbols::SymbolExportKind;
 use rustc_middle::middle::lang_items;
 use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem};
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
@@ -34,6 +36,7 @@ use rustc_session::cgu_reuse_tracker::CguReuse;
 use rustc_session::config::{self, CrateType, EntryFnType, OutputType};
 use rustc_session::Session;
 use rustc_span::symbol::sym;
+use rustc_span::Symbol;
 use rustc_span::{DebuggerVisualizerFile, DebuggerVisualizerType};
 use rustc_target::abi::{Align, VariantIdx};
 
@@ -815,21 +818,16 @@ impl CrateInfo {
             crate_name: Default::default(),
             used_crates,
             used_crate_source: Default::default(),
-            lang_item_to_crate: Default::default(),
-            missing_lang_items: Default::default(),
             dependency_formats: tcx.dependency_formats(()).clone(),
             windows_subsystem,
             natvis_debugger_visualizers: Default::default(),
         };
-        let lang_items = tcx.lang_items();
-
         let crates = tcx.crates(());
 
         let n_crates = crates.len();
         info.native_libraries.reserve(n_crates);
         info.crate_name.reserve(n_crates);
         info.used_crate_source.reserve(n_crates);
-        info.missing_lang_items.reserve(n_crates);
 
         for &cnum in crates.iter() {
             info.native_libraries
@@ -847,17 +845,37 @@ impl CrateInfo {
             if tcx.is_no_builtins(cnum) {
                 info.is_no_builtins.insert(cnum);
             }
-            let missing = tcx.missing_lang_items(cnum);
-            for &item in missing.iter() {
-                if let Ok(id) = lang_items.require(item) {
-                    info.lang_item_to_crate.insert(item, id.krate);
-                }
-            }
+        }
 
-            // No need to look for lang items that don't actually need to exist.
-            let missing =
-                missing.iter().cloned().filter(|&l| lang_items::required(tcx, l)).collect();
-            info.missing_lang_items.insert(cnum, missing);
+        // Handle circular dependencies in the standard library.
+        // See comment before `add_linked_symbol_object` function for the details.
+        // With msvc-like linkers it's both unnecessary (they support circular dependencies),
+        // and causes linking issues (when weak lang item symbols are "privatized" by LTO).
+        let target = &tcx.sess.target;
+        if !target.is_like_msvc {
+            let missing_weak_lang_items: FxHashSet<&Symbol> = info
+                .used_crates
+                .iter()
+                .flat_map(|cnum| {
+                    tcx.missing_lang_items(*cnum)
+                        .iter()
+                        .filter(|l| lang_items::required(tcx, **l))
+                        .filter_map(|item| WEAK_ITEMS_SYMBOLS.get(item))
+                })
+                .collect();
+            let prefix = if target.is_like_windows && target.arch == "x86" { "_" } else { "" };
+            info.linked_symbols
+                .iter_mut()
+                .filter(|(crate_type, _)| {
+                    !matches!(crate_type, CrateType::Rlib | CrateType::Staticlib)
+                })
+                .for_each(|(_, linked_symbols)| {
+                    linked_symbols.extend(
+                        missing_weak_lang_items
+                            .iter()
+                            .map(|item| (format!("{prefix}{item}"), SymbolExportKind::Text)),
+                    )
+                });
         }
 
         let embed_visualizers = tcx.sess.crate_types().iter().any(|&crate_type| match crate_type {
@@ -878,7 +896,7 @@ impl CrateInfo {
             }
         });
 
-        if tcx.sess.target.is_like_msvc && embed_visualizers {
+        if target.is_like_msvc && embed_visualizers {
             info.natvis_debugger_visualizers =
                 collect_debugger_visualizers_transitive(tcx, DebuggerVisualizerType::Natvis);
         }
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index 0faf51b062b..52da7abcac5 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -25,7 +25,6 @@ use rustc_ast as ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::Lrc;
 use rustc_hir::def_id::CrateNum;
-use rustc_hir::LangItem;
 use rustc_middle::dep_graph::WorkProduct;
 use rustc_middle::middle::dependency_format::Dependencies;
 use rustc_middle::middle::exported_symbols::SymbolExportKind;
@@ -152,8 +151,6 @@ pub struct CrateInfo {
     pub used_libraries: Vec<NativeLib>,
     pub used_crate_source: FxHashMap<CrateNum, Lrc<CrateSource>>,
     pub used_crates: Vec<CrateNum>,
-    pub lang_item_to_crate: FxHashMap<LangItem, CrateNum>,
-    pub missing_lang_items: FxHashMap<CrateNum, Vec<LangItem>>,
     pub dependency_formats: Lrc<Dependencies>,
     pub windows_subsystem: Option<String>,
     pub natvis_debugger_visualizers: BTreeSet<DebuggerVisualizerFile>,
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 16aad07194d..6393dd9d634 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -77,10 +77,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout);
 
         let llval = match name {
-            sym::assume => {
-                bx.assume(args[0].immediate());
-                return;
-            }
             sym::abort => {
                 bx.abort();
                 return;
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index c612634fce2..37b1e036247 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -72,10 +72,6 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
     ) -> Self {
         let layout = bx.layout_of(ty);
 
-        if layout.is_zst() {
-            return OperandRef::new_zst(bx, layout);
-        }
-
         let val = match val {
             ConstValue::Scalar(x) => {
                 let Abi::Scalar(scalar) = layout.abi else {
@@ -84,10 +80,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
                 let llval = bx.scalar_to_backend(x, scalar, bx.immediate_backend_type(layout));
                 OperandValue::Immediate(llval)
             }
-            ConstValue::ZeroSized => {
-                let llval = bx.zst_to_backend(bx.immediate_backend_type(layout));
-                OperandValue::Immediate(llval)
-            }
+            ConstValue::ZeroSized => return OperandRef::new_zst(bx, layout),
             ConstValue::Slice { data, start, end } => {
                 let Abi::ScalarPair(a_scalar, _) = layout.abi else {
                     bug!("from_const: invalid ScalarPair layout: {:#?}", layout);
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index 04b8c8636f6..13d8f6eddd1 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -244,7 +244,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
                 };
                 bx.intcast(tag.immediate(), cast_to, signed)
             }
-            TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => {
+            TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => {
                 // Rebase from niche values to discriminants, and check
                 // whether the result is in range for the niche variants.
                 let niche_llty = bx.cx().immediate_backend_type(tag.layout);
@@ -302,7 +302,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
                 bx.select(
                     is_niche,
                     niche_discr,
-                    bx.cx().const_uint(cast_to, dataful_variant.as_u32() as u64),
+                    bx.cx().const_uint(cast_to, untagged_variant.as_u32() as u64),
                 )
             }
         }
@@ -337,11 +337,11 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
             }
             Variants::Multiple {
                 tag_encoding:
-                    TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start },
+                    TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start },
                 tag_field,
                 ..
             } => {
-                if variant_index != dataful_variant {
+                if variant_index != untagged_variant {
                     let niche = self.project_field(bx, tag_field);
                     let niche_llty = bx.cx().immediate_backend_type(niche.layout);
                     let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs
index f452f29883f..1db0fb3a6f1 100644
--- a/compiler/rustc_codegen_ssa/src/mir/statement.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs
@@ -1,4 +1,5 @@
 use rustc_middle::mir;
+use rustc_middle::mir::NonDivergingIntrinsic;
 
 use super::FunctionCx;
 use super::LocalRef;
@@ -73,11 +74,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 self.codegen_coverage(&mut bx, coverage.clone(), statement.source_info.scope);
                 bx
             }
-            mir::StatementKind::CopyNonOverlapping(box mir::CopyNonOverlapping {
-                ref src,
-                ref dst,
-                ref count,
-            }) => {
+            mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(ref op)) => {
+                let op_val = self.codegen_operand(&mut bx, op);
+                bx.assume(op_val.immediate());
+                bx
+            }
+            mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(
+                mir::CopyNonOverlapping { ref count, ref src, ref dst },
+            )) => {
                 let dst_val = self.codegen_operand(&mut bx, dst);
                 let src_val = self.codegen_operand(&mut bx, src);
                 let count = self.codegen_operand(&mut bx, count).immediate();
diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs
index 8a91d4735ba..fdc7a30e841 100644
--- a/compiler/rustc_codegen_ssa/src/traits/consts.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs
@@ -29,7 +29,6 @@ pub trait ConstMethods<'tcx>: BackendTypes {
     fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value;
 
     fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value;
-    fn zst_to_backend(&self, llty: Self::Type) -> Self::Value;
     fn from_const_alloc(
         &self,
         layout: TyAndLayout<'tcx>,
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index adda9639990..7dba5059307 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -8,7 +8,7 @@ use rustc_hir::def_id::DefId;
 use rustc_middle::mir::{
     self,
     interpret::{ConstValue, GlobalId, InterpResult, PointerArithmetic, Scalar},
-    BinOp,
+    BinOp, NonDivergingIntrinsic,
 };
 use rustc_middle::ty;
 use rustc_middle::ty::layout::LayoutOf as _;
@@ -79,9 +79,9 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
             ty::Projection(_)
             | ty::Opaque(_, _)
             | ty::Param(_)
-            | ty::Bound(_, _)
             | ty::Placeholder(_)
             | ty::Infer(_) => throw_inval!(TooGeneric),
+            ty::Bound(_, _) => bug!("bound ty during ctfe"),
             ty::Bool
             | ty::Char
             | ty::Int(_)
@@ -506,12 +506,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 // These just return their argument
                 self.copy_op(&args[0], dest, /*allow_transmute*/ false)?;
             }
-            sym::assume => {
-                let cond = self.read_scalar(&args[0])?.to_bool()?;
-                if !cond {
-                    throw_ub_format!("`assume` intrinsic called with `false`");
-                }
-            }
             sym::raw_eq => {
                 let result = self.raw_eq_intrinsic(&args[0], &args[1])?;
                 self.write_scalar(result, dest)?;
@@ -536,6 +530,32 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         Ok(true)
     }
 
+    pub(super) fn emulate_nondiverging_intrinsic(
+        &mut self,
+        intrinsic: &NonDivergingIntrinsic<'tcx>,
+    ) -> InterpResult<'tcx> {
+        match intrinsic {
+            NonDivergingIntrinsic::Assume(op) => {
+                let op = self.eval_operand(op, None)?;
+                let cond = self.read_scalar(&op)?.to_bool()?;
+                if !cond {
+                    throw_ub_format!("`assume` called with `false`");
+                }
+                Ok(())
+            }
+            NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping {
+                count,
+                src,
+                dst,
+            }) => {
+                let src = self.eval_operand(src, None)?;
+                let dst = self.eval_operand(dst, None)?;
+                let count = self.eval_operand(count, None)?;
+                self.copy_intrinsic(&src, &dst, &count, /* nonoverlapping */ true)
+            }
+        }
+    }
+
     pub fn exact_div(
         &mut self,
         a: &ImmTy<'tcx, M::Provenance>,
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index 5aabb14fba8..530e252b7c0 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -6,6 +6,7 @@ use std::borrow::{Borrow, Cow};
 use std::fmt::Debug;
 use std::hash::Hash;
 
+use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_middle::mir;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::def_id::DefId;
@@ -323,6 +324,15 @@ pub trait Machine<'mir, 'tcx>: Sized {
         kind: Option<MemoryKind<Self::MemoryKind>>,
     ) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra>>>;
 
+    fn eval_inline_asm(
+        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
+        _template: &'tcx [InlineAsmTemplatePiece],
+        _operands: &[mir::InlineAsmOperand<'tcx>],
+        _options: InlineAsmOptions,
+    ) -> InterpResult<'tcx> {
+        throw_unsup_format!("inline assembly is not supported")
+    }
+
     /// Hook for performing extra checks on a memory read access.
     ///
     /// Takes read-only access to the allocation so we can keep all the memory read
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index 35c2cf8102d..f6c4f7dd112 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -559,7 +559,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         layout: Option<TyAndLayout<'tcx>>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
         match c.kind() {
-            ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric),
+            ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(..) => throw_inval!(TooGeneric),
             ty::ConstKind::Error(DelaySpanBugEmitted { reported, .. }) => {
                 throw_inval!(AlreadyReported(reported))
             }
@@ -567,7 +567,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let instance = self.resolve(uv.def, uv.substs)?;
                 Ok(self.eval_to_allocation(GlobalId { instance, promoted: uv.promoted })?.into())
             }
-            ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => {
+            ty::ConstKind::Bound(..) | ty::ConstKind::Infer(..) => {
                 span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", c)
             }
             ty::ConstKind::Value(valtree) => {
@@ -718,7 +718,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 // Return the cast value, and the index.
                 (discr_val, index.0)
             }
-            TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => {
+            TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => {
                 let tag_val = tag_val.to_scalar();
                 // Compute the variant this niche value/"tag" corresponds to. With niche layout,
                 // discriminant (encoded in niche/tag) and variant index are the same.
@@ -736,7 +736,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                         if !ptr_valid {
                             throw_ub!(InvalidTag(dbg_val))
                         }
-                        dataful_variant
+                        untagged_variant
                     }
                     Ok(tag_bits) => {
                         let tag_bits = tag_bits.assert_bits(tag_layout.size);
@@ -766,7 +766,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                             assert!(usize::try_from(variant_index).unwrap() < variants_len);
                             VariantIdx::from_u32(variant_index)
                         } else {
-                            dataful_variant
+                            untagged_variant
                         }
                     }
                 };
@@ -780,13 +780,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 }
 
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64", not(bootstrap)))]
 mod size_asserts {
     use super::*;
     use rustc_data_structures::static_assert_size;
     // These are in alphabetical order, which is easy to maintain.
-    static_assert_size!(Immediate, 56);
-    static_assert_size!(ImmTy<'_>, 72);
-    static_assert_size!(Operand, 64);
-    static_assert_size!(OpTy<'_>, 88);
+    static_assert_size!(Immediate, 48);
+    static_assert_size!(ImmTy<'_>, 64);
+    static_assert_size!(Operand, 56);
+    static_assert_size!(OpTy<'_>, 80);
 }
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index a03b0dfb603..b328892906d 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -817,7 +817,7 @@ where
             }
             abi::Variants::Multiple {
                 tag_encoding:
-                    TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start },
+                    TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start },
                 tag: tag_layout,
                 tag_field,
                 ..
@@ -825,7 +825,7 @@ where
                 // No need to validate that the discriminant here because the
                 // `TyAndLayout::for_variant()` call earlier already checks the variant is valid.
 
-                if variant_index != dataful_variant {
+                if variant_index != untagged_variant {
                     let variants_start = niche_variants.start().as_u32();
                     let variant_index_relative = variant_index
                         .as_u32()
@@ -890,6 +890,8 @@ mod size_asserts {
     static_assert_size!(MemPlaceMeta, 24);
     static_assert_size!(MemPlace, 40);
     static_assert_size!(MPlaceTy<'_>, 64);
-    static_assert_size!(Place, 48);
-    static_assert_size!(PlaceTy<'_>, 72);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(Place, 40);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(PlaceTy<'_>, 64);
 }
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 6b827149f50..c6e04cbfb6b 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -114,13 +114,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 M::retag(self, *kind, &dest)?;
             }
 
-            // Call CopyNonOverlapping
-            CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { src, dst, count }) => {
-                let src = self.eval_operand(src, None)?;
-                let dst = self.eval_operand(dst, None)?;
-                let count = self.eval_operand(count, None)?;
-                self.copy_intrinsic(&src, &dst, &count, /* nonoverlapping */ true)?;
-            }
+            Intrinsic(box ref intrinsic) => self.emulate_nondiverging_intrinsic(intrinsic)?,
 
             // Statements we do not track.
             AscribeUserType(..) => {}
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index ea366eba772..50a82aa0e72 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -1,5 +1,6 @@
 use std::borrow::Cow;
 
+use rustc_ast::ast::InlineAsmOptions;
 use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
 use rustc_middle::ty::Instance;
 use rustc_middle::{
@@ -166,8 +167,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 terminator.kind
             ),
 
-            // Inline assembly can't be interpreted.
-            InlineAsm { .. } => throw_unsup_format!("inline assembly is not supported"),
+            InlineAsm { template, ref operands, options, destination, .. } => {
+                M::eval_inline_asm(self, template, operands, options)?;
+                if options.contains(InlineAsmOptions::NORETURN) {
+                    throw_ub_format!("returned from noreturn inline assembly");
+                }
+                self.go_to_block(
+                    destination
+                        .expect("InlineAsm terminators without noreturn must have a destination"),
+                )
+            }
         }
 
         Ok(())
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 cbfdb47dd1a..3fa40dc3059 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -678,7 +678,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
             | StatementKind::Retag { .. }
             | StatementKind::AscribeUserType(..)
             | StatementKind::Coverage(..)
-            | StatementKind::CopyNonOverlapping(..)
+            | StatementKind::Intrinsic(..)
             | StatementKind::Nop => {}
         }
     }
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index b7988625839..8576e0f0f7c 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -7,9 +7,10 @@ use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::mir::visit::NonUseContext::VarDebugInfo;
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
 use rustc_middle::mir::{
-    traversal, AggregateKind, BasicBlock, BinOp, Body, BorrowKind, CastKind, Local, Location,
-    MirPass, MirPhase, Operand, Place, PlaceElem, PlaceRef, ProjectionElem, RuntimePhase, Rvalue,
-    SourceScope, Statement, StatementKind, Terminator, TerminatorKind, UnOp, START_BLOCK,
+    traversal, AggregateKind, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping,
+    Local, Location, MirPass, MirPhase, NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef,
+    ProjectionElem, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, Terminator,
+    TerminatorKind, UnOp, START_BLOCK,
 };
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::subst::Subst;
@@ -89,20 +90,21 @@ pub fn equal_up_to_regions<'tcx>(
 
     // Normalize lifetimes away on both sides, then compare.
     let normalize = |ty: Ty<'tcx>| {
-        let ty = ty.fold_with(&mut BottomUpFolder {
-            tcx,
-            // FIXME: We erase all late-bound lifetimes, but this is not fully correct.
-            // If you have a type like `<for<'a> fn(&'a u32) as SomeTrait>::Assoc`,
-            // this is not necessarily equivalent to `<fn(&'static u32) as SomeTrait>::Assoc`,
-            // since one may have an `impl SomeTrait for fn(&32)` and
-            // `impl SomeTrait for fn(&'static u32)` at the same time which
-            // specify distinct values for Assoc. (See also #56105)
-            lt_op: |_| tcx.lifetimes.re_erased,
-            // Leave consts and types unchanged.
-            ct_op: |ct| ct,
-            ty_op: |ty| ty,
-        });
-        tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty)
+        tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty).fold_with(
+            &mut BottomUpFolder {
+                tcx,
+                // FIXME: We erase all late-bound lifetimes, but this is not fully correct.
+                // If you have a type like `<for<'a> fn(&'a u32) as SomeTrait>::Assoc`,
+                // this is not necessarily equivalent to `<fn(&'static u32) as SomeTrait>::Assoc`,
+                // since one may have an `impl SomeTrait for fn(&32)` and
+                // `impl SomeTrait for fn(&'static u32)` at the same time which
+                // specify distinct values for Assoc. (See also #56105)
+                lt_op: |_| tcx.lifetimes.re_erased,
+                // Leave consts and types unchanged.
+                ct_op: |ct| ct,
+                ty_op: |ty| ty,
+            },
+        )
     };
     tcx.infer_ctxt().enter(|infcx| infcx.can_eq(param_env, normalize(src), normalize(dest)).is_ok())
 }
@@ -636,11 +638,18 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                     );
                 }
             }
-            StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
-                ref src,
-                ref dst,
-                ref count,
-            }) => {
+            StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => {
+                let ty = op.ty(&self.body.local_decls, self.tcx);
+                if !ty.is_bool() {
+                    self.fail(
+                        location,
+                        format!("`assume` argument must be `bool`, but got: `{}`", ty),
+                    );
+                }
+            }
+            StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(
+                CopyNonOverlapping { src, dst, count },
+            )) => {
                 let src_ty = src.ty(&self.body.local_decls, self.tcx);
                 let op_src_ty = if let Some(src_deref) = src_ty.builtin_deref(true) {
                     src_deref.ty
diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
index 07a96dd7dbb..e351b650a16 100644
--- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs
+++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
@@ -117,6 +117,10 @@ pub trait ObligationProcessor {
 }
 
 /// The result type used by `process_obligation`.
+// `repr(C)` to inhibit the niche filling optimization. Otherwise, the `match` appearing
+// in `process_obligations` is significantly slower, which can substantially affect
+// benchmarks like `rustc-perf`'s inflate and keccak.
+#[repr(C)]
 #[derive(Debug)]
 pub enum ProcessResult<O, E> {
     Unchanged,
diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl
index 60086cd6e47..2899b8304bc 100644
--- a/compiler/rustc_error_messages/locales/en-US/infer.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl
@@ -104,9 +104,67 @@ infer_relate_object_bound = ...so that it can be closed over into an object
 infer_data_borrowed = ...so that the type `{$name}` is not borrowed for too long
 infer_reference_outlives_referent = ...so that the reference type `{$name}` does not outlive the data it points at
 infer_relate_param_bound = ...so that the type `{$name}` will meet its required lifetime bounds{$continues ->
-[true] ...
-*[false] {""}
+    [true] ...
+    *[false] {""}
 }
 infer_relate_param_bound_2 = ...that is required by this bound
 infer_relate_region_param_bound = ...so that the declared lifetime parameter bounds are satisfied
 infer_compare_impl_item_obligation = ...so that the definition in impl matches the definition from the trait
+
+infer_nothing = {""}
+
+infer_lifetime_mismatch = lifetime mismatch
+
+infer_declared_different = this parameter and the return type are declared with different lifetimes...
+infer_data_returned = ...but data{$label_var1_exists ->
+    [true] {" "}from `{$label_var1}`
+    *[false] {""}
+} is returned here
+
+infer_data_lifetime_flow = ...but data with one lifetime flows into the other here
+infer_declared_multiple = this type is declared with multiple lifetimes...
+infer_types_declared_different = these two types are declared with different lifetimes...
+infer_data_flows = ...but data{$label_var1_exists ->
+    [true] -> {" "}from `{$label_var1}`
+    *[false] -> {""}
+} flows{$label_var2_exists ->
+    [true] -> {" "}into `{$label_var2}`
+    *[false] -> {""}
+} here
+
+infer_lifetime_param_suggestion = consider introducing a named lifetime parameter{$is_impl ->
+    [true] {" "}and update trait if needed
+    *[false] {""}
+}
+infer_lifetime_param_suggestion_elided = each elided lifetime in input position becomes a distinct lifetime
+
+infer_region_explanation = {$pref_kind ->
+    *[should_not_happen] [{$pref_kind}]
+    [empty] {""}
+}{$pref_kind ->
+    [empty] {""}
+    *[other] {" "}
+}{$desc_kind ->
+    *[should_not_happen] [{$desc_kind}]
+    [restatic] the static lifetime
+    [reempty] the empty lifetime
+    [reemptyuni] the empty lifetime in universe {$desc_arg}
+    [revar] lifetime {$desc_arg}
+
+    [as_defined] the lifetime `{$desc_arg}` as defined here
+    [as_defined_anon] the anonymous lifetime as defined here
+    [defined_here] the anonymous lifetime defined here
+    [anon_num_here] the anonymous lifetime #{$desc_num_arg} defined here
+    [defined_here_reg] the lifetime `{$desc_arg}` as defined here
+}{$suff_kind ->
+    *[should_not_happen] [{$suff_kind}]
+    [empty]{""}
+    [continues] ...
+}
+
+infer_mismatched_static_lifetime = incompatible lifetime on type
+infer_msl_impl_note = ...does not necessarily outlive the static lifetime introduced by the compatible `impl`
+infer_msl_introduces_static = introduces a `'static` lifetime requirement
+infer_msl_unmet_req = because this has an unmet lifetime requirement
+infer_msl_trait_note = this has an implicit `'static` lifetime requirement
+infer_msl_trait_sugg = consider relaxing the implicit `'static` requirement
diff --git a/compiler/rustc_error_messages/locales/en-US/middle.ftl b/compiler/rustc_error_messages/locales/en-US/middle.ftl
new file mode 100644
index 00000000000..ed834886453
--- /dev/null
+++ b/compiler/rustc_error_messages/locales/en-US/middle.ftl
@@ -0,0 +1,17 @@
+middle_drop_check_overflow =
+    overflow while adding drop-check rules for {$ty}
+    .note = overflowed on {$overflow_ty}
+
+middle_opaque_hidden_type_mismatch =
+    concrete type differs from previous defining opaque type use
+    .label = expected `{$self_ty}`, got `{$other_ty}`
+
+middle_conflict_types =
+    this expression supplies two conflicting concrete types for the same opaque type
+
+middle_previous_use_here =
+    previous use here
+
+middle_limit_invalid =
+    `limit` must be a non-negative integer
+    .label = {$error_str}
diff --git a/compiler/rustc_error_messages/locales/en-US/parser.ftl b/compiler/rustc_error_messages/locales/en-US/parser.ftl
index 3b37a393846..f74df3d9746 100644
--- a/compiler/rustc_error_messages/locales/en-US/parser.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/parser.ftl
@@ -150,3 +150,9 @@ parser_dotdotdot = unexpected token: `...`
 
 parser_left_arrow_operator = unexpected token: `<-`
     .suggestion = if you meant to write a comparison against a negative value, add a space in between `<` and `-`
+
+parser_remove_let = expected pattern, found `let`
+    .suggestion = remove the unnecessary `let` keyword
+
+parser_use_eq_instead = unexpected `==`
+    .suggestion = try using `=` instead
diff --git a/compiler/rustc_error_messages/locales/en-US/session.ftl b/compiler/rustc_error_messages/locales/en-US/session.ftl
index 983e5cee823..d2a2958f624 100644
--- a/compiler/rustc_error_messages/locales/en-US/session.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/session.ftl
@@ -14,3 +14,45 @@ session_feature_diagnostic_for_issue =
 
 session_feature_diagnostic_help =
     add `#![feature({$feature})]` to the crate attributes to enable
+
+session_not_circumvent_feature = `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine
+
+session_profile_use_file_does_not_exist = file `{$path}` passed to `-C profile-use` does not exist.
+
+session_linker_plugin_lto_windows_not_supported = linker plugin based LTO is not supported together with `-C prefer-dynamic` when targeting Windows-like targets
+
+session_profile_sample_use_file_does_not_exist = file `{$path}` passed to `-C profile-sample-use` does not exist.
+
+session_target_requires_unwind_tables = target requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no`
+
+session_sanitizer_not_supported = {$us} sanitizer is not supported for this target
+
+session_sanitizers_not_supported = {$us} sanitizers are not supported for this target
+
+session_cannot_mix_and_match_sanitizers = `-Zsanitizer={$first}` is incompatible with `-Zsanitizer={$second}`
+
+session_cannot_enable_crt_static_linux = sanitizer is incompatible with statically linked libc, disable it using `-C target-feature=-crt-static`
+
+session_sanitizer_cfi_enabled = `-Zsanitizer=cfi` requires `-Clto`
+
+session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination` requires `-Clto`
+
+session_unsupported_dwarf_version = requested DWARF version {$dwarf_version} is greater than 5
+
+session_target_invalid_address_space = invalid address space `{$addr_space}` for `{$cause}` in "data-layout": {$err}
+
+session_target_invalid_bits = invalid {$kind} `{$bit}` for `{$cause}` in "data-layout": {$err}
+
+session_target_missing_alignment = missing alignment for `{$cause}` in "data-layout"
+
+session_target_invalid_alignment = invalid alignment for `{$cause}` in "data-layout": {$err}
+
+session_target_inconsistent_architecture = inconsistent target specification: "data-layout" claims architecture is {$dl}-endian, while "target-endian" is `{$target}`
+
+session_target_inconsistent_pointer_width = inconsistent target specification: "data-layout" claims pointers are {$pointer_size}-bit, while "target-pointer-width" is `{$target}`
+
+session_target_invalid_bits_size = {$err}
+
+session_target_stack_protector_not_supported = `-Z stack-protector={$stack_protector}` is not supported for target {$target_triple} and will be ignored
+
+session_split_debuginfo_unstable_platform = `-Csplit-debuginfo={$debuginfo}` is unstable on this platform
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 5281a287b0d..b6e0f3faa73 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -47,6 +47,7 @@ fluent_messages! {
     interface => "../locales/en-US/interface.ftl",
     infer => "../locales/en-US/infer.ftl",
     lint => "../locales/en-US/lint.ftl",
+    middle => "../locales/en-US/middle.ftl",
     monomorphize => "../locales/en-US/monomorphize.ftl",
     metadata => "../locales/en-US/metadata.ftl",
     parser => "../locales/en-US/parser.ftl",
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index a052aaee047..a774b52c8a5 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -10,10 +10,11 @@ use rustc_lint_defs::{Applicability, LintExpectationId};
 use rustc_span::edition::LATEST_STABLE_EDITION;
 use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol};
 use rustc_span::{edition::Edition, Span, DUMMY_SP};
-use rustc_target::spec::PanicStrategy;
+use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple};
 use std::borrow::Cow;
 use std::fmt;
 use std::hash::{Hash, Hasher};
+use std::num::ParseIntError;
 use std::path::{Path, PathBuf};
 
 /// Error type for `Diagnostic`'s `suggestions` field, indicating that
@@ -91,6 +92,10 @@ into_diagnostic_arg_using_display!(
     Edition,
     Ident,
     MacroRulesNormalizedIdent,
+    ParseIntError,
+    StackProtector,
+    &TargetTriple,
+    SplitDebuginfo
 );
 
 impl IntoDiagnosticArg for bool {
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 68abdd0bad1..3e02d2ebb7e 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -69,8 +69,8 @@ pub type PResult<'a, T> = Result<T, DiagnosticBuilder<'a, ErrorGuaranteed>>;
 // (See also the comment on `DiagnosticBuilder`'s `diagnostic` field.)
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(PResult<'_, ()>, 16);
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(PResult<'_, bool>, 24);
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64", not(bootstrap)))]
+rustc_data_structures::static_assert_size!(PResult<'_, bool>, 16);
 
 #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)]
 pub enum SuggestionStyle {
@@ -456,7 +456,7 @@ struct HandlerInner {
 }
 
 /// A key denoting where from a diagnostic was stashed.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
 pub enum StashKey {
     ItemNoType,
     UnderscoreForArrayLengths,
@@ -1250,14 +1250,14 @@ impl HandlerInner {
 
     fn treat_err_as_bug(&self) -> bool {
         self.flags.treat_err_as_bug.map_or(false, |c| {
-            self.err_count()
-                + self.lint_err_count
-                + self.delayed_span_bugs.len()
-                + self.delayed_good_path_bugs.len()
-                >= c.get()
+            self.err_count() + self.lint_err_count + self.delayed_bug_count() >= c.get()
         })
     }
 
+    fn delayed_bug_count(&self) -> usize {
+        self.delayed_span_bugs.len() + self.delayed_good_path_bugs.len()
+    }
+
     fn print_error_count(&mut self, registry: &Registry) {
         self.emit_stashed_diagnostics();
 
@@ -1412,12 +1412,7 @@ impl HandlerInner {
         // incrementing `err_count` by one, so we need to +1 the comparing.
         // FIXME: Would be nice to increment err_count in a more coherent way.
         if self.flags.treat_err_as_bug.map_or(false, |c| {
-            self.err_count()
-                + self.lint_err_count
-                + self.delayed_span_bugs.len()
-                + self.delayed_good_path_bugs.len()
-                + 1
-                >= c.get()
+            self.err_count() + self.lint_err_count + self.delayed_bug_count() + 1 >= c.get()
         }) {
             // FIXME: don't abort here if report_delayed_bugs is off
             self.span_bug(sp, msg);
@@ -1518,14 +1513,24 @@ impl HandlerInner {
         if self.treat_err_as_bug() {
             match (
                 self.err_count() + self.lint_err_count,
+                self.delayed_bug_count(),
                 self.flags.treat_err_as_bug.map(|c| c.get()).unwrap_or(0),
             ) {
-                (1, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"),
-                (0 | 1, _) => {}
-                (count, as_bug) => panic!(
-                    "aborting after {} errors due to `-Z treat-err-as-bug={}`",
-                    count, as_bug,
-                ),
+                (1, 0, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"),
+                (0, 1, 1) => panic!("aborting due delayed bug with `-Z treat-err-as-bug=1`"),
+                (count, delayed_count, as_bug) => {
+                    if delayed_count > 0 {
+                        panic!(
+                            "aborting after {} errors and {} delayed bugs due to `-Z treat-err-as-bug={}`",
+                            count, delayed_count, as_bug,
+                        )
+                    } else {
+                        panic!(
+                            "aborting after {} errors due to `-Z treat-err-as-bug={}`",
+                            count, as_bug,
+                        )
+                    }
+                }
             }
         }
     }
diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs
index c4890b4a9c4..cf2c023c2f8 100644
--- a/compiler/rustc_expand/src/build.rs
+++ b/compiler/rustc_expand/src/build.rs
@@ -178,8 +178,7 @@ impl<'a> ExtCtxt<'a> {
         ex: P<ast::Expr>,
     ) -> ast::Stmt {
         let pat = if mutbl {
-            let binding_mode = ast::BindingMode::ByValue(ast::Mutability::Mut);
-            self.pat_ident_binding_mode(sp, ident, binding_mode)
+            self.pat_ident_binding_mode(sp, ident, ast::BindingAnnotation::MUT)
         } else {
             self.pat_ident(sp, ident)
         };
@@ -445,17 +444,16 @@ impl<'a> ExtCtxt<'a> {
         self.pat(span, PatKind::Lit(expr))
     }
     pub fn pat_ident(&self, span: Span, ident: Ident) -> P<ast::Pat> {
-        let binding_mode = ast::BindingMode::ByValue(ast::Mutability::Not);
-        self.pat_ident_binding_mode(span, ident, binding_mode)
+        self.pat_ident_binding_mode(span, ident, ast::BindingAnnotation::NONE)
     }
 
     pub fn pat_ident_binding_mode(
         &self,
         span: Span,
         ident: Ident,
-        bm: ast::BindingMode,
+        ann: ast::BindingAnnotation,
     ) -> P<ast::Pat> {
-        let pat = PatKind::Ident(bm, ident.with_span_pos(span), None);
+        let pat = PatKind::Ident(ann, ident.with_span_pos(span), None);
         self.pat(span, pat)
     }
     pub fn pat_path(&self, span: Span, path: ast::Path) -> P<ast::Pat> {
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index e359d50c4e9..38a02cb1d7c 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -823,6 +823,14 @@ pub fn is_builtin_only_local(name: Symbol) -> bool {
     BUILTIN_ATTRIBUTE_MAP.get(&name).map_or(false, |attr| attr.only_local)
 }
 
+pub fn is_valid_for_get_attr(name: Symbol) -> bool {
+    BUILTIN_ATTRIBUTE_MAP.get(&name).map_or(false, |attr| match attr.duplicates {
+        WarnFollowing | ErrorFollowing | ErrorPreceding | FutureWarnFollowing
+        | FutureWarnPreceding => true,
+        DuplicatesOk | WarnFollowingWordOnly => false,
+    })
+}
+
 pub static BUILTIN_ATTRIBUTE_MAP: LazyLock<FxHashMap<Symbol, &BuiltinAttribute>> =
     LazyLock::new(|| {
         let mut map = FxHashMap::default();
diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs
index e44c9291f84..bdaa0ee88eb 100644
--- a/compiler/rustc_feature/src/lib.rs
+++ b/compiler/rustc_feature/src/lib.rs
@@ -151,7 +151,7 @@ pub use active::{Features, ACTIVE_FEATURES, INCOMPATIBLE_FEATURES};
 pub use builtin_attrs::AttributeDuplicates;
 pub use builtin_attrs::{
     deprecated_attributes, find_gated_cfg, is_builtin_attr_name, is_builtin_only_local,
-    AttributeGate, AttributeTemplate, AttributeType, BuiltinAttribute, GatedCfg,
-    BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
+    is_valid_for_get_attr, AttributeGate, AttributeTemplate, AttributeType, BuiltinAttribute,
+    GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
 };
 pub use removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES};
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index 2d2648a8f35..b44ee02cfe3 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -308,6 +308,7 @@ pub enum Res<Id = hir::HirId> {
     ///
     /// **Belongs to the type namespace.**
     PrimTy(hir::PrimTy),
+
     /// The `Self` type, optionally with the [`DefId`] of the trait it belongs to and
     /// optionally with the [`DefId`] of the item introducing the `Self` type alias.
     ///
@@ -355,7 +356,8 @@ pub enum Res<Id = hir::HirId> {
     /// const fn baz<T>() -> usize { 10 }
     /// ```
     /// We do however allow `Self` in repeat expression even if it is generic to not break code
-    /// which already works on stable while causing the `const_evaluatable_unchecked` future compat lint:
+    /// which already works on stable while causing the `const_evaluatable_unchecked` future compat
+    /// lint:
     /// ```
     /// fn foo<T>() {
     ///     let _bar = [1_u8; std::mem::size_of::<*mut T>()];
@@ -370,6 +372,7 @@ pub enum Res<Id = hir::HirId> {
         /// from mentioning generics (i.e. when used in an anonymous constant).
         alias_to: Option<(DefId, bool)>,
     },
+
     /// A tool attribute module; e.g., the `rustfmt` in `#[rustfmt::skip]`.
     ///
     /// **Belongs to the type namespace.**
@@ -383,6 +386,7 @@ pub enum Res<Id = hir::HirId> {
     ///
     /// *See also [`Res::SelfTy`].*
     SelfCtor(DefId),
+
     /// A local variable or function parameter.
     ///
     /// **Belongs to the value namespace.**
@@ -453,7 +457,7 @@ impl PartialRes {
 
 /// Different kinds of symbols can coexist even if they share the same textual name.
 /// Therefore, they each have a separate universe (known as a "namespace").
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 pub enum Namespace {
     /// The type namespace includes `struct`s, `enum`s, `union`s, `trait`s, and `mod`s
     /// (and, by extension, crates).
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 08282f13897..cc5aed6cb54 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -7,7 +7,7 @@ use crate::LangItem;
 use rustc_ast as ast;
 use rustc_ast::util::parser::ExprPrecedence;
 use rustc_ast::{Attribute, FloatTy, IntTy, Label, LitKind, TraitObjectSyntax, UintTy};
-pub use rustc_ast::{BorrowKind, ImplPolarity, IsAuto};
+pub use rustc_ast::{BindingAnnotation, BorrowKind, ByRef, ImplPolarity, IsAuto};
 pub use rustc_ast::{CaptureBy, Movability, Mutability};
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_data_structures::fingerprint::Fingerprint;
@@ -202,13 +202,8 @@ impl Path<'_> {
 pub struct PathSegment<'hir> {
     /// The identifier portion of this path segment.
     pub ident: Ident,
-    // `id` and `res` are optional. We currently only use these in save-analysis,
-    // any path segments without these will not have save-analysis info and
-    // therefore will not have 'jump to def' in IDEs, but otherwise will not be
-    // affected. (In general, we don't bother to get the defs for synthesized
-    // segments, only for segments which have come from the AST).
-    pub hir_id: Option<HirId>,
-    pub res: Option<Res>,
+    pub hir_id: HirId,
+    pub res: Res,
 
     /// Type/lifetime parameters attached to this path. They come in
     /// two flavors: `Path<A,B,C>` and `Path(A,B) -> C`. Note that
@@ -226,12 +221,12 @@ pub struct PathSegment<'hir> {
 
 impl<'hir> PathSegment<'hir> {
     /// Converts an identifier to the corresponding segment.
-    pub fn from_ident(ident: Ident) -> PathSegment<'hir> {
-        PathSegment { ident, hir_id: None, res: None, infer_args: true, args: None }
+    pub fn new(ident: Ident, hir_id: HirId, res: Res) -> PathSegment<'hir> {
+        PathSegment { ident, hir_id, res, infer_args: true, args: None }
     }
 
     pub fn invalid() -> Self {
-        Self::from_ident(Ident::empty())
+        Self::new(Ident::empty(), HirId::INVALID, Res::Err)
     }
 
     pub fn args(&self) -> &GenericArgs<'hir> {
@@ -264,7 +259,7 @@ impl InferArg {
 
 #[derive(Debug, HashStable_Generic)]
 pub enum GenericArg<'hir> {
-    Lifetime(Lifetime),
+    Lifetime(&'hir Lifetime),
     Type(&'hir Ty<'hir>),
     Const(ConstArg),
     Infer(InferArg),
@@ -435,7 +430,7 @@ pub enum GenericBound<'hir> {
     Trait(PolyTraitRef<'hir>, TraitBoundModifier),
     // FIXME(davidtwco): Introduce `PolyTraitRef::LangItem`
     LangItemTrait(LangItem, Span, HirId, &'hir GenericArgs<'hir>),
-    Outlives(Lifetime),
+    Outlives(&'hir Lifetime),
 }
 
 impl GenericBound<'_> {
@@ -761,7 +756,7 @@ impl<'hir> WhereBoundPredicate<'hir> {
 pub struct WhereRegionPredicate<'hir> {
     pub span: Span,
     pub in_where_clause: bool,
-    pub lifetime: Lifetime,
+    pub lifetime: &'hir Lifetime,
     pub bounds: GenericBounds<'hir>,
 }
 
@@ -1049,30 +1044,6 @@ pub struct PatField<'hir> {
     pub span: Span,
 }
 
-/// Explicit binding annotations given in the HIR for a binding. Note
-/// that this is not the final binding *mode* that we infer after type
-/// inference.
-#[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)]
-pub enum BindingAnnotation {
-    /// No binding annotation given: this means that the final binding mode
-    /// will depend on whether we have skipped through a `&` reference
-    /// when matching. For example, the `x` in `Some(x)` will have binding
-    /// mode `None`; if you do `let Some(x) = &Some(22)`, it will
-    /// ultimately be inferred to be by-reference.
-    ///
-    /// Note that implicit reference skipping is not implemented yet (#42640).
-    Unannotated,
-
-    /// Annotated with `mut x` -- could be either ref or not, similar to `None`.
-    Mutable,
-
-    /// Annotated as `ref`, like `ref x`
-    Ref,
-
-    /// Annotated as `ref mut x`.
-    RefMut,
-}
-
 #[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)]
 pub enum RangeEnd {
     Included,
@@ -1088,6 +1059,35 @@ impl fmt::Display for RangeEnd {
     }
 }
 
+// Equivalent to `Option<usize>`. That type takes up 16 bytes on 64-bit, but
+// this type only takes up 4 bytes, at the cost of being restricted to a
+// maximum value of `u32::MAX - 1`. In practice, this is more than enough.
+#[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable_Generic)]
+pub struct DotDotPos(u32);
+
+impl DotDotPos {
+    // Panics if n >= u32::MAX.
+    pub fn new(n: Option<usize>) -> Self {
+        match n {
+            Some(n) => {
+                assert!(n < u32::MAX as usize);
+                Self(n as u32)
+            }
+            None => Self(u32::MAX),
+        }
+    }
+
+    pub fn as_opt_usize(&self) -> Option<usize> {
+        if self.0 == u32::MAX { None } else { Some(self.0 as usize) }
+    }
+}
+
+impl fmt::Debug for DotDotPos {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.as_opt_usize().fmt(f)
+    }
+}
+
 #[derive(Debug, HashStable_Generic)]
 pub enum PatKind<'hir> {
     /// Represents a wildcard pattern (i.e., `_`).
@@ -1104,9 +1104,9 @@ pub enum PatKind<'hir> {
     Struct(QPath<'hir>, &'hir [PatField<'hir>], bool),
 
     /// A tuple struct/variant pattern `Variant(x, y, .., z)`.
-    /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
+    /// If the `..` pattern fragment is present, then `DotDotPos` denotes its position.
     /// `0 <= position <= subpats.len()`
-    TupleStruct(QPath<'hir>, &'hir [Pat<'hir>], Option<usize>),
+    TupleStruct(QPath<'hir>, &'hir [Pat<'hir>], DotDotPos),
 
     /// An or-pattern `A | B | C`.
     /// Invariant: `pats.len() >= 2`.
@@ -1118,7 +1118,7 @@ pub enum PatKind<'hir> {
     /// A tuple pattern (e.g., `(a, b)`).
     /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
     /// `0 <= position <= subpats.len()`
-    Tuple(&'hir [Pat<'hir>], Option<usize>),
+    Tuple(&'hir [Pat<'hir>], DotDotPos),
 
     /// A `box` pattern.
     Box(&'hir Pat<'hir>),
@@ -1881,11 +1881,11 @@ pub enum ExprKind<'hir> {
     ///
     /// The `PathSegment` represents the method name and its generic arguments
     /// (within the angle brackets).
-    /// The first element of the `&[Expr]` is the expression that evaluates
+    /// The `&Expr` is the expression that evaluates
     /// to the object on which the method is being called on (the receiver),
-    /// and the remaining elements are the rest of the arguments.
+    /// and the `&[Expr]` is the rest of the arguments.
     /// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
-    /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d], span)`.
+    /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, x, [a, b, c, d], span)`.
     /// The final `Span` represents the span of the function and arguments
     /// (e.g. `foo::<Bar, Baz>(a, b, c, d)` in `x.foo::<Bar, Baz>(a, b, c, d)`
     ///
@@ -1893,7 +1893,7 @@ pub enum ExprKind<'hir> {
     /// the `hir_id` of the `MethodCall` node itself.
     ///
     /// [`type_dependent_def_id`]: ../../rustc_middle/ty/struct.TypeckResults.html#method.type_dependent_def_id
-    MethodCall(&'hir PathSegment<'hir>, &'hir [Expr<'hir>], Span),
+    MethodCall(&'hir PathSegment<'hir>, &'hir Expr<'hir>, &'hir [Expr<'hir>], Span),
     /// A tuple (e.g., `(a, b, c, d)`).
     Tup(&'hir [Expr<'hir>]),
     /// A binary operation (e.g., `a + b`, `a * b`).
@@ -2528,7 +2528,7 @@ pub enum TyKind<'hir> {
     /// A raw pointer (i.e., `*const T` or `*mut T`).
     Ptr(MutTy<'hir>),
     /// A reference (i.e., `&'a T` or `&'a mut T`).
-    Rptr(Lifetime, MutTy<'hir>),
+    Rptr(&'hir Lifetime, MutTy<'hir>),
     /// A bare function (e.g., `fn(usize) -> bool`).
     BareFn(&'hir BareFnTy<'hir>),
     /// The never type (`!`).
@@ -2547,7 +2547,7 @@ pub enum TyKind<'hir> {
     OpaqueDef(ItemId, &'hir [GenericArg<'hir>]),
     /// A trait object type `Bound1 + Bound2 + Bound3`
     /// where `Bound` is a trait or a lifetime.
-    TraitObject(&'hir [PolyTraitRef<'hir>], Lifetime, TraitObjectSyntax),
+    TraitObject(&'hir [PolyTraitRef<'hir>], &'hir Lifetime, TraitObjectSyntax),
     /// Unused for now.
     Typeof(AnonConst),
     /// `TyKind::Infer` means the type should be inferred instead of it having been
@@ -3497,30 +3497,35 @@ mod size_asserts {
     // These are in alphabetical order, which is easy to maintain.
     static_assert_size!(Block<'_>, 48);
     static_assert_size!(Body<'_>, 32);
-    static_assert_size!(Expr<'_>, 56);
-    static_assert_size!(ExprKind<'_>, 40);
+    static_assert_size!(Expr<'_>, 64);
+    static_assert_size!(ExprKind<'_>, 48);
     static_assert_size!(FnDecl<'_>, 40);
     static_assert_size!(ForeignItem<'_>, 72);
     static_assert_size!(ForeignItemKind<'_>, 40);
-    static_assert_size!(GenericArg<'_>, 40);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(GenericArg<'_>, 24);
     static_assert_size!(GenericBound<'_>, 48);
     static_assert_size!(Generics<'_>, 56);
     static_assert_size!(Impl<'_>, 80);
-    static_assert_size!(ImplItem<'_>, 88);
-    static_assert_size!(ImplItemKind<'_>, 40);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(ImplItem<'_>, 80);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(ImplItemKind<'_>, 32);
     static_assert_size!(Item<'_>, 80);
     static_assert_size!(ItemKind<'_>, 48);
     static_assert_size!(Local<'_>, 64);
     static_assert_size!(Param<'_>, 32);
-    static_assert_size!(Pat<'_>, 88);
-    static_assert_size!(PatKind<'_>, 64);
+    static_assert_size!(Pat<'_>, 72);
+    static_assert_size!(PatKind<'_>, 48);
     static_assert_size!(Path<'_>, 48);
     static_assert_size!(PathSegment<'_>, 56);
     static_assert_size!(QPath<'_>, 24);
     static_assert_size!(Stmt<'_>, 32);
     static_assert_size!(StmtKind<'_>, 16);
-    static_assert_size!(TraitItem<'_>, 96);
-    static_assert_size!(TraitItemKind<'_>, 56);
-    static_assert_size!(Ty<'_>, 72);
-    static_assert_size!(TyKind<'_>, 56);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(TraitItem<'_>, 88);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(TraitItemKind<'_>, 48);
+    static_assert_size!(Ty<'_>, 48);
+    static_assert_size!(TyKind<'_>, 32);
 }
diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs
index 346ac9e9644..e586d5cd5d9 100644
--- a/compiler/rustc_hir/src/hir_id.rs
+++ b/compiler/rustc_hir/src/hir_id.rs
@@ -20,6 +20,9 @@ pub struct HirId {
 }
 
 impl HirId {
+    /// Signal local id which should never be used.
+    pub const INVALID: HirId = HirId { owner: CRATE_DEF_ID, local_id: ItemLocalId::INVALID };
+
     #[inline]
     pub fn expect_owner(self) -> LocalDefId {
         assert_eq!(self.local_id.index(), 0);
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 3d5e22add71..20ec788463a 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -724,7 +724,7 @@ pub fn walk_path_segment<'v, V: Visitor<'v>>(
     segment: &'v PathSegment<'v>,
 ) {
     visitor.visit_ident(segment.ident);
-    walk_list!(visitor, visit_id, segment.hir_id);
+    visitor.visit_id(segment.hir_id);
     if let Some(ref args) = segment.args {
         visitor.visit_generic_args(path_span, args);
     }
@@ -1094,8 +1094,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
             visitor.visit_expr(callee_expression);
             walk_list!(visitor, visit_expr, arguments);
         }
-        ExprKind::MethodCall(ref segment, arguments, _) => {
+        ExprKind::MethodCall(ref segment, receiver, arguments, _) => {
             visitor.visit_path_segment(expression.span, segment);
+            visitor.visit_expr(receiver);
             walk_list!(visitor, visit_expr, arguments);
         }
         ExprKind::Binary(_, ref left_expression, ref right_expression) => {
diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs
index 93112199b60..0c1819bb0c7 100644
--- a/compiler/rustc_hir/src/pat_util.rs
+++ b/compiler/rustc_hir/src/pat_util.rs
@@ -1,6 +1,6 @@
 use crate::def::{CtorOf, DefKind, Res};
 use crate::def_id::DefId;
-use crate::hir::{self, HirId, PatKind};
+use crate::hir::{self, BindingAnnotation, ByRef, HirId, PatKind};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::symbol::Ident;
@@ -35,7 +35,7 @@ pub trait EnumerateAndAdjustIterator {
     fn enumerate_and_adjust(
         self,
         expected_len: usize,
-        gap_pos: Option<usize>,
+        gap_pos: hir::DotDotPos,
     ) -> EnumerateAndAdjust<Self>
     where
         Self: Sized;
@@ -45,7 +45,7 @@ impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
     fn enumerate_and_adjust(
         self,
         expected_len: usize,
-        gap_pos: Option<usize>,
+        gap_pos: hir::DotDotPos,
     ) -> EnumerateAndAdjust<Self>
     where
         Self: Sized,
@@ -53,7 +53,7 @@ impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
         let actual_len = self.len();
         EnumerateAndAdjust {
             enumerate: self.enumerate(),
-            gap_pos: gap_pos.unwrap_or(expected_len),
+            gap_pos: gap_pos.as_opt_usize().unwrap_or(expected_len),
             gap_len: expected_len - actual_len,
         }
     }
@@ -93,12 +93,7 @@ impl hir::Pat<'_> {
 
     pub fn simple_ident(&self) -> Option<Ident> {
         match self.kind {
-            PatKind::Binding(
-                hir::BindingAnnotation::Unannotated | hir::BindingAnnotation::Mutable,
-                _,
-                ident,
-                None,
-            ) => Some(ident),
+            PatKind::Binding(BindingAnnotation(ByRef::No, _), _, ident, None) => Some(ident),
             _ => None,
         }
     }
@@ -135,11 +130,11 @@ impl hir::Pat<'_> {
     pub fn contains_explicit_ref_binding(&self) -> Option<hir::Mutability> {
         let mut result = None;
         self.each_binding(|annotation, _, _, _| match annotation {
-            hir::BindingAnnotation::Ref => match result {
+            hir::BindingAnnotation::REF => match result {
                 None | Some(hir::Mutability::Not) => result = Some(hir::Mutability::Not),
                 _ => {}
             },
-            hir::BindingAnnotation::RefMut => result = Some(hir::Mutability::Mut),
+            hir::BindingAnnotation::REF_MUT => result = Some(hir::Mutability::Mut),
             _ => {}
         });
         result
diff --git a/compiler/rustc_hir/src/weak_lang_items.rs b/compiler/rustc_hir/src/weak_lang_items.rs
index b6a85c0472e..da9c9c1216e 100644
--- a/compiler/rustc_hir/src/weak_lang_items.rs
+++ b/compiler/rustc_hir/src/weak_lang_items.rs
@@ -18,6 +18,12 @@ pub static WEAK_ITEMS_REFS: LazyLock<FxIndexMap<Symbol, LangItem>> = LazyLock::n
     map
 });
 
+pub static WEAK_ITEMS_SYMBOLS: LazyLock<FxIndexMap<LangItem, Symbol>> = LazyLock::new(|| {
+    let mut map = FxIndexMap::default();
+    $(map.insert(LangItem::$item, sym::$sym);)*
+    map
+});
+
 pub fn link_name(attrs: &[ast::Attribute]) -> Option<Symbol>
 {
     lang_items::extract(attrs).and_then(|(name, _)| {
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 42663da8a3f..35a58296e37 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -9,7 +9,9 @@ use rustc_ast_pretty::pp::{self, Breaks};
 use rustc_ast_pretty::pprust::{Comments, PrintState};
 use rustc_hir as hir;
 use rustc_hir::LifetimeParamKind;
-use rustc_hir::{GenericArg, GenericParam, GenericParamKind, Node, Term};
+use rustc_hir::{
+    BindingAnnotation, ByRef, GenericArg, GenericParam, GenericParamKind, Mutability, Node, Term,
+};
 use rustc_hir::{GenericBound, PatKind, RangeEnd, TraitBoundModifier};
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::{kw, Ident, IdentPrinter, Symbol};
@@ -1181,15 +1183,20 @@ impl<'a> State<'a> {
         self.print_call_post(args)
     }
 
-    fn print_expr_method_call(&mut self, segment: &hir::PathSegment<'_>, args: &[hir::Expr<'_>]) {
-        let base_args = &args[1..];
-        self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX);
+    fn print_expr_method_call(
+        &mut self,
+        segment: &hir::PathSegment<'_>,
+        receiver: &hir::Expr<'_>,
+        args: &[hir::Expr<'_>],
+    ) {
+        let base_args = args;
+        self.print_expr_maybe_paren(&receiver, parser::PREC_POSTFIX);
         self.word(".");
         self.print_ident(segment.ident);
 
         let generic_args = segment.args();
         if !generic_args.args.is_empty() || !generic_args.bindings.is_empty() {
-            self.print_generic_args(generic_args, segment.infer_args, true);
+            self.print_generic_args(generic_args, true);
         }
 
         self.print_call_post(base_args)
@@ -1394,8 +1401,8 @@ impl<'a> State<'a> {
             hir::ExprKind::Call(func, args) => {
                 self.print_expr_call(func, args);
             }
-            hir::ExprKind::MethodCall(segment, args, _) => {
-                self.print_expr_method_call(segment, args);
+            hir::ExprKind::MethodCall(segment, receiver, args, _) => {
+                self.print_expr_method_call(segment, receiver, args);
             }
             hir::ExprKind::Binary(op, lhs, rhs) => {
                 self.print_expr_binary(op, lhs, rhs);
@@ -1592,7 +1599,7 @@ impl<'a> State<'a> {
             }
             if segment.ident.name != kw::PathRoot {
                 self.print_ident(segment.ident);
-                self.print_generic_args(segment.args(), segment.infer_args, colons_before_params);
+                self.print_generic_args(segment.args(), colons_before_params);
             }
         }
     }
@@ -1600,7 +1607,7 @@ impl<'a> State<'a> {
     pub fn print_path_segment(&mut self, segment: &hir::PathSegment<'_>) {
         if segment.ident.name != kw::PathRoot {
             self.print_ident(segment.ident);
-            self.print_generic_args(segment.args(), segment.infer_args, false);
+            self.print_generic_args(segment.args(), false);
         }
     }
 
@@ -1619,11 +1626,7 @@ impl<'a> State<'a> {
                     }
                     if segment.ident.name != kw::PathRoot {
                         self.print_ident(segment.ident);
-                        self.print_generic_args(
-                            segment.args(),
-                            segment.infer_args,
-                            colons_before_params,
-                        );
+                        self.print_generic_args(segment.args(), colons_before_params);
                     }
                 }
 
@@ -1631,11 +1634,7 @@ impl<'a> State<'a> {
                 self.word("::");
                 let item_segment = path.segments.last().unwrap();
                 self.print_ident(item_segment.ident);
-                self.print_generic_args(
-                    item_segment.args(),
-                    item_segment.infer_args,
-                    colons_before_params,
-                )
+                self.print_generic_args(item_segment.args(), colons_before_params)
             }
             hir::QPath::TypeRelative(qself, item_segment) => {
                 // If we've got a compound-qualified-path, let's push an additional pair of angle
@@ -1651,11 +1650,7 @@ impl<'a> State<'a> {
 
                 self.word("::");
                 self.print_ident(item_segment.ident);
-                self.print_generic_args(
-                    item_segment.args(),
-                    item_segment.infer_args,
-                    colons_before_params,
-                )
+                self.print_generic_args(item_segment.args(), colons_before_params)
             }
             hir::QPath::LangItem(lang_item, span, _) => {
                 self.word("#[lang = \"");
@@ -1668,7 +1663,6 @@ impl<'a> State<'a> {
     fn print_generic_args(
         &mut self,
         generic_args: &hir::GenericArgs<'_>,
-        infer_args: bool,
         colons_before_params: bool,
     ) {
         if generic_args.parenthesized {
@@ -1715,13 +1709,6 @@ impl<'a> State<'a> {
                 );
             }
 
-            // FIXME(eddyb): this would leak into error messages (e.g.,
-            // "non-exhaustive patterns: `Some::<..>(_)` not covered").
-            if infer_args && false {
-                start_or_comma(self);
-                self.word("..");
-            }
-
             for binding in generic_args.bindings {
                 start_or_comma(self);
                 self.print_type_binding(binding);
@@ -1735,7 +1722,7 @@ impl<'a> State<'a> {
 
     pub fn print_type_binding(&mut self, binding: &hir::TypeBinding<'_>) {
         self.print_ident(binding.ident);
-        self.print_generic_args(binding.gen_args, false, false);
+        self.print_generic_args(binding.gen_args, false);
         self.space();
         match binding.kind {
             hir::TypeBindingKind::Equality { ref term } => {
@@ -1758,20 +1745,12 @@ impl<'a> State<'a> {
         // is that it doesn't matter
         match pat.kind {
             PatKind::Wild => self.word("_"),
-            PatKind::Binding(binding_mode, _, ident, sub) => {
-                match binding_mode {
-                    hir::BindingAnnotation::Ref => {
-                        self.word_nbsp("ref");
-                        self.print_mutability(hir::Mutability::Not, false);
-                    }
-                    hir::BindingAnnotation::RefMut => {
-                        self.word_nbsp("ref");
-                        self.print_mutability(hir::Mutability::Mut, false);
-                    }
-                    hir::BindingAnnotation::Unannotated => {}
-                    hir::BindingAnnotation::Mutable => {
-                        self.word_nbsp("mut");
-                    }
+            PatKind::Binding(BindingAnnotation(by_ref, mutbl), _, ident, sub) => {
+                if by_ref == ByRef::Yes {
+                    self.word_nbsp("ref");
+                }
+                if mutbl == Mutability::Mut {
+                    self.word_nbsp("mut");
                 }
                 self.print_ident(ident);
                 if let Some(p) = sub {
@@ -1782,7 +1761,8 @@ impl<'a> State<'a> {
             PatKind::TupleStruct(ref qpath, elts, ddpos) => {
                 self.print_qpath(qpath, true);
                 self.popen();
-                if let Some(ddpos) = ddpos {
+                if let Some(ddpos) = ddpos.as_opt_usize() {
+                    let ddpos = ddpos as usize;
                     self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p));
                     if ddpos != 0 {
                         self.word_space(",");
@@ -1825,7 +1805,7 @@ impl<'a> State<'a> {
             }
             PatKind::Tuple(elts, ddpos) => {
                 self.popen();
-                if let Some(ddpos) = ddpos {
+                if let Some(ddpos) = ddpos.as_opt_usize() {
                     self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p));
                     if ddpos != 0 {
                         self.word_space(",");
@@ -2413,9 +2393,9 @@ fn contains_exterior_struct_lit(value: &hir::Expr<'_>) -> bool {
             contains_exterior_struct_lit(x)
         }
 
-        hir::ExprKind::MethodCall(.., exprs, _) => {
+        hir::ExprKind::MethodCall(_, receiver, ..) => {
             // `X { y: 1 }.bar(...)`
-            contains_exterior_struct_lit(&exprs[0])
+            contains_exterior_struct_lit(receiver)
         }
 
         _ => false,
diff --git a/compiler/rustc_infer/src/errors.rs b/compiler/rustc_infer/src/errors.rs
deleted file mode 100644
index 938f8aa77a5..00000000000
--- a/compiler/rustc_infer/src/errors.rs
+++ /dev/null
@@ -1,254 +0,0 @@
-use rustc_errors::{fluent, AddSubdiagnostic, DiagnosticMessage, DiagnosticStyledString};
-use rustc_hir::FnRetTy;
-use rustc_macros::SessionDiagnostic;
-use rustc_span::{BytePos, Span};
-
-use crate::infer::error_reporting::{
-    need_type_info::{GeneratorKindAsDiagArg, UnderspecifiedArgKind},
-    ObligationCauseAsDiagArg,
-};
-
-#[derive(SessionDiagnostic)]
-#[diag(infer::opaque_hidden_type)]
-pub struct OpaqueHiddenTypeDiag {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-    #[note(infer::opaque_type)]
-    pub opaque_type: Span,
-    #[note(infer::hidden_type)]
-    pub hidden_type: Span,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(infer::type_annotations_needed, code = "E0282")]
-pub struct AnnotationRequired<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub source_kind: &'static str,
-    pub source_name: &'a str,
-    #[label]
-    pub failure_span: Option<Span>,
-    #[subdiagnostic]
-    pub bad_label: Option<InferenceBadError<'a>>,
-    #[subdiagnostic]
-    pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
-    #[subdiagnostic]
-    pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
-}
-
-// Copy of `AnnotationRequired` for E0283
-#[derive(SessionDiagnostic)]
-#[diag(infer::type_annotations_needed, code = "E0283")]
-pub struct AmbigousImpl<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub source_kind: &'static str,
-    pub source_name: &'a str,
-    #[label]
-    pub failure_span: Option<Span>,
-    #[subdiagnostic]
-    pub bad_label: Option<InferenceBadError<'a>>,
-    #[subdiagnostic]
-    pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
-    #[subdiagnostic]
-    pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
-}
-
-// Copy of `AnnotationRequired` for E0284
-#[derive(SessionDiagnostic)]
-#[diag(infer::type_annotations_needed, code = "E0284")]
-pub struct AmbigousReturn<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub source_kind: &'static str,
-    pub source_name: &'a str,
-    #[label]
-    pub failure_span: Option<Span>,
-    #[subdiagnostic]
-    pub bad_label: Option<InferenceBadError<'a>>,
-    #[subdiagnostic]
-    pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
-    #[subdiagnostic]
-    pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
-}
-
-#[derive(SessionDiagnostic)]
-#[diag(infer::need_type_info_in_generator, code = "E0698")]
-pub struct NeedTypeInfoInGenerator<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub generator_kind: GeneratorKindAsDiagArg,
-    #[subdiagnostic]
-    pub bad_label: InferenceBadError<'a>,
-}
-
-// Used when a better one isn't available
-#[derive(SessionSubdiagnostic)]
-#[label(infer::label_bad)]
-pub struct InferenceBadError<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub bad_kind: &'static str,
-    pub prefix_kind: UnderspecifiedArgKind,
-    pub has_parent: bool,
-    pub prefix: &'a str,
-    pub parent_prefix: &'a str,
-    pub parent_name: String,
-    pub name: String,
-}
-
-#[derive(SessionSubdiagnostic)]
-pub enum SourceKindSubdiag<'a> {
-    #[suggestion_verbose(
-        infer::source_kind_subdiag_let,
-        code = ": {type_name}",
-        applicability = "has-placeholders"
-    )]
-    LetLike {
-        #[primary_span]
-        span: Span,
-        name: String,
-        type_name: String,
-        kind: &'static str,
-        x_kind: &'static str,
-        prefix_kind: UnderspecifiedArgKind,
-        prefix: &'a str,
-        arg_name: String,
-    },
-    #[label(infer::source_kind_subdiag_generic_label)]
-    GenericLabel {
-        #[primary_span]
-        span: Span,
-        is_type: bool,
-        param_name: String,
-        parent_exists: bool,
-        parent_prefix: String,
-        parent_name: String,
-    },
-    #[suggestion_verbose(
-        infer::source_kind_subdiag_generic_suggestion,
-        code = "::<{args}>",
-        applicability = "has-placeholders"
-    )]
-    GenericSuggestion {
-        #[primary_span]
-        span: Span,
-        arg_count: usize,
-        args: String,
-    },
-}
-
-// Has to be implemented manually because multipart suggestions are not supported by the derive macro.
-// Would be a part of `SourceKindSubdiag` otherwise.
-pub enum SourceKindMultiSuggestion<'a> {
-    FullyQualified {
-        span: Span,
-        def_path: String,
-        adjustment: &'a str,
-        successor: (&'a str, BytePos),
-    },
-    ClosureReturn {
-        ty_info: String,
-        data: &'a FnRetTy<'a>,
-        should_wrap_expr: Option<Span>,
-    },
-}
-
-impl AddSubdiagnostic for SourceKindMultiSuggestion<'_> {
-    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
-        match self {
-            Self::FullyQualified { span, def_path, adjustment, successor } => {
-                let suggestion = vec![
-                    (span.shrink_to_lo(), format!("{def_path}({adjustment}")),
-                    (span.shrink_to_hi().with_hi(successor.1), successor.0.to_string()),
-                ];
-                diag.multipart_suggestion_verbose(
-                    fluent::infer::source_kind_fully_qualified,
-                    suggestion,
-                    rustc_errors::Applicability::HasPlaceholders,
-                );
-            }
-            Self::ClosureReturn { ty_info, data, should_wrap_expr } => {
-                let (arrow, post) = match data {
-                    FnRetTy::DefaultReturn(_) => ("-> ", " "),
-                    _ => ("", ""),
-                };
-                let suggestion = match should_wrap_expr {
-                    Some(end_span) => vec![
-                        (data.span(), format!("{}{}{}{{ ", arrow, ty_info, post)),
-                        (end_span, " }".to_string()),
-                    ],
-                    None => vec![(data.span(), format!("{}{}{}", arrow, ty_info, post))],
-                };
-                diag.multipart_suggestion_verbose(
-                    fluent::infer::source_kind_closure_return,
-                    suggestion,
-                    rustc_errors::Applicability::HasPlaceholders,
-                );
-            }
-        }
-    }
-}
-
-pub enum RegionOriginNote<'a> {
-    Plain {
-        span: Span,
-        msg: DiagnosticMessage,
-    },
-    WithName {
-        span: Span,
-        msg: DiagnosticMessage,
-        name: &'a str,
-        continues: bool,
-    },
-    WithRequirement {
-        span: Span,
-        requirement: ObligationCauseAsDiagArg<'a>,
-        expected_found: Option<(DiagnosticStyledString, DiagnosticStyledString)>,
-    },
-}
-
-impl AddSubdiagnostic for RegionOriginNote<'_> {
-    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
-        let mut label_or_note = |span, msg: DiagnosticMessage| {
-            let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count();
-            let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count();
-            let span_is_primary = diag.span.primary_spans().iter().all(|&sp| sp == span);
-            if span_is_primary && sub_count == 0 && expanded_sub_count == 0 {
-                diag.span_label(span, msg);
-            } else if span_is_primary && expanded_sub_count == 0 {
-                diag.note(msg);
-            } else {
-                diag.span_note(span, msg);
-            }
-        };
-        match self {
-            RegionOriginNote::Plain { span, msg } => {
-                label_or_note(span, msg);
-            }
-            RegionOriginNote::WithName { span, msg, name, continues } => {
-                label_or_note(span, msg);
-                diag.set_arg("name", name);
-                diag.set_arg("continues", continues);
-            }
-            RegionOriginNote::WithRequirement {
-                span,
-                requirement,
-                expected_found: Some((expected, found)),
-            } => {
-                label_or_note(span, fluent::infer::subtype);
-                diag.set_arg("requirement", requirement);
-
-                diag.note_expected_found(&"", expected, &"", found);
-            }
-            RegionOriginNote::WithRequirement { span, requirement, expected_found: None } => {
-                // FIXME: this really should be handled at some earlier stage. Our
-                // handling of region checking when type errors are present is
-                // *terrible*.
-                label_or_note(span, fluent::infer::subtype_2);
-                diag.set_arg("requirement", requirement);
-            }
-        };
-    }
-}
diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs
new file mode 100644
index 00000000000..d232a186462
--- /dev/null
+++ b/compiler/rustc_infer/src/errors/mod.rs
@@ -0,0 +1,499 @@
+use hir::GenericParamKind;
+use rustc_errors::{
+    fluent, AddSubdiagnostic, Applicability, DiagnosticMessage, DiagnosticStyledString, MultiSpan,
+};
+use rustc_hir as hir;
+use rustc_hir::{FnRetTy, Ty};
+use rustc_macros::SessionDiagnostic;
+use rustc_middle::ty::{Region, TyCtxt};
+use rustc_span::symbol::kw;
+use rustc_span::{symbol::Ident, BytePos, Span};
+
+use crate::infer::error_reporting::{
+    need_type_info::{GeneratorKindAsDiagArg, UnderspecifiedArgKind},
+    ObligationCauseAsDiagArg,
+};
+
+pub mod note_and_explain;
+
+#[derive(SessionDiagnostic)]
+#[diag(infer::opaque_hidden_type)]
+pub struct OpaqueHiddenTypeDiag {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[note(infer::opaque_type)]
+    pub opaque_type: Span,
+    #[note(infer::hidden_type)]
+    pub hidden_type: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(infer::type_annotations_needed, code = "E0282")]
+pub struct AnnotationRequired<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub source_kind: &'static str,
+    pub source_name: &'a str,
+    #[label]
+    pub failure_span: Option<Span>,
+    #[subdiagnostic]
+    pub bad_label: Option<InferenceBadError<'a>>,
+    #[subdiagnostic]
+    pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
+    #[subdiagnostic]
+    pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
+}
+
+// Copy of `AnnotationRequired` for E0283
+#[derive(SessionDiagnostic)]
+#[diag(infer::type_annotations_needed, code = "E0283")]
+pub struct AmbigousImpl<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub source_kind: &'static str,
+    pub source_name: &'a str,
+    #[label]
+    pub failure_span: Option<Span>,
+    #[subdiagnostic]
+    pub bad_label: Option<InferenceBadError<'a>>,
+    #[subdiagnostic]
+    pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
+    #[subdiagnostic]
+    pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
+}
+
+// Copy of `AnnotationRequired` for E0284
+#[derive(SessionDiagnostic)]
+#[diag(infer::type_annotations_needed, code = "E0284")]
+pub struct AmbigousReturn<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub source_kind: &'static str,
+    pub source_name: &'a str,
+    #[label]
+    pub failure_span: Option<Span>,
+    #[subdiagnostic]
+    pub bad_label: Option<InferenceBadError<'a>>,
+    #[subdiagnostic]
+    pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
+    #[subdiagnostic]
+    pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(infer::need_type_info_in_generator, code = "E0698")]
+pub struct NeedTypeInfoInGenerator<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub generator_kind: GeneratorKindAsDiagArg,
+    #[subdiagnostic]
+    pub bad_label: InferenceBadError<'a>,
+}
+
+// Used when a better one isn't available
+#[derive(SessionSubdiagnostic)]
+#[label(infer::label_bad)]
+pub struct InferenceBadError<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub bad_kind: &'static str,
+    pub prefix_kind: UnderspecifiedArgKind,
+    pub has_parent: bool,
+    pub prefix: &'a str,
+    pub parent_prefix: &'a str,
+    pub parent_name: String,
+    pub name: String,
+}
+
+#[derive(SessionSubdiagnostic)]
+pub enum SourceKindSubdiag<'a> {
+    #[suggestion_verbose(
+        infer::source_kind_subdiag_let,
+        code = ": {type_name}",
+        applicability = "has-placeholders"
+    )]
+    LetLike {
+        #[primary_span]
+        span: Span,
+        name: String,
+        type_name: String,
+        kind: &'static str,
+        x_kind: &'static str,
+        prefix_kind: UnderspecifiedArgKind,
+        prefix: &'a str,
+        arg_name: String,
+    },
+    #[label(infer::source_kind_subdiag_generic_label)]
+    GenericLabel {
+        #[primary_span]
+        span: Span,
+        is_type: bool,
+        param_name: String,
+        parent_exists: bool,
+        parent_prefix: String,
+        parent_name: String,
+    },
+    #[suggestion_verbose(
+        infer::source_kind_subdiag_generic_suggestion,
+        code = "::<{args}>",
+        applicability = "has-placeholders"
+    )]
+    GenericSuggestion {
+        #[primary_span]
+        span: Span,
+        arg_count: usize,
+        args: String,
+    },
+}
+
+#[derive(SessionSubdiagnostic)]
+pub enum SourceKindMultiSuggestion<'a> {
+    #[multipart_suggestion_verbose(
+        infer::source_kind_fully_qualified,
+        applicability = "has-placeholders"
+    )]
+    FullyQualified {
+        #[suggestion_part(code = "{def_path}({adjustment}")]
+        span_lo: Span,
+        #[suggestion_part(code = "{successor_pos}")]
+        span_hi: Span,
+        def_path: String,
+        adjustment: &'a str,
+        successor_pos: &'a str,
+    },
+    #[multipart_suggestion_verbose(
+        infer::source_kind_closure_return,
+        applicability = "has-placeholders"
+    )]
+    ClosureReturn {
+        #[suggestion_part(code = "{start_span_code}")]
+        start_span: Span,
+        start_span_code: String,
+        #[suggestion_part(code = " }}")]
+        end_span: Option<Span>,
+    },
+}
+
+impl<'a> SourceKindMultiSuggestion<'a> {
+    pub fn new_fully_qualified(
+        span: Span,
+        def_path: String,
+        adjustment: &'a str,
+        successor: (&'a str, BytePos),
+    ) -> Self {
+        Self::FullyQualified {
+            span_lo: span.shrink_to_lo(),
+            span_hi: span.shrink_to_hi().with_hi(successor.1),
+            def_path,
+            adjustment,
+            successor_pos: successor.0,
+        }
+    }
+
+    pub fn new_closure_return(
+        ty_info: String,
+        data: &'a FnRetTy<'a>,
+        should_wrap_expr: Option<Span>,
+    ) -> Self {
+        let (arrow, post) = match data {
+            FnRetTy::DefaultReturn(_) => ("-> ", " "),
+            _ => ("", ""),
+        };
+        let (start_span, start_span_code, end_span) = match should_wrap_expr {
+            Some(end_span) => {
+                (data.span(), format!("{}{}{}{{ ", arrow, ty_info, post), Some(end_span))
+            }
+            None => (data.span(), format!("{}{}{}", arrow, ty_info, post), None),
+        };
+        Self::ClosureReturn { start_span, start_span_code, end_span }
+    }
+}
+
+pub enum RegionOriginNote<'a> {
+    Plain {
+        span: Span,
+        msg: DiagnosticMessage,
+    },
+    WithName {
+        span: Span,
+        msg: DiagnosticMessage,
+        name: &'a str,
+        continues: bool,
+    },
+    WithRequirement {
+        span: Span,
+        requirement: ObligationCauseAsDiagArg<'a>,
+        expected_found: Option<(DiagnosticStyledString, DiagnosticStyledString)>,
+    },
+}
+
+impl AddSubdiagnostic for RegionOriginNote<'_> {
+    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+        let mut label_or_note = |span, msg: DiagnosticMessage| {
+            let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count();
+            let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count();
+            let span_is_primary = diag.span.primary_spans().iter().all(|&sp| sp == span);
+            if span_is_primary && sub_count == 0 && expanded_sub_count == 0 {
+                diag.span_label(span, msg);
+            } else if span_is_primary && expanded_sub_count == 0 {
+                diag.note(msg);
+            } else {
+                diag.span_note(span, msg);
+            }
+        };
+        match self {
+            RegionOriginNote::Plain { span, msg } => {
+                label_or_note(span, msg);
+            }
+            RegionOriginNote::WithName { span, msg, name, continues } => {
+                label_or_note(span, msg);
+                diag.set_arg("name", name);
+                diag.set_arg("continues", continues);
+            }
+            RegionOriginNote::WithRequirement {
+                span,
+                requirement,
+                expected_found: Some((expected, found)),
+            } => {
+                label_or_note(span, fluent::infer::subtype);
+                diag.set_arg("requirement", requirement);
+
+                diag.note_expected_found(&"", expected, &"", found);
+            }
+            RegionOriginNote::WithRequirement { span, requirement, expected_found: None } => {
+                // FIXME: this really should be handled at some earlier stage. Our
+                // handling of region checking when type errors are present is
+                // *terrible*.
+                label_or_note(span, fluent::infer::subtype_2);
+                diag.set_arg("requirement", requirement);
+            }
+        };
+    }
+}
+
+pub enum LifetimeMismatchLabels {
+    InRet {
+        param_span: Span,
+        ret_span: Span,
+        span: Span,
+        label_var1: Option<Ident>,
+    },
+    Normal {
+        hir_equal: bool,
+        ty_sup: Span,
+        ty_sub: Span,
+        span: Span,
+        sup: Option<Ident>,
+        sub: Option<Ident>,
+    },
+}
+
+impl AddSubdiagnostic for LifetimeMismatchLabels {
+    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+        match self {
+            LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => {
+                diag.span_label(param_span, fluent::infer::declared_different);
+                diag.span_label(ret_span, fluent::infer::nothing);
+                diag.span_label(span, fluent::infer::data_returned);
+                diag.set_arg("label_var1_exists", label_var1.is_some());
+                diag.set_arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default());
+            }
+            LifetimeMismatchLabels::Normal {
+                hir_equal,
+                ty_sup,
+                ty_sub,
+                span,
+                sup: label_var1,
+                sub: label_var2,
+            } => {
+                if hir_equal {
+                    diag.span_label(ty_sup, fluent::infer::declared_multiple);
+                    diag.span_label(ty_sub, fluent::infer::nothing);
+                    diag.span_label(span, fluent::infer::data_lifetime_flow);
+                } else {
+                    diag.span_label(ty_sup, fluent::infer::types_declared_different);
+                    diag.span_label(ty_sub, fluent::infer::nothing);
+                    diag.span_label(span, fluent::infer::data_flows);
+                    diag.set_arg("label_var1_exists", label_var1.is_some());
+                    diag.set_arg(
+                        "label_var1",
+                        label_var1.map(|x| x.to_string()).unwrap_or_default(),
+                    );
+                    diag.set_arg("label_var2_exists", label_var2.is_some());
+                    diag.set_arg(
+                        "label_var2",
+                        label_var2.map(|x| x.to_string()).unwrap_or_default(),
+                    );
+                }
+            }
+        }
+    }
+}
+
+pub struct AddLifetimeParamsSuggestion<'a> {
+    pub tcx: TyCtxt<'a>,
+    pub sub: Region<'a>,
+    pub ty_sup: &'a Ty<'a>,
+    pub ty_sub: &'a Ty<'a>,
+    pub add_note: bool,
+}
+
+impl AddSubdiagnostic for AddLifetimeParamsSuggestion<'_> {
+    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+        let mut mk_suggestion = || {
+            let (
+                hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
+                hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. },
+            ) = (self.ty_sub, self.ty_sup) else {
+                return false;
+            };
+
+            if !lifetime_sub.name.is_anonymous() || !lifetime_sup.name.is_anonymous() {
+                return false;
+            };
+
+            let Some(anon_reg) = self.tcx.is_suitable_region(self.sub) else {
+                return false;
+            };
+
+            let hir_id = self.tcx.hir().local_def_id_to_hir_id(anon_reg.def_id);
+
+            let node = self.tcx.hir().get(hir_id);
+            let is_impl = matches!(&node, hir::Node::ImplItem(_));
+            let generics = match node {
+                hir::Node::Item(&hir::Item {
+                    kind: hir::ItemKind::Fn(_, ref generics, ..),
+                    ..
+                })
+                | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
+                | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics,
+                _ => return false,
+            };
+
+            let suggestion_param_name = generics
+                .params
+                .iter()
+                .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
+                .map(|p| p.name.ident().name)
+                .find(|i| *i != kw::UnderscoreLifetime);
+            let introduce_new = suggestion_param_name.is_none();
+            let suggestion_param_name =
+                suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned());
+
+            debug!(?lifetime_sup.span);
+            debug!(?lifetime_sub.span);
+            let make_suggestion = |span: rustc_span::Span| {
+                if span.is_empty() {
+                    (span, format!("{}, ", suggestion_param_name))
+                } else if let Ok("&") = self.tcx.sess.source_map().span_to_snippet(span).as_deref()
+                {
+                    (span.shrink_to_hi(), format!("{} ", suggestion_param_name))
+                } else {
+                    (span, suggestion_param_name.clone())
+                }
+            };
+            let mut suggestions =
+                vec![make_suggestion(lifetime_sub.span), make_suggestion(lifetime_sup.span)];
+
+            if introduce_new {
+                let new_param_suggestion = if let Some(first) =
+                    generics.params.iter().find(|p| !p.name.ident().span.is_empty())
+                {
+                    (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name))
+                } else {
+                    (generics.span, format!("<{}>", suggestion_param_name))
+                };
+
+                suggestions.push(new_param_suggestion);
+            }
+
+            diag.multipart_suggestion(
+                fluent::infer::lifetime_param_suggestion,
+                suggestions,
+                Applicability::MaybeIncorrect,
+            );
+            diag.set_arg("is_impl", is_impl);
+            true
+        };
+        if mk_suggestion() && self.add_note {
+            diag.note(fluent::infer::lifetime_param_suggestion_elided);
+        }
+    }
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(infer::lifetime_mismatch, code = "E0623")]
+pub struct LifetimeMismatch<'a> {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub labels: LifetimeMismatchLabels,
+    #[subdiagnostic]
+    pub suggestion: AddLifetimeParamsSuggestion<'a>,
+}
+
+pub struct IntroducesStaticBecauseUnmetLifetimeReq {
+    pub unmet_requirements: MultiSpan,
+    pub binding_span: Span,
+}
+
+impl AddSubdiagnostic for IntroducesStaticBecauseUnmetLifetimeReq {
+    fn add_to_diagnostic(mut self, diag: &mut rustc_errors::Diagnostic) {
+        self.unmet_requirements
+            .push_span_label(self.binding_span, fluent::infer::msl_introduces_static);
+        diag.span_note(self.unmet_requirements, fluent::infer::msl_unmet_req);
+    }
+}
+
+pub struct ImplNote {
+    pub impl_span: Option<Span>,
+}
+
+impl AddSubdiagnostic for ImplNote {
+    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+        match self.impl_span {
+            Some(span) => diag.span_note(span, fluent::infer::msl_impl_note),
+            None => diag.note(fluent::infer::msl_impl_note),
+        };
+    }
+}
+
+pub enum TraitSubdiag {
+    Note { span: Span },
+    Sugg { span: Span },
+}
+
+// FIXME(#100717) used in `Vec<TraitSubdiag>` so requires eager translation/list support
+impl AddSubdiagnostic for TraitSubdiag {
+    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+        match self {
+            TraitSubdiag::Note { span } => {
+                diag.span_note(span, "this has an implicit `'static` lifetime requirement");
+            }
+            TraitSubdiag::Sugg { span } => {
+                diag.span_suggestion_verbose(
+                    span,
+                    "consider relaxing the implicit `'static` requirement",
+                    " + '_".to_owned(),
+                    rustc_errors::Applicability::MaybeIncorrect,
+                );
+            }
+        }
+    }
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(infer::mismatched_static_lifetime)]
+pub struct MismatchedStaticLifetime<'a> {
+    #[primary_span]
+    pub cause_span: Span,
+    #[subdiagnostic]
+    pub unmet_lifetime_reqs: IntroducesStaticBecauseUnmetLifetimeReq,
+    #[subdiagnostic]
+    pub expl: Option<note_and_explain::RegionExplanation<'a>>,
+    #[subdiagnostic]
+    pub impl_note: ImplNote,
+    #[subdiagnostic]
+    pub trait_subdiags: Vec<TraitSubdiag>,
+}
diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs
new file mode 100644
index 00000000000..6f1f9522c86
--- /dev/null
+++ b/compiler/rustc_infer/src/errors/note_and_explain.rs
@@ -0,0 +1,179 @@
+use crate::infer::error_reporting::nice_region_error::find_anon_type;
+use rustc_errors::{self, fluent, AddSubdiagnostic, IntoDiagnosticArg};
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_span::{symbol::kw, Span};
+
+#[derive(Default)]
+struct DescriptionCtx<'a> {
+    span: Option<Span>,
+    kind: &'a str,
+    arg: String,
+    num_arg: u32,
+}
+
+impl<'a> DescriptionCtx<'a> {
+    fn new<'tcx>(
+        tcx: TyCtxt<'tcx>,
+        region: ty::Region<'tcx>,
+        alt_span: Option<Span>,
+    ) -> Option<Self> {
+        let mut me = DescriptionCtx::default();
+        me.span = alt_span;
+        match *region {
+            ty::ReEarlyBound(_) | ty::ReFree(_) => {
+                return Self::from_early_bound_and_free_regions(tcx, region);
+            }
+            ty::ReStatic => {
+                me.kind = "restatic";
+            }
+
+            ty::ReEmpty(ty::UniverseIndex::ROOT) => me.kind = "reempty",
+
+            ty::ReEmpty(ui) => {
+                me.kind = "reemptyuni";
+                me.arg = format!("{:?}", ui);
+            }
+
+            ty::RePlaceholder(_) => return None,
+
+            // FIXME(#13998) RePlaceholder should probably print like
+            // ReFree rather than dumping Debug output on the user.
+            //
+            // We shouldn't really be having unification failures with ReVar
+            // and ReLateBound though.
+            ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => {
+                me.kind = "revar";
+                me.arg = format!("{:?}", region);
+            }
+        };
+        Some(me)
+    }
+
+    fn from_early_bound_and_free_regions<'tcx>(
+        tcx: TyCtxt<'tcx>,
+        region: ty::Region<'tcx>,
+    ) -> Option<Self> {
+        let mut me = DescriptionCtx::default();
+        let scope = region.free_region_binding_scope(tcx).expect_local();
+        match *region {
+            ty::ReEarlyBound(ref br) => {
+                let mut sp = tcx.def_span(scope);
+                if let Some(param) =
+                    tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
+                {
+                    sp = param.span;
+                }
+                if br.has_name() {
+                    me.kind = "as_defined";
+                    me.arg = br.name.to_string();
+                } else {
+                    me.kind = "as_defined_anon";
+                };
+                me.span = Some(sp)
+            }
+            ty::ReFree(ref fr) => {
+                if !fr.bound_region.is_named()
+                    && let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region)
+                {
+                    me.kind = "defined_here";
+                    me.span = Some(ty.span);
+                } else {
+                    match fr.bound_region {
+                        ty::BoundRegionKind::BrNamed(_, name) => {
+                            let mut sp = tcx.def_span(scope);
+                            if let Some(param) =
+                                tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
+                            {
+                                sp = param.span;
+                            }
+                            if name == kw::UnderscoreLifetime {
+                                me.kind = "as_defined_anon";
+                            } else {
+                                me.kind = "as_defined";
+                                me.arg = name.to_string();
+                            };
+                            me.span = Some(sp);
+                        }
+                        ty::BrAnon(idx) => {
+                            me.kind = "anon_num_here";
+                            me.num_arg = idx+1;
+                            me.span = Some(tcx.def_span(scope));
+                        },
+                        _ => {
+                            me.kind = "defined_here_reg";
+                            me.arg = region.to_string();
+                            me.span = Some(tcx.def_span(scope));
+                        },
+                    }
+                }
+            }
+            _ => bug!(),
+        }
+        Some(me)
+    }
+
+    fn add_to(self, diag: &mut rustc_errors::Diagnostic) {
+        diag.set_arg("desc_kind", self.kind);
+        diag.set_arg("desc_arg", self.arg);
+        diag.set_arg("desc_num_arg", self.num_arg);
+    }
+}
+
+pub enum PrefixKind {
+    Empty,
+}
+
+pub enum SuffixKind {
+    Continues,
+}
+
+impl IntoDiagnosticArg for PrefixKind {
+    fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+        let kind = match self {
+            Self::Empty => "empty",
+        }
+        .into();
+        rustc_errors::DiagnosticArgValue::Str(kind)
+    }
+}
+
+impl IntoDiagnosticArg for SuffixKind {
+    fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+        let kind = match self {
+            Self::Continues => "continues",
+        }
+        .into();
+        rustc_errors::DiagnosticArgValue::Str(kind)
+    }
+}
+
+pub struct RegionExplanation<'a> {
+    desc: DescriptionCtx<'a>,
+    prefix: PrefixKind,
+    suffix: SuffixKind,
+}
+
+impl RegionExplanation<'_> {
+    pub fn new<'tcx>(
+        tcx: TyCtxt<'tcx>,
+        region: ty::Region<'tcx>,
+        alt_span: Option<Span>,
+        prefix: PrefixKind,
+        suffix: SuffixKind,
+    ) -> Option<Self> {
+        Some(Self { desc: DescriptionCtx::new(tcx, region, alt_span)?, prefix, suffix })
+    }
+}
+
+impl AddSubdiagnostic for RegionExplanation<'_> {
+    fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) {
+        if let Some(span) = self.desc.span {
+            diag.span_note(span, fluent::infer::region_explanation);
+        } else {
+            diag.note(fluent::infer::region_explanation);
+        }
+        self.desc.add_to(diag);
+        diag.set_arg("pref_kind", self.prefix);
+        diag.set_arg("suff_kind", self.suffix);
+    }
+}
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index d4350aa5734..c1fb59009d3 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -486,7 +486,7 @@ struct Generalizer<'cx, 'tcx> {
 
     param_env: ty::ParamEnv<'tcx>,
 
-    cache: SsoHashMap<Ty<'tcx>, RelateResult<'tcx, Ty<'tcx>>>,
+    cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>,
 }
 
 /// Result from a generalization operation. This includes
@@ -593,8 +593,8 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
     fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
         assert_eq!(t, t2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
 
-        if let Some(result) = self.cache.get(&t) {
-            return result.clone();
+        if let Some(&result) = self.cache.get(&t) {
+            return Ok(result);
         }
         debug!("generalize: t={:?}", t);
 
@@ -664,10 +664,10 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
                 Ok(t)
             }
             _ => relate::super_relate_tys(self, t, t),
-        };
+        }?;
 
-        self.cache.insert(t, result.clone());
-        return result;
+        self.cache.insert(t, result);
+        Ok(result)
     }
 
     fn regions(
@@ -743,9 +743,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
                     }
                 }
             }
-            ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted })
-                if self.tcx().lazy_normalization() =>
-            {
+            ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => {
                 assert_eq!(promoted, None);
                 let substs = self.relate_with_variance(
                     ty::Variance::Invariant,
@@ -967,9 +965,7 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
                     }
                 }
             }
-            ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted })
-                if self.tcx().lazy_normalization() =>
-            {
+            ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => {
                 assert_eq!(promoted, None);
                 let substs = self.relate_with_variance(
                     ty::Variance::Invariant,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 6dad9873d61..0196bd26217 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -1586,28 +1586,31 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             Some(values) => {
                 let values = self.resolve_vars_if_possible(values);
                 let (is_simple_error, exp_found) = match values {
-                    ValuePairs::Terms(infer::ExpectedFound {
-                        expected: ty::Term::Ty(expected),
-                        found: ty::Term::Ty(found),
-                    }) => {
-                        let is_simple_err = expected.is_simple_text() && found.is_simple_text();
-                        OpaqueTypesVisitor::visit_expected_found(self.tcx, expected, found, span)
-                            .report(diag);
-
-                        (
-                            is_simple_err,
-                            Mismatch::Variable(infer::ExpectedFound { expected, found }),
-                        )
+                    ValuePairs::Terms(infer::ExpectedFound { expected, found }) => {
+                        match (expected.unpack(), found.unpack()) {
+                            (ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => {
+                                let is_simple_err =
+                                    expected.is_simple_text() && found.is_simple_text();
+                                OpaqueTypesVisitor::visit_expected_found(
+                                    self.tcx, expected, found, span,
+                                )
+                                .report(diag);
+
+                                (
+                                    is_simple_err,
+                                    Mismatch::Variable(infer::ExpectedFound { expected, found }),
+                                )
+                            }
+                            (ty::TermKind::Const(_), ty::TermKind::Const(_)) => {
+                                (false, Mismatch::Fixed("constant"))
+                            }
+                            _ => (false, Mismatch::Fixed("type")),
+                        }
                     }
-                    ValuePairs::Terms(infer::ExpectedFound {
-                        expected: ty::Term::Const(_),
-                        found: ty::Term::Const(_),
-                    }) => (false, Mismatch::Fixed("constant")),
                     ValuePairs::TraitRefs(_) | ValuePairs::PolyTraitRefs(_) => {
                         (false, Mismatch::Fixed("trait"))
                     }
                     ValuePairs::Regions(_) => (false, Mismatch::Fixed("lifetime")),
-                    _ => (false, Mismatch::Fixed("type")),
                 };
                 let vals = match self.values_str(values) {
                     Some((expected, found)) => Some((expected, found)),
@@ -2273,11 +2276,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             return None;
         }
 
-        Some(match (exp_found.expected, exp_found.found) {
-            (ty::Term::Ty(expected), ty::Term::Ty(found)) => self.cmp(expected, found),
-            (expected, found) => (
-                DiagnosticStyledString::highlighted(expected.to_string()),
-                DiagnosticStyledString::highlighted(found.to_string()),
+        Some(match (exp_found.expected.unpack(), exp_found.found.unpack()) {
+            (ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => self.cmp(expected, found),
+            _ => (
+                DiagnosticStyledString::highlighted(exp_found.expected.to_string()),
+                DiagnosticStyledString::highlighted(exp_found.found.to_string()),
             ),
         })
     }
@@ -2395,19 +2398,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             type_param_span: Option<(Span, bool)>,
             bound_kind: GenericKind<'tcx>,
             sub: S,
+            add_lt_sugg: Option<(Span, String)>,
         ) {
             let msg = "consider adding an explicit lifetime bound";
             if let Some((sp, has_lifetimes)) = type_param_span {
                 let suggestion =
                     if has_lifetimes { format!(" + {}", sub) } else { format!(": {}", sub) };
-                err.span_suggestion_verbose(
-                    sp,
-                    &format!("{}...", msg),
-                    suggestion,
+                let mut suggestions = vec![(sp, suggestion)];
+                if let Some(add_lt_sugg) = add_lt_sugg {
+                    suggestions.push(add_lt_sugg);
+                }
+                err.multipart_suggestion_verbose(
+                    format!("{msg}..."),
+                    suggestions,
                     Applicability::MaybeIncorrect, // Issue #41966
                 );
             } else {
-                let consider = format!("{} `{}: {}`...", msg, bound_kind, sub,);
+                let consider = format!("{} `{}: {}`...", msg, bound_kind, sub);
                 err.help(&consider);
             }
         }
@@ -2423,7 +2430,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     };
                     let mut sugg =
                         vec![(sp, suggestion), (span.shrink_to_hi(), format!(" + {}", new_lt))];
-                    if let Some(lt) = add_lt_sugg {
+                    if let Some(lt) = add_lt_sugg.clone() {
                         sugg.push(lt);
                         sugg.rotate_right(1);
                     }
@@ -2529,7 +2536,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 // for the bound is not suitable for suggestions when `-Zverbose` is set because it
                 // uses `Debug` output, so we handle it specially here so that suggestions are
                 // always correct.
-                binding_suggestion(&mut err, type_param_span, bound_kind, name);
+                binding_suggestion(&mut err, type_param_span, bound_kind, name, None);
                 err
             }
 
@@ -2542,7 +2549,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     "{} may not live long enough",
                     labeled_user_string
                 );
-                binding_suggestion(&mut err, type_param_span, bound_kind, "'static");
+                binding_suggestion(&mut err, type_param_span, bound_kind, "'static", None);
                 err
             }
 
@@ -2576,7 +2583,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                             new_binding_suggestion(&mut err, type_param_span);
                         }
                         _ => {
-                            binding_suggestion(&mut err, type_param_span, bound_kind, new_lt);
+                            binding_suggestion(
+                                &mut err,
+                                type_param_span,
+                                bound_kind,
+                                new_lt,
+                                add_lt_sugg,
+                            );
                         }
                     }
                 }
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 91a05367eee..cb2be93589d 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
@@ -341,7 +341,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 multi_suggestions,
                 bad_label,
             }
-            .into_diagnostic(&self.tcx.sess.parse_sess),
+            .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
             TypeAnnotationNeeded::E0283 => AmbigousImpl {
                 span,
                 source_kind,
@@ -351,7 +351,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 multi_suggestions,
                 bad_label,
             }
-            .into_diagnostic(&self.tcx.sess.parse_sess),
+            .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
             TypeAnnotationNeeded::E0284 => AmbigousReturn {
                 span,
                 source_kind,
@@ -361,7 +361,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 multi_suggestions,
                 bad_label,
             }
-            .into_diagnostic(&self.tcx.sess.parse_sess),
+            .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
         }
     }
 
@@ -511,20 +511,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     _ => "",
                 };
 
-                multi_suggestions.push(SourceKindMultiSuggestion::FullyQualified {
-                    span: receiver.span,
+                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);
-                multi_suggestions.push(SourceKindMultiSuggestion::ClosureReturn {
+                multi_suggestions.push(SourceKindMultiSuggestion::new_closure_return(
                     ty_info,
                     data,
                     should_wrap_expr,
-                });
+                ));
             }
         }
         match error_code {
@@ -537,7 +537,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 multi_suggestions,
                 bad_label: None,
             }
-            .into_diagnostic(&self.tcx.sess.parse_sess),
+            .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
             TypeAnnotationNeeded::E0283 => AmbigousImpl {
                 span,
                 source_kind,
@@ -547,7 +547,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 multi_suggestions,
                 bad_label: None,
             }
-            .into_diagnostic(&self.tcx.sess.parse_sess),
+            .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
             TypeAnnotationNeeded::E0284 => AmbigousReturn {
                 span,
                 source_kind,
@@ -557,7 +557,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 multi_suggestions,
                 bad_label: None,
             }
-            .into_diagnostic(&self.tcx.sess.parse_sess),
+            .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
         }
     }
 
@@ -575,7 +575,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             span,
             generator_kind: GeneratorKindAsDiagArg(kind),
         }
-        .into_diagnostic(&self.tcx.sess.parse_sess)
+        .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic)
     }
 }
 
@@ -901,7 +901,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
                     }
                 }
             }
-            hir::ExprKind::MethodCall(segment, _, _) => {
+            hir::ExprKind::MethodCall(segment, ..) => {
                 if let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id) {
                     let generics = tcx.generics_of(def_id);
                     let insertable: Option<_> = try {
@@ -909,7 +909,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
                             None?
                         }
                         let substs = self.node_substs_opt(expr.hir_id)?;
-                        let span = tcx.hir().span(segment.hir_id?);
+                        let span = tcx.hir().span(segment.hir_id);
                         let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
                         InsertableGenericArgs {
                             insert_span,
@@ -957,13 +957,13 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
         path.segments
             .iter()
             .filter_map(move |segment| {
-                let res = segment.res?;
+                let res = segment.res;
                 let generics_def_id = tcx.res_generics_def_id(res)?;
                 let generics = tcx.generics_of(generics_def_id);
                 if generics.has_impl_trait() {
                     return None;
                 }
-                let span = tcx.hir().span(segment.hir_id?);
+                let span = tcx.hir().span(segment.hir_id);
                 let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
                 Some(InsertableGenericArgs {
                     insert_span,
@@ -996,7 +996,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
                     if !segment.infer_args || generics.has_impl_trait() {
                         None?;
                     }
-                    let span = tcx.hir().span(segment.hir_id?);
+                    let span = tcx.hir().span(segment.hir_id);
                     let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
                     InsertableGenericArgs { insert_span, substs, generics_def_id: def_id, def_id }
                 };
@@ -1132,7 +1132,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
                 let generic_args = &generics.own_substs_no_defaults(tcx, substs)
                     [generics.own_counts().lifetimes..];
                 let span = match expr.kind {
-                    ExprKind::MethodCall(path, _, _) => path.ident.span,
+                    ExprKind::MethodCall(path, ..) => path.ident.span,
                     _ => expr.span,
                 };
 
@@ -1181,7 +1181,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
             })
             .any(|generics| generics.has_impl_trait())
         };
-        if let ExprKind::MethodCall(path, args, span) = expr.kind
+        if let ExprKind::MethodCall(path, receiver, args, span) = expr.kind
             && let Some(substs) = self.node_substs_opt(expr.hir_id)
             && substs.iter().any(|arg| self.generic_arg_contains_target(arg))
             && let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id)
@@ -1189,12 +1189,12 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
             && !has_impl_trait(def_id)
         {
             let successor =
-                args.get(1).map_or_else(|| (")", span.hi()), |arg| (", ", arg.span.lo()));
+                args.get(0).map_or_else(|| (")", span.hi()), |arg| (", ", arg.span.lo()));
             let substs = self.infcx.resolve_vars_if_possible(substs);
             self.update_infer_source(InferSource {
                 span: path.ident.span,
                 kind: InferSourceKind::FullyQualifiedMethodCall {
-                    receiver: args.first().unwrap(),
+                    receiver,
                     successor,
                     substs,
                     def_id,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
index 9a2ab3e3224..3a4320a9a8f 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
@@ -1,6 +1,9 @@
 //! Error Reporting for Anonymous Region Lifetime Errors
 //! where both the regions are anonymous.
 
+use crate::errors::AddLifetimeParamsSuggestion;
+use crate::errors::LifetimeMismatch;
+use crate::errors::LifetimeMismatchLabels;
 use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
 use crate::infer::error_reporting::nice_region_error::util::AnonymousParamInfo;
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
@@ -8,11 +11,10 @@ use crate::infer::lexical_region_resolve::RegionResolutionError;
 use crate::infer::SubregionOrigin;
 use crate::infer::TyCtxt;
 
-use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed};
-use rustc_hir as hir;
-use rustc_hir::{GenericParamKind, Ty};
+use rustc_errors::AddSubdiagnostic;
+use rustc_errors::{Diagnostic, ErrorGuaranteed};
+use rustc_hir::Ty;
 use rustc_middle::ty::Region;
-use rustc_span::symbol::kw;
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     /// Print the error message for lifetime errors when both the concerned regions are anonymous.
@@ -98,137 +100,50 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         let sub_is_ret_type =
             self.is_return_type_anon(scope_def_id_sub, bregion_sub, ty_fndecl_sub);
 
-        let span_label_var1 = match anon_param_sup.pat.simple_ident() {
-            Some(simple_ident) => format!(" from `{}`", simple_ident),
-            None => String::new(),
-        };
-
-        let span_label_var2 = match anon_param_sub.pat.simple_ident() {
-            Some(simple_ident) => format!(" into `{}`", simple_ident),
-            None => String::new(),
-        };
-
         debug!(
             "try_report_anon_anon_conflict: sub_is_ret_type={:?} sup_is_ret_type={:?}",
             sub_is_ret_type, sup_is_ret_type
         );
 
-        let mut err = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch");
-
-        match (sup_is_ret_type, sub_is_ret_type) {
+        let labels = match (sup_is_ret_type, sub_is_ret_type) {
             (ret_capture @ Some(ret_span), _) | (_, ret_capture @ Some(ret_span)) => {
                 let param_span =
                     if sup_is_ret_type == ret_capture { ty_sub.span } else { ty_sup.span };
-
-                err.span_label(
+                LifetimeMismatchLabels::InRet {
                     param_span,
-                    "this parameter and the return type are declared with different lifetimes...",
-                );
-                err.span_label(ret_span, "");
-                err.span_label(span, format!("...but data{} is returned here", span_label_var1));
-            }
-
-            (None, None) => {
-                if ty_sup.hir_id == ty_sub.hir_id {
-                    err.span_label(ty_sup.span, "this type is declared with multiple lifetimes...");
-                    err.span_label(ty_sub.span, "");
-                    err.span_label(span, "...but data with one lifetime flows into the other here");
-                } else {
-                    err.span_label(
-                        ty_sup.span,
-                        "these two types are declared with different lifetimes...",
-                    );
-                    err.span_label(ty_sub.span, "");
-                    err.span_label(
-                        span,
-                        format!("...but data{} flows{} here", span_label_var1, span_label_var2),
-                    );
+                    ret_span,
+                    span,
+                    label_var1: anon_param_sup.pat.simple_ident(),
                 }
             }
-        }
 
-        if suggest_adding_lifetime_params(self.tcx(), sub, ty_sup, ty_sub, &mut err) {
-            err.note("each elided lifetime in input position becomes a distinct lifetime");
-        }
+            (None, None) => LifetimeMismatchLabels::Normal {
+                hir_equal: ty_sup.hir_id == ty_sub.hir_id,
+                ty_sup: ty_sup.span,
+                ty_sub: ty_sub.span,
+                span,
+                sup: anon_param_sup.pat.simple_ident(),
+                sub: anon_param_sub.pat.simple_ident(),
+            },
+        };
 
-        let reported = err.emit();
+        let suggestion =
+            AddLifetimeParamsSuggestion { tcx: self.tcx(), sub, ty_sup, ty_sub, add_note: true };
+        let err = LifetimeMismatch { span, labels, suggestion };
+        let reported = self.tcx().sess.emit_err(err);
         Some(reported)
     }
 }
 
+/// Currently only used in rustc_borrowck, probably should be
+/// removed in favour of public_errors::AddLifetimeParamsSuggestion
 pub fn suggest_adding_lifetime_params<'tcx>(
     tcx: TyCtxt<'tcx>,
     sub: Region<'tcx>,
-    ty_sup: &Ty<'_>,
-    ty_sub: &Ty<'_>,
+    ty_sup: &'tcx Ty<'_>,
+    ty_sub: &'tcx Ty<'_>,
     err: &mut Diagnostic,
-) -> bool {
-    let (
-        hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
-        hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. },
-    ) = (ty_sub, ty_sup) else {
-        return false;
-    };
-
-    if !lifetime_sub.name.is_anonymous() || !lifetime_sup.name.is_anonymous() {
-        return false;
-    };
-
-    let Some(anon_reg) = tcx.is_suitable_region(sub) else {
-        return false;
-    };
-
-    let hir_id = tcx.hir().local_def_id_to_hir_id(anon_reg.def_id);
-
-    let node = tcx.hir().get(hir_id);
-    let is_impl = matches!(&node, hir::Node::ImplItem(_));
-    let generics = match node {
-        hir::Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, ref generics, ..), .. })
-        | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
-        | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics,
-        _ => return false,
-    };
-
-    let suggestion_param_name = generics
-        .params
-        .iter()
-        .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
-        .map(|p| p.name.ident().name)
-        .find(|i| *i != kw::UnderscoreLifetime);
-    let introduce_new = suggestion_param_name.is_none();
-    let suggestion_param_name =
-        suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned());
-
-    debug!(?lifetime_sup.span);
-    debug!(?lifetime_sub.span);
-    let make_suggestion = |span: rustc_span::Span| {
-        if span.is_empty() {
-            (span, format!("{}, ", suggestion_param_name))
-        } else if let Ok("&") = tcx.sess.source_map().span_to_snippet(span).as_deref() {
-            (span.shrink_to_hi(), format!("{} ", suggestion_param_name))
-        } else {
-            (span, suggestion_param_name.clone())
-        }
-    };
-    let mut suggestions =
-        vec![make_suggestion(lifetime_sub.span), make_suggestion(lifetime_sup.span)];
-
-    if introduce_new {
-        let new_param_suggestion =
-            if let Some(first) = generics.params.iter().find(|p| !p.name.ident().span.is_empty()) {
-                (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name))
-            } else {
-                (generics.span, format!("<{}>", suggestion_param_name))
-            };
-
-        suggestions.push(new_param_suggestion);
-    }
-
-    let mut sugg = String::from("consider introducing a named lifetime parameter");
-    if is_impl {
-        sugg.push_str(" and update trait if needed");
-    }
-    err.multipart_suggestion(sugg, suggestions, Applicability::MaybeIncorrect);
-
-    true
+) {
+    let suggestion = AddLifetimeParamsSuggestion { tcx, sub, ty_sup, ty_sub, add_note: false };
+    suggestion.add_to_diagnostic(err);
 }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
index c20b96cae2e..1410e2b63b0 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
@@ -1,13 +1,14 @@
 //! Error Reporting for when the lifetime for a type doesn't match the `impl` selected for a predicate
 //! to hold.
 
+use crate::errors::{note_and_explain, IntroducesStaticBecauseUnmetLifetimeReq};
+use crate::errors::{ImplNote, MismatchedStaticLifetime, TraitSubdiag};
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
-use crate::infer::error_reporting::note_and_explain_region;
 use crate::infer::lexical_region_resolve::RegionResolutionError;
 use crate::infer::{SubregionOrigin, TypeTrace};
 use crate::traits::ObligationCauseCode;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
+use rustc_errors::{ErrorGuaranteed, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::intravisit::Visitor;
 use rustc_middle::ty::TypeVisitor;
@@ -39,12 +40,23 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             = *parent.code() else {
             return None;
         };
-        let mut err = self.tcx().sess.struct_span_err(cause.span, "incompatible lifetime on type");
+
         // FIXME: we should point at the lifetime
-        let mut multi_span: MultiSpan = vec![binding_span].into();
-        multi_span.push_span_label(binding_span, "introduces a `'static` lifetime requirement");
-        err.span_note(multi_span, "because this has an unmet lifetime requirement");
-        note_and_explain_region(self.tcx(), &mut err, "", sup, "...", Some(binding_span));
+        let multi_span: MultiSpan = vec![binding_span].into();
+        let multispan_subdiag = IntroducesStaticBecauseUnmetLifetimeReq {
+            unmet_requirements: multi_span,
+            binding_span,
+        };
+
+        let expl = note_and_explain::RegionExplanation::new(
+            self.tcx(),
+            sup,
+            Some(binding_span),
+            note_and_explain::PrefixKind::Empty,
+            note_and_explain::SuffixKind::Continues,
+        );
+        let mut impl_span = None;
+        let mut trait_subdiags = Vec::new();
         if let Some(impl_node) = self.tcx().hir().get_if_local(*impl_def_id) {
             // If an impl is local, then maybe this isn't what they want. Try to
             // be as helpful as possible with implicit lifetimes.
@@ -73,31 +85,30 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                 // there aren't trait objects or because none are implicit, then just
                 // write a single note on the impl itself.
 
-                let impl_span = self.tcx().def_span(*impl_def_id);
-                err.span_note(impl_span, "...does not necessarily outlive the static lifetime introduced by the compatible `impl`");
+                impl_span = Some(self.tcx().def_span(*impl_def_id));
             } else {
                 // Otherwise, point at all implicit static lifetimes
 
-                err.note("...does not necessarily outlive the static lifetime introduced by the compatible `impl`");
                 for span in &traits {
-                    err.span_note(*span, "this has an implicit `'static` lifetime requirement");
+                    trait_subdiags.push(TraitSubdiag::Note { span: *span });
                     // It would be nice to put this immediately under the above note, but they get
                     // pushed to the end.
-                    err.span_suggestion_verbose(
-                        span.shrink_to_hi(),
-                        "consider relaxing the implicit `'static` requirement",
-                        " + '_",
-                        Applicability::MaybeIncorrect,
-                    );
+                    trait_subdiags.push(TraitSubdiag::Sugg { span: span.shrink_to_hi() });
                 }
             }
         } else {
             // Otherwise just point out the impl.
 
-            let impl_span = self.tcx().def_span(*impl_def_id);
-            err.span_note(impl_span, "...does not necessarily outlive the static lifetime introduced by the compatible `impl`");
+            impl_span = Some(self.tcx().def_span(*impl_def_id));
         }
-        let reported = err.emit();
+        let err = MismatchedStaticLifetime {
+            cause_span: cause.span,
+            unmet_lifetime_reqs: multispan_subdiag,
+            expl,
+            impl_note: ImplNote { impl_span },
+            trait_subdiags,
+        };
+        let reported = self.tcx().sess.emit_err(err);
         Some(reported)
     }
 }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
index da465a76429..a6a39d062d5 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
@@ -154,16 +154,11 @@ impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
             }
             hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
                 [segment]
-                    if segment
-                        .res
-                        .map(|res| {
-                            matches!(
-                                res,
-                                Res::SelfTy { trait_: _, alias_to: _ }
-                                    | Res::Def(hir::def::DefKind::TyParam, _)
-                            )
-                        })
-                        .unwrap_or(false) =>
+                    if matches!(
+                        segment.res,
+                        Res::SelfTy { trait_: _, alias_to: _ }
+                            | Res::Def(hir::def::DefKind::TyParam, _)
+                    ) =>
                 {
                     self.types.push(path.span);
                 }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index fe037a458a7..bbbc044b85a 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -353,12 +353,11 @@ pub enum ValuePairs<'tcx> {
 
 impl<'tcx> ValuePairs<'tcx> {
     pub fn ty(&self) -> Option<(Ty<'tcx>, Ty<'tcx>)> {
-        if let ValuePairs::Terms(ExpectedFound {
-            expected: ty::Term::Ty(expected),
-            found: ty::Term::Ty(found),
-        }) = self
+        if let ValuePairs::Terms(ExpectedFound { expected, found }) = self
+            && let Some(expected) = expected.ty()
+            && let Some(found) = found.ty()
         {
-            Some((*expected, *found))
+            Some((expected, found))
         } else {
             None
         }
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index c7d7ef40d9d..75233495040 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -50,13 +50,13 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
         }
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
-        debug!("param_bound(param_ty={:?})", param_ty);
-
         // Start with anything like `T: 'a` we can scrape from the
         // environment. If the environment contains something like
         // `for<'a> T: 'a`, then we know that `T` outlives everything.
         let declared_bounds_from_env = self.declared_generic_bounds_from_env(param_ty);
+        debug!(?declared_bounds_from_env);
         let mut param_bounds = vec![];
         for declared_bound in declared_bounds_from_env {
             let bound_region = declared_bound.map_bound(|outlives| outlives.1);
@@ -65,6 +65,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
                 param_bounds.push(VerifyBound::OutlivedBy(region));
             } else {
                 // This is `for<'a> T: 'a`. This means that `T` outlives everything! All done here.
+                debug!("found that {param_ty:?} outlives any lifetime, returning empty vector");
                 return VerifyBound::AllBounds(vec![]);
             }
         }
@@ -72,6 +73,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
         // Add in the default bound of fn body that applies to all in
         // scope type parameters:
         if let Some(r) = self.implicit_region_bound {
+            debug!("adding implicit region bound of {r:?}");
             param_bounds.push(VerifyBound::OutlivedBy(r));
         }
 
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index bb534a3c7af..c41b154c3e0 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -573,13 +573,24 @@ fn write_out_deps(
         // Account for explicitly marked-to-track files
         // (e.g. accessed in proc macros).
         let file_depinfo = sess.parse_sess.file_depinfo.borrow();
-        let extra_tracked_files = file_depinfo.iter().map(|path_sym| {
-            let path = PathBuf::from(path_sym.as_str());
+
+        let normalize_path = |path: PathBuf| {
             let file = FileName::from(path);
             escape_dep_filename(&file.prefer_local().to_string())
-        });
+        };
+
+        let extra_tracked_files =
+            file_depinfo.iter().map(|path_sym| normalize_path(PathBuf::from(path_sym.as_str())));
         files.extend(extra_tracked_files);
 
+        // We also need to track used PGO profile files
+        if let Some(ref profile_instr) = sess.opts.cg.profile_use {
+            files.push(normalize_path(profile_instr.as_path().to_path_buf()));
+        }
+        if let Some(ref profile_sample) = sess.opts.unstable_opts.profile_sample_use {
+            files.push(normalize_path(profile_sample.as_path().to_path_buf()));
+        }
+
         if sess.binary_dep_depinfo() {
             if let Some(ref backend) = sess.opts.unstable_opts.codegen_backend {
                 if backend.contains('.') {
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index 178366f7d80..a79c982649a 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -141,7 +141,7 @@ pub enum TokenKind {
     Unknown,
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum DocStyle {
     Outer,
     Inner,
diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs
index 121fefdc620..b97f8acb37f 100644
--- a/compiler/rustc_lint/src/array_into_iter.rs
+++ b/compiler/rustc_lint/src/array_into_iter.rs
@@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
         }
 
         // We only care about method call expressions.
-        if let hir::ExprKind::MethodCall(call, args, _) = &expr.kind {
+        if let hir::ExprKind::MethodCall(call, receiver_arg, ..) = &expr.kind {
             if call.ident.name != sym::into_iter {
                 return;
             }
@@ -75,7 +75,6 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
             };
 
             // As this is a method call expression, we have at least one argument.
-            let receiver_arg = &args[0];
             let receiver_ty = cx.typeck_results().expr_ty(receiver_arg);
             let adjustments = cx.typeck_results().expr_adjustments(receiver_arg);
 
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 48942211eba..f06bfa912ca 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -259,17 +259,8 @@ impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns {
                         == Some(cx.tcx.field_index(fieldpat.hir_id, cx.typeck_results()))
                     {
                         cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, |lint| {
-                            let binding = match binding_annot {
-                                hir::BindingAnnotation::Unannotated => None,
-                                hir::BindingAnnotation::Mutable => Some("mut"),
-                                hir::BindingAnnotation::Ref => Some("ref"),
-                                hir::BindingAnnotation::RefMut => Some("ref mut"),
-                            };
-                            let suggested_ident = if let Some(binding) = binding {
-                                format!("{} {}", binding, ident)
-                            } else {
-                                ident.to_string()
-                            };
+                            let suggested_ident =
+                                format!("{}{}", binding_annot.prefix_str(), ident);
                             lint.build(fluent::lint::builtin_non_shorthand_field_patterns)
                                 .set_arg("ident", ident.clone())
                                 .span_suggestion(
@@ -2412,13 +2403,13 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
                         _ => {}
                     }
                 }
-            } else if let hir::ExprKind::MethodCall(_, ref args, _) = expr.kind {
+            } else if let hir::ExprKind::MethodCall(_, receiver, ..) = expr.kind {
                 // Find problematic calls to `MaybeUninit::assume_init`.
                 let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
                 if cx.tcx.is_diagnostic_item(sym::assume_init, def_id) {
                     // This is a call to *some* method named `assume_init`.
                     // See if the `self` parameter is one of the dangerous constructors.
-                    if let hir::ExprKind::Call(ref path_expr, _) = args[0].kind {
+                    if let hir::ExprKind::Call(ref path_expr, _) = receiver.kind {
                         if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
                             let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
                             match cx.tcx.get_diagnostic_name(def_id) {
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 9a163cf207e..7ca6ec5d962 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -50,6 +50,10 @@ use std::cell::Cell;
 use std::iter;
 use std::slice;
 
+type EarlyLintPassFactory = dyn Fn() -> EarlyLintPassObject + sync::Send + sync::Sync;
+type LateLintPassFactory =
+    dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::Send + sync::Sync;
+
 /// Information about the registered lints.
 ///
 /// This is basically the subset of `Context` that we can
@@ -64,11 +68,11 @@ pub struct LintStore {
     /// interior mutability, we don't enforce this (and lints should, in theory,
     /// be compatible with being constructed more than once, though not
     /// necessarily in a sane manner. This is safe though.)
-    pub pre_expansion_passes: Vec<Box<dyn Fn() -> EarlyLintPassObject + sync::Send + sync::Sync>>,
-    pub early_passes: Vec<Box<dyn Fn() -> EarlyLintPassObject + sync::Send + sync::Sync>>,
-    pub late_passes: Vec<Box<dyn Fn() -> LateLintPassObject + sync::Send + sync::Sync>>,
+    pub pre_expansion_passes: Vec<Box<EarlyLintPassFactory>>,
+    pub early_passes: Vec<Box<EarlyLintPassFactory>>,
+    pub late_passes: Vec<Box<LateLintPassFactory>>,
     /// This is unique in that we construct them per-module, so not once.
-    pub late_module_passes: Vec<Box<dyn Fn() -> LateLintPassObject + sync::Send + sync::Sync>>,
+    pub late_module_passes: Vec<Box<LateLintPassFactory>>,
 
     /// Lints indexed by name.
     by_name: FxHashMap<String, TargetLint>,
@@ -186,14 +190,20 @@ impl LintStore {
 
     pub fn register_late_pass(
         &mut self,
-        pass: impl Fn() -> LateLintPassObject + 'static + sync::Send + sync::Sync,
+        pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
+        + 'static
+        + sync::Send
+        + sync::Sync,
     ) {
         self.late_passes.push(Box::new(pass));
     }
 
     pub fn register_late_mod_pass(
         &mut self,
-        pass: impl Fn() -> LateLintPassObject + 'static + sync::Send + sync::Sync,
+        pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
+        + 'static
+        + sync::Send
+        + sync::Sync,
     ) {
         self.late_module_passes.push(Box::new(pass));
     }
@@ -558,7 +568,7 @@ pub trait LintPassObject: Sized {}
 
 impl LintPassObject for EarlyLintPassObject {}
 
-impl LintPassObject for LateLintPassObject {}
+impl LintPassObject for LateLintPassObject<'_> {}
 
 pub trait LintContext: Sized {
     type PassObject: LintPassObject;
@@ -949,8 +959,8 @@ impl<'a> EarlyContext<'a> {
     }
 }
 
-impl LintContext for LateContext<'_> {
-    type PassObject = LateLintPassObject;
+impl<'tcx> LintContext for LateContext<'tcx> {
+    type PassObject = LateLintPassObject<'tcx>;
 
     /// Gets the overall compiler `Session` object.
     fn sess(&self) -> &Session {
diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs
index 606d8bda8aa..5c183d4091e 100644
--- a/compiler/rustc_lint/src/errors.rs
+++ b/compiler/rustc_lint/src/errors.rs
@@ -1,6 +1,6 @@
-use rustc_errors::{fluent, AddSubdiagnostic, ErrorGuaranteed};
+use rustc_errors::{fluent, AddSubdiagnostic, ErrorGuaranteed, Handler};
 use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
-use rustc_session::{lint::Level, parse::ParseSess, SessionDiagnostic};
+use rustc_session::{lint::Level, SessionDiagnostic};
 use rustc_span::{Span, Symbol};
 
 #[derive(SessionDiagnostic)]
@@ -122,9 +122,9 @@ pub struct CheckNameUnknown {
 impl SessionDiagnostic<'_> for CheckNameUnknown {
     fn into_diagnostic(
         self,
-        sess: &ParseSess,
+        handler: &Handler,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = sess.struct_err(fluent::lint::check_name_unknown);
+        let mut diag = handler.struct_err(fluent::lint::check_name_unknown);
         diag.code(rustc_errors::error_code!(E0602));
         if let Some(suggestion) = self.suggestion {
             diag.help(fluent::lint::help);
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 16b7d2cbbae..dd1fc5916db 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -51,7 +51,7 @@ fn typeck_results_of_method_fn<'tcx>(
     expr: &Expr<'_>,
 ) -> Option<(Span, DefId, ty::subst::SubstsRef<'tcx>)> {
     match expr.kind {
-        ExprKind::MethodCall(segment, _, _)
+        ExprKind::MethodCall(segment, ..)
             if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) =>
         {
             Some((segment.ident.span, def_id, cx.typeck_results().node_substs(expr.hir_id)))
@@ -118,8 +118,7 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
         _: rustc_hir::HirId,
     ) {
         if let Some(segment) = path.segments.iter().nth_back(1)
-        && let Some(res) = &segment.res
-        && lint_ty_kind_usage(cx, res)
+        && lint_ty_kind_usage(cx, &segment.res)
         {
             let span = path.span.with_hi(
                 segment.args.map_or(segment.ident.span, |a| a.span_ext).hi()
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index 8a336844dc2..66dc3ed59a3 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -306,12 +306,12 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
     }
 }
 
-struct LateLintPassObjects<'a> {
-    lints: &'a mut [LateLintPassObject],
+struct LateLintPassObjects<'a, 'tcx> {
+    lints: &'a mut [LateLintPassObject<'tcx>],
 }
 
 #[allow(rustc::lint_pass_impl_without_macro)]
-impl LintPass for LateLintPassObjects<'_> {
+impl LintPass for LateLintPassObjects<'_, '_> {
     fn name(&self) -> &'static str {
         panic!()
     }
@@ -329,7 +329,7 @@ macro_rules! expand_late_lint_pass_impl_methods {
 
 macro_rules! late_lint_pass_impl {
     ([], [$hir:tt], $methods:tt) => {
-        impl<$hir> LateLintPass<$hir> for LateLintPassObjects<'_> {
+        impl<$hir> LateLintPass<$hir> for LateLintPassObjects<'_, $hir> {
             expand_late_lint_pass_impl_methods!([$hir], $methods);
         }
     };
@@ -382,7 +382,7 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx>>(
     late_lint_mod_pass(tcx, module_def_id, builtin_lints);
 
     let mut passes: Vec<_> =
-        unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)()).collect();
+        unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)(tcx)).collect();
 
     if !passes.is_empty() {
         late_lint_mod_pass(tcx, module_def_id, LateLintPassObjects { lints: &mut passes[..] });
@@ -418,7 +418,8 @@ fn late_lint_pass_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, pass: T)
 }
 
 fn late_lint_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, builtin_lints: T) {
-    let mut passes = unerased_lint_store(tcx).late_passes.iter().map(|p| (p)()).collect::<Vec<_>>();
+    let mut passes =
+        unerased_lint_store(tcx).late_passes.iter().map(|p| (p)(tcx)).collect::<Vec<_>>();
 
     if !tcx.sess.opts.unstable_opts.no_interleave_lints {
         if !passes.is_empty() {
@@ -434,7 +435,7 @@ fn late_lint_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, builtin_lints
         }
 
         let mut passes: Vec<_> =
-            unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)()).collect();
+            unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)(tcx)).collect();
 
         for pass in &mut passes {
             tcx.sess.prof.extra_verbose_generic_activity("run_late_module_lint", pass.name()).run(
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 370a75cf700..e0e6f1a8c08 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -260,26 +260,41 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) {
         )
     }
 
-    macro_rules! register_pass {
+    macro_rules! register_early_pass {
         ($method:ident, $ty:ident, $constructor:expr) => {
             store.register_lints(&$ty::get_lints());
             store.$method(|| Box::new($constructor));
         };
     }
 
-    macro_rules! register_passes {
+    macro_rules! register_late_pass {
+        ($method:ident, $ty:ident, $constructor:expr) => {
+            store.register_lints(&$ty::get_lints());
+            store.$method(|_| Box::new($constructor));
+        };
+    }
+
+    macro_rules! register_early_passes {
+        ($method:ident, [$($passes:ident: $constructor:expr,)*]) => (
+            $(
+                register_early_pass!($method, $passes, $constructor);
+            )*
+        )
+    }
+
+    macro_rules! register_late_passes {
         ($method:ident, [$($passes:ident: $constructor:expr,)*]) => (
             $(
-                register_pass!($method, $passes, $constructor);
+                register_late_pass!($method, $passes, $constructor);
             )*
         )
     }
 
     if no_interleave_lints {
-        pre_expansion_lint_passes!(register_passes, register_pre_expansion_pass);
-        early_lint_passes!(register_passes, register_early_pass);
-        late_lint_passes!(register_passes, register_late_pass);
-        late_lint_mod_passes!(register_passes, register_late_mod_pass);
+        pre_expansion_lint_passes!(register_early_passes, register_pre_expansion_pass);
+        early_lint_passes!(register_early_passes, register_early_pass);
+        late_lint_passes!(register_late_passes, register_late_pass);
+        late_lint_mod_passes!(register_late_passes, register_late_mod_pass);
     } else {
         store.register_lints(&BuiltinCombinedPreExpansionLintPass::get_lints());
         store.register_lints(&BuiltinCombinedEarlyLintPass::get_lints());
@@ -510,19 +525,19 @@ fn register_internals(store: &mut LintStore) {
     store.register_lints(&LintPassImpl::get_lints());
     store.register_early_pass(|| Box::new(LintPassImpl));
     store.register_lints(&DefaultHashTypes::get_lints());
-    store.register_late_pass(|| Box::new(DefaultHashTypes));
+    store.register_late_pass(|_| Box::new(DefaultHashTypes));
     store.register_lints(&QueryStability::get_lints());
-    store.register_late_pass(|| Box::new(QueryStability));
+    store.register_late_pass(|_| Box::new(QueryStability));
     store.register_lints(&ExistingDocKeyword::get_lints());
-    store.register_late_pass(|| Box::new(ExistingDocKeyword));
+    store.register_late_pass(|_| Box::new(ExistingDocKeyword));
     store.register_lints(&TyTyKind::get_lints());
-    store.register_late_pass(|| Box::new(TyTyKind));
+    store.register_late_pass(|_| Box::new(TyTyKind));
     store.register_lints(&Diagnostics::get_lints());
-    store.register_late_pass(|| Box::new(Diagnostics));
+    store.register_late_pass(|_| Box::new(Diagnostics));
     store.register_lints(&BadOptAccess::get_lints());
-    store.register_late_pass(|| Box::new(BadOptAccess));
+    store.register_late_pass(|_| Box::new(BadOptAccess));
     store.register_lints(&PassByValue::get_lints());
-    store.register_late_pass(|| Box::new(PassByValue));
+    store.register_late_pass(|_| Box::new(PassByValue));
     // FIXME(davidtwco): deliberately do not include `UNTRANSLATABLE_DIAGNOSTIC` and
     // `DIAGNOSTIC_OUTSIDE_OF_IMPL` here because `-Wrustc::internal` is provided to every crate and
     // these lints will trigger all of the time - change this once migration to diagnostic structs
diff --git a/compiler/rustc_lint/src/methods.rs b/compiler/rustc_lint/src/methods.rs
index ff5a01749c1..5f7f03480c0 100644
--- a/compiler/rustc_lint/src/methods.rs
+++ b/compiler/rustc_lint/src/methods.rs
@@ -44,9 +44,13 @@ fn in_macro(span: Span) -> bool {
 
 fn first_method_call<'tcx>(
     expr: &'tcx Expr<'tcx>,
-) -> Option<(&'tcx PathSegment<'tcx>, &'tcx [Expr<'tcx>])> {
-    if let ExprKind::MethodCall(path, args, _) = &expr.kind {
-        if args.iter().any(|e| e.span.from_expansion()) { None } else { Some((path, *args)) }
+) -> Option<(&'tcx PathSegment<'tcx>, &'tcx Expr<'tcx>)> {
+    if let ExprKind::MethodCall(path, receiver, args, ..) = &expr.kind {
+        if args.iter().any(|e| e.span.from_expansion()) || receiver.span.from_expansion() {
+            None
+        } else {
+            Some((path, *receiver))
+        }
     } else {
         None
     }
@@ -59,15 +63,13 @@ impl<'tcx> LateLintPass<'tcx> for TemporaryCStringAsPtr {
         }
 
         match first_method_call(expr) {
-            Some((path, args)) if path.ident.name == sym::as_ptr => {
-                let unwrap_arg = &args[0];
+            Some((path, unwrap_arg)) if path.ident.name == sym::as_ptr => {
                 let as_ptr_span = path.ident.span;
                 match first_method_call(unwrap_arg) {
-                    Some((path, args))
+                    Some((path, receiver))
                         if path.ident.name == sym::unwrap || path.ident.name == sym::expect =>
                     {
-                        let source_arg = &args[0];
-                        lint_cstring_as_ptr(cx, as_ptr_span, source_arg, unwrap_arg);
+                        lint_cstring_as_ptr(cx, as_ptr_span, receiver, unwrap_arg);
                     }
                     _ => return,
                 }
diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs
index 11a752ff097..d1449496d33 100644
--- a/compiler/rustc_lint/src/noop_method_call.rs
+++ b/compiler/rustc_lint/src/noop_method_call.rs
@@ -41,7 +41,7 @@ declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL]);
 impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         // We only care about method calls.
-        let ExprKind::MethodCall(call, elements, _) = &expr.kind else {
+        let ExprKind::MethodCall(call, receiver, ..) = &expr.kind else {
             return
         };
         // We only care about method calls corresponding to the `Clone`, `Deref` and `Borrow`
@@ -81,7 +81,6 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
         ) {
             return;
         }
-        let receiver = &elements[0];
         let receiver_ty = cx.typeck_results().expr_ty(receiver);
         let expr_ty = cx.typeck_results().expr_ty_adjusted(expr);
         if receiver_ty != expr_ty {
diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs
index 90c554c2e04..666e61b85ac 100644
--- a/compiler/rustc_lint/src/passes.rs
+++ b/compiler/rustc_lint/src/passes.rs
@@ -244,4 +244,4 @@ macro_rules! declare_combined_early_lint_pass {
 
 /// A lint pass boxed up as a trait object.
 pub type EarlyLintPassObject = Box<dyn EarlyLintPass + sync::Send + 'static>;
-pub type LateLintPassObject = Box<dyn for<'tcx> LateLintPass<'tcx> + sync::Send + 'static>;
+pub type LateLintPassObject<'tcx> = Box<dyn LateLintPass<'tcx> + sync::Send + 'tcx>;
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 03166519981..9736b555703 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1458,7 +1458,7 @@ impl InvalidAtomicOrdering {
             sym::AtomicI64,
             sym::AtomicI128,
         ];
-        if let ExprKind::MethodCall(ref method_path, args, _) = &expr.kind
+        if let ExprKind::MethodCall(ref method_path, _, args, _) = &expr.kind
             && recognized_names.contains(&method_path.ident.name)
             && let Some(m_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
             && let Some(impl_did) = cx.tcx.impl_of_method(m_def_id)
@@ -1494,8 +1494,8 @@ impl InvalidAtomicOrdering {
     fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) {
         if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::load, sym::store])
             && let Some((ordering_arg, invalid_ordering)) = match method {
-                sym::load => Some((&args[1], sym::Release)),
-                sym::store => Some((&args[2], sym::Acquire)),
+                sym::load => Some((&args[0], sym::Release)),
+                sym::store => Some((&args[1], sym::Acquire)),
                 _ => None,
             }
             && let Some(ordering) = Self::match_ordering(cx, ordering_arg)
@@ -1536,8 +1536,8 @@ impl InvalidAtomicOrdering {
             else {return };
 
         let fail_order_arg = match method {
-            sym::fetch_update => &args[2],
-            sym::compare_exchange | sym::compare_exchange_weak => &args[4],
+            sym::fetch_update => &args[1],
+            sym::compare_exchange | sym::compare_exchange_weak => &args[3],
             _ => return,
         };
 
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 1f4e5b48091..9a7d722c05a 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -751,7 +751,7 @@ impl UnusedParens {
         avoid_or: bool,
         avoid_mut: bool,
     ) {
-        use ast::{BindingMode, Mutability, PatKind};
+        use ast::{BindingAnnotation, PatKind};
 
         if let PatKind::Paren(inner) = &value.kind {
             match inner.kind {
@@ -763,7 +763,9 @@ impl UnusedParens {
                 // Avoid `p0 | .. | pn` if we should.
                 PatKind::Or(..) if avoid_or => return,
                 // Avoid `mut x` and `mut x @ p` if we should:
-                PatKind::Ident(BindingMode::ByValue(Mutability::Mut), ..) if avoid_mut => return,
+                PatKind::Ident(BindingAnnotation::MUT, ..) if avoid_mut => {
+                    return;
+                }
                 // Otherwise proceed with linting.
                 _ => {}
             }
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 05d2a214d0b..24e18826048 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -134,7 +134,12 @@ extern "C" LLVMPassRef LLVMRustCreateMemorySanitizerPass(int TrackOrigins, bool
   const bool CompileKernel = false;
 
   return wrap(createMemorySanitizerLegacyPassPass(
-      MemorySanitizerOptions{TrackOrigins, Recover, CompileKernel}));
+#if LLVM_VERSION_GE(14, 0)
+      MemorySanitizerOptions{TrackOrigins, Recover, CompileKernel, /*EagerChecks=*/true}
+#else
+      MemorySanitizerOptions{TrackOrigins, Recover, CompileKernel}
+#endif
+  ));
 #else
   report_fatal_error("Legacy PM not supported with LLVM 15");
 #endif
@@ -930,18 +935,28 @@ LLVMRustOptimizeWithNewPassManager(
 
   if (SanitizerOptions) {
     if (SanitizerOptions->SanitizeMemory) {
+#if LLVM_VERSION_GE(14, 0)
+      MemorySanitizerOptions Options(
+          SanitizerOptions->SanitizeMemoryTrackOrigins,
+          SanitizerOptions->SanitizeMemoryRecover,
+          /*CompileKernel=*/false,
+          /*EagerChecks=*/true);
+#else
       MemorySanitizerOptions Options(
           SanitizerOptions->SanitizeMemoryTrackOrigins,
           SanitizerOptions->SanitizeMemoryRecover,
           /*CompileKernel=*/false);
+#endif
       OptimizerLastEPCallbacks.push_back(
         [Options](ModulePassManager &MPM, OptimizationLevel Level) {
-#if LLVM_VERSION_GE(14, 0)
+#if LLVM_VERSION_GE(14, 0) && LLVM_VERSION_LT(16, 0)
           MPM.addPass(ModuleMemorySanitizerPass(Options));
 #else
           MPM.addPass(MemorySanitizerPass(Options));
 #endif
+#if LLVM_VERSION_LT(16, 0)
           MPM.addPass(createModuleToFunctionPassAdaptor(MemorySanitizerPass(Options)));
+#endif
         }
       );
     }
@@ -972,8 +987,12 @@ LLVMRustOptimizeWithNewPassManager(
             /*UseAfterScope=*/true,
             AsanDetectStackUseAfterReturnMode::Runtime,
           };
+#if LLVM_VERSION_LT(16, 0)
           MPM.addPass(ModuleAddressSanitizerPass(opts));
 #else
+          MPM.addPass(AddressSanitizerPass(opts));
+#endif
+#else
           MPM.addPass(ModuleAddressSanitizerPass(
               /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover));
           MPM.addPass(createModuleToFunctionPassAdaptor(AddressSanitizerPass(
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
index 244edec2841..cf1c5945529 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
@@ -88,7 +88,7 @@ impl<'a> SessionDiagnosticDerive<'a> {
             {
                 fn into_diagnostic(
                     self,
-                    #sess: &'__session_diagnostic_sess rustc_session::parse::ParseSess
+                    #sess: &'__session_diagnostic_sess rustc_errors::Handler
                 ) -> rustc_errors::DiagnosticBuilder<'__session_diagnostic_sess, G> {
                     use rustc_errors::IntoDiagnosticArg;
                     #implementation
diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs
index 18d0248333a..8378d2b791d 100644
--- a/compiler/rustc_metadata/src/errors.rs
+++ b/compiler/rustc_metadata/src/errors.rs
@@ -424,9 +424,9 @@ pub(crate) struct MultipleCandidates {
 impl SessionDiagnostic<'_> for MultipleCandidates {
     fn into_diagnostic(
         self,
-        sess: &'_ rustc_session::parse::ParseSess,
+        handler: &'_ rustc_errors::Handler,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = sess.struct_err(rustc_errors::fluent::metadata::multiple_candidates);
+        let mut diag = handler.struct_err(rustc_errors::fluent::metadata::multiple_candidates);
         diag.set_arg("crate_name", self.crate_name);
         diag.set_arg("flavor", self.flavor);
         diag.code(error_code!(E0465));
@@ -540,9 +540,9 @@ pub struct InvalidMetadataFiles {
 impl SessionDiagnostic<'_> for InvalidMetadataFiles {
     fn into_diagnostic(
         self,
-        sess: &'_ rustc_session::parse::ParseSess,
+        handler: &'_ rustc_errors::Handler,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = sess.struct_err(rustc_errors::fluent::metadata::invalid_meta_files);
+        let mut diag = handler.struct_err(rustc_errors::fluent::metadata::invalid_meta_files);
         diag.set_arg("crate_name", self.crate_name);
         diag.set_arg("add_info", self.add_info);
         diag.code(error_code!(E0786));
@@ -568,9 +568,9 @@ pub struct CannotFindCrate {
 impl SessionDiagnostic<'_> for CannotFindCrate {
     fn into_diagnostic(
         self,
-        sess: &'_ rustc_session::parse::ParseSess,
+        handler: &'_ rustc_errors::Handler,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = sess.struct_err(rustc_errors::fluent::metadata::cannot_find_crate);
+        let mut diag = handler.struct_err(rustc_errors::fluent::metadata::cannot_find_crate);
         diag.set_arg("crate_name", self.crate_name);
         diag.set_arg("add_info", self.add_info);
         diag.set_arg("locator_triple", self.locator_triple.triple());
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 6f026678170..562246f4e8a 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -911,8 +911,14 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         self.root.tables.generics_of.get(self, item_id).unwrap().decode((self, sess))
     }
 
-    fn get_visibility(self, id: DefIndex) -> ty::Visibility {
-        self.root.tables.visibility.get(self, id).unwrap().decode(self)
+    fn get_visibility(self, id: DefIndex) -> ty::Visibility<DefId> {
+        self.root
+            .tables
+            .visibility
+            .get(self, id)
+            .unwrap()
+            .decode(self)
+            .map_id(|index| self.local_def_id(index))
     }
 
     fn get_trait_item_def_id(self, id: DefIndex) -> Option<DefId> {
@@ -1182,7 +1188,10 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
             .map(move |index| respan(self.get_span(index, sess), self.item_name(index)))
     }
 
-    fn get_struct_field_visibilities(self, id: DefIndex) -> impl Iterator<Item = Visibility> + 'a {
+    fn get_struct_field_visibilities(
+        self,
+        id: DefIndex,
+    ) -> impl Iterator<Item = Visibility<DefId>> + 'a {
         self.root
             .tables
             .children
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 6b447ebd999..dede1b2122a 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -210,7 +210,6 @@ provide! { tcx, def_id, other, cdata,
     lookup_const_stability => { table }
     lookup_default_body_stability => { table }
     lookup_deprecation_entry => { table }
-    visibility => { table }
     unused_generic_params => { table }
     opt_def_kind => { table_direct }
     impl_parent => { table }
@@ -225,6 +224,7 @@ provide! { tcx, def_id, other, cdata,
     generator_kind => { table }
     trait_def => { table }
 
+    visibility => { cdata.get_visibility(def_id.index) }
     adt_def => { cdata.get_adt_def(def_id.index, tcx) }
     adt_destructor => {
         let _ = cdata;
@@ -485,7 +485,7 @@ impl CStore {
     pub fn struct_field_visibilities_untracked(
         &self,
         def: DefId,
-    ) -> impl Iterator<Item = Visibility> + '_ {
+    ) -> impl Iterator<Item = Visibility<DefId>> + '_ {
         self.get_crate_data(def.krate).get_struct_field_visibilities(def.index)
     }
 
@@ -493,7 +493,7 @@ impl CStore {
         self.get_crate_data(def.krate).get_ctor_def_id_and_kind(def.index)
     }
 
-    pub fn visibility_untracked(&self, def: DefId) -> Visibility {
+    pub fn visibility_untracked(&self, def: DefId) -> Visibility<DefId> {
         self.get_crate_data(def.krate).get_visibility(def.index)
     }
 
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 039486ba02c..b807663b10f 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1138,7 +1138,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 record!(self.tables.codegen_fn_attrs[def_id] <- self.tcx.codegen_fn_attrs(def_id));
             }
             if should_encode_visibility(def_kind) {
-                record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
+                let vis =
+                    self.tcx.local_visibility(local_id).map_id(|def_id| def_id.local_def_index);
+                record!(self.tables.visibility[def_id] <- vis);
             }
             if should_encode_stability(def_kind) {
                 self.encode_stability(def_id);
@@ -1727,7 +1729,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             self.tables.opt_def_kind.set(LOCAL_CRATE.as_def_id().index, DefKind::Mod);
             record!(self.tables.def_span[LOCAL_CRATE.as_def_id()] <- tcx.def_span(LOCAL_CRATE.as_def_id()));
             self.encode_attrs(LOCAL_CRATE.as_def_id().expect_local());
-            record!(self.tables.visibility[LOCAL_CRATE.as_def_id()] <- tcx.visibility(LOCAL_CRATE.as_def_id()));
+            let vis = tcx.local_visibility(CRATE_DEF_ID).map_id(|def_id| def_id.local_def_index);
+            record!(self.tables.visibility[LOCAL_CRATE.as_def_id()] <- vis);
             if let Some(stability) = stability {
                 record!(self.tables.lookup_stability[LOCAL_CRATE.as_def_id()] <- stability);
             }
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 6f849a58580..748b3afec37 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -338,7 +338,7 @@ define_tables! {
     children: Table<DefIndex, LazyArray<DefIndex>>,
 
     opt_def_kind: Table<DefIndex, DefKind>,
-    visibility: Table<DefIndex, LazyValue<ty::Visibility>>,
+    visibility: Table<DefIndex, LazyValue<ty::Visibility<DefIndex>>>,
     def_span: Table<DefIndex, LazyValue<Span>>,
     def_ident_span: Table<DefIndex, LazyValue<Span>>,
     lookup_stability: Table<DefIndex, LazyValue<attr::Stability>>,
diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs
new file mode 100644
index 00000000000..18b31a75bcc
--- /dev/null
+++ b/compiler/rustc_middle/src/error.rs
@@ -0,0 +1,50 @@
+use rustc_macros::SessionDiagnostic;
+use rustc_span::Span;
+
+use crate::ty::Ty;
+
+#[derive(SessionDiagnostic)]
+#[diag(middle::drop_check_overflow, code = "E0320")]
+#[note]
+pub struct DropCheckOverflow<'tcx> {
+    #[primary_span]
+    pub span: Span,
+    pub ty: Ty<'tcx>,
+    pub overflow_ty: Ty<'tcx>,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(middle::opaque_hidden_type_mismatch)]
+pub struct OpaqueHiddenTypeMismatch<'tcx> {
+    pub self_ty: Ty<'tcx>,
+    pub other_ty: Ty<'tcx>,
+    #[primary_span]
+    #[label]
+    pub other_span: Span,
+    #[subdiagnostic]
+    pub sub: TypeMismatchReason,
+}
+
+#[derive(SessionSubdiagnostic)]
+pub enum TypeMismatchReason {
+    #[label(middle::conflict_types)]
+    ConflictType {
+        #[primary_span]
+        span: Span,
+    },
+    #[note(middle::previous_use_here)]
+    PreviousUse {
+        #[primary_span]
+        span: Span,
+    },
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(middle::limit_invalid)]
+pub struct LimitInvalid<'a> {
+    #[primary_span]
+    pub span: Span,
+    #[label]
+    pub value_span: Span,
+    pub error_str: &'a str,
+}
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index be9e5865e54..4064a8f9733 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -86,6 +86,7 @@ pub mod query;
 pub mod arena;
 #[macro_use]
 pub mod dep_graph;
+pub(crate) mod error;
 pub mod hir;
 pub mod infer;
 pub mod lint;
@@ -95,6 +96,7 @@ pub mod mir;
 pub mod thir;
 pub mod traits;
 pub mod ty;
+mod values;
 
 pub mod util {
     pub mod bug;
diff --git a/compiler/rustc_middle/src/metadata.rs b/compiler/rustc_middle/src/metadata.rs
index c8e78747d8e..5ff014c7815 100644
--- a/compiler/rustc_middle/src/metadata.rs
+++ b/compiler/rustc_middle/src/metadata.rs
@@ -2,6 +2,7 @@ use crate::ty;
 
 use rustc_hir::def::Res;
 use rustc_macros::HashStable;
+use rustc_span::def_id::DefId;
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 
@@ -18,7 +19,7 @@ pub struct ModChild {
     /// Local variables cannot be exported, so this `Res` doesn't need the ID parameter.
     pub res: Res<!>,
     /// Visibility of the item.
-    pub vis: ty::Visibility,
+    pub vis: ty::Visibility<DefId>,
     /// Span of the item.
     pub span: Span,
     /// A proper `macro_rules` item (not a reexport).
diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs
index acced0492ef..53c4d926784 100644
--- a/compiler/rustc_middle/src/middle/limits.rs
+++ b/compiler/rustc_middle/src/middle/limits.rs
@@ -10,6 +10,7 @@
 //! just peeks and looks for that attribute.
 
 use crate::bug;
+use crate::error::LimitInvalid;
 use crate::ty;
 use rustc_ast::Attribute;
 use rustc_session::Session;
@@ -56,9 +57,6 @@ fn get_limit(krate_attrs: &[Attribute], sess: &Session, name: Symbol, default: u
             match s.as_str().parse() {
                 Ok(n) => return Limit::new(n),
                 Err(e) => {
-                    let mut err =
-                        sess.struct_span_err(attr.span, "`limit` must be a non-negative integer");
-
                     let value_span = attr
                         .meta()
                         .and_then(|meta| meta.name_value_literal_span())
@@ -74,9 +72,7 @@ fn get_limit(krate_attrs: &[Attribute], sess: &Session, name: Symbol, default: u
                         IntErrorKind::Zero => bug!("zero is a valid `limit`"),
                         kind => bug!("unimplemented IntErrorKind variant: {:?}", kind),
                     };
-
-                    err.span_label(value_span, error_str);
-                    err.emit();
+                    sess.emit_err(LimitInvalid { span: attr.span, value_span, error_str });
                 }
             }
         }
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index f3676604bb0..753e1f4b9da 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -839,10 +839,6 @@ pub struct LocalDecl<'tcx> {
     pub source_info: SourceInfo,
 }
 
-// `LocalDecl` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(LocalDecl<'_>, 56);
-
 /// Extra information about a some locals that's used for diagnostics and for
 /// classifying variables into local variables, statics, etc, which is needed e.g.
 /// for unsafety checking.
@@ -1317,10 +1313,6 @@ pub struct Statement<'tcx> {
     pub kind: StatementKind<'tcx>,
 }
 
-// `Statement` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(Statement<'_>, 32);
-
 impl Statement<'_> {
     /// Changes a statement to a nop. This is both faster than deleting instructions and avoids
     /// invalidating statement indices in `Location`s.
@@ -1370,13 +1362,7 @@ impl Debug for Statement<'_> {
                 write!(fmt, "Coverage::{:?} for {:?}", kind, rgn)
             }
             Coverage(box ref coverage) => write!(fmt, "Coverage::{:?}", coverage.kind),
-            CopyNonOverlapping(box crate::mir::CopyNonOverlapping {
-                ref src,
-                ref dst,
-                ref count,
-            }) => {
-                write!(fmt, "copy_nonoverlapping(src={:?}, dst={:?}, count={:?})", src, dst, count)
-            }
+            Intrinsic(box ref intrinsic) => write!(fmt, "{intrinsic}"),
             Nop => write!(fmt, "nop"),
         }
     }
@@ -1478,7 +1464,9 @@ impl<'tcx> Place<'tcx> {
     /// It's guaranteed to be in the first place
     pub fn has_deref(&self) -> bool {
         // To make sure this is not accidently used in wrong mir phase
-        debug_assert!(!self.projection[1..].contains(&PlaceElem::Deref));
+        debug_assert!(
+            self.projection.is_empty() || !self.projection[1..].contains(&PlaceElem::Deref)
+        );
         self.projection.first() == Some(&PlaceElem::Deref)
     }
 
@@ -2900,3 +2888,17 @@ impl Location {
         }
     }
 }
+
+// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+mod size_asserts {
+    use super::*;
+    use rustc_data_structures::static_assert_size;
+    // These are in alphabetical order, which is easy to maintain.
+    static_assert_size!(BasicBlockData<'_>, 144);
+    static_assert_size!(LocalDecl<'_>, 56);
+    static_assert_size!(Statement<'_>, 32);
+    static_assert_size!(StatementKind<'_>, 16);
+    static_assert_size!(Terminator<'_>, 112);
+    static_assert_size!(TerminatorKind<'_>, 96);
+}
diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs
index 6e64a3b80c1..4e06d91012c 100644
--- a/compiler/rustc_middle/src/mir/spanview.rs
+++ b/compiler/rustc_middle/src/mir/spanview.rs
@@ -249,7 +249,7 @@ pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str {
         Retag(..) => "Retag",
         AscribeUserType(..) => "AscribeUserType",
         Coverage(..) => "Coverage",
-        CopyNonOverlapping(..) => "CopyNonOverlapping",
+        Intrinsic(..) => "Intrinsic",
         Nop => "Nop",
     }
 }
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index d7b9d59eced..1f7643a76af 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -327,6 +327,34 @@ pub enum StatementKind<'tcx> {
     /// executed.
     Coverage(Box<Coverage>),
 
+    /// Denotes a call to an intrinsic that does not require an unwind path and always returns.
+    /// This avoids adding a new block and a terminator for simple intrinsics.
+    Intrinsic(Box<NonDivergingIntrinsic<'tcx>>),
+
+    /// No-op. Useful for deleting instructions without affecting statement indices.
+    Nop,
+}
+
+#[derive(
+    Clone,
+    TyEncodable,
+    TyDecodable,
+    Debug,
+    PartialEq,
+    Hash,
+    HashStable,
+    TypeFoldable,
+    TypeVisitable
+)]
+pub enum NonDivergingIntrinsic<'tcx> {
+    /// Denotes a call to the intrinsic function `assume`.
+    ///
+    /// The operand must be a boolean. Optimizers may use the value of the boolean to backtrack its
+    /// computation to infer information about other variables. So if the boolean came from a
+    /// `x < y` operation, subsequent operations on `x` and `y` could elide various bound checks.
+    /// If the argument is `false`, this operation is equivalent to `TerminatorKind::Unreachable`.
+    Assume(Operand<'tcx>),
+
     /// Denotes a call to the intrinsic function `copy_nonoverlapping`.
     ///
     /// First, all three operands are evaluated. `src` and `dest` must each be a reference, pointer,
@@ -340,10 +368,18 @@ pub enum StatementKind<'tcx> {
     ///
     /// **Needs clarification**: Is this typed or not, ie is there a typed load and store involved?
     /// I vaguely remember Ralf saying somewhere that he thought it should not be.
-    CopyNonOverlapping(Box<CopyNonOverlapping<'tcx>>),
+    CopyNonOverlapping(CopyNonOverlapping<'tcx>),
+}
 
-    /// No-op. Useful for deleting instructions without affecting statement indices.
-    Nop,
+impl std::fmt::Display for NonDivergingIntrinsic<'_> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Self::Assume(op) => write!(f, "assume({op:?})"),
+            Self::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => {
+                write!(f, "copy_nonoverlapping(dst = {dst:?}, src = {src:?}, count = {count:?})")
+            }
+        }
+    }
 }
 
 /// Describes what kind of retag is to be performed.
@@ -705,7 +741,7 @@ pub enum TerminatorKind<'tcx> {
 }
 
 /// Information about an assertion failure.
-#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, PartialOrd)]
+#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
 pub enum AssertKind<O> {
     BoundsCheck { len: O, index: O },
     Overflow(BinOp, O, O),
@@ -1195,7 +1231,8 @@ pub enum BinOp {
 mod size_asserts {
     use super::*;
     // These are in alphabetical order, which is easy to maintain.
-    static_assert_size!(AggregateKind<'_>, 48);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(AggregateKind<'_>, 40);
     static_assert_size!(Operand<'_>, 24);
     static_assert_size!(Place<'_>, 16);
     static_assert_size!(PlaceElem<'_>, 24);
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index 9ccf5aea63c..02a9958525b 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -14,7 +14,7 @@ use std::slice;
 
 pub use super::query::*;
 
-#[derive(Debug, Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, PartialOrd)]
+#[derive(Debug, Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
 pub struct SwitchTargets {
     /// Possible values. The locations to branch to in each case
     /// are found in the corresponding indices from the `targets` vector.
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 7bd65f42e3f..708ea4398c8 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -425,14 +425,15 @@ macro_rules! make_mir_visitor {
                             location
                         )
                     }
-                    StatementKind::CopyNonOverlapping(box crate::mir::CopyNonOverlapping{
-                        src,
-                        dst,
-                        count,
-                    }) => {
-                      self.visit_operand(src, location);
-                      self.visit_operand(dst, location);
-                      self.visit_operand(count, location)
+                    StatementKind::Intrinsic(box ref $($mutability)? intrinsic) => {
+                        match intrinsic {
+                            NonDivergingIntrinsic::Assume(op) => self.visit_operand(op, location),
+                            NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => {
+                                self.visit_operand(src, location);
+                                self.visit_operand(dst, location);
+                                self.visit_operand(count, location);
+                            }
+                        }
                     }
                     StatementKind::Nop => {}
                 }
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 8e7bacca262..4478b45cf14 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1607,7 +1607,7 @@ rustc_queries! {
         desc { "looking up late bound vars" }
     }
 
-    query visibility(def_id: DefId) -> ty::Visibility {
+    query visibility(def_id: DefId) -> ty::Visibility<DefId> {
         desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) }
         separate_provide_extern
     }
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 59e14337f4e..c50f8b0eebe 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -23,7 +23,7 @@ use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, AdtDef, Ty, UpvarSubsts};
 use rustc_middle::ty::{CanonicalUserType, CanonicalUserTypeAnnotation};
 use rustc_span::def_id::LocalDefId;
-use rustc_span::{Span, Symbol, DUMMY_SP};
+use rustc_span::{sym, Span, Symbol, DUMMY_SP};
 use rustc_target::abi::VariantIdx;
 use rustc_target::asm::InlineAsmRegOrRegClass;
 use std::fmt;
@@ -695,17 +695,32 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
                 Ok(())
             }
             PatKind::Variant { ref subpatterns, .. } | PatKind::Leaf { ref subpatterns } => {
-                let variant = match self.kind {
-                    PatKind::Variant { adt_def, variant_index, .. } => {
-                        Some(adt_def.variant(variant_index))
-                    }
-                    _ => self.ty.ty_adt_def().and_then(|adt| {
-                        if !adt.is_enum() { Some(adt.non_enum_variant()) } else { None }
+                let variant_and_name = match self.kind {
+                    PatKind::Variant { adt_def, variant_index, .. } => ty::tls::with(|tcx| {
+                        let variant = adt_def.variant(variant_index);
+                        let adt_did = adt_def.did();
+                        let name = if tcx.get_diagnostic_item(sym::Option) == Some(adt_did)
+                            || tcx.get_diagnostic_item(sym::Result) == Some(adt_did)
+                        {
+                            variant.name.to_string()
+                        } else {
+                            format!("{}::{}", tcx.def_path_str(adt_def.did()), variant.name)
+                        };
+                        Some((variant, name))
+                    }),
+                    _ => self.ty.ty_adt_def().and_then(|adt_def| {
+                        if !adt_def.is_enum() {
+                            ty::tls::with(|tcx| {
+                                Some((adt_def.non_enum_variant(), tcx.def_path_str(adt_def.did())))
+                            })
+                        } else {
+                            None
+                        }
                     }),
                 };
 
-                if let Some(variant) = variant {
-                    write!(f, "{}", variant.name)?;
+                if let Some((variant, name)) = &variant_and_name {
+                    write!(f, "{}", name)?;
 
                     // Only for Adt we can have `S {...}`,
                     // which we handle separately here.
@@ -730,8 +745,9 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
                     }
                 }
 
-                let num_fields = variant.map_or(subpatterns.len(), |v| v.fields.len());
-                if num_fields != 0 || variant.is_none() {
+                let num_fields =
+                    variant_and_name.as_ref().map_or(subpatterns.len(), |(v, _)| v.fields.len());
+                if num_fields != 0 || variant_and_name.is_none() {
                     write!(f, "(")?;
                     for i in 0..num_fields {
                         write!(f, "{}", start_or_comma())?;
@@ -809,8 +825,12 @@ mod size_asserts {
     static_assert_size!(Block, 56);
     static_assert_size!(Expr<'_>, 64);
     static_assert_size!(ExprKind<'_>, 40);
-    static_assert_size!(Pat<'_>, 72);
-    static_assert_size!(PatKind<'_>, 56);
-    static_assert_size!(Stmt<'_>, 56);
-    static_assert_size!(StmtKind<'_>, 48);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(Pat<'_>, 64);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(PatKind<'_>, 48);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(Stmt<'_>, 48);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(StmtKind<'_>, 40);
 }
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index ab7e5ba3a10..a56fac7c4dd 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -12,7 +12,7 @@ pub mod util;
 use crate::infer::canonical::Canonical;
 use crate::ty::abstract_const::NotConstEvaluatable;
 use crate::ty::subst::SubstsRef;
-use crate::ty::{self, AdtKind, Predicate, Ty, TyCtxt};
+use crate::ty::{self, AdtKind, Ty, TyCtxt};
 
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, Diagnostic};
@@ -416,7 +416,7 @@ pub enum ObligationCauseCode<'tcx> {
     BinOp {
         rhs_span: Option<Span>,
         is_lit: bool,
-        output_pred: Option<Predicate<'tcx>>,
+        output_ty: Option<Ty<'tcx>>,
     },
 }
 
diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs
index 1f9b474ade1..0e6cacb9fd0 100644
--- a/compiler/rustc_middle/src/traits/query.rs
+++ b/compiler/rustc_middle/src/traits/query.rs
@@ -5,11 +5,11 @@
 //! The providers for the queries defined here can be found in
 //! `rustc_traits`.
 
+use crate::error::DropCheckOverflow;
 use crate::infer::canonical::{Canonical, QueryResponse};
 use crate::ty::error::TypeError;
 use crate::ty::subst::GenericArg;
 use crate::ty::{self, Ty, TyCtxt};
-use rustc_errors::struct_span_err;
 use rustc_span::source_map::Span;
 use std::iter::FromIterator;
 
@@ -117,15 +117,7 @@ pub struct DropckOutlivesResult<'tcx> {
 impl<'tcx> DropckOutlivesResult<'tcx> {
     pub fn report_overflows(&self, tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) {
         if let Some(overflow_ty) = self.overflows.get(0) {
-            let mut err = struct_span_err!(
-                tcx.sess,
-                span,
-                E0320,
-                "overflow while adding drop-check rules for {}",
-                ty,
-            );
-            err.note(&format!("overflowed on {}", overflow_ty));
-            err.emit();
+            tcx.sess.emit_err(DropCheckOverflow { span, ty, overflow_ty: *overflow_ty });
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs
index c97156ac17f..55ee5bd2f81 100644
--- a/compiler/rustc_middle/src/ty/assoc.rs
+++ b/compiler/rustc_middle/src/ty/assoc.rs
@@ -42,7 +42,7 @@ impl AssocItem {
     }
 
     #[inline]
-    pub fn visibility(&self, tcx: TyCtxt<'_>) -> Visibility {
+    pub fn visibility(&self, tcx: TyCtxt<'_>) -> Visibility<DefId> {
         tcx.visibility(self.def_id)
     }
 
diff --git a/compiler/rustc_middle/src/ty/binding.rs b/compiler/rustc_middle/src/ty/binding.rs
index 3d65429f2e5..a5b05a4f9b5 100644
--- a/compiler/rustc_middle/src/ty/binding.rs
+++ b/compiler/rustc_middle/src/ty/binding.rs
@@ -1,6 +1,4 @@
-use rustc_hir::BindingAnnotation;
-use rustc_hir::BindingAnnotation::*;
-use rustc_hir::Mutability;
+use rustc_hir::{BindingAnnotation, ByRef, Mutability};
 
 #[derive(Clone, PartialEq, TyEncodable, TyDecodable, Debug, Copy, HashStable)]
 pub enum BindingMode {
@@ -11,12 +9,10 @@ pub enum BindingMode {
 TrivialTypeTraversalAndLiftImpls! { BindingMode, }
 
 impl BindingMode {
-    pub fn convert(ba: BindingAnnotation) -> BindingMode {
-        match ba {
-            Unannotated => BindingMode::BindByValue(Mutability::Not),
-            Mutable => BindingMode::BindByValue(Mutability::Mut),
-            Ref => BindingMode::BindByReference(Mutability::Not),
-            RefMut => BindingMode::BindByReference(Mutability::Mut),
+    pub fn convert(BindingAnnotation(by_ref, mutbl): BindingAnnotation) -> BindingMode {
+        match by_ref {
+            ByRef::No => BindingMode::BindByValue(mutbl),
+            ByRef::Yes => BindingMode::BindByReference(mutbl),
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index 3840e79cebd..ff20da65c01 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -180,6 +180,7 @@ impl<'tcx> ConstKind<'tcx> {
         param_env: ParamEnv<'tcx>,
         eval_mode: EvalMode,
     ) -> Option<Result<EvalResult<'tcx>, ErrorGuaranteed>> {
+        assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}");
         if let ConstKind::Unevaluated(unevaluated) = self {
             use crate::mir::interpret::ErrorHandled;
 
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 262d59f8ff8..53e91e48c24 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -22,6 +22,7 @@ use crate::ty::{
     FloatVar, FloatVid, GenericParamDefKind, InferConst, InferTy, IntTy, IntVar, IntVid, List,
     ParamConst, ParamTy, PolyFnSig, Predicate, PredicateKind, PredicateS, ProjectionTy, Region,
     RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy,
+    Visibility,
 };
 use rustc_ast as ast;
 use rustc_data_structures::fingerprint::Fingerprint;
@@ -1251,7 +1252,7 @@ impl<'tcx> TyCtxt<'tcx> {
         output_filenames: OutputFilenames,
     ) -> GlobalCtxt<'tcx> {
         let data_layout = TargetDataLayout::parse(&s.target).unwrap_or_else(|err| {
-            s.fatal(&err);
+            s.emit_fatal(err);
         });
         let interners = CtxtInterners::new(arena);
         let common_types = CommonTypes::new(
@@ -1728,6 +1729,11 @@ impl<'tcx> TyCtxt<'tcx> {
             .chain(self.crates(()).iter().copied())
             .flat_map(move |cnum| self.traits_in_crate(cnum).iter().copied())
     }
+
+    #[inline]
+    pub fn local_visibility(self, def_id: LocalDefId) -> Visibility {
+        self.visibility(def_id.to_def_id()).expect_local()
+    }
 }
 
 /// A trait implemented for all `X<'a>` types that can be safely and
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index dd2f4321060..e4ad96b659b 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -102,13 +102,25 @@ pub fn suggest_arbitrary_trait_bound<'tcx>(
     generics: &hir::Generics<'_>,
     err: &mut Diagnostic,
     trait_pred: PolyTraitPredicate<'tcx>,
+    associated_ty: Option<(&'static str, Ty<'tcx>)>,
 ) -> bool {
     if !trait_pred.is_suggestable(tcx, false) {
         return false;
     }
 
     let param_name = trait_pred.skip_binder().self_ty().to_string();
-    let constraint = trait_pred.print_modifiers_and_trait_path().to_string();
+    let mut constraint = trait_pred.print_modifiers_and_trait_path().to_string();
+
+    if let Some((name, term)) = associated_ty {
+        // FIXME: this case overlaps with code in TyCtxt::note_and_explain_type_err.
+        // That should be extracted into a helper function.
+        if constraint.ends_with('>') {
+            constraint = format!("{}, {} = {}>", &constraint[..constraint.len() - 1], name, term);
+        } else {
+            constraint.push_str(&format!("<{} = {}>", name, term));
+        }
+    }
+
     let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name);
 
     // Skip, there is a param named Self
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index ea6bb8a7abd..c22c899c5cc 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -1,5 +1,5 @@
 use crate::ty::subst::{GenericArg, GenericArgKind};
-use crate::ty::{self, InferConst, Term, Ty, TypeFlags};
+use crate::ty::{self, InferConst, Ty, TypeFlags};
 use std::slice;
 
 #[derive(Debug)]
@@ -243,9 +243,9 @@ impl FlagComputation {
             }
             ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => {
                 self.add_projection_ty(projection_ty);
-                match term {
-                    Term::Ty(ty) => self.add_ty(ty),
-                    Term::Const(c) => self.add_const(c),
+                match term.unpack() {
+                    ty::TermKind::Ty(ty) => self.add_ty(ty),
+                    ty::TermKind::Const(c) => self.add_const(c),
                 }
             }
             ty::PredicateKind::WellFormed(arg) => {
@@ -320,9 +320,9 @@ impl FlagComputation {
 
     fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) {
         self.add_substs(projection.substs);
-        match projection.term {
-            ty::Term::Ty(ty) => self.add_ty(ty),
-            ty::Term::Const(ct) => self.add_const(ct),
+        match projection.term.unpack() {
+            ty::TermKind::Ty(ty) => self.add_ty(ty),
+            ty::TermKind::Const(ct) => self.add_const(ct),
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index a1d980af921..8631ee91fa4 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -328,6 +328,7 @@ impl<'tcx> GenericPredicates<'tcx> {
         }
     }
 
+    #[instrument(level = "debug", skip(self, tcx))]
     fn instantiate_into(
         &self,
         tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 2c587b76f02..abb7ddd88b1 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -22,7 +22,7 @@ use rustc_target::abi::call::{
 use rustc_target::abi::*;
 use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Target};
 
-use std::cmp;
+use std::cmp::{self, Ordering};
 use std::fmt;
 use std::iter;
 use std::num::NonZeroUsize;
@@ -1046,131 +1046,191 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                 // that allow representation optimization.)
                 assert!(def.is_enum());
 
-                // The current code for niche-filling relies on variant indices
-                // instead of actual discriminants, so dataful enums with
-                // explicit discriminants (RFC #2363) would misbehave.
-                let no_explicit_discriminants = def
-                    .variants()
-                    .iter_enumerated()
-                    .all(|(i, v)| v.discr == ty::VariantDiscr::Relative(i.as_u32()));
-
-                let mut niche_filling_layout = None;
-
-                // Niche-filling enum optimization.
-                if !def.repr().inhibit_enum_layout_opt() && no_explicit_discriminants {
-                    let mut dataful_variant = None;
-                    let mut niche_variants = VariantIdx::MAX..=VariantIdx::new(0);
+                // Until we've decided whether to use the tagged or
+                // niche filling LayoutS, we don't want to intern the
+                // variant layouts, so we can't store them in the
+                // overall LayoutS. Store the overall LayoutS
+                // and the variant LayoutSs here until then.
+                struct TmpLayout<'tcx> {
+                    layout: LayoutS<'tcx>,
+                    variants: IndexVec<VariantIdx, LayoutS<'tcx>>,
+                }
 
-                    // Find one non-ZST variant.
-                    'variants: for (v, fields) in variants.iter_enumerated() {
-                        if absent(fields) {
-                            continue 'variants;
+                let calculate_niche_filling_layout =
+                    || -> Result<Option<TmpLayout<'tcx>>, LayoutError<'tcx>> {
+                        // The current code for niche-filling relies on variant indices
+                        // instead of actual discriminants, so enums with
+                        // explicit discriminants (RFC #2363) would misbehave.
+                        if def.repr().inhibit_enum_layout_opt()
+                            || def
+                                .variants()
+                                .iter_enumerated()
+                                .any(|(i, v)| v.discr != ty::VariantDiscr::Relative(i.as_u32()))
+                        {
+                            return Ok(None);
                         }
-                        for f in fields {
-                            if !f.is_zst() {
-                                if dataful_variant.is_none() {
-                                    dataful_variant = Some(v);
-                                    continue 'variants;
-                                } else {
-                                    dataful_variant = None;
-                                    break 'variants;
-                                }
-                            }
+
+                        if variants.len() < 2 {
+                            return Ok(None);
                         }
-                        niche_variants = *niche_variants.start().min(&v)..=v;
-                    }
 
-                    if niche_variants.start() > niche_variants.end() {
-                        dataful_variant = None;
-                    }
+                        let mut align = dl.aggregate_align;
+                        let mut variant_layouts = variants
+                            .iter_enumerated()
+                            .map(|(j, v)| {
+                                let mut st = self.univariant_uninterned(
+                                    ty,
+                                    v,
+                                    &def.repr(),
+                                    StructKind::AlwaysSized,
+                                )?;
+                                st.variants = Variants::Single { index: j };
+
+                                align = align.max(st.align);
+
+                                Ok(st)
+                            })
+                            .collect::<Result<IndexVec<VariantIdx, _>, _>>()?;
+
+                        let largest_variant_index = match variant_layouts
+                            .iter_enumerated()
+                            .max_by_key(|(_i, layout)| layout.size.bytes())
+                            .map(|(i, _layout)| i)
+                        {
+                            None => return Ok(None),
+                            Some(i) => i,
+                        };
 
-                    if let Some(i) = dataful_variant {
-                        let count = (niche_variants.end().as_u32()
-                            - niche_variants.start().as_u32()
-                            + 1) as u128;
+                        let all_indices = VariantIdx::new(0)..=VariantIdx::new(variants.len() - 1);
+                        let needs_disc = |index: VariantIdx| {
+                            index != largest_variant_index && !absent(&variants[index])
+                        };
+                        let niche_variants = all_indices.clone().find(|v| needs_disc(*v)).unwrap()
+                            ..=all_indices.rev().find(|v| needs_disc(*v)).unwrap();
+
+                        let count = niche_variants.size_hint().1.unwrap() as u128;
 
                         // Find the field with the largest niche
-                        let niche_candidate = variants[i]
+                        let (field_index, niche, (niche_start, niche_scalar)) = match variants
+                            [largest_variant_index]
                             .iter()
                             .enumerate()
                             .filter_map(|(j, field)| Some((j, field.largest_niche?)))
-                            .max_by_key(|(_, niche)| niche.available(dl));
-
-                        if let Some((field_index, niche, (niche_start, niche_scalar))) =
-                            niche_candidate.and_then(|(field_index, niche)| {
-                                Some((field_index, niche, niche.reserve(self, count)?))
-                            })
+                            .max_by_key(|(_, niche)| niche.available(dl))
+                            .and_then(|(j, niche)| Some((j, niche, niche.reserve(self, count)?)))
                         {
-                            let mut align = dl.aggregate_align;
-                            let st = variants
-                                .iter_enumerated()
-                                .map(|(j, v)| {
-                                    let mut st = self.univariant_uninterned(
-                                        ty,
-                                        v,
-                                        &def.repr(),
-                                        StructKind::AlwaysSized,
-                                    )?;
-                                    st.variants = Variants::Single { index: j };
+                            None => return Ok(None),
+                            Some(x) => x,
+                        };
 
-                                    align = align.max(st.align);
+                        let niche_offset = niche.offset
+                            + variant_layouts[largest_variant_index].fields.offset(field_index);
+                        let niche_size = niche.value.size(dl);
+                        let size = variant_layouts[largest_variant_index].size.align_to(align.abi);
 
-                                    Ok(tcx.intern_layout(st))
-                                })
-                                .collect::<Result<IndexVec<VariantIdx, _>, _>>()?;
+                        let all_variants_fit =
+                            variant_layouts.iter_enumerated_mut().all(|(i, layout)| {
+                                if i == largest_variant_index {
+                                    return true;
+                                }
 
-                            let offset = st[i].fields().offset(field_index) + niche.offset;
+                                layout.largest_niche = None;
 
-                            // Align the total size to the largest alignment.
-                            let size = st[i].size().align_to(align.abi);
+                                if layout.size <= niche_offset {
+                                    // This variant will fit before the niche.
+                                    return true;
+                                }
 
-                            let abi = if st.iter().all(|v| v.abi().is_uninhabited()) {
-                                Abi::Uninhabited
-                            } else if align == st[i].align() && size == st[i].size() {
-                                // When the total alignment and size match, we can use the
-                                // same ABI as the scalar variant with the reserved niche.
-                                match st[i].abi() {
-                                    Abi::Scalar(_) => Abi::Scalar(niche_scalar),
-                                    Abi::ScalarPair(first, second) => {
-                                        // Only the niche is guaranteed to be initialised,
-                                        // so use union layout for the other primitive.
-                                        if offset.bytes() == 0 {
-                                            Abi::ScalarPair(niche_scalar, second.to_union())
-                                        } else {
-                                            Abi::ScalarPair(first.to_union(), niche_scalar)
+                                // Determine if it'll fit after the niche.
+                                let this_align = layout.align.abi;
+                                let this_offset = (niche_offset + niche_size).align_to(this_align);
+
+                                if this_offset + layout.size > size {
+                                    return false;
+                                }
+
+                                // It'll fit, but we need to make some adjustments.
+                                match layout.fields {
+                                    FieldsShape::Arbitrary { ref mut offsets, .. } => {
+                                        for (j, offset) in offsets.iter_mut().enumerate() {
+                                            if !variants[i][j].is_zst() {
+                                                *offset += this_offset;
+                                            }
                                         }
                                     }
-                                    _ => Abi::Aggregate { sized: true },
+                                    _ => {
+                                        panic!("Layout of fields should be Arbitrary for variants")
+                                    }
                                 }
-                            } else {
-                                Abi::Aggregate { sized: true }
-                            };
 
-                            let largest_niche = Niche::from_scalar(dl, offset, niche_scalar);
-
-                            niche_filling_layout = Some(LayoutS {
-                                variants: Variants::Multiple {
-                                    tag: niche_scalar,
-                                    tag_encoding: TagEncoding::Niche {
-                                        dataful_variant: i,
-                                        niche_variants,
-                                        niche_start,
-                                    },
-                                    tag_field: 0,
-                                    variants: st,
-                                },
-                                fields: FieldsShape::Arbitrary {
-                                    offsets: vec![offset],
-                                    memory_index: vec![0],
-                                },
-                                abi,
-                                largest_niche,
-                                size,
-                                align,
+                                // It can't be a Scalar or ScalarPair because the offset isn't 0.
+                                if !layout.abi.is_uninhabited() {
+                                    layout.abi = Abi::Aggregate { sized: true };
+                                }
+                                layout.size += this_offset;
+
+                                true
                             });
+
+                        if !all_variants_fit {
+                            return Ok(None);
                         }
-                    }
-                }
+
+                        let largest_niche = Niche::from_scalar(dl, niche_offset, niche_scalar);
+
+                        let others_zst = variant_layouts.iter_enumerated().all(|(i, layout)| {
+                            i == largest_variant_index || layout.size == Size::ZERO
+                        });
+                        let same_size = size == variant_layouts[largest_variant_index].size;
+                        let same_align = align == variant_layouts[largest_variant_index].align;
+
+                        let abi = if variant_layouts.iter().all(|v| v.abi.is_uninhabited()) {
+                            Abi::Uninhabited
+                        } else if same_size && same_align && others_zst {
+                            match variant_layouts[largest_variant_index].abi {
+                                // When the total alignment and size match, we can use the
+                                // same ABI as the scalar variant with the reserved niche.
+                                Abi::Scalar(_) => Abi::Scalar(niche_scalar),
+                                Abi::ScalarPair(first, second) => {
+                                    // Only the niche is guaranteed to be initialised,
+                                    // so use union layouts for the other primitive.
+                                    if niche_offset == Size::ZERO {
+                                        Abi::ScalarPair(niche_scalar, second.to_union())
+                                    } else {
+                                        Abi::ScalarPair(first.to_union(), niche_scalar)
+                                    }
+                                }
+                                _ => Abi::Aggregate { sized: true },
+                            }
+                        } else {
+                            Abi::Aggregate { sized: true }
+                        };
+
+                        let layout = LayoutS {
+                            variants: Variants::Multiple {
+                                tag: niche_scalar,
+                                tag_encoding: TagEncoding::Niche {
+                                    untagged_variant: largest_variant_index,
+                                    niche_variants,
+                                    niche_start,
+                                },
+                                tag_field: 0,
+                                variants: IndexVec::new(),
+                            },
+                            fields: FieldsShape::Arbitrary {
+                                offsets: vec![niche_offset],
+                                memory_index: vec![0],
+                            },
+                            abi,
+                            largest_niche,
+                            size,
+                            align,
+                        };
+
+                        Ok(Some(TmpLayout { layout, variants: variant_layouts }))
+                    };
+
+                let niche_filling_layout = calculate_niche_filling_layout()?;
 
                 let (mut min, mut max) = (i128::MAX, i128::MIN);
                 let discr_type = def.repr().discr_type();
@@ -1425,15 +1485,12 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
 
                 let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag);
 
-                let layout_variants =
-                    layout_variants.into_iter().map(|v| tcx.intern_layout(v)).collect();
-
                 let tagged_layout = LayoutS {
                     variants: Variants::Multiple {
                         tag,
                         tag_encoding: TagEncoding::Direct,
                         tag_field: 0,
-                        variants: layout_variants,
+                        variants: IndexVec::new(),
                     },
                     fields: FieldsShape::Arbitrary {
                         offsets: vec![Size::ZERO],
@@ -1445,20 +1502,45 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                     size,
                 };
 
-                let best_layout = match (tagged_layout, niche_filling_layout) {
-                    (tagged_layout, Some(niche_filling_layout)) => {
+                let tagged_layout = TmpLayout { layout: tagged_layout, variants: layout_variants };
+
+                let mut best_layout = match (tagged_layout, niche_filling_layout) {
+                    (tl, Some(nl)) => {
                         // Pick the smaller layout; otherwise,
                         // pick the layout with the larger niche; otherwise,
                         // pick tagged as it has simpler codegen.
-                        cmp::min_by_key(tagged_layout, niche_filling_layout, |layout| {
-                            let niche_size = layout.largest_niche.map_or(0, |n| n.available(dl));
-                            (layout.size, cmp::Reverse(niche_size))
-                        })
+                        use Ordering::*;
+                        let niche_size = |tmp_l: &TmpLayout<'_>| {
+                            tmp_l.layout.largest_niche.map_or(0, |n| n.available(dl))
+                        };
+                        match (
+                            tl.layout.size.cmp(&nl.layout.size),
+                            niche_size(&tl).cmp(&niche_size(&nl)),
+                        ) {
+                            (Greater, _) => nl,
+                            (Equal, Less) => nl,
+                            _ => tl,
+                        }
                     }
-                    (tagged_layout, None) => tagged_layout,
+                    (tl, None) => tl,
+                };
+
+                // Now we can intern the variant layouts and store them in the enum layout.
+                best_layout.layout.variants = match best_layout.layout.variants {
+                    Variants::Multiple { tag, tag_encoding, tag_field, .. } => Variants::Multiple {
+                        tag,
+                        tag_encoding,
+                        tag_field,
+                        variants: best_layout
+                            .variants
+                            .into_iter()
+                            .map(|layout| tcx.intern_layout(layout))
+                            .collect(),
+                    },
+                    _ => bug!(),
                 };
 
-                tcx.intern_layout(best_layout)
+                tcx.intern_layout(best_layout.layout)
             }
 
             // Types with no meaningful known layout.
@@ -2559,11 +2641,11 @@ where
                     // using more niches than just null (e.g., the first page of
                     // the address space, or unaligned pointers).
                     Variants::Multiple {
-                        tag_encoding: TagEncoding::Niche { dataful_variant, .. },
+                        tag_encoding: TagEncoding::Niche { untagged_variant, .. },
                         tag_field,
                         ..
                     } if this.fields.offset(tag_field) == offset => {
-                        Some(this.for_variant(cx, dataful_variant))
+                        Some(this.for_variant(cx, untagged_variant))
                     }
                     _ => Some(this),
                 };
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index ed04e766033..4635a9d5575 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -15,6 +15,7 @@ pub use self::AssocItemContainer::*;
 pub use self::BorrowKind::*;
 pub use self::IntVarValue::*;
 pub use self::Variance::*;
+use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason};
 use crate::metadata::ModChild;
 use crate::middle::privacy::AccessLevels;
 use crate::mir::{Body, GeneratorLayout};
@@ -40,6 +41,7 @@ use rustc_hir::Node;
 use rustc_index::vec::IndexVec;
 use rustc_macros::HashStable;
 use rustc_query_system::ich::StableHashingContext;
+use rustc_serialize::{Decodable, Encodable};
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{ExpnId, Span};
@@ -49,6 +51,9 @@ pub use vtable::*;
 
 use std::fmt::Debug;
 use std::hash::{Hash, Hasher};
+use std::marker::PhantomData;
+use std::mem;
+use std::num::NonZeroUsize;
 use std::ops::ControlFlow;
 use std::{fmt, str};
 
@@ -178,11 +183,6 @@ pub struct ResolverAstLowering {
     pub label_res_map: NodeMap<ast::NodeId>,
     /// Resolutions for lifetimes.
     pub lifetimes_res_map: NodeMap<LifetimeRes>,
-    /// Mapping from generics `def_id`s to TAIT generics `def_id`s.
-    /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic
-    /// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this
-    /// field from the original parameter 'a to the new parameter 'a1.
-    pub generics_def_id_map: Vec<FxHashMap<LocalDefId, LocalDefId>>,
     /// Lifetime parameters that lowering will have to introduce.
     pub extra_lifetime_params_map: NodeMap<Vec<(Ident, ast::NodeId, LifetimeRes)>>,
 
@@ -263,11 +263,11 @@ impl fmt::Display for ImplPolarity {
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, Encodable, Decodable, HashStable)]
-pub enum Visibility {
+pub enum Visibility<Id = LocalDefId> {
     /// Visible everywhere (including in other crates).
     Public,
     /// Visible only in the given crate-local module.
-    Restricted(DefId),
+    Restricted(Id),
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)]
@@ -358,28 +358,45 @@ impl<'tcx> DefIdTree for TyCtxt<'tcx> {
     }
 }
 
-impl Visibility {
-    /// Returns `true` if an item with this visibility is accessible from the given block.
-    pub fn is_accessible_from<T: DefIdTree>(self, module: DefId, tree: T) -> bool {
-        let restriction = match self {
-            // Public items are visible everywhere.
-            Visibility::Public => return true,
-            // Restricted items are visible in an arbitrary local module.
-            Visibility::Restricted(other) if other.krate != module.krate => return false,
-            Visibility::Restricted(module) => module,
-        };
+impl<Id> Visibility<Id> {
+    pub fn is_public(self) -> bool {
+        matches!(self, Visibility::Public)
+    }
+
+    pub fn map_id<OutId>(self, f: impl FnOnce(Id) -> OutId) -> Visibility<OutId> {
+        match self {
+            Visibility::Public => Visibility::Public,
+            Visibility::Restricted(id) => Visibility::Restricted(f(id)),
+        }
+    }
+}
+
+impl<Id: Into<DefId>> Visibility<Id> {
+    pub fn to_def_id(self) -> Visibility<DefId> {
+        self.map_id(Into::into)
+    }
 
-        tree.is_descendant_of(module, restriction)
+    /// Returns `true` if an item with this visibility is accessible from the given module.
+    pub fn is_accessible_from(self, module: impl Into<DefId>, tree: impl DefIdTree) -> bool {
+        match self {
+            // Public items are visible everywhere.
+            Visibility::Public => true,
+            Visibility::Restricted(id) => tree.is_descendant_of(module.into(), id.into()),
+        }
     }
 
     /// Returns `true` if this visibility is at least as accessible as the given visibility
-    pub fn is_at_least<T: DefIdTree>(self, vis: Visibility, tree: T) -> bool {
-        let vis_restriction = match vis {
-            Visibility::Public => return self == Visibility::Public,
-            Visibility::Restricted(module) => module,
-        };
+    pub fn is_at_least(self, vis: Visibility<impl Into<DefId>>, tree: impl DefIdTree) -> bool {
+        match vis {
+            Visibility::Public => self.is_public(),
+            Visibility::Restricted(id) => self.is_accessible_from(id, tree),
+        }
+    }
+}
 
-        self.is_accessible_from(vis_restriction, tree)
+impl Visibility<DefId> {
+    pub fn expect_local(self) -> Visibility {
+        self.map_id(|id| id.expect_local())
     }
 
     // Returns `true` if this item is visible anywhere in the local crate.
@@ -389,10 +406,6 @@ impl Visibility {
             Visibility::Restricted(def_id) => def_id.is_local(),
         }
     }
-
-    pub fn is_public(self) -> bool {
-        matches!(self, Visibility::Public)
-    }
 }
 
 /// The crate variances map is computed during typeck and contains the
@@ -463,15 +476,6 @@ pub(crate) struct TyS<'tcx> {
     outer_exclusive_binder: ty::DebruijnIndex,
 }
 
-// `TyS` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(TyS<'_>, 40);
-
-// We are actually storing a stable hash cache next to the type, so let's
-// also check the full size
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(WithStableHash<TyS<'_>>, 56);
-
 /// Use this rather than `TyS`, whenever possible.
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
 #[rustc_diagnostic_item = "Ty"]
@@ -528,10 +532,6 @@ pub(crate) struct PredicateS<'tcx> {
     outer_exclusive_binder: ty::DebruijnIndex,
 }
 
-// This type is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(PredicateS<'_>, 56);
-
 /// Use this rather than `PredicateS`, whenever possible.
 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
 #[rustc_pass_by_value]
@@ -915,42 +915,135 @@ pub struct CoercePredicate<'tcx> {
 }
 pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>;
 
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable)]
-pub enum Term<'tcx> {
-    Ty(Ty<'tcx>),
-    Const(Const<'tcx>),
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct Term<'tcx> {
+    ptr: NonZeroUsize,
+    marker: PhantomData<(Ty<'tcx>, Const<'tcx>)>,
+}
+
+impl Debug for Term<'_> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let data = if let Some(ty) = self.ty() {
+            format!("Term::Ty({:?})", ty)
+        } else if let Some(ct) = self.ct() {
+            format!("Term::Ct({:?})", ct)
+        } else {
+            unreachable!()
+        };
+        f.write_str(&data)
+    }
 }
 
 impl<'tcx> From<Ty<'tcx>> for Term<'tcx> {
     fn from(ty: Ty<'tcx>) -> Self {
-        Term::Ty(ty)
+        TermKind::Ty(ty).pack()
     }
 }
 
 impl<'tcx> From<Const<'tcx>> for Term<'tcx> {
     fn from(c: Const<'tcx>) -> Self {
-        Term::Const(c)
+        TermKind::Const(c).pack()
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Term<'tcx> {
+    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
+        self.unpack().hash_stable(hcx, hasher);
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for Term<'tcx> {
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        Ok(self.unpack().try_fold_with(folder)?.pack())
+    }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for Term<'tcx> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        self.unpack().visit_with(visitor)
+    }
+}
+
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for Term<'tcx> {
+    fn encode(&self, e: &mut E) {
+        self.unpack().encode(e)
+    }
+}
+
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for Term<'tcx> {
+    fn decode(d: &mut D) -> Self {
+        let res: TermKind<'tcx> = Decodable::decode(d);
+        res.pack()
     }
 }
 
 impl<'tcx> Term<'tcx> {
+    #[inline]
+    pub fn unpack(self) -> TermKind<'tcx> {
+        let ptr = self.ptr.get();
+        // SAFETY: use of `Interned::new_unchecked` here is ok because these
+        // pointers were originally created from `Interned` types in `pack()`,
+        // and this is just going in the other direction.
+        unsafe {
+            match ptr & TAG_MASK {
+                TYPE_TAG => TermKind::Ty(Ty(Interned::new_unchecked(
+                    &*((ptr & !TAG_MASK) as *const WithStableHash<ty::TyS<'tcx>>),
+                ))),
+                CONST_TAG => TermKind::Const(ty::Const(Interned::new_unchecked(
+                    &*((ptr & !TAG_MASK) as *const ty::ConstS<'tcx>),
+                ))),
+                _ => core::intrinsics::unreachable(),
+            }
+        }
+    }
+
     pub fn ty(&self) -> Option<Ty<'tcx>> {
-        if let Term::Ty(ty) = self { Some(*ty) } else { None }
+        if let TermKind::Ty(ty) = self.unpack() { Some(ty) } else { None }
     }
 
     pub fn ct(&self) -> Option<Const<'tcx>> {
-        if let Term::Const(c) = self { Some(*c) } else { None }
+        if let TermKind::Const(c) = self.unpack() { Some(c) } else { None }
     }
 
     pub fn into_arg(self) -> GenericArg<'tcx> {
-        match self {
-            Term::Ty(ty) => ty.into(),
-            Term::Const(c) => c.into(),
+        match self.unpack() {
+            TermKind::Ty(ty) => ty.into(),
+            TermKind::Const(c) => c.into(),
         }
     }
 }
 
+const TAG_MASK: usize = 0b11;
+const TYPE_TAG: usize = 0b00;
+const CONST_TAG: usize = 0b01;
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
+pub enum TermKind<'tcx> {
+    Ty(Ty<'tcx>),
+    Const(Const<'tcx>),
+}
+
+impl<'tcx> TermKind<'tcx> {
+    #[inline]
+    fn pack(self) -> Term<'tcx> {
+        let (tag, ptr) = match self {
+            TermKind::Ty(ty) => {
+                // Ensure we can use the tag bits.
+                assert_eq!(mem::align_of_val(&*ty.0.0) & TAG_MASK, 0);
+                (TYPE_TAG, ty.0.0 as *const WithStableHash<ty::TyS<'tcx>> as usize)
+            }
+            TermKind::Const(ct) => {
+                // Ensure we can use the tag bits.
+                assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0);
+                (CONST_TAG, ct.0.0 as *const ty::ConstS<'tcx> as usize)
+            }
+        };
+
+        Term { ptr: unsafe { NonZeroUsize::new_unchecked(ptr | tag) }, marker: PhantomData }
+    }
+}
+
 /// This kind of predicate has no *direct* correspondent in the
 /// syntax, but it roughly corresponds to the syntactic forms:
 ///
@@ -1184,20 +1277,17 @@ pub struct OpaqueHiddenType<'tcx> {
 impl<'tcx> OpaqueHiddenType<'tcx> {
     pub fn report_mismatch(&self, other: &Self, tcx: TyCtxt<'tcx>) {
         // Found different concrete types for the opaque type.
-        let mut err = tcx.sess.struct_span_err(
-            other.span,
-            "concrete type differs from previous defining opaque type use",
-        );
-        err.span_label(other.span, format!("expected `{}`, got `{}`", self.ty, other.ty));
-        if self.span == other.span {
-            err.span_label(
-                self.span,
-                "this expression supplies two conflicting concrete types for the same opaque type",
-            );
+        let sub_diag = if self.span == other.span {
+            TypeMismatchReason::ConflictType { span: self.span }
         } else {
-            err.span_note(self.span, "previous use here");
-        }
-        err.emit();
+            TypeMismatchReason::PreviousUse { span: self.span }
+        };
+        tcx.sess.emit_err(OpaqueHiddenTypeMismatch {
+            self_ty: self.ty,
+            other_ty: other.ty,
+            other_span: other.span,
+            sub: sub_diag,
+        });
     }
 }
 
@@ -1797,7 +1887,7 @@ pub enum VariantDiscr {
 pub struct FieldDef {
     pub did: DefId,
     pub name: Symbol,
-    pub vis: Visibility,
+    pub vis: Visibility<DefId>,
 }
 
 impl PartialEq for FieldDef {
@@ -2274,7 +2364,11 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     pub fn get_attr(self, did: DefId, attr: Symbol) -> Option<&'tcx ast::Attribute> {
-        self.get_attrs(did, attr).next()
+        if cfg!(debug_assertions) && !rustc_feature::is_valid_for_get_attr(attr) {
+            bug!("get_attr: unexpected called with DefId `{:?}`, attr `{:?}`", did, attr);
+        } else {
+            self.get_attrs(did, attr).next()
+        }
     }
 
     /// Determines whether an item is annotated with an attribute.
@@ -2534,3 +2628,14 @@ pub struct DestructuredConst<'tcx> {
     pub variant: Option<VariantIdx>,
     pub fields: &'tcx [ty::Const<'tcx>],
 }
+
+// Some types are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+mod size_asserts {
+    use super::*;
+    use rustc_data_structures::static_assert_size;
+    // These are in alphabetical order, which is easy to maintain.
+    static_assert_size!(PredicateS<'_>, 48);
+    static_assert_size!(TyS<'_>, 40);
+    static_assert_size!(WithStableHash<TyS<'_>>, 56);
+}
diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs
index ca24c0d1ce3..9c8dc30e2db 100644
--- a/compiler/rustc_middle/src/ty/parameterized.rs
+++ b/compiler/rustc_middle/src/ty/parameterized.rs
@@ -1,4 +1,4 @@
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, DefIndex};
 use rustc_index::vec::{Idx, IndexVec};
 
 use crate::middle::exported_symbols::ExportedSymbol;
@@ -60,7 +60,7 @@ trivially_parameterized_over_tcx! {
     ty::ImplPolarity,
     ty::ReprOptions,
     ty::TraitDef,
-    ty::Visibility,
+    ty::Visibility<DefIndex>,
     ty::adjustment::CoerceUnsizedInfo,
     ty::fast_reject::SimplifiedTypeGen<DefId>,
     rustc_ast::Attribute,
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 329478f27b7..1ae3063dae4 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1,7 +1,7 @@
 use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar};
 use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
 use crate::ty::{
-    self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, Ty, TyCtxt, TypeFoldable,
+    self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, TermKind, Ty, TyCtxt, TypeFoldable,
     TypeSuperFoldable, TypeSuperVisitable, TypeVisitable,
 };
 use rustc_apfloat::ieee::{Double, Single};
@@ -855,7 +855,7 @@ pub trait PrettyPrinter<'tcx>:
                         }
 
                         p!(")");
-                        if let Term::Ty(ty) = return_ty.skip_binder() {
+                        if let Some(ty) = return_ty.skip_binder().ty() {
                             if !ty.is_unit() {
                                 p!(" -> ", print(return_ty));
                             }
@@ -942,13 +942,9 @@ pub trait PrettyPrinter<'tcx>:
 
                         p!(write("{} = ", tcx.associated_item(assoc_item_def_id).name));
 
-                        match term {
-                            Term::Ty(ty) => {
-                                p!(print(ty))
-                            }
-                            Term::Const(c) => {
-                                p!(print(c));
-                            }
+                        match term.unpack() {
+                            TermKind::Ty(ty) => p!(print(ty)),
+                            TermKind::Const(c) => p!(print(c)),
                         };
                     }
 
@@ -2608,9 +2604,9 @@ define_print_and_forward_display! {
     }
 
     ty::Term<'tcx> {
-      match self {
-        ty::Term::Ty(ty) => p!(print(ty)),
-        ty::Term::Const(c) => p!(print(c)),
+      match self.unpack() {
+        ty::TermKind::Ty(ty) => p!(print(ty)),
+        ty::TermKind::Const(c) => p!(print(c)),
       }
     }
 
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 818affa7113..81476195d29 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -6,7 +6,7 @@
 
 use crate::ty::error::{ExpectedFound, TypeError};
 use crate::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
-use crate::ty::{self, ImplSubject, Term, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{self, ImplSubject, Term, TermKind, Ty, TyCtxt, TypeFoldable};
 use rustc_hir as ast;
 use rustc_hir::def_id::DefId;
 use rustc_span::DUMMY_SP;
@@ -594,10 +594,6 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
         );
     }
 
-    let eagerly_eval = |x: ty::Const<'tcx>| x.eval(tcx, relation.param_env());
-    let a = eagerly_eval(a);
-    let b = eagerly_eval(b);
-
     // Currently, the values that can be unified are primitive types,
     // and those that derive both `PartialEq` and `Eq`, corresponding
     // to structural-match types.
@@ -803,15 +799,15 @@ impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> {
     }
 }
 
-impl<'tcx> Relate<'tcx> for ty::Term<'tcx> {
+impl<'tcx> Relate<'tcx> for Term<'tcx> {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
         a: Self,
         b: Self,
     ) -> RelateResult<'tcx, Self> {
-        Ok(match (a, b) {
-            (Term::Ty(a), Term::Ty(b)) => relation.relate(a, b)?.into(),
-            (Term::Const(a), Term::Const(b)) => relation.relate(a, b)?.into(),
+        Ok(match (a.unpack(), b.unpack()) {
+            (TermKind::Ty(a), TermKind::Ty(b)) => relation.relate(a, b)?.into(),
+            (TermKind::Const(a), TermKind::Const(b)) => relation.relate(a, b)?.into(),
             _ => return Err(TypeError::Mismatch),
         })
     }
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 57555433f55..e6bd2eed565 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -7,7 +7,7 @@ use crate::mir::ProjectionKind;
 use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
 use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
 use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
-use crate::ty::{self, InferConst, Lift, Term, Ty, TyCtxt};
+use crate::ty::{self, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
 use rustc_data_structures::functor::IdFunctor;
 use rustc_hir as hir;
 use rustc_hir::def::Namespace;
@@ -344,10 +344,13 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialPredicate<'a> {
 impl<'a, 'tcx> Lift<'tcx> for Term<'a> {
     type Lifted = ty::Term<'tcx>;
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        Some(match self {
-            Term::Ty(ty) => Term::Ty(tcx.lift(ty)?),
-            Term::Const(c) => Term::Const(tcx.lift(c)?),
-        })
+        Some(
+            match self.unpack() {
+                TermKind::Ty(ty) => TermKind::Ty(tcx.lift(ty)?),
+                TermKind::Const(c) => TermKind::Const(tcx.lift(c)?),
+            }
+            .pack(),
+        )
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs
index 5e042c3acfc..5f8cb578202 100644
--- a/compiler/rustc_middle/src/ty/visit.rs
+++ b/compiler/rustc_middle/src/ty/visit.rs
@@ -666,7 +666,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector {
         // ignore the inputs to a projection, as they may not appear
         // in the normalized form
         if self.just_constrained {
-            if let ty::Projection(..) = t.kind() {
+            if let ty::Projection(..) | ty::Opaque(..) = t.kind() {
                 return ControlFlow::CONTINUE;
             }
         }
diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs
index 02fe1f3a7bd..831724bc4b0 100644
--- a/compiler/rustc_middle/src/ty/walk.rs
+++ b/compiler/rustc_middle/src/ty/walk.rs
@@ -165,9 +165,9 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
                         }
                     };
 
-                    substs.iter().rev().chain(opt_ty.map(|term| match term {
-                        ty::Term::Ty(ty) => ty.into(),
-                        ty::Term::Const(ct) => ct.into(),
+                    substs.iter().rev().chain(opt_ty.map(|term| match term.unpack() {
+                        ty::TermKind::Ty(ty) => ty.into(),
+                        ty::TermKind::Const(ct) => ct.into(),
                     }))
                 }));
             }
diff --git a/compiler/rustc_query_impl/src/values.rs b/compiler/rustc_middle/src/values.rs
index 0ed48f8d4a0..7fbe9ae2a84 100644
--- a/compiler/rustc_query_impl/src/values.rs
+++ b/compiler/rustc_middle/src/values.rs
@@ -1,39 +1,28 @@
-use super::QueryCtxt;
-use rustc_middle::ty::{self, AdtSizedConstraint, Ty};
+use rustc_middle::ty::{self, AdtSizedConstraint, Ty, TyCtxt};
+use rustc_query_system::Value;
 
-pub(super) trait Value<'tcx>: Sized {
-    fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> Self;
-}
-
-impl<'tcx, T> Value<'tcx> for T {
-    default fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> T {
-        tcx.sess.abort_if_errors();
-        bug!("Value::from_cycle_error called without errors");
-    }
-}
-
-impl<'tcx> Value<'tcx> for Ty<'_> {
-    fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> Self {
+impl<'tcx> Value<TyCtxt<'tcx>> for Ty<'_> {
+    fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self {
         // SAFETY: This is never called when `Self` is not `Ty<'tcx>`.
         // FIXME: Represent the above fact in the trait system somehow.
         unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(tcx.ty_error()) }
     }
 }
 
-impl<'tcx> Value<'tcx> for ty::SymbolName<'_> {
-    fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> Self {
+impl<'tcx> Value<TyCtxt<'tcx>> for ty::SymbolName<'_> {
+    fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self {
         // SAFETY: This is never called when `Self` is not `SymbolName<'tcx>`.
         // FIXME: Represent the above fact in the trait system somehow.
         unsafe {
             std::mem::transmute::<ty::SymbolName<'tcx>, ty::SymbolName<'_>>(ty::SymbolName::new(
-                *tcx, "<error>",
+                tcx, "<error>",
             ))
         }
     }
 }
 
-impl<'tcx> Value<'tcx> for AdtSizedConstraint<'_> {
-    fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> Self {
+impl<'tcx> Value<TyCtxt<'tcx>> for AdtSizedConstraint<'_> {
+    fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self {
         // SAFETY: This is never called when `Self` is not `AdtSizedConstraint<'tcx>`.
         // FIXME: Represent the above fact in the trait system somehow.
         unsafe {
@@ -44,8 +33,8 @@ impl<'tcx> Value<'tcx> for AdtSizedConstraint<'_> {
     }
 }
 
-impl<'tcx> Value<'tcx> for ty::Binder<'_, ty::FnSig<'_>> {
-    fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> Self {
+impl<'tcx> Value<TyCtxt<'tcx>> for ty::Binder<'_, ty::FnSig<'_>> {
+    fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self {
         let err = tcx.ty_error();
         // FIXME(compiler-errors): It would be nice if we could get the
         // query key, so we could at least generate a fn signature that
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 763038c52d7..7f992c18a18 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -1036,7 +1036,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                             VarBindingForm {
                                 binding_mode,
                                 opt_ty_info,
-                                opt_match_place: Some((Some(place), span)),
+                                opt_match_place: Some((None, span)),
                                 pat_span: span,
                             },
                         )))))
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 9ed1c064d2b..d059877f8e7 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -261,15 +261,19 @@ impl<'tcx> Cx<'tcx> {
 
         let kind = match expr.kind {
             // Here comes the interesting stuff:
-            hir::ExprKind::MethodCall(segment, ref args, fn_span) => {
+            hir::ExprKind::MethodCall(segment, receiver, ref args, fn_span) => {
                 // Rewrite a.b(c) into UFCS form like Trait::b(a, c)
                 let expr = self.method_callee(expr, segment.ident.span, None);
                 // When we apply adjustments to the receiver, use the span of
                 // the overall method call for better diagnostics. args[0]
                 // is guaranteed to exist, since a method call always has a receiver.
-                let old_adjustment_span = self.adjustment_span.replace((args[0].hir_id, expr_span));
+                let old_adjustment_span =
+                    self.adjustment_span.replace((receiver.hir_id, expr_span));
                 info!("Using method span: {:?}", expr.span);
-                let args = self.mirror_exprs(args);
+                let args = std::iter::once(receiver)
+                    .chain(args.iter())
+                    .map(|expr| self.mirror_expr(expr))
+                    .collect();
                 self.adjustment_span = old_adjustment_span;
                 ExprKind::Call {
                     ty: expr.ty,
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index d2f93b679ac..4968032b416 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -202,6 +202,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
 
     fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
         let mut ty = self.typeck_results.node_type(pat.hir_id);
+        let mut span = pat.span;
 
         let kind = match pat.kind {
             hir::PatKind::Wild => PatKind::Wild,
@@ -262,6 +263,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             }
 
             hir::PatKind::Binding(_, id, ident, ref sub) => {
+                if let Some(ident_span) = ident.span.find_ancestor_inside(span) {
+                    span = span.with_hi(ident_span.hi());
+                }
+
                 let bm = *self
                     .typeck_results
                     .pat_binding_modes()
@@ -326,14 +331,14 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             hir::PatKind::Or(ref pats) => PatKind::Or { pats: self.lower_patterns(pats) },
         };
 
-        Box::new(Pat { span: pat.span, ty, kind })
+        Box::new(Pat { span, ty, kind })
     }
 
     fn lower_tuple_subpats(
         &mut self,
         pats: &'tcx [hir::Pat<'tcx>],
         expected_len: usize,
-        gap_pos: Option<usize>,
+        gap_pos: hir::DotDotPos,
     ) -> Vec<FieldPat<'tcx>> {
         pats.iter()
             .enumerate_and_adjust(expected_len, gap_pos)
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index 319183eb9b3..115d34ff8fa 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -754,8 +754,8 @@ fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>(
     hir_id: HirId,
     witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
 ) {
-    let joined_patterns = joined_uncovered_patterns(cx, &witnesses);
     cx.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, hir_id, sp, |build| {
+        let joined_patterns = joined_uncovered_patterns(cx, &witnesses);
         let mut lint = build.build("some variants are not matched explicitly");
         lint.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns));
         lint.help(
diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
index 483c1e274aa..3e08a8799ef 100644
--- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
@@ -270,7 +270,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
             | StatementKind::Retag(..)
             | StatementKind::AscribeUserType(..)
             | StatementKind::Coverage(..)
-            | StatementKind::CopyNonOverlapping(..)
+            | StatementKind::Intrinsic(..)
             | StatementKind::Nop => None,
         };
         if let Some(destination) = destination {
diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
index f6b5af90a85..18760b6c6fa 100644
--- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
@@ -142,7 +142,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
             | StatementKind::FakeRead(..)
             | StatementKind::Nop
             | StatementKind::Retag(..)
-            | StatementKind::CopyNonOverlapping(..)
+            | StatementKind::Intrinsic(..)
             | StatementKind::StorageLive(..) => {}
         }
     }
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index c3258386223..f46fd118bde 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -330,7 +330,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
             StatementKind::Retag { .. }
             | StatementKind::AscribeUserType(..)
             | StatementKind::Coverage(..)
-            | StatementKind::CopyNonOverlapping(..)
+            | StatementKind::Intrinsic(..)
             | StatementKind::Nop => {}
         }
     }
diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs
index 0f5fd77f7ab..beff19a3ab2 100644
--- a/compiler/rustc_mir_transform/src/check_unsafety.rs
+++ b/compiler/rustc_mir_transform/src/check_unsafety.rs
@@ -105,7 +105,8 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
                 // safe (at least as emitted during MIR construction)
             }
 
-            StatementKind::CopyNonOverlapping(..) => unreachable!(),
+            // Move to above list once mir construction uses it.
+            StatementKind::Intrinsic(..) => unreachable!(),
         }
         self.super_statement(statement, location);
     }
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index 423e78317aa..9f842c929dc 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -825,7 +825,7 @@ pub(super) fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span>
 
         // Retain spans from all other statements
         StatementKind::FakeRead(box (_, _)) // Not including `ForGuardBinding`
-        | StatementKind::CopyNonOverlapping(..)
+        | StatementKind::Intrinsic(..)
         | StatementKind::Assign(_)
         | StatementKind::SetDiscriminant { .. }
         | StatementKind::Deinit(..)
diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
index 9163672f570..3f3870cc7ba 100644
--- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs
+++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
@@ -52,7 +52,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
                 | StatementKind::StorageLive(_)
                 | StatementKind::StorageDead(_)
                 | StatementKind::Coverage(_)
-                | StatementKind::CopyNonOverlapping(_)
+                | StatementKind::Intrinsic(_)
                 | StatementKind::Nop => (),
 
                 StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => {
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index da55510920e..9bc47613e4c 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -537,7 +537,7 @@ impl<'a> Conflicts<'a> {
             | StatementKind::FakeRead(..)
             | StatementKind::AscribeUserType(..)
             | StatementKind::Coverage(..)
-            | StatementKind::CopyNonOverlapping(..)
+            | StatementKind::Intrinsic(..)
             | StatementKind::Nop => {}
         }
     }
diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs
index dbff4a6bd69..705cf776fb2 100644
--- a/compiler/rustc_mir_transform/src/generator.rs
+++ b/compiler/rustc_mir_transform/src/generator.rs
@@ -1452,7 +1452,7 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
             | StatementKind::Retag(..)
             | StatementKind::AscribeUserType(..)
             | StatementKind::Coverage(..)
-            | StatementKind::CopyNonOverlapping(..)
+            | StatementKind::Intrinsic(..)
             | StatementKind::Nop => {}
         }
     }
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index b7ba616510c..9892580e63d 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -46,12 +46,31 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
                         let mut args = args.drain(..);
                         block.statements.push(Statement {
                             source_info: terminator.source_info,
-                            kind: StatementKind::CopyNonOverlapping(Box::new(
-                                rustc_middle::mir::CopyNonOverlapping {
-                                    src: args.next().unwrap(),
-                                    dst: args.next().unwrap(),
-                                    count: args.next().unwrap(),
-                                },
+                            kind: StatementKind::Intrinsic(Box::new(
+                                NonDivergingIntrinsic::CopyNonOverlapping(
+                                    rustc_middle::mir::CopyNonOverlapping {
+                                        src: args.next().unwrap(),
+                                        dst: args.next().unwrap(),
+                                        count: args.next().unwrap(),
+                                    },
+                                ),
+                            )),
+                        });
+                        assert_eq!(
+                            args.next(),
+                            None,
+                            "Extra argument for copy_non_overlapping intrinsic"
+                        );
+                        drop(args);
+                        terminator.kind = TerminatorKind::Goto { target };
+                    }
+                    sym::assume => {
+                        let target = target.unwrap();
+                        let mut args = args.drain(..);
+                        block.statements.push(Statement {
+                            source_info: terminator.source_info,
+                            kind: StatementKind::Intrinsic(Box::new(
+                                NonDivergingIntrinsic::Assume(args.next().unwrap()),
                             )),
                         });
                         assert_eq!(
diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs
index 67ea5cfdb3c..67dae71468f 100644
--- a/compiler/rustc_mir_transform/src/pass_manager.rs
+++ b/compiler/rustc_mir_transform/src/pass_manager.rs
@@ -103,7 +103,7 @@ fn run_passes_inner<'tcx>(
         let name = pass.name();
 
         // Gather information about what we should be doing for this pass
-        let overriden =
+        let overridden =
             overridden_passes.iter().rev().find(|(s, _)| s == &*name).map(|(_name, polarity)| {
                 trace!(
                     pass = %name,
@@ -112,7 +112,7 @@ fn run_passes_inner<'tcx>(
                 );
                 *polarity
             });
-        let is_enabled = overriden.unwrap_or_else(|| pass.is_enabled(&tcx.sess));
+        let is_enabled = overridden.unwrap_or_else(|| pass.is_enabled(&tcx.sess));
         let new_phase = pass.phase_change();
         let dump_enabled = (is_enabled && pass.is_mir_dump_enabled()) || new_phase.is_some();
         let validate = (validate && is_enabled)
diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
index 41a0bfac41a..f1bbf2ea7e8 100644
--- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
+++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
@@ -51,7 +51,7 @@ impl RemoveNoopLandingPads {
                 StatementKind::Assign { .. }
                 | StatementKind::SetDiscriminant { .. }
                 | StatementKind::Deinit(..)
-                | StatementKind::CopyNonOverlapping(..)
+                | StatementKind::Intrinsic(..)
                 | StatementKind::Retag { .. } => {
                     return false;
                 }
diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs
index 190f9c1ac15..2f116aaa958 100644
--- a/compiler/rustc_mir_transform/src/separate_const_switch.rs
+++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs
@@ -249,7 +249,7 @@ fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData<
             | StatementKind::AscribeUserType(_, _)
             | StatementKind::Coverage(_)
             | StatementKind::StorageDead(_)
-            | StatementKind::CopyNonOverlapping(_)
+            | StatementKind::Intrinsic(_)
             | StatementKind::Nop => {}
         }
     }
@@ -317,7 +317,7 @@ fn find_determining_place<'tcx>(
             | StatementKind::Retag(_, _)
             | StatementKind::AscribeUserType(_, _)
             | StatementKind::Coverage(_)
-            | StatementKind::CopyNonOverlapping(_)
+            | StatementKind::Intrinsic(_)
             | StatementKind::Nop => {}
 
             // If the discriminant is set, it is always set
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index bed48db959a..57d372fda56 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -499,7 +499,7 @@ impl UsedLocals {
 impl<'tcx> Visitor<'tcx> for UsedLocals {
     fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
         match statement.kind {
-            StatementKind::CopyNonOverlapping(..)
+            StatementKind::Intrinsic(..)
             | StatementKind::Retag(..)
             | StatementKind::Coverage(..)
             | StatementKind::FakeRead(..)
diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs
index 77b6cfa1f69..d5f05e790d3 100644
--- a/compiler/rustc_monomorphize/src/errors.rs
+++ b/compiler/rustc_monomorphize/src/errors.rs
@@ -47,9 +47,10 @@ pub struct UnusedGenericParams {
 impl SessionDiagnostic<'_> for UnusedGenericParams {
     fn into_diagnostic(
         self,
-        sess: &'_ rustc_session::parse::ParseSess,
+        handler: &'_ rustc_errors::Handler,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = sess.struct_err(rustc_errors::fluent::monomorphize::unused_generic_params);
+        let mut diag =
+            handler.struct_err(rustc_errors::fluent::monomorphize::unused_generic_params);
         diag.set_span(self.span);
         for (span, name) in self.param_spans.into_iter().zip(self.param_names) {
             // FIXME: I can figure out how to do a label with a fluent string with a fixed message,
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index dd806e2130e..be524db785b 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -10,9 +10,9 @@ use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter, Lit, LitKind, TokenKind};
 use rustc_ast::util::parser::AssocOp;
 use rustc_ast::{
-    AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, Block,
-    BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Mutability, Param, Pat,
-    PatKind, Path, PathSegment, QSelf, Ty, TyKind,
+    AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingAnnotation, Block,
+    BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Param, Pat, PatKind,
+    Path, PathSegment, QSelf, Ty, TyKind,
 };
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashSet;
@@ -37,7 +37,7 @@ const TURBOFISH_SUGGESTION_STR: &str =
 pub(super) fn dummy_arg(ident: Ident) -> Param {
     let pat = P(Pat {
         id: ast::DUMMY_NODE_ID,
-        kind: PatKind::Ident(BindingMode::ByValue(Mutability::Not), ident, None),
+        kind: PatKind::Ident(BindingAnnotation::NONE, ident, None),
         span: ident.span,
         tokens: None,
     });
@@ -705,6 +705,22 @@ pub(crate) struct LeftArrowOperator {
     pub span: Span,
 }
 
+#[derive(SessionDiagnostic)]
+#[diag(parser::remove_let)]
+pub(crate) struct RemoveLet {
+    #[primary_span]
+    #[suggestion(applicability = "machine-applicable", code = "")]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(parser::use_eq_instead)]
+pub(crate) struct UseEqInstead {
+    #[primary_span]
+    #[suggestion_short(applicability = "machine-applicable", code = "=")]
+    pub span: Span,
+}
+
 // SnapshotParser is used to create a snapshot of the parser
 // without causing duplicate errors being emitted when the `Parser`
 // is dropped.
@@ -949,6 +965,14 @@ impl<'a> Parser<'a> {
             }
         }
 
+        if self.token.kind == TokenKind::EqEq
+            && self.prev_token.is_ident()
+            && expected.iter().any(|tok| matches!(tok, TokenType::Token(TokenKind::Eq)))
+        {
+            // Likely typo: `=` → `==` in let expr or enum item
+            return Err(self.sess.create_err(UseEqInstead { span: self.token.span }));
+        }
+
         let expect = tokens_to_string(&expected);
         let actual = super::token_descr(&self.token);
         let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 {
@@ -2961,7 +2985,7 @@ impl<'a> Parser<'a> {
                                 }
                                 _ => {}
                             },
-                            PatKind::Ident(BindingMode::ByValue(Mutability::Not), ident, None) => {
+                            PatKind::Ident(BindingAnnotation::NONE, ident, None) => {
                                 match &first_pat.kind {
                                     PatKind::Ident(_, old_ident, _) => {
                                         let path = PatKind::Path(
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index d4828a20120..ed37ede65d5 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1977,6 +1977,9 @@ impl<'a> Parser<'a> {
         open_delim_span: Span,
     ) -> PResult<'a, ()> {
         if self.token.kind == token::Comma {
+            if !self.sess.source_map().is_multiline(prev_span.until(self.token.span)) {
+                return Ok(());
+            }
             let mut snapshot = self.create_snapshot_for_diagnostic();
             snapshot.bump();
             match snapshot.parse_seq_to_before_end(
@@ -1997,7 +2000,7 @@ impl<'a> Parser<'a> {
                     return Err(MissingSemicolonBeforeArray {
                         open_delim: open_delim_span,
                         semicolon: prev_span.shrink_to_hi(),
-                    }.into_diagnostic(self.sess));
+                    }.into_diagnostic(&self.sess.span_diagnostic));
                 }
                 Ok(_) => (),
                 Err(err) => err.cancel(),
@@ -2745,7 +2748,8 @@ impl<'a> Parser<'a> {
     fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, P<Expr>> {
         let (attrs, body) = self.parse_inner_attrs_and_block()?;
         if self.eat_keyword(kw::Catch) {
-            Err(CatchAfterTry { span: self.prev_token.span }.into_diagnostic(self.sess))
+            Err(CatchAfterTry { span: self.prev_token.span }
+                .into_diagnostic(&self.sess.span_diagnostic))
         } else {
             let span = span_lo.to(body.span);
             self.sess.gated_spans.gate(sym::try_blocks, span);
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 5b75d1d5f22..b190a7062de 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -8,7 +8,7 @@ use rustc_ast::token::{self, Delimiter, TokenKind};
 use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
 use rustc_ast::{self as ast, AttrVec, Attribute, DUMMY_NODE_ID};
 use rustc_ast::{Async, Const, Defaultness, IsAuto, Mutability, Unsafe, UseTree, UseTreeKind};
-use rustc_ast::{BindingMode, Block, FnDecl, FnSig, Param, SelfKind};
+use rustc_ast::{BindingAnnotation, Block, FnDecl, FnSig, Param, SelfKind};
 use rustc_ast::{EnumDef, FieldDef, Generics, TraitRef, Ty, TyKind, Variant, VariantData};
 use rustc_ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, VisibilityKind};
 use rustc_ast::{MacArgs, MacCall, MacDelimiter};
@@ -1526,6 +1526,17 @@ impl<'a> Parser<'a> {
         if self.token == token::Comma {
             seen_comma = true;
         }
+        if self.eat(&token::Semi) {
+            let sp = self.prev_token.span;
+            let mut err = self.struct_span_err(sp, format!("{adt_ty} fields are separated by `,`"));
+            err.span_suggestion_short(
+                sp,
+                "replace `;` with `,`",
+                ",",
+                Applicability::MachineApplicable,
+            );
+            return Err(err);
+        }
         match self.token.kind {
             token::Comma => {
                 self.bump();
@@ -2322,7 +2333,7 @@ impl<'a> Parser<'a> {
                 match ty {
                     Ok(ty) => {
                         let ident = Ident::new(kw::Empty, this.prev_token.span);
-                        let bm = BindingMode::ByValue(Mutability::Not);
+                        let bm = BindingAnnotation::NONE;
                         let pat = this.mk_pat_ident(ty.span, bm, ident);
                         (pat, ty)
                     }
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 8b3200d45fc..120a3c267f1 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -1,11 +1,12 @@
 use super::{ForceCollect, Parser, PathStyle, TrailingToken};
+use crate::parser::diagnostics::RemoveLet;
 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
 use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter};
 use rustc_ast::{
-    self as ast, AttrVec, BindingMode, Expr, ExprKind, MacCall, Mutability, Pat, PatField, PatKind,
-    Path, QSelf, RangeEnd, RangeSyntax,
+    self as ast, AttrVec, BindingAnnotation, ByRef, Expr, ExprKind, MacCall, Mutability, Pat,
+    PatField, PatKind, Path, QSelf, RangeEnd, RangeSyntax,
 };
 use rustc_ast_pretty::pprust;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult};
@@ -320,7 +321,13 @@ impl<'a> Parser<'a> {
         maybe_recover_from_interpolated_ty_qpath!(self, true);
         maybe_whole!(self, NtPat, |x| x);
 
-        let lo = self.token.span;
+        let mut lo = self.token.span;
+
+        if self.token.is_keyword(kw::Let) && self.look_ahead(1, |tok| tok.can_begin_pattern()) {
+            self.bump();
+            self.sess.emit_err(RemoveLet { span: lo });
+            lo = self.token.span;
+        }
 
         let pat = if self.check(&token::BinOp(token::And)) || self.token.kind == token::AndAnd {
             self.parse_pat_deref(expected)?
@@ -353,7 +360,7 @@ impl<'a> Parser<'a> {
         } else if self.eat_keyword(kw::Ref) {
             // Parse ref ident @ pat / ref mut ident @ pat
             let mutbl = self.parse_mutability();
-            self.parse_pat_ident(BindingMode::ByRef(mutbl))?
+            self.parse_pat_ident(BindingAnnotation(ByRef::Yes, mutbl))?
         } else if self.eat_keyword(kw::Box) {
             self.parse_pat_box()?
         } else if self.check_inline_const(0) {
@@ -369,7 +376,7 @@ impl<'a> Parser<'a> {
             // Parse `ident @ pat`
             // This can give false positives and parse nullary enums,
             // they are dealt with later in resolve.
-            self.parse_pat_ident(BindingMode::ByValue(Mutability::Not))?
+            self.parse_pat_ident(BindingAnnotation::NONE)?
         } else if self.is_start_of_pat_with_path() {
             // Parse pattern starting with a path
             let (qself, path) = if self.eat_lt() {
@@ -578,7 +585,8 @@ impl<'a> Parser<'a> {
         let mut pat = self.parse_pat_no_top_alt(Some("identifier"))?;
 
         // If we don't have `mut $ident (@ pat)?`, error.
-        if let PatKind::Ident(BindingMode::ByValue(m @ Mutability::Not), ..) = &mut pat.kind {
+        if let PatKind::Ident(BindingAnnotation(ByRef::No, m @ Mutability::Not), ..) = &mut pat.kind
+        {
             // Don't recurse into the subpattern.
             // `mut` on the outer binding doesn't affect the inner bindings.
             *m = Mutability::Mut;
@@ -604,7 +612,7 @@ impl<'a> Parser<'a> {
             )
             .emit();
 
-        self.parse_pat_ident(BindingMode::ByRef(Mutability::Mut))
+        self.parse_pat_ident(BindingAnnotation::REF_MUT)
     }
 
     /// Turn all by-value immutable bindings in a pattern into mutable bindings.
@@ -613,7 +621,8 @@ impl<'a> Parser<'a> {
         struct AddMut(bool);
         impl MutVisitor for AddMut {
             fn visit_pat(&mut self, pat: &mut P<Pat>) {
-                if let PatKind::Ident(BindingMode::ByValue(m @ Mutability::Not), ..) = &mut pat.kind
+                if let PatKind::Ident(BindingAnnotation(ByRef::No, m @ Mutability::Not), ..) =
+                    &mut pat.kind
                 {
                     self.0 = true;
                     *m = Mutability::Mut;
@@ -838,7 +847,7 @@ impl<'a> Parser<'a> {
     /// Parses `ident` or `ident @ pat`.
     /// Used by the copy foo and ref foo patterns to give a good
     /// error message when parsing mistakes like `ref foo(a, b)`.
-    fn parse_pat_ident(&mut self, binding_mode: BindingMode) -> PResult<'a, PatKind> {
+    fn parse_pat_ident(&mut self, binding_annotation: BindingAnnotation) -> PResult<'a, PatKind> {
         let ident = self.parse_ident()?;
         let sub = if self.eat(&token::At) {
             Some(self.parse_pat_no_top_alt(Some("binding pattern"))?)
@@ -856,7 +865,7 @@ impl<'a> Parser<'a> {
                 .struct_span_err(self.prev_token.span, "expected identifier, found enum pattern"));
         }
 
-        Ok(PatKind::Ident(binding_mode, ident, sub))
+        Ok(PatKind::Ident(binding_annotation, ident, sub))
     }
 
     /// Parse a struct ("record") pattern (e.g. `Foo { ... }` or `Foo::Bar { ... }`).
@@ -936,11 +945,7 @@ impl<'a> Parser<'a> {
                 None
             };
 
-            Ok(PatKind::Ident(
-                BindingMode::ByValue(Mutability::Not),
-                Ident::new(kw::Box, box_span),
-                sub,
-            ))
+            Ok(PatKind::Ident(BindingAnnotation::NONE, Ident::new(kw::Box, box_span), sub))
         } else {
             let pat = self.parse_pat_with_range_pat(false, None)?;
             self.sess.gated_spans.gate(sym::box_patterns, box_span.to(self.prev_token.span));
@@ -1117,14 +1122,12 @@ impl<'a> Parser<'a> {
             let fieldname = self.parse_field_name()?;
             hi = self.prev_token.span;
 
-            let bind_type = match (is_ref, is_mut) {
-                (true, true) => BindingMode::ByRef(Mutability::Mut),
-                (true, false) => BindingMode::ByRef(Mutability::Not),
-                (false, true) => BindingMode::ByValue(Mutability::Mut),
-                (false, false) => BindingMode::ByValue(Mutability::Not),
+            let mutability = match is_mut {
+                false => Mutability::Not,
+                true => Mutability::Mut,
             };
-
-            let fieldpat = self.mk_pat_ident(boxed_span.to(hi), bind_type, fieldname);
+            let ann = BindingAnnotation(ByRef::from(is_ref), mutability);
+            let fieldpat = self.mk_pat_ident(boxed_span.to(hi), ann, fieldname);
             let subpat =
                 if is_box { self.mk_pat(lo.to(hi), PatKind::Box(fieldpat)) } else { fieldpat };
             (subpat, fieldname, true)
@@ -1141,8 +1144,8 @@ impl<'a> Parser<'a> {
         })
     }
 
-    pub(super) fn mk_pat_ident(&self, span: Span, bm: BindingMode, ident: Ident) -> P<Pat> {
-        self.mk_pat(span, PatKind::Ident(bm, ident, None))
+    pub(super) fn mk_pat_ident(&self, span: Span, ann: BindingAnnotation, ident: Ident) -> P<Pat> {
+        self.mk_pat(span, PatKind::Ident(ann, ident, None))
     }
 
     pub(super) fn mk_pat(&self, span: Span, kind: PatKind) -> P<Pat> {
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index a63af4159e8..d0b46aa2c45 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -1651,6 +1651,7 @@ impl CheckAttrVisitor<'_> {
                         E0552,
                         "unrecognized representation hint"
                     )
+                    .help("valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`")
                     .emit();
 
                     continue;
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 625c854ea77..a7ce0f312af 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -226,19 +226,16 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
         lhs: &hir::Pat<'_>,
         res: Res,
         pats: &[hir::Pat<'_>],
-        dotdot: Option<usize>,
+        dotdot: hir::DotDotPos,
     ) {
         let variant = match self.typeck_results().node_type(lhs.hir_id).kind() {
             ty::Adt(adt, _) => adt.variant_of_res(res),
             _ => span_bug!(lhs.span, "non-ADT in tuple struct pattern"),
         };
-        let first_n = pats.iter().enumerate().take(dotdot.unwrap_or(pats.len()));
+        let dotdot = dotdot.as_opt_usize().unwrap_or(pats.len());
+        let first_n = pats.iter().enumerate().take(dotdot);
         let missing = variant.fields.len() - pats.len();
-        let last_n = pats
-            .iter()
-            .enumerate()
-            .skip(dotdot.unwrap_or(pats.len()))
-            .map(|(idx, pat)| (idx + missing, pat));
+        let last_n = pats.iter().enumerate().skip(dotdot).map(|(idx, pat)| (idx + missing, pat));
         for (idx, pat) in first_n.chain(last_n) {
             if let PatKind::Wild = pat.kind {
                 continue;
diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs
index 212ea9e57a3..3bb8c0bb48c 100644
--- a/compiler/rustc_passes/src/hir_id_validator.rs
+++ b/compiler/rustc_passes/src/hir_id_validator.rs
@@ -103,7 +103,7 @@ impl<'a, 'hir> HirIdValidator<'a, 'hir> {
             self.error(|| {
                 format!(
                     "ItemLocalIds not assigned densely in {}. \
-                Max ItemLocalId = {}, missing IDs = {:?}; seens IDs = {:?}",
+                Max ItemLocalId = {}, missing IDs = {:#?}; seens IDs = {:#?}",
                     self.hir_map.def_path(owner).to_string_no_crate_verbose(),
                     max,
                     missing_items,
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index 81ac0e1b6d4..075069feb52 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -437,6 +437,11 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
         }
     }
 
+    fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
+        self.record("Lifetime", Id::Node(lifetime.hir_id), lifetime);
+        hir_visit::walk_lifetime(self, lifetime)
+    }
+
     fn visit_path(&mut self, path: &'v hir::Path<'v>, _id: hir::HirId) {
         self.record("Path", Id::None, path);
         hir_visit::walk_path(self, path)
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 2a6889af7c2..6a4cd79cde7 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -1039,9 +1039,10 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                 self.propagate_through_expr(&f, succ)
             }
 
-            hir::ExprKind::MethodCall(.., ref args, _) => {
+            hir::ExprKind::MethodCall(.., receiver, ref args, _) => {
                 let succ = self.check_is_ty_uninhabited(expr, succ);
-                self.propagate_through_exprs(args, succ)
+                let succ = self.propagate_through_exprs(args, succ);
+                self.propagate_through_expr(receiver, succ)
             }
 
             hir::ExprKind::Tup(ref exprs) => self.propagate_through_exprs(exprs, succ),
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index 296b6ed5d99..607973446fc 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -76,7 +76,7 @@ fn check_no_patterns(tcx: TyCtxt<'_>, params: &[hir::Param<'_>]) {
     for param in params {
         match param.pat.kind {
             hir::PatKind::Wild
-            | hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, _, None) => {}
+            | hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, _, None) => {}
             _ => {
                 tcx.sess
                     .struct_span_err(
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index f884e04a951..a24b191aebf 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -832,7 +832,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
                 // added, such as `core::intrinsics::transmute`
                 let parents = path.segments.iter().rev().skip(1);
                 for path_segment in parents {
-                    if let Some(def_id) = path_segment.res.as_ref().and_then(Res::opt_def_id) {
+                    if let Some(def_id) = path_segment.res.opt_def_id() {
                         // use `None` for id to prevent deprecation check
                         self.tcx.check_stability_allow_unstable(
                             def_id,
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index ba69bc23118..b2966f0d218 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -1,6 +1,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(associated_type_defaults)]
 #![feature(control_flow_enum)]
+#![feature(let_else)]
 #![feature(rustc_private)]
 #![feature(try_blocks)]
 #![recursion_limit = "256"]
@@ -334,7 +335,9 @@ impl<'a, 'tcx, VL: VisibilityLike> DefIdVisitor<'tcx> for FindMin<'a, 'tcx, VL>
         _kind: &str,
         _descr: &dyn fmt::Display,
     ) -> ControlFlow<Self::BreakTy> {
-        self.min = VL::new_min(self, def_id);
+        if let Some(def_id) = def_id.as_local() {
+            self.min = VL::new_min(self, def_id);
+        }
         ControlFlow::CONTINUE
     }
 }
@@ -342,7 +345,7 @@ impl<'a, 'tcx, VL: VisibilityLike> DefIdVisitor<'tcx> for FindMin<'a, 'tcx, VL>
 trait VisibilityLike: Sized {
     const MAX: Self;
     const SHALLOW: bool = false;
-    fn new_min(find: &FindMin<'_, '_, Self>, def_id: DefId) -> Self;
+    fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self;
 
     // Returns an over-approximation (`skip_assoc_tys` = true) of visibility due to
     // associated types for which we can't determine visibility precisely.
@@ -357,8 +360,8 @@ trait VisibilityLike: Sized {
 }
 impl VisibilityLike for ty::Visibility {
     const MAX: Self = ty::Visibility::Public;
-    fn new_min(find: &FindMin<'_, '_, Self>, def_id: DefId) -> Self {
-        min(find.tcx.visibility(def_id), find.min, find.tcx)
+    fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self {
+        min(find.tcx.local_visibility(def_id), find.min, find.tcx)
     }
 }
 impl VisibilityLike for Option<AccessLevel> {
@@ -373,15 +376,8 @@ impl VisibilityLike for Option<AccessLevel> {
     // both "shallow" version of its self type and "shallow" version of its trait if it exists
     // (which require reaching the `DefId`s in them).
     const SHALLOW: bool = true;
-    fn new_min(find: &FindMin<'_, '_, Self>, def_id: DefId) -> Self {
-        cmp::min(
-            if let Some(def_id) = def_id.as_local() {
-                find.access_levels.map.get(&def_id).copied()
-            } else {
-                Self::MAX
-            },
-            find.min,
-        )
+    fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self {
+        cmp::min(find.access_levels.map.get(&def_id).copied(), find.min)
     }
 }
 
@@ -511,15 +507,15 @@ impl<'tcx> EmbargoVisitor<'tcx> {
         let module = self.tcx.hir().get_module(module_def_id).0;
         for item_id in module.item_ids {
             let def_kind = self.tcx.def_kind(item_id.def_id);
-            let vis = self.tcx.visibility(item_id.def_id);
+            let vis = self.tcx.local_visibility(item_id.def_id);
             self.update_macro_reachable_def(item_id.def_id, def_kind, vis, defining_mod);
         }
         if let Some(exports) = self.tcx.module_reexports(module_def_id) {
             for export in exports {
-                if export.vis.is_accessible_from(defining_mod.to_def_id(), self.tcx) {
+                if export.vis.is_accessible_from(defining_mod, self.tcx) {
                     if let Res::Def(def_kind, def_id) = export.res {
                         if let Some(def_id) = def_id.as_local() {
-                            let vis = self.tcx.visibility(def_id.to_def_id());
+                            let vis = self.tcx.local_visibility(def_id);
                             self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod);
                         }
                     }
@@ -542,7 +538,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
         match def_kind {
             // No type privacy, so can be directly marked as reachable.
             DefKind::Const | DefKind::Static(_) | DefKind::TraitAlias | DefKind::TyAlias => {
-                if vis.is_accessible_from(module.to_def_id(), self.tcx) {
+                if vis.is_accessible_from(module, self.tcx) {
                     self.update(def_id, level);
                 }
             }
@@ -554,7 +550,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
             DefKind::Macro(_) => {
                 let item = self.tcx.hir().expect_item(def_id);
                 if let hir::ItemKind::Macro(MacroDef { macro_rules: false, .. }, _) = item.kind {
-                    if vis.is_accessible_from(module.to_def_id(), self.tcx) {
+                    if vis.is_accessible_from(module, self.tcx) {
                         self.update(def_id, level);
                     }
                 }
@@ -565,7 +561,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
             // hygiene these don't need to be marked reachable. The contents of
             // the module, however may be reachable.
             DefKind::Mod => {
-                if vis.is_accessible_from(module.to_def_id(), self.tcx) {
+                if vis.is_accessible_from(module, self.tcx) {
                     self.update_macro_reachable(def_id, module);
                 }
             }
@@ -579,8 +575,8 @@ impl<'tcx> EmbargoVisitor<'tcx> {
                     {
                         for field in struct_def.fields() {
                             let def_id = self.tcx.hir().local_def_id(field.hir_id);
-                            let field_vis = self.tcx.visibility(def_id);
-                            if field_vis.is_accessible_from(module.to_def_id(), self.tcx) {
+                            let field_vis = self.tcx.local_visibility(def_id);
+                            if field_vis.is_accessible_from(module, self.tcx) {
                                 self.reach(def_id, level).ty();
                             }
                         }
@@ -654,7 +650,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
             hir::ItemKind::Impl(ref impl_) => {
                 for impl_item_ref in impl_.items {
                     if impl_.of_trait.is_some()
-                        || self.tcx.visibility(impl_item_ref.id.def_id) == ty::Visibility::Public
+                        || self.tcx.visibility(impl_item_ref.id.def_id).is_public()
                     {
                         self.update(impl_item_ref.id.def_id, item_level);
                     }
@@ -682,7 +678,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
             }
             hir::ItemKind::ForeignMod { items, .. } => {
                 for foreign_item in items {
-                    if self.tcx.visibility(foreign_item.id.def_id) == ty::Visibility::Public {
+                    if self.tcx.visibility(foreign_item.id.def_id).is_public() {
                         self.update(foreign_item.id.def_id, item_level);
                     }
                 }
@@ -1117,7 +1113,7 @@ impl<'tcx> TypePrivacyVisitor<'tcx> {
     }
 
     fn item_is_accessible(&self, did: DefId) -> bool {
-        self.tcx.visibility(did).is_accessible_from(self.current_item.to_def_id(), self.tcx)
+        self.tcx.visibility(did).is_accessible_from(self.current_item, self.tcx)
     }
 
     // Take node-id of an expression or pattern and check its type for privacy.
@@ -1609,8 +1605,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
                     let mut found_pub_static = false;
                     for impl_item_ref in impl_.items {
                         if self.access_levels.is_reachable(impl_item_ref.id.def_id)
-                            || self.tcx.visibility(impl_item_ref.id.def_id)
-                                == ty::Visibility::Public
+                            || self.tcx.visibility(impl_item_ref.id.def_id).is_public()
                         {
                             let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
                             match impl_item_ref.kind {
@@ -1780,17 +1775,17 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
             );
         }
 
-        let hir_id = match def_id.as_local() {
-            Some(def_id) => self.tcx.hir().local_def_id_to_hir_id(def_id),
-            None => return false,
+        let Some(local_def_id) = def_id.as_local() else {
+            return false;
         };
 
-        let vis = self.tcx.visibility(def_id);
+        let vis = self.tcx.local_visibility(local_def_id);
         if !vis.is_at_least(self.required_visibility, self.tcx) {
+            let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id);
             let vis_descr = match vis {
                 ty::Visibility::Public => "public",
                 ty::Visibility::Restricted(vis_def_id) => {
-                    if vis_def_id == self.tcx.parent_module(hir_id).to_def_id() {
+                    if vis_def_id == self.tcx.parent_module(hir_id) {
                         "private"
                     } else if vis_def_id.is_top_level_module() {
                         "crate-private"
@@ -1906,7 +1901,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
 
     pub fn check_item(&mut self, id: ItemId) {
         let tcx = self.tcx;
-        let item_visibility = tcx.visibility(id.def_id);
+        let item_visibility = tcx.local_visibility(id.def_id);
         let def_kind = tcx.def_kind(id.def_id);
 
         match def_kind {
@@ -1957,7 +1952,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
                 let item = tcx.hir().item(id);
                 if let hir::ItemKind::ForeignMod { items, .. } = item.kind {
                     for foreign_item in items {
-                        let vis = tcx.visibility(foreign_item.id.def_id);
+                        let vis = tcx.local_visibility(foreign_item.id.def_id);
                         self.check(foreign_item.id.def_id, vis).generics().predicates().ty();
                     }
                 }
@@ -1972,7 +1967,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
 
                     for field in struct_def.fields() {
                         let def_id = tcx.hir().local_def_id(field.hir_id);
-                        let field_visibility = tcx.visibility(def_id);
+                        let field_visibility = tcx.local_visibility(def_id);
                         self.check(def_id, min(item_visibility, field_visibility, tcx)).ty();
                     }
                 }
@@ -1992,7 +1987,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
                     }
                     for impl_item_ref in impl_.items {
                         let impl_item_vis = if impl_.of_trait.is_none() {
-                            min(tcx.visibility(impl_item_ref.id.def_id), impl_vis, tcx)
+                            min(tcx.local_visibility(impl_item_ref.id.def_id), impl_vis, tcx)
                         } else {
                             impl_vis
                         };
@@ -2019,8 +2014,11 @@ pub fn provide(providers: &mut Providers) {
     };
 }
 
-fn visibility(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Visibility {
-    let def_id = def_id.expect_local();
+fn visibility(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Visibility<DefId> {
+    local_visibility(tcx, def_id.expect_local()).to_def_id()
+}
+
+fn local_visibility(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Visibility {
     match tcx.resolutions(()).visibilities.get(&def_id) {
         Some(vis) => *vis,
         None => {
@@ -2037,7 +2035,7 @@ fn visibility(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Visibility {
                 | Node::Item(hir::Item {
                     kind: hir::ItemKind::Use(_, hir::UseKind::ListStem) | hir::ItemKind::OpaqueTy(..),
                     ..
-                }) => ty::Visibility::Restricted(tcx.parent_module(hir_id).to_def_id()),
+                }) => ty::Visibility::Restricted(tcx.parent_module(hir_id)),
                 // Visibilities of trait impl items are inherited from their traits
                 // and are not filled in resolve.
                 Node::ImplItem(impl_item) => {
@@ -2050,7 +2048,7 @@ fn visibility(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Visibility {
                                 tcx.sess.delay_span_bug(tr.path.span, "trait without a def-id");
                                 ty::Visibility::Public
                             },
-                            |def_id| tcx.visibility(def_id),
+                            |def_id| tcx.visibility(def_id).expect_local(),
                         ),
                         _ => span_bug!(impl_item.span, "the parent is not a trait impl"),
                     }
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index 8ea09880694..26d397f70e0 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -34,9 +34,6 @@ pub use rustc_query_system::query::{deadlock, QueryContext};
 mod keys;
 use keys::Key;
 
-mod values;
-use self::values::Value;
-
 pub use rustc_query_system::query::QueryConfig;
 pub(crate) use rustc_query_system::query::{QueryDescription, QueryVTable};
 
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index 274df5b5e5e..1e375deb20d 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -18,6 +18,7 @@ use rustc_query_system::query::{
     force_query, QueryConfig, QueryContext, QueryDescription, QueryJobId, QueryMap,
     QuerySideEffects, QueryStackFrame,
 };
+use rustc_query_system::Value;
 use std::any::Any;
 use std::num::NonZeroU64;
 use thin_vec::ThinVec;
@@ -174,21 +175,17 @@ impl<'tcx> QueryCtxt<'tcx> {
 }
 
 macro_rules! handle_cycle_error {
-    ([][$tcx: expr, $error:expr]) => {{
-        $error.emit();
-        Value::from_cycle_error($tcx)
+    ([]) => {{
+        rustc_query_system::HandleCycleError::Error
     }};
-    ([(fatal_cycle) $($rest:tt)*][$tcx:expr, $error:expr]) => {{
-        $error.emit();
-        $tcx.sess.abort_if_errors();
-        unreachable!()
+    ([(fatal_cycle) $($rest:tt)*]) => {{
+        rustc_query_system::HandleCycleError::Fatal
     }};
-    ([(cycle_delay_bug) $($rest:tt)*][$tcx:expr, $error:expr]) => {{
-        $error.delay_as_bug();
-        Value::from_cycle_error($tcx)
+    ([(cycle_delay_bug) $($rest:tt)*]) => {{
+        rustc_query_system::HandleCycleError::DelayBug
     }};
-    ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
-        handle_cycle_error!([$($modifiers)*][$($args)*])
+    ([$other:tt $($modifiers:tt)*]) => {
+        handle_cycle_error!([$($modifiers)*])
     };
 }
 
@@ -320,6 +317,7 @@ fn force_from_dep_node<'tcx, Q>(tcx: TyCtxt<'tcx>, dep_node: DepNode) -> bool
 where
     Q: QueryDescription<QueryCtxt<'tcx>>,
     Q::Key: DepNodeParams<TyCtxt<'tcx>>,
+    Q::Value: Value<TyCtxt<'tcx>>,
 {
     if let Some(key) = Q::Key::recover(tcx, &dep_node) {
         #[cfg(debug_assertions)]
@@ -418,7 +416,7 @@ macro_rules! define_queries {
                     depth_limit: depth_limit!([$($modifiers)*]),
                     dep_kind: dep_graph::DepKind::$name,
                     hash_result: hash_result!([$($modifiers)*]),
-                    handle_cycle_error: |tcx, mut error| handle_cycle_error!([$($modifiers)*][tcx, error]),
+                    handle_cycle_error: handle_cycle_error!([$($modifiers)*]),
                     compute,
                     cache_on_disk,
                     try_load_from_disk: Self::TRY_LOAD_FROM_DISK,
diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml
index bafc6b0a082..d7599a56c0b 100644
--- a/compiler/rustc_query_system/Cargo.toml
+++ b/compiler/rustc_query_system/Cargo.toml
@@ -21,6 +21,7 @@ rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
+rustc_type_ir = { path = "../rustc_type_ir" }
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
 thin-vec = "0.2.8"
 tracing = "0.1"
diff --git a/compiler/rustc_query_system/src/error.rs b/compiler/rustc_query_system/src/error.rs
index 5f992ec9e21..3fb06cbedbd 100644
--- a/compiler/rustc_query_system/src/error.rs
+++ b/compiler/rustc_query_system/src/error.rs
@@ -12,6 +12,13 @@ impl AddSubdiagnostic for CycleStack {
     }
 }
 
+#[derive(Copy, Clone)]
+pub enum HandleCycleError {
+    Error,
+    Fatal,
+    DelayBug,
+}
+
 #[derive(SessionSubdiagnostic)]
 pub enum StackCount {
     #[note(query_system::cycle_stack_single)]
diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs
index d7732cb1825..0bc811eb044 100644
--- a/compiler/rustc_query_system/src/ich/impls_syntax.rs
+++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs
@@ -148,3 +148,5 @@ impl<'tcx> HashStable<StableHashingContext<'tcx>> for rustc_feature::Features {
         });
     }
 }
+
+impl<'ctx> rustc_type_ir::HashStableContext for StableHashingContext<'ctx> {}
diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs
index 7067bc5f09c..8a88b5c3340 100644
--- a/compiler/rustc_query_system/src/lib.rs
+++ b/compiler/rustc_query_system/src/lib.rs
@@ -20,3 +20,7 @@ pub mod dep_graph;
 mod error;
 pub mod ich;
 pub mod query;
+mod values;
+
+pub use error::HandleCycleError;
+pub use values::Value;
diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs
index ea38df836cb..c63e110a62e 100644
--- a/compiler/rustc_query_system/src/query/config.rs
+++ b/compiler/rustc_query_system/src/query/config.rs
@@ -2,12 +2,12 @@
 
 use crate::dep_graph::DepNode;
 use crate::dep_graph::SerializedDepNodeIndex;
+use crate::error::HandleCycleError;
 use crate::ich::StableHashingContext;
 use crate::query::caches::QueryCache;
 use crate::query::{QueryContext, QueryState};
 
 use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
 use std::fmt::Debug;
 use std::hash::Hash;
 
@@ -19,6 +19,7 @@ pub trait QueryConfig {
     type Stored: Clone;
 }
 
+#[derive(Copy, Clone)]
 pub struct QueryVTable<CTX: QueryContext, K, V> {
     pub anon: bool,
     pub dep_kind: CTX::DepKind,
@@ -28,7 +29,7 @@ pub struct QueryVTable<CTX: QueryContext, K, V> {
 
     pub compute: fn(CTX::DepContext, K) -> V,
     pub hash_result: Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>,
-    pub handle_cycle_error: fn(CTX, DiagnosticBuilder<'_, ErrorGuaranteed>) -> V,
+    pub handle_cycle_error: HandleCycleError,
     pub try_load_from_disk: Option<fn(CTX, SerializedDepNodeIndex) -> Option<V>>,
 }
 
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index ddb5cd06344..45b4079fb54 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -572,7 +572,7 @@ pub(crate) fn report_cycle<'a>(
         stack_count,
     };
 
-    cycle_diag.into_diagnostic(&sess.parse_sess)
+    cycle_diag.into_diagnostic(&sess.parse_sess.span_diagnostic)
 }
 
 pub fn print_query_stack<CTX: QueryContext>(
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index 7bbc22e8293..e39e39860cb 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -7,6 +7,8 @@ use crate::query::caches::QueryCache;
 use crate::query::config::{QueryDescription, QueryVTable};
 use crate::query::job::{report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo};
 use crate::query::{QueryContext, QueryMap, QuerySideEffects, QueryStackFrame};
+use crate::values::Value;
+use crate::HandleCycleError;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
 #[cfg(parallel_compiler)]
@@ -118,19 +120,46 @@ where
 fn mk_cycle<CTX, V, R>(
     tcx: CTX,
     error: CycleError,
-    handle_cycle_error: fn(CTX, DiagnosticBuilder<'_, ErrorGuaranteed>) -> V,
+    handler: HandleCycleError,
     cache: &dyn crate::query::QueryStorage<Value = V, Stored = R>,
 ) -> R
 where
     CTX: QueryContext,
-    V: std::fmt::Debug,
+    V: std::fmt::Debug + Value<CTX::DepContext>,
     R: Clone,
 {
     let error = report_cycle(tcx.dep_context().sess(), error);
-    let value = handle_cycle_error(tcx, error);
+    let value = handle_cycle_error(*tcx.dep_context(), error, handler);
     cache.store_nocache(value)
 }
 
+fn handle_cycle_error<CTX, V>(
+    tcx: CTX,
+    mut error: DiagnosticBuilder<'_, ErrorGuaranteed>,
+    handler: HandleCycleError,
+) -> V
+where
+    CTX: DepContext,
+    V: Value<CTX>,
+{
+    use HandleCycleError::*;
+    match handler {
+        Error => {
+            error.emit();
+            Value::from_cycle_error(tcx)
+        }
+        Fatal => {
+            error.emit();
+            tcx.sess().abort_if_errors();
+            unreachable!()
+        }
+        DelayBug => {
+            error.delay_as_bug();
+            Value::from_cycle_error(tcx)
+        }
+    }
+}
+
 impl<'tcx, K> JobOwner<'tcx, K>
 where
     K: Eq + Hash + Clone,
@@ -336,6 +365,7 @@ fn try_execute_query<CTX, C>(
 where
     C: QueryCache,
     C::Key: Clone + DepNodeParams<CTX::DepContext>,
+    C::Value: Value<CTX::DepContext>,
     CTX: QueryContext,
 {
     match JobOwner::<'_, C::Key>::try_start(&tcx, state, span, key.clone()) {
@@ -686,6 +716,7 @@ pub fn get_query<Q, CTX>(tcx: CTX, span: Span, key: Q::Key, mode: QueryMode) ->
 where
     Q: QueryDescription<CTX>,
     Q::Key: DepNodeParams<CTX::DepContext>,
+    Q::Value: Value<CTX::DepContext>,
     CTX: QueryContext,
 {
     let query = Q::make_vtable(tcx, &key);
@@ -718,6 +749,7 @@ pub fn force_query<Q, CTX>(tcx: CTX, key: Q::Key, dep_node: DepNode<CTX::DepKind
 where
     Q: QueryDescription<CTX>,
     Q::Key: DepNodeParams<CTX::DepContext>,
+    Q::Value: Value<CTX::DepContext>,
     CTX: QueryContext,
 {
     // We may be concurrently trying both execute and force a query.
diff --git a/compiler/rustc_query_system/src/values.rs b/compiler/rustc_query_system/src/values.rs
new file mode 100644
index 00000000000..aeef66f86da
--- /dev/null
+++ b/compiler/rustc_query_system/src/values.rs
@@ -0,0 +1,14 @@
+use crate::dep_graph::DepContext;
+
+pub trait Value<CTX: DepContext>: Sized {
+    fn from_cycle_error(tcx: CTX) -> Self;
+}
+
+impl<CTX: DepContext, T> Value<CTX> for T {
+    default fn from_cycle_error(tcx: CTX) -> T {
+        tcx.sess().abort_if_errors();
+        // Ideally we would use `bug!` here. But bug! is only defined in rustc_middle, and it's
+        // non-trivial to define it earlier.
+        panic!("Value::from_cycle_error called without errors");
+    }
+}
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 51e8c24b9c2..9cb735b3685 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -39,24 +39,26 @@ use std::ptr;
 
 type Res = def::Res<NodeId>;
 
-impl<'a> ToNameBinding<'a> for (Module<'a>, ty::Visibility, Span, LocalExpnId) {
+impl<'a, Id: Into<DefId>> ToNameBinding<'a>
+    for (Module<'a>, ty::Visibility<Id>, Span, LocalExpnId)
+{
     fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> {
         arenas.alloc_name_binding(NameBinding {
             kind: NameBindingKind::Module(self.0),
             ambiguity: None,
-            vis: self.1,
+            vis: self.1.to_def_id(),
             span: self.2,
             expansion: self.3,
         })
     }
 }
 
-impl<'a> ToNameBinding<'a> for (Res, ty::Visibility, Span, LocalExpnId) {
+impl<'a, Id: Into<DefId>> ToNameBinding<'a> for (Res, ty::Visibility<Id>, Span, LocalExpnId) {
     fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> {
         arenas.alloc_name_binding(NameBinding {
             kind: NameBindingKind::Res(self.0, false),
             ambiguity: None,
-            vis: self.1,
+            vis: self.1.to_def_id(),
             span: self.2,
             expansion: self.3,
         })
@@ -70,7 +72,7 @@ impl<'a> ToNameBinding<'a> for (Res, ty::Visibility, Span, LocalExpnId, IsMacroE
         arenas.alloc_name_binding(NameBinding {
             kind: NameBindingKind::Res(self.0, true),
             ambiguity: None,
-            vis: self.1,
+            vis: self.1.to_def_id(),
             span: self.2,
             expansion: self.3,
         })
@@ -260,7 +262,9 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                         self.r.visibilities[&def_id.expect_local()]
                     }
                     // Otherwise, the visibility is restricted to the nearest parent `mod` item.
-                    _ => ty::Visibility::Restricted(self.parent_scope.module.nearest_parent_mod()),
+                    _ => ty::Visibility::Restricted(
+                        self.parent_scope.module.nearest_parent_mod().expect_local(),
+                    ),
                 })
             }
             ast::VisibilityKind::Restricted { ref path, id, .. } => {
@@ -311,7 +315,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                             } else {
                                 let vis = ty::Visibility::Restricted(res.def_id());
                                 if self.r.is_accessible_from(vis, parent_scope.module) {
-                                    Ok(vis)
+                                    Ok(vis.expect_local())
                                 } else {
                                     Err(VisResolutionError::AncestorOnly(path.span))
                                 }
@@ -649,7 +653,9 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                         true,
                         // The whole `use` item
                         item,
-                        ty::Visibility::Restricted(self.parent_scope.module.nearest_parent_mod()),
+                        ty::Visibility::Restricted(
+                            self.parent_scope.module.nearest_parent_mod().expect_local(),
+                        ),
                         root_span,
                     );
                 }
@@ -765,10 +771,10 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                 if let Some(ctor_node_id) = vdata.ctor_id() {
                     // If the structure is marked as non_exhaustive then lower the visibility
                     // to within the crate.
-                    let mut ctor_vis = if vis == ty::Visibility::Public
+                    let mut ctor_vis = if vis.is_public()
                         && self.r.session.contains_name(&item.attrs, sym::non_exhaustive)
                     {
-                        ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id())
+                        ty::Visibility::Restricted(CRATE_DEF_ID)
                     } else {
                         vis
                     };
@@ -785,7 +791,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                         if ctor_vis.is_at_least(field_vis, &*self.r) {
                             ctor_vis = field_vis;
                         }
-                        ret_fields.push(field_vis);
+                        ret_fields.push(field_vis.to_def_id());
                     }
                     let ctor_def_id = self.r.local_def_id(ctor_node_id);
                     let ctor_res = Res::Def(
@@ -795,7 +801,9 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                     self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion));
                     self.r.visibilities.insert(ctor_def_id, ctor_vis);
 
-                    self.r.struct_constructors.insert(def_id, (ctor_res, ctor_vis, ret_fields));
+                    self.r
+                        .struct_constructors
+                        .insert(def_id, (ctor_res, ctor_vis.to_def_id(), ret_fields));
                 }
             }
 
@@ -867,8 +875,8 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
         }
         .map(|module| {
             let used = self.process_macro_use_imports(item, module);
-            let binding =
-                (module, ty::Visibility::Public, sp, expansion).to_name_binding(self.r.arenas);
+            let vis = ty::Visibility::<LocalDefId>::Public;
+            let binding = (module, vis, sp, expansion).to_name_binding(self.r.arenas);
             (used, Some(ModuleOrUniformRoot::Module(module)), binding)
         })
         .unwrap_or((true, None, self.r.dummy_binding));
@@ -1117,7 +1125,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                 root_span: span,
                 span,
                 module_path: Vec::new(),
-                vis: Cell::new(Some(ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id()))),
+                vis: Cell::new(Some(ty::Visibility::Restricted(CRATE_DEF_ID))),
                 used: Cell::new(false),
             })
         };
@@ -1263,7 +1271,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
             let vis = if is_macro_export {
                 ty::Visibility::Public
             } else {
-                ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id())
+                ty::Visibility::Restricted(CRATE_DEF_ID)
             };
             let binding = (res, vis, span, expansion).to_name_binding(self.r.arenas);
             self.r.set_binding_parent_module(binding, parent_scope.module);
@@ -1294,7 +1302,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                 }
                 _ => self.resolve_visibility(&item.vis),
             };
-            if vis != ty::Visibility::Public {
+            if !vis.is_public() {
                 self.insert_unused_macro(ident, def_id, item.id, &rule_spans);
             }
             self.r.define(module, ident, MacroNS, (res, vis, span, expansion));
@@ -1507,10 +1515,10 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
         self.r.visibilities.insert(def_id, vis);
 
         // If the variant is marked as non_exhaustive then lower the visibility to within the crate.
-        let ctor_vis = if vis == ty::Visibility::Public
+        let ctor_vis = if vis.is_public()
             && self.r.session.contains_name(&variant.attrs, sym::non_exhaustive)
         {
-            ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id())
+            ty::Visibility::Restricted(CRATE_DEF_ID)
         } else {
             vis
         };
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index b84a610833d..2287aa1eb25 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -6,6 +6,7 @@ use rustc_middle::bug;
 use rustc_middle::ty;
 use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK;
 use rustc_session::lint::BuiltinLintDiagnostics;
+use rustc_span::def_id::LocalDefId;
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext};
 use rustc_span::symbol::{kw, Ident};
@@ -26,6 +27,8 @@ use Determinacy::*;
 use Namespace::*;
 use RibKind::*;
 
+type Visibility = ty::Visibility<LocalDefId>;
+
 impl<'a> Resolver<'a> {
     /// A generic scope visitor.
     /// Visits scopes in order to resolve some identifier in them or perform other actions.
@@ -424,8 +427,7 @@ impl<'a> Resolver<'a> {
                 let ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt));
                 let ok = |res, span, arenas| {
                     Ok((
-                        (res, ty::Visibility::Public, span, LocalExpnId::ROOT)
-                            .to_name_binding(arenas),
+                        (res, Visibility::Public, span, LocalExpnId::ROOT).to_name_binding(arenas),
                         Flags::empty(),
                     ))
                 };
@@ -438,7 +440,7 @@ impl<'a> Resolver<'a> {
                         {
                             let binding = (
                                 Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
-                                ty::Visibility::Public,
+                                Visibility::Public,
                                 attr.span,
                                 expn_id,
                             )
@@ -841,9 +843,8 @@ impl<'a> Resolver<'a> {
                 if ns == TypeNS {
                     if ident.name == kw::Crate || ident.name == kw::DollarCrate {
                         let module = self.resolve_crate_root(ident);
-                        let binding =
-                            (module, ty::Visibility::Public, module.span, LocalExpnId::ROOT)
-                                .to_name_binding(self.arenas);
+                        let binding = (module, Visibility::Public, module.span, LocalExpnId::ROOT)
+                            .to_name_binding(self.arenas);
                         return Ok(binding);
                     } else if ident.name == kw::Super || ident.name == kw::SelfLower {
                         // FIXME: Implement these with renaming requirements so that e.g.
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 27745cee52d..c133c272bac 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -214,7 +214,7 @@ impl<'a> Resolver<'a> {
         binding: &'a NameBinding<'a>,
         import: &'a Import<'a>,
     ) -> &'a NameBinding<'a> {
-        let import_vis = import.expect_vis();
+        let import_vis = import.expect_vis().to_def_id();
         let vis = if binding.vis.is_at_least(import_vis, self)
             || pub_use_of_private_extern_crate_hack(import, binding)
         {
@@ -227,7 +227,7 @@ impl<'a> Resolver<'a> {
             if vis == import_vis
                 || max_vis.get().map_or(true, |max_vis| vis.is_at_least(max_vis, self))
             {
-                max_vis.set(Some(vis))
+                max_vis.set(Some(vis.expect_local()))
             }
         }
 
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index dbe4d691f04..b37feb15890 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -20,7 +20,7 @@ use rustc_errors::DiagnosticId;
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, PartialRes, PerNS};
 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
-use rustc_hir::{PrimTy, TraitCandidate};
+use rustc_hir::{BindingAnnotation, PrimTy, TraitCandidate};
 use rustc_middle::middle::resolve_lifetime::Set1;
 use rustc_middle::ty::DefIdTree;
 use rustc_middle::{bug, span_bug};
@@ -50,7 +50,7 @@ use diagnostics::{
 #[derive(Copy, Clone, Debug)]
 struct BindingInfo {
     span: Span,
-    binding_mode: BindingMode,
+    annotation: BindingAnnotation,
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
@@ -2865,10 +2865,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
 
         pat.walk(&mut |pat| {
             match pat.kind {
-                PatKind::Ident(binding_mode, ident, ref sub_pat)
+                PatKind::Ident(annotation, ident, ref sub_pat)
                     if sub_pat.is_some() || self.is_base_res_local(pat.id) =>
                 {
-                    binding_map.insert(ident, BindingInfo { span: ident.span, binding_mode });
+                    binding_map.insert(ident, BindingInfo { span: ident.span, annotation });
                 }
                 PatKind::Or(ref ps) => {
                     // Check the consistency of this or-pattern and
@@ -2925,7 +2925,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                         binding_error.target.insert(pat_outer.span);
                     }
                     Some(binding_outer) => {
-                        if binding_outer.binding_mode != binding_inner.binding_mode {
+                        if binding_outer.annotation != binding_inner.annotation {
                             // The binding modes in the outer and inner bindings differ.
                             inconsistent_vars
                                 .entry(name)
@@ -3146,14 +3146,14 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
     fn try_resolve_as_non_binding(
         &mut self,
         pat_src: PatternSource,
-        bm: BindingMode,
+        ann: BindingAnnotation,
         ident: Ident,
         has_sub: bool,
     ) -> Option<Res> {
         // An immutable (no `mut`) by-value (no `ref`) binding pattern without
         // a sub pattern (no `@ $pat`) is syntactically ambiguous as it could
         // also be interpreted as a path to e.g. a constant, variant, etc.
-        let is_syntactic_ambiguity = !has_sub && bm == BindingMode::ByValue(Mutability::Not);
+        let is_syntactic_ambiguity = !has_sub && ann == BindingAnnotation::NONE;
 
         let ls_binding = self.maybe_resolve_ident_in_lexical_scope(ident, ValueNS)?;
         let (res, binding) = match ls_binding {
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index c72981ed96f..101679aa6dc 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -525,6 +525,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
         }
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
         match &item.kind {
             hir::ItemKind::Impl(hir::Impl { of_trait, .. }) => {
@@ -839,6 +840,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
         }
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
         use self::hir::TraitItemKind::*;
         match trait_item.kind {
@@ -888,6 +890,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
         }
     }
 
+    #[instrument(level = "debug", skip(self))]
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
         use self::hir::ImplItemKind::*;
         match impl_item.kind {
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index a15a0c298a9..749a78a7552 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -57,7 +57,7 @@ use rustc_span::{Span, DUMMY_SP};
 use smallvec::{smallvec, SmallVec};
 use std::cell::{Cell, RefCell};
 use std::collections::BTreeSet;
-use std::{cmp, fmt, ptr};
+use std::{fmt, ptr};
 
 use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion};
 use imports::{Import, ImportKind, ImportResolver, NameResolution};
@@ -163,7 +163,6 @@ enum ImplTraitContext {
     Universal(LocalDefId),
 }
 
-#[derive(Eq)]
 struct BindingError {
     name: Symbol,
     origin: BTreeSet<Span>,
@@ -171,24 +170,6 @@ struct BindingError {
     could_be_path: bool,
 }
 
-impl PartialOrd for BindingError {
-    fn partial_cmp(&self, other: &BindingError) -> Option<cmp::Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-impl PartialEq for BindingError {
-    fn eq(&self, other: &BindingError) -> bool {
-        self.name == other.name
-    }
-}
-
-impl Ord for BindingError {
-    fn cmp(&self, other: &BindingError) -> cmp::Ordering {
-        self.name.cmp(&other.name)
-    }
-}
-
 enum ResolutionError<'a> {
     /// Error E0401: can't use type or const parameters from outer function.
     GenericParamsFromOuterFunction(Res, HasGenericParams),
@@ -648,7 +629,7 @@ pub struct NameBinding<'a> {
     ambiguity: Option<(&'a NameBinding<'a>, AmbiguityKind)>,
     expansion: LocalExpnId,
     span: Span,
-    vis: ty::Visibility,
+    vis: ty::Visibility<DefId>,
 }
 
 pub trait ToNameBinding<'a> {
@@ -845,7 +826,7 @@ impl<'a> NameBinding<'a> {
     }
 }
 
-#[derive(Debug, Default, Clone)]
+#[derive(Default, Clone)]
 pub struct ExternPreludeEntry<'a> {
     extern_crate_item: Option<&'a NameBinding<'a>>,
     pub introduced_by_item: bool,
@@ -911,11 +892,6 @@ pub struct Resolver<'a> {
     label_res_map: NodeMap<NodeId>,
     /// Resolutions for lifetimes.
     lifetimes_res_map: NodeMap<LifetimeRes>,
-    /// Mapping from generics `def_id`s to TAIT generics `def_id`s.
-    /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic
-    /// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this
-    /// field from the original parameter 'a to the new parameter 'a1.
-    generics_def_id_map: Vec<FxHashMap<LocalDefId, LocalDefId>>,
     /// Lifetime parameters that lowering will have to introduce.
     extra_lifetime_params_map: NodeMap<Vec<(Ident, NodeId, LifetimeRes)>>,
 
@@ -1017,7 +993,7 @@ pub struct Resolver<'a> {
     /// Table for mapping struct IDs into struct constructor IDs,
     /// it's not used during normal resolution, only for better error reporting.
     /// Also includes of list of each fields visibility
-    struct_constructors: DefIdMap<(Res, ty::Visibility, Vec<ty::Visibility>)>,
+    struct_constructors: DefIdMap<(Res, ty::Visibility<DefId>, Vec<ty::Visibility<DefId>>)>,
 
     /// Features enabled for this crate.
     active_features: FxHashSet<Symbol>,
@@ -1278,7 +1254,6 @@ impl<'a> Resolver<'a> {
             import_res_map: Default::default(),
             label_res_map: Default::default(),
             lifetimes_res_map: Default::default(),
-            generics_def_id_map: Vec::new(),
             extra_lifetime_params_map: Default::default(),
             extern_crate_map: Default::default(),
             reexport_map: FxHashMap::default(),
@@ -1445,7 +1420,6 @@ impl<'a> Resolver<'a> {
             import_res_map: self.import_res_map,
             label_res_map: self.label_res_map,
             lifetimes_res_map: self.lifetimes_res_map,
-            generics_def_id_map: self.generics_def_id_map,
             extra_lifetime_params_map: self.extra_lifetime_params_map,
             next_node_id: self.next_node_id,
             node_id_to_def_id: self.node_id_to_def_id,
@@ -1490,7 +1464,6 @@ impl<'a> Resolver<'a> {
             import_res_map: self.import_res_map.clone(),
             label_res_map: self.label_res_map.clone(),
             lifetimes_res_map: self.lifetimes_res_map.clone(),
-            generics_def_id_map: self.generics_def_id_map.clone(),
             extra_lifetime_params_map: self.extra_lifetime_params_map.clone(),
             next_node_id: self.next_node_id.clone(),
             node_id_to_def_id: self.node_id_to_def_id.clone(),
@@ -1816,7 +1789,11 @@ impl<'a> Resolver<'a> {
         self.pat_span_map.insert(node, span);
     }
 
-    fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool {
+    fn is_accessible_from(
+        &self,
+        vis: ty::Visibility<impl Into<DefId>>,
+        module: Module<'a>,
+    ) -> bool {
         vis.is_accessible_from(module.nearest_parent_mod(), self)
     }
 
@@ -1870,10 +1847,8 @@ impl<'a> Resolver<'a> {
                     self.crate_loader.maybe_process_path_extern(ident.name)?
                 };
                 let crate_root = self.expect_module(crate_id.as_def_id());
-                Some(
-                    (crate_root, ty::Visibility::Public, DUMMY_SP, LocalExpnId::ROOT)
-                        .to_name_binding(self.arenas),
-                )
+                let vis = ty::Visibility::<LocalDefId>::Public;
+                Some((crate_root, vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(self.arenas))
             }
         })
     }
diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs
index c9fc6b9e47a..6658892881d 100644
--- a/compiler/rustc_save_analysis/src/dump_visitor.rs
+++ b/compiler/rustc_save_analysis/src/dump_visitor.rs
@@ -803,6 +803,7 @@ impl<'tcx> DumpVisitor<'tcx> {
         &mut self,
         ex: &'tcx hir::Expr<'tcx>,
         seg: &'tcx hir::PathSegment<'tcx>,
+        receiver: &'tcx hir::Expr<'tcx>,
         args: &'tcx [hir::Expr<'tcx>],
     ) {
         debug!("process_method_call {:?} {:?}", ex, ex.span);
@@ -823,6 +824,7 @@ impl<'tcx> DumpVisitor<'tcx> {
         }
 
         // walk receiver and args
+        self.visit_expr(receiver);
         walk_list!(self, visit_expr, args);
     }
 
@@ -912,7 +914,10 @@ impl<'tcx> DumpVisitor<'tcx> {
                     _,
                 )
                 | Res::SelfTy { .. } => {
-                    self.dump_path_segment_ref(id, &hir::PathSegment::from_ident(ident));
+                    self.dump_path_segment_ref(
+                        id,
+                        &hir::PathSegment::new(ident, hir::HirId::INVALID, Res::Err),
+                    );
                 }
                 def => {
                     error!("unexpected definition kind when processing collected idents: {:?}", def)
@@ -1340,7 +1345,9 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
                 let res = self.save_ctxt.get_path_res(hir_expr.hir_id);
                 self.process_struct_lit(ex, path, fields, adt.variant_of_res(res), *rest)
             }
-            hir::ExprKind::MethodCall(ref seg, args, _) => self.process_method_call(ex, seg, args),
+            hir::ExprKind::MethodCall(ref seg, receiver, args, _) => {
+                self.process_method_call(ex, seg, receiver, args)
+            }
             hir::ExprKind::Field(ref sub_ex, _) => {
                 self.visit_expr(&sub_ex);
 
diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs
index 16af5338510..89bca39512f 100644
--- a/compiler/rustc_save_analysis/src/lib.rs
+++ b/compiler/rustc_save_analysis/src/lib.rs
@@ -596,13 +596,14 @@ impl<'tcx> SaveContext<'tcx> {
             Node::TraitRef(tr) => tr.path.res,
 
             Node::Item(&hir::Item { kind: hir::ItemKind::Use(path, _), .. }) => path.res,
-            Node::PathSegment(seg) => match seg.res {
-                Some(res) if res != Res::Err => res,
-                _ => {
+            Node::PathSegment(seg) => {
+                if seg.res != Res::Err {
+                    seg.res
+                } else {
                     let parent_node = self.tcx.hir().get_parent_node(hir_id);
                     self.get_path_res(parent_node)
                 }
-            },
+            }
 
             Node::Expr(&hir::Expr { kind: hir::ExprKind::Struct(ref qpath, ..), .. }) => {
                 self.typeck_results().qpath_res(qpath, hir_id)
@@ -648,7 +649,7 @@ impl<'tcx> SaveContext<'tcx> {
     }
 
     pub fn get_path_segment_data(&self, path_seg: &hir::PathSegment<'_>) -> Option<Ref> {
-        self.get_path_segment_data_with_id(path_seg, path_seg.hir_id?)
+        self.get_path_segment_data_with_id(path_seg, path_seg.hir_id)
     }
 
     pub fn get_path_segment_data_with_id(
@@ -865,23 +866,12 @@ impl<'l> Visitor<'l> for PathCollector<'l> {
             hir::PatKind::TupleStruct(ref path, ..) | hir::PatKind::Path(ref path) => {
                 self.collected_paths.push((p.hir_id, path));
             }
-            hir::PatKind::Binding(bm, _, ident, _) => {
+            hir::PatKind::Binding(hir::BindingAnnotation(_, mutbl), _, ident, _) => {
                 debug!(
                     "PathCollector, visit ident in pat {}: {:?} {:?}",
                     ident, p.span, ident.span
                 );
-                let immut = match bm {
-                    // Even if the ref is mut, you can't change the ref, only
-                    // the data pointed at, so showing the initialising expression
-                    // is still worthwhile.
-                    hir::BindingAnnotation::Unannotated | hir::BindingAnnotation::Ref => {
-                        hir::Mutability::Not
-                    }
-                    hir::BindingAnnotation::Mutable | hir::BindingAnnotation::RefMut => {
-                        hir::Mutability::Mut
-                    }
-                };
-                self.collected_idents.push((p.hir_id, ident, immut));
+                self.collected_idents.push((p.hir_id, ident, mutbl));
             }
             _ => {}
         }
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 04bd685f190..8bb3878fbbb 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -898,7 +898,7 @@ fn default_configuration(sess: &Session) -> CrateConfig {
     let max_atomic_width = sess.target.max_atomic_width();
     let atomic_cas = sess.target.atomic_cas;
     let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
-        sess.fatal(&err);
+        sess.emit_fatal(err);
     });
 
     let mut ret = CrateConfig::default();
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index 7252f1799da..3c93cfab183 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -1,10 +1,12 @@
 use std::num::NonZeroU32;
 
-use crate as rustc_session;
 use crate::cgu_reuse_tracker::CguReuse;
-use rustc_errors::MultiSpan;
+use crate::{self as rustc_session, SessionDiagnostic};
+use rustc_errors::{fluent, DiagnosticBuilder, Handler, MultiSpan};
 use rustc_macros::SessionDiagnostic;
 use rustc_span::{Span, Symbol};
+use rustc_target::abi::TargetDataLayoutErrors;
+use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple};
 
 #[derive(SessionDiagnostic)]
 #[diag(session::incorrect_cgu_reuse_type)]
@@ -43,3 +45,128 @@ pub struct FeatureDiagnosticForIssue {
 pub struct FeatureDiagnosticHelp {
     pub feature: Symbol,
 }
+
+impl SessionDiagnostic<'_, !> for TargetDataLayoutErrors<'_> {
+    fn into_diagnostic(self, sess: &Handler) -> DiagnosticBuilder<'_, !> {
+        let mut diag;
+        match self {
+            TargetDataLayoutErrors::InvalidAddressSpace { addr_space, err, cause } => {
+                diag = sess.struct_fatal(fluent::session::target_invalid_address_space);
+                diag.set_arg("addr_space", addr_space);
+                diag.set_arg("cause", cause);
+                diag.set_arg("err", err);
+                diag
+            }
+            TargetDataLayoutErrors::InvalidBits { kind, bit, cause, err } => {
+                diag = sess.struct_fatal(fluent::session::target_invalid_bits);
+                diag.set_arg("kind", kind);
+                diag.set_arg("bit", bit);
+                diag.set_arg("cause", cause);
+                diag.set_arg("err", err);
+                diag
+            }
+            TargetDataLayoutErrors::MissingAlignment { cause } => {
+                diag = sess.struct_fatal(fluent::session::target_missing_alignment);
+                diag.set_arg("cause", cause);
+                diag
+            }
+            TargetDataLayoutErrors::InvalidAlignment { cause, err } => {
+                diag = sess.struct_fatal(fluent::session::target_invalid_alignment);
+                diag.set_arg("cause", cause);
+                diag.set_arg("err", err);
+                diag
+            }
+            TargetDataLayoutErrors::InconsistentTargetArchitecture { dl, target } => {
+                diag = sess.struct_fatal(fluent::session::target_inconsistent_architecture);
+                diag.set_arg("dl", dl);
+                diag.set_arg("target", target);
+                diag
+            }
+            TargetDataLayoutErrors::InconsistentTargetPointerWidth { pointer_size, target } => {
+                diag = sess.struct_fatal(fluent::session::target_inconsistent_pointer_width);
+                diag.set_arg("pointer_size", pointer_size);
+                diag.set_arg("target", target);
+                diag
+            }
+            TargetDataLayoutErrors::InvalidBitsSize { err } => {
+                diag = sess.struct_fatal(fluent::session::target_invalid_bits_size);
+                diag.set_arg("err", err);
+                diag
+            }
+        }
+    }
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(session::not_circumvent_feature)]
+pub struct NotCircumventFeature;
+
+#[derive(SessionDiagnostic)]
+#[diag(session::linker_plugin_lto_windows_not_supported)]
+pub struct LinkerPluginToWindowsNotSupported;
+
+#[derive(SessionDiagnostic)]
+#[diag(session::profile_use_file_does_not_exist)]
+pub struct ProfileUseFileDoesNotExist<'a> {
+    pub path: &'a std::path::Path,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(session::profile_sample_use_file_does_not_exist)]
+pub struct ProfileSampleUseFileDoesNotExist<'a> {
+    pub path: &'a std::path::Path,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(session::target_requires_unwind_tables)]
+pub struct TargetRequiresUnwindTables;
+
+#[derive(SessionDiagnostic)]
+#[diag(session::sanitizer_not_supported)]
+pub struct SanitizerNotSupported {
+    pub us: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(session::sanitizers_not_supported)]
+pub struct SanitizersNotSupported {
+    pub us: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(session::cannot_mix_and_match_sanitizers)]
+pub struct CannotMixAndMatchSanitizers {
+    pub first: String,
+    pub second: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(session::cannot_enable_crt_static_linux)]
+pub struct CannotEnableCrtStaticLinux;
+
+#[derive(SessionDiagnostic)]
+#[diag(session::sanitizer_cfi_enabled)]
+pub struct SanitizerCfiEnabled;
+
+#[derive(SessionDiagnostic)]
+#[diag(session::unstable_virtual_function_elimination)]
+pub struct UnstableVirtualFunctionElimination;
+
+#[derive(SessionDiagnostic)]
+#[diag(session::unsupported_dwarf_version)]
+pub struct UnsupportedDwarfVersion {
+    pub dwarf_version: u32,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(session::target_stack_protector_not_supported)]
+pub struct StackProtectorNotSupportedForTarget<'a> {
+    pub stack_protector: StackProtector,
+    pub target_triple: &'a TargetTriple,
+}
+
+#[derive(SessionDiagnostic)]
+#[diag(session::split_debuginfo_unstable_platform)]
+pub struct SplitDebugInfoUnstablePlatform {
+    pub debuginfo: SplitDebuginfo,
+}
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index 5b95d73bd4d..9bc7fbfbe14 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -343,7 +343,7 @@ impl ParseSess {
         &'a self,
         err: impl SessionDiagnostic<'a>,
     ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
-        err.into_diagnostic(self)
+        err.into_diagnostic(&self.span_diagnostic)
     }
 
     pub fn emit_err<'a>(&'a self, err: impl SessionDiagnostic<'a>) -> ErrorGuaranteed {
@@ -354,7 +354,7 @@ impl ParseSess {
         &'a self,
         warning: impl SessionDiagnostic<'a, ()>,
     ) -> DiagnosticBuilder<'a, ()> {
-        warning.into_diagnostic(self)
+        warning.into_diagnostic(&self.span_diagnostic)
     }
 
     pub fn emit_warning<'a>(&'a self, warning: impl SessionDiagnostic<'a, ()>) {
@@ -365,7 +365,7 @@ impl ParseSess {
         &'a self,
         fatal: impl SessionDiagnostic<'a, !>,
     ) -> DiagnosticBuilder<'a, !> {
-        fatal.into_diagnostic(self)
+        fatal.into_diagnostic(&self.span_diagnostic)
     }
 
     pub fn emit_fatal<'a>(&'a self, fatal: impl SessionDiagnostic<'a, !>) -> ! {
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index a49af23be23..caf9d582ab0 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -2,6 +2,13 @@ use crate::cgu_reuse_tracker::CguReuseTracker;
 use crate::code_stats::CodeStats;
 pub use crate::code_stats::{DataTypeKind, FieldInfo, SizeKind, VariantInfo};
 use crate::config::{self, CrateType, InstrumentCoverage, OptLevel, OutputType, SwitchWithOptPath};
+use crate::errors::{
+    CannotEnableCrtStaticLinux, CannotMixAndMatchSanitizers, LinkerPluginToWindowsNotSupported,
+    NotCircumventFeature, ProfileSampleUseFileDoesNotExist, ProfileUseFileDoesNotExist,
+    SanitizerCfiEnabled, SanitizerNotSupported, SanitizersNotSupported,
+    SplitDebugInfoUnstablePlatform, StackProtectorNotSupportedForTarget,
+    TargetRequiresUnwindTables, UnstableVirtualFunctionElimination, UnsupportedDwarfVersion,
+};
 use crate::parse::{add_feature_diagnostics, ParseSess};
 use crate::search_paths::{PathKind, SearchPath};
 use crate::{filesearch, lint};
@@ -21,7 +28,7 @@ use rustc_errors::json::JsonEmitter;
 use rustc_errors::registry::Registry;
 use rustc_errors::{
     error_code, fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage,
-    EmissionGuarantee, ErrorGuaranteed, FluentBundle, LazyFallbackBundle, MultiSpan,
+    EmissionGuarantee, ErrorGuaranteed, FluentBundle, Handler, LazyFallbackBundle, MultiSpan,
 };
 use rustc_macros::HashStable_Generic;
 pub use rustc_span::def_id::StableCrateId;
@@ -220,9 +227,9 @@ pub struct PerfStats {
 /// `#[derive(SessionDiagnostic)]` -- see [rustc_macros::SessionDiagnostic].
 #[rustc_diagnostic_item = "SessionDiagnostic"]
 pub trait SessionDiagnostic<'a, T: EmissionGuarantee = ErrorGuaranteed> {
-    /// Write out as a diagnostic out of `sess`.
+    /// Write out as a diagnostic out of `Handler`.
     #[must_use]
-    fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, T>;
+    fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, T>;
 }
 
 impl Session {
@@ -235,6 +242,9 @@ impl Session {
         if !unleashed_features.is_empty() {
             let mut must_err = false;
             // Create a diagnostic pointing at where things got unleashed.
+            // FIXME(#100717): needs eager translation/lists
+            #[allow(rustc::untranslatable_diagnostic)]
+            #[allow(rustc::diagnostic_outside_of_impl)]
             let mut diag = self.struct_warn("skipping const checks");
             for &(span, feature_gate) in unleashed_features.iter() {
                 // FIXME: `span_label` doesn't do anything, so we use "help" as a hack.
@@ -250,10 +260,7 @@ impl Session {
             // If we should err, make sure we did.
             if must_err && self.has_errors().is_none() {
                 // We have skipped a feature gate, and not run into other errors... reject.
-                self.err(
-                    "`-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature \
-                     gates, except when testing error paths in the CTFE engine",
-                );
+                self.emit_err(NotCircumventFeature);
             }
         }
     }
@@ -534,9 +541,13 @@ impl Session {
             Err(ErrorGuaranteed::unchecked_claim_error_was_emitted())
         }
     }
+    #[allow(rustc::untranslatable_diagnostic)]
+    #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) {
         self.diagnostic().span_warn(sp, msg)
     }
+    #[allow(rustc::untranslatable_diagnostic)]
+    #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn span_warn_with_code<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -585,6 +596,8 @@ impl Session {
     ) {
         self.diagnostic().span_note_without_error(sp, msg)
     }
+    #[allow(rustc::untranslatable_diagnostic)]
+    #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn struct_note_without_error(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -1469,40 +1482,28 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
         && sess.opts.cg.prefer_dynamic
         && sess.target.is_like_windows
     {
-        sess.err(
-            "Linker plugin based LTO is not supported together with \
-                  `-C prefer-dynamic` when targeting Windows-like targets",
-        );
+        sess.emit_err(LinkerPluginToWindowsNotSupported);
     }
 
     // Make sure that any given profiling data actually exists so LLVM can't
     // decide to silently skip PGO.
     if let Some(ref path) = sess.opts.cg.profile_use {
         if !path.exists() {
-            sess.err(&format!(
-                "File `{}` passed to `-C profile-use` does not exist.",
-                path.display()
-            ));
+            sess.emit_err(ProfileUseFileDoesNotExist { path });
         }
     }
 
     // Do the same for sample profile data.
     if let Some(ref path) = sess.opts.unstable_opts.profile_sample_use {
         if !path.exists() {
-            sess.err(&format!(
-                "File `{}` passed to `-C profile-sample-use` does not exist.",
-                path.display()
-            ));
+            sess.emit_err(ProfileSampleUseFileDoesNotExist { path });
         }
     }
 
     // Unwind tables cannot be disabled if the target requires them.
     if let Some(include_uwtables) = sess.opts.cg.force_unwind_tables {
         if sess.target.requires_uwtable && !include_uwtables {
-            sess.err(
-                "target requires unwind tables, they cannot be disabled with \
-                     `-C force-unwind-tables=no`.",
-            );
+            sess.emit_err(TargetRequiresUnwindTables);
         }
     }
 
@@ -1512,64 +1513,55 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
     match unsupported_sanitizers.into_iter().count() {
         0 => {}
         1 => {
-            sess.err(&format!(
-                "{} sanitizer is not supported for this target",
-                unsupported_sanitizers
-            ));
+            sess.emit_err(SanitizerNotSupported { us: unsupported_sanitizers.to_string() });
         }
         _ => {
-            sess.err(&format!(
-                "{} sanitizers are not supported for this target",
-                unsupported_sanitizers
-            ));
+            sess.emit_err(SanitizersNotSupported { us: unsupported_sanitizers.to_string() });
         }
     }
     // Cannot mix and match sanitizers.
     let mut sanitizer_iter = sess.opts.unstable_opts.sanitizer.into_iter();
     if let (Some(first), Some(second)) = (sanitizer_iter.next(), sanitizer_iter.next()) {
-        sess.err(&format!("`-Zsanitizer={first}` is incompatible with `-Zsanitizer={second}`"));
+        sess.emit_err(CannotMixAndMatchSanitizers {
+            first: first.to_string(),
+            second: second.to_string(),
+        });
     }
 
     // Cannot enable crt-static with sanitizers on Linux
     if sess.crt_static(None) && !sess.opts.unstable_opts.sanitizer.is_empty() {
-        sess.err(
-            "sanitizer is incompatible with statically linked libc, \
-                                disable it using `-C target-feature=-crt-static`",
-        );
+        sess.emit_err(CannotEnableCrtStaticLinux);
     }
 
     // LLVM CFI and VFE both require LTO.
     if sess.lto() != config::Lto::Fat {
         if sess.is_sanitizer_cfi_enabled() {
-            sess.err("`-Zsanitizer=cfi` requires `-Clto`");
+            sess.emit_err(SanitizerCfiEnabled);
         }
         if sess.opts.unstable_opts.virtual_function_elimination {
-            sess.err("`-Zvirtual-function-elimination` requires `-Clto`");
+            sess.emit_err(UnstableVirtualFunctionElimination);
         }
     }
 
     if sess.opts.unstable_opts.stack_protector != StackProtector::None {
         if !sess.target.options.supports_stack_protector {
-            sess.warn(&format!(
-                "`-Z stack-protector={}` is not supported for target {} and will be ignored",
-                sess.opts.unstable_opts.stack_protector, sess.opts.target_triple
-            ))
+            sess.emit_warning(StackProtectorNotSupportedForTarget {
+                stack_protector: sess.opts.unstable_opts.stack_protector,
+                target_triple: &sess.opts.target_triple,
+            });
         }
     }
 
     if let Some(dwarf_version) = sess.opts.unstable_opts.dwarf_version {
         if dwarf_version > 5 {
-            sess.err(&format!("requested DWARF version {} is greater than 5", dwarf_version));
+            sess.emit_err(UnsupportedDwarfVersion { dwarf_version });
         }
     }
 
     if !sess.target.options.supported_split_debuginfo.contains(&sess.split_debuginfo())
         && !sess.opts.unstable_opts.unstable_options
     {
-        sess.err(&format!(
-            "`-Csplit-debuginfo={}` is unstable on this platform",
-            sess.split_debuginfo()
-        ));
+        sess.emit_err(SplitDebugInfoUnstablePlatform { debuginfo: sess.split_debuginfo() });
     }
 }
 
@@ -1614,14 +1606,20 @@ fn early_error_handler(output: config::ErrorOutputType) -> rustc_errors::Handler
     rustc_errors::Handler::with_emitter(true, None, emitter)
 }
 
+#[allow(rustc::untranslatable_diagnostic)]
+#[allow(rustc::diagnostic_outside_of_impl)]
 pub fn early_error_no_abort(output: config::ErrorOutputType, msg: &str) -> ErrorGuaranteed {
     early_error_handler(output).struct_err(msg).emit()
 }
 
+#[allow(rustc::untranslatable_diagnostic)]
+#[allow(rustc::diagnostic_outside_of_impl)]
 pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! {
     early_error_handler(output).struct_fatal(msg).emit()
 }
 
+#[allow(rustc::untranslatable_diagnostic)]
+#[allow(rustc::diagnostic_outside_of_impl)]
 pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
     early_error_handler(output).struct_warn(msg).emit()
 }
diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs
index a1533fe46b3..ceb6b6c68b0 100644
--- a/compiler/rustc_span/src/def_id.rs
+++ b/compiler/rustc_span/src/def_id.rs
@@ -305,6 +305,12 @@ impl DefId {
     }
 }
 
+impl From<LocalDefId> for DefId {
+    fn from(local: LocalDefId) -> DefId {
+        local.to_def_id()
+    }
+}
+
 impl<E: Encoder> Encodable<E> for DefId {
     default fn encode(&self, s: &mut E) {
         self.krate.encode(s);
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 cb61f76af1d..b1de979e8f8 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
@@ -13,7 +13,7 @@ use rustc_hir as hir;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
 use rustc_middle::ty::{
     self, Binder, Const, ExistentialPredicate, FloatTy, FnSig, IntTy, List, Region, RegionKind,
-    Term, Ty, TyCtxt, UintTy,
+    TermKind, Ty, TyCtxt, UintTy,
 };
 use rustc_span::def_id::DefId;
 use rustc_span::symbol::sym;
@@ -243,13 +243,9 @@ fn encode_predicate<'tcx>(
             let name = encode_ty_name(tcx, projection.item_def_id);
             let _ = write!(s, "u{}{}", name.len(), &name);
             s.push_str(&encode_substs(tcx, projection.substs, dict, options));
-            match projection.term {
-                Term::Ty(ty) => {
-                    s.push_str(&encode_ty(tcx, ty, dict, options));
-                }
-                Term::Const(c) => {
-                    s.push_str(&encode_const(tcx, c, dict, options));
-                }
+            match projection.term.unpack() {
+                TermKind::Ty(ty) => s.push_str(&encode_ty(tcx, ty, dict, options)),
+                TermKind::Const(c) => s.push_str(&encode_const(tcx, c, dict, options)),
             }
         }
         ty::ExistentialPredicate::AutoTrait(def_id) => {
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 71fa5a44887..cfb8d47e545 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -543,9 +543,9 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
                         let name = cx.tcx.associated_item(projection.item_def_id).name;
                         cx.push("p");
                         cx.push_ident(name.as_str());
-                        cx = match projection.term {
-                            ty::Term::Ty(ty) => ty.print(cx),
-                            ty::Term::Const(c) => c.print(cx),
+                        cx = match projection.term.unpack() {
+                            ty::TermKind::Ty(ty) => ty.print(cx),
+                            ty::TermKind::Const(c) => c.print(cx),
                         }?;
                     }
                     ty::ExistentialPredicate::AutoTrait(def_id) => {
diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs
index 92ce4d91d84..ec334e5887a 100644
--- a/compiler/rustc_target/src/abi/mod.rs
+++ b/compiler/rustc_target/src/abi/mod.rs
@@ -7,7 +7,7 @@ use crate::spec::Target;
 use std::convert::{TryFrom, TryInto};
 use std::fmt;
 use std::iter::Step;
-use std::num::NonZeroUsize;
+use std::num::{NonZeroUsize, ParseIntError};
 use std::ops::{Add, AddAssign, Deref, Mul, RangeInclusive, Sub};
 use std::str::FromStr;
 
@@ -69,34 +69,46 @@ impl Default for TargetDataLayout {
     }
 }
 
+pub enum TargetDataLayoutErrors<'a> {
+    InvalidAddressSpace { addr_space: &'a str, cause: &'a str, err: ParseIntError },
+    InvalidBits { kind: &'a str, bit: &'a str, cause: &'a str, err: ParseIntError },
+    MissingAlignment { cause: &'a str },
+    InvalidAlignment { cause: &'a str, err: String },
+    InconsistentTargetArchitecture { dl: &'a str, target: &'a str },
+    InconsistentTargetPointerWidth { pointer_size: u64, target: u32 },
+    InvalidBitsSize { err: String },
+}
+
 impl TargetDataLayout {
-    pub fn parse(target: &Target) -> Result<TargetDataLayout, String> {
+    pub fn parse<'a>(target: &'a Target) -> Result<TargetDataLayout, TargetDataLayoutErrors<'a>> {
         // Parse an address space index from a string.
-        let parse_address_space = |s: &str, cause: &str| {
+        let parse_address_space = |s: &'a str, cause: &'a str| {
             s.parse::<u32>().map(AddressSpace).map_err(|err| {
-                format!("invalid address space `{}` for `{}` in \"data-layout\": {}", s, cause, err)
+                TargetDataLayoutErrors::InvalidAddressSpace { addr_space: s, cause, err }
             })
         };
 
         // Parse a bit count from a string.
-        let parse_bits = |s: &str, kind: &str, cause: &str| {
-            s.parse::<u64>().map_err(|err| {
-                format!("invalid {} `{}` for `{}` in \"data-layout\": {}", kind, s, cause, err)
+        let parse_bits = |s: &'a str, kind: &'a str, cause: &'a str| {
+            s.parse::<u64>().map_err(|err| TargetDataLayoutErrors::InvalidBits {
+                kind,
+                bit: s,
+                cause,
+                err,
             })
         };
 
         // Parse a size string.
-        let size = |s: &str, cause: &str| parse_bits(s, "size", cause).map(Size::from_bits);
+        let size = |s: &'a str, cause: &'a str| parse_bits(s, "size", cause).map(Size::from_bits);
 
         // Parse an alignment string.
-        let align = |s: &[&str], cause: &str| {
+        let align = |s: &[&'a str], cause: &'a str| {
             if s.is_empty() {
-                return Err(format!("missing alignment for `{}` in \"data-layout\"", cause));
+                return Err(TargetDataLayoutErrors::MissingAlignment { cause });
             }
             let align_from_bits = |bits| {
-                Align::from_bits(bits).map_err(|err| {
-                    format!("invalid alignment for `{}` in \"data-layout\": {}", cause, err)
-                })
+                Align::from_bits(bits)
+                    .map_err(|err| TargetDataLayoutErrors::InvalidAlignment { cause, err })
             };
             let abi = parse_bits(s[0], "alignment", cause)?;
             let pref = s.get(1).map_or(Ok(abi), |pref| parse_bits(pref, "alignment", cause))?;
@@ -158,25 +170,24 @@ impl TargetDataLayout {
 
         // Perform consistency checks against the Target information.
         if dl.endian != target.endian {
-            return Err(format!(
-                "inconsistent target specification: \"data-layout\" claims \
-                 architecture is {}-endian, while \"target-endian\" is `{}`",
-                dl.endian.as_str(),
-                target.endian.as_str(),
-            ));
+            return Err(TargetDataLayoutErrors::InconsistentTargetArchitecture {
+                dl: dl.endian.as_str(),
+                target: target.endian.as_str(),
+            });
         }
 
         let target_pointer_width: u64 = target.pointer_width.into();
         if dl.pointer_size.bits() != target_pointer_width {
-            return Err(format!(
-                "inconsistent target specification: \"data-layout\" claims \
-                 pointers are {}-bit, while \"target-pointer-width\" is `{}`",
-                dl.pointer_size.bits(),
-                target.pointer_width
-            ));
+            return Err(TargetDataLayoutErrors::InconsistentTargetPointerWidth {
+                pointer_size: dl.pointer_size.bits(),
+                target: target.pointer_width,
+            });
         }
 
-        dl.c_enum_min_size = Integer::from_size(Size::from_bits(target.c_enum_min_bits))?;
+        dl.c_enum_min_size = match Integer::from_size(Size::from_bits(target.c_enum_min_bits)) {
+            Ok(bits) => bits,
+            Err(err) => return Err(TargetDataLayoutErrors::InvalidBitsSize { err }),
+        };
 
         Ok(dl)
     }
@@ -1130,7 +1141,7 @@ pub enum TagEncoding {
 
     /// Niche (values invalid for a type) encoding the discriminant:
     /// Discriminant and variant index coincide.
-    /// The variant `dataful_variant` contains a niche at an arbitrary
+    /// The variant `untagged_variant` contains a niche at an arbitrary
     /// offset (field `tag_field` of the enum), which for a variant with
     /// discriminant `d` is set to
     /// `(d - niche_variants.start).wrapping_add(niche_start)`.
@@ -1139,7 +1150,7 @@ pub enum TagEncoding {
     /// `None` has a null pointer for the second tuple field, and
     /// `Some` is the identity function (with a non-null reference).
     Niche {
-        dataful_variant: VariantIdx,
+        untagged_variant: VariantIdx,
         niche_variants: RangeInclusive<VariantIdx>,
         niche_start: u128,
     },
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index 81977f25ca2..ab0afc54514 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -1,7 +1,7 @@
-use rustc_errors::{fluent, ErrorGuaranteed};
+use rustc_errors::{fluent, ErrorGuaranteed, Handler};
 use rustc_macros::SessionDiagnostic;
 use rustc_middle::ty::{PolyTraitRef, Ty, Unevaluated};
-use rustc_session::{parse::ParseSess, Limit, SessionDiagnostic};
+use rustc_session::{Limit, SessionDiagnostic};
 use rustc_span::{Span, Symbol};
 
 #[derive(SessionDiagnostic)]
@@ -69,9 +69,9 @@ pub struct NegativePositiveConflict<'a> {
 impl SessionDiagnostic<'_> for NegativePositiveConflict<'_> {
     fn into_diagnostic(
         self,
-        sess: &ParseSess,
+        handler: &Handler,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = sess.struct_err(fluent::trait_selection::negative_positive_conflict);
+        let mut diag = handler.struct_err(fluent::trait_selection::negative_positive_conflict);
         diag.set_arg("trait_desc", self.trait_desc);
         diag.set_arg(
             "self_desc",
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index 9d30374f8b8..ba403ab2da2 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -24,6 +24,13 @@ pub trait InferCtxtExt<'tcx> {
         span: Span,
     ) -> bool;
 
+    fn type_is_sized_modulo_regions(
+        &self,
+        param_env: ty::ParamEnv<'tcx>,
+        ty: Ty<'tcx>,
+        span: Span,
+    ) -> bool;
+
     fn partially_normalize_associated_types_in<T>(
         &self,
         cause: ObligationCause<'tcx>,
@@ -74,6 +81,16 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
         traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id, span)
     }
 
+    fn type_is_sized_modulo_regions(
+        &self,
+        param_env: ty::ParamEnv<'tcx>,
+        ty: Ty<'tcx>,
+        span: Span,
+    ) -> bool {
+        let lang_item = self.tcx.require_lang_item(LangItem::Sized, None);
+        traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item, span)
+    }
+
     /// Normalizes associated types in `value`, potentially returning
     /// new obligations that must further be processed.
     fn partially_normalize_associated_types_in<T>(
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 1223c7ced7a..98e93ad3fc5 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -10,7 +10,7 @@ use crate::traits::project::ProjectAndUnifyResult;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::visit::TypeVisitable;
-use rustc_middle::ty::{Region, RegionVid, Term};
+use rustc_middle::ty::{Region, RegionVid};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 
@@ -612,7 +612,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
     }
 
     fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool {
-        if let Term::Ty(ty) = p.term().skip_binder() {
+        if let Some(ty) = p.term().skip_binder().ty() {
             matches!(ty.kind(), ty::Projection(proj) if proj == &p.skip_binder().projection_ty)
         } else {
             false
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 34b877d3f72..efdb1ace139 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1895,9 +1895,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
                         // FIXME(compiler-errors): This could be generalized, both to
                         // be more granular, and probably look past other `#[fundamental]`
                         // types, too.
-                        self.tcx
-                            .visibility(def.did())
-                            .is_accessible_from(body_id.owner.to_def_id(), self.tcx)
+                        self.tcx.visibility(def.did()).is_accessible_from(body_id.owner, self.tcx)
                     } else {
                         true
                     }
@@ -2210,12 +2208,12 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
                         && let [
                             ..,
                             trait_path_segment @ hir::PathSegment {
-                                res: Some(rustc_hir::def::Res::Def(rustc_hir::def::DefKind::Trait, trait_id)),
+                                res: rustc_hir::def::Res::Def(rustc_hir::def::DefKind::Trait, trait_id),
                                 ..
                             },
                             hir::PathSegment {
                                 ident: assoc_item_name,
-                                res: Some(rustc_hir::def::Res::Def(_, item_id)),
+                                res: rustc_hir::def::Res::Def(_, item_id),
                                 ..
                             }
                         ] = path.segments
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 02adae5bde1..ecbeb9d79b1 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -25,8 +25,7 @@ use rustc_middle::hir::map;
 use rustc_middle::ty::{
     self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
     GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, IsSuggestable,
-    ProjectionPredicate, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
-    TypeVisitable,
+    ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
 };
 use rustc_middle::ty::{TypeAndMut, TypeckResults};
 use rustc_session::Limit;
@@ -174,7 +173,7 @@ pub trait InferCtxtExt<'tcx> {
         &self,
         err: &mut Diagnostic,
         trait_pred: ty::PolyTraitPredicate<'tcx>,
-        proj_pred: Option<ty::PolyProjectionPredicate<'tcx>>,
+        associated_item: Option<(&'static str, Ty<'tcx>)>,
         body_id: hir::HirId,
     );
 
@@ -467,7 +466,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         &self,
         mut err: &mut Diagnostic,
         trait_pred: ty::PolyTraitPredicate<'tcx>,
-        proj_pred: Option<ty::PolyProjectionPredicate<'tcx>>,
+        associated_ty: Option<(&'static str, Ty<'tcx>)>,
         body_id: hir::HirId,
     ) {
         let trait_pred = self.resolve_numeric_literals_with_default(trait_pred);
@@ -604,21 +603,18 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                         trait_pred.print_modifiers_and_trait_path().to_string()
                     );
 
-                    if let Some(proj_pred) = proj_pred {
-                        let ProjectionPredicate { projection_ty, term } = proj_pred.skip_binder();
-                        let item = self.tcx.associated_item(projection_ty.item_def_id);
-
+                    if let Some((name, term)) = associated_ty {
                         // FIXME: this case overlaps with code in TyCtxt::note_and_explain_type_err.
                         // That should be extracted into a helper function.
                         if constraint.ends_with('>') {
                             constraint = format!(
-                                "{}, {}={}>",
+                                "{}, {} = {}>",
                                 &constraint[..constraint.len() - 1],
-                                item.name,
+                                name,
                                 term
                             );
                         } else {
-                            constraint.push_str(&format!("<{}={}>", item.name, term));
+                            constraint.push_str(&format!("<{} = {}>", name, term));
                         }
                     }
 
@@ -648,7 +644,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     ..
                 }) if !param_ty => {
                     // Missing generic type parameter bound.
-                    if suggest_arbitrary_trait_bound(self.tcx, generics, &mut err, trait_pred) {
+                    if suggest_arbitrary_trait_bound(
+                        self.tcx,
+                        generics,
+                        &mut err,
+                        trait_pred,
+                        associated_ty,
+                    ) {
                         return;
                     }
                 }
@@ -774,7 +776,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             // Get the local name of this closure. This can be inaccurate because
             // of the possibility of reassignment, but this should be good enough.
             match &kind {
-                hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, ident, None) => {
+                hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, ident, None) => {
                     Some(ident.name)
                 }
                 _ => {
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 398635674ab..8a093bf4281 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -552,7 +552,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
                     )
                     .ok()
                     .flatten()
-                    .unwrap_or_else(|| ty::Term::Ty(ty.super_fold_with(self)))
+                    .unwrap_or_else(|| ty.super_fold_with(self).into())
                 };
                 // For cases like #95134 we would like to catch overflows early
                 // otherwise they slip away away and cause ICE.
@@ -635,13 +635,18 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
 
     #[instrument(skip(self), level = "debug")]
     fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        if self.selcx.tcx().lazy_normalization() || !self.eager_inference_replacement {
+        let tcx = self.selcx.tcx();
+        if tcx.lazy_normalization() {
             constant
         } else {
             let constant = constant.super_fold_with(self);
-            debug!(?constant);
-            debug!("self.param_env: {:?}", self.param_env);
-            constant.eval(self.selcx.tcx(), self.param_env)
+            debug!(?constant, ?self.param_env);
+            with_replaced_escaping_bound_vars(
+                self.selcx.infcx(),
+                &mut self.universes,
+                constant,
+                |constant| constant.eval(tcx, self.param_env),
+            )
         }
     }
 
@@ -671,6 +676,41 @@ pub struct BoundVarReplacer<'me, 'tcx> {
     universe_indices: &'me mut Vec<Option<ty::UniverseIndex>>,
 }
 
+/// Executes `f` on `value` after replacing all escaping bound variables with placeholders
+/// and then replaces these placeholders with the original bound variables in the result.
+///
+/// In most places, bound variables should be replaced right when entering a binder, making
+/// this function unnecessary. However, normalization currently does not do that, so we have
+/// to do this lazily.
+///
+/// You should not add any additional uses of this function, at least not without first
+/// discussing it with t-types.
+///
+/// FIXME(@lcnr): We may even consider experimenting with eagerly replacing bound vars during
+/// normalization as well, at which point this function will be unnecessary and can be removed.
+pub fn with_replaced_escaping_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>, R: TypeFoldable<'tcx>>(
+    infcx: &'a InferCtxt<'a, 'tcx>,
+    universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>,
+    value: T,
+    f: impl FnOnce(T) -> R,
+) -> R {
+    if value.has_escaping_bound_vars() {
+        let (value, mapped_regions, mapped_types, mapped_consts) =
+            BoundVarReplacer::replace_bound_vars(infcx, universe_indices, value);
+        let result = f(value);
+        PlaceholderReplacer::replace_placeholders(
+            infcx,
+            mapped_regions,
+            mapped_types,
+            mapped_consts,
+            universe_indices,
+            result,
+        )
+    } else {
+        f(value)
+    }
+}
+
 impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> {
     /// Returns `Some` if we *were* able to replace bound vars. If there are any bound vars that
     /// use a binding level above `universe_indices.len()`, we fail.
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 61c556b726d..f65fc5bad0d 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -6,7 +6,7 @@ use crate::infer::at::At;
 use crate::infer::canonical::OriginalQueryValues;
 use crate::infer::{InferCtxt, InferOk};
 use crate::traits::error_reporting::InferCtxtExt;
-use crate::traits::project::needs_normalization;
+use crate::traits::project::{needs_normalization, BoundVarReplacer, PlaceholderReplacer};
 use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
 use rustc_data_structures::sso::SsoHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -283,11 +283,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
                 let tcx = self.infcx.tcx;
                 let infcx = self.infcx;
                 let (data, mapped_regions, mapped_types, mapped_consts) =
-                    crate::traits::project::BoundVarReplacer::replace_bound_vars(
-                        infcx,
-                        &mut self.universes,
-                        data,
-                    );
+                    BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
                 let data = data.try_fold_with(self)?;
 
                 let mut orig_values = OriginalQueryValues::default();
@@ -313,8 +309,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
                 debug!("QueryNormalizer: result = {:#?}", result);
                 debug!("QueryNormalizer: obligations = {:#?}", obligations);
                 self.obligations.extend(obligations);
-
-                let res = crate::traits::project::PlaceholderReplacer::replace_placeholders(
+                let res = PlaceholderReplacer::replace_placeholders(
                     infcx,
                     mapped_regions,
                     mapped_types,
@@ -343,7 +338,13 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
         constant: ty::Const<'tcx>,
     ) -> Result<ty::Const<'tcx>, Self::Error> {
         let constant = constant.try_super_fold_with(self)?;
-        Ok(constant.eval(self.infcx.tcx, self.param_env))
+        debug!(?constant, ?self.param_env);
+        Ok(crate::traits::project::with_replaced_escaping_bound_vars(
+            self.infcx,
+            &mut self.universes,
+            constant,
+            |constant| constant.eval(self.infcx.tcx, self.param_env),
+        ))
     }
 
     fn try_fold_mir_const(
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index bb6009cb22a..9a571837e9f 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -129,9 +129,9 @@ pub fn predicate_obligations<'a, 'tcx>(
         }
         ty::PredicateKind::Projection(t) => {
             wf.compute_projection(t.projection_ty);
-            wf.compute(match t.term {
-                ty::Term::Ty(ty) => ty.into(),
-                ty::Term::Const(c) => c.into(),
+            wf.compute(match t.term.unpack() {
+                ty::TermKind::Ty(ty) => ty.into(),
+                ty::TermKind::Const(c) => c.into(),
             })
         }
         ty::PredicateKind::WellFormed(arg) => {
@@ -434,6 +434,7 @@ impl<'tcx> WfPredicates<'tcx> {
     }
 
     /// Pushes all the predicates needed to validate that `ty` is WF into `out`.
+    #[instrument(level = "debug", skip(self))]
     fn compute(&mut self, arg: GenericArg<'tcx>) {
         let mut walker = arg.walk();
         let param_env = self.param_env;
@@ -488,6 +489,8 @@ impl<'tcx> WfPredicates<'tcx> {
                 }
             };
 
+            debug!("wf bounds for ty={:?} ty.kind={:#?}", ty, ty.kind());
+
             match *ty.kind() {
                 ty::Bool
                 | ty::Char
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index 5488bca8f47..da30344ef7e 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -23,6 +23,9 @@ pub mod sty;
 pub use codec::*;
 pub use sty::*;
 
+/// Needed so we can use #[derive(HashStable_Generic)]
+pub trait HashStableContext {}
+
 pub trait Interner {
     type AdtDef: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
     type SubstsRef: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
@@ -295,6 +298,7 @@ rustc_index::newtype_index! {
     /// is the outer fn.
     ///
     /// [dbi]: https://en.wikipedia.org/wiki/De_Bruijn_index
+    #[derive(HashStable_Generic)]
     pub struct DebruijnIndex {
         DEBUG_FORMAT = "DebruijnIndex({})",
         const INNERMOST = 0,
@@ -366,7 +370,7 @@ impl DebruijnIndex {
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
-#[derive(Encodable, Decodable)]
+#[derive(Encodable, Decodable, HashStable_Generic)]
 pub enum IntTy {
     Isize,
     I8,
@@ -413,7 +417,7 @@ impl IntTy {
 }
 
 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Debug)]
-#[derive(Encodable, Decodable)]
+#[derive(Encodable, Decodable, HashStable_Generic)]
 pub enum UintTy {
     Usize,
     U8,
@@ -460,7 +464,7 @@ impl UintTy {
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
-#[derive(Encodable, Decodable)]
+#[derive(Encodable, Decodable, HashStable_Generic)]
 pub enum FloatTy {
     F32,
     F64,
@@ -597,7 +601,7 @@ impl UnifyKey for FloatVid {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Decodable, Encodable, Hash)]
+#[derive(Copy, Clone, PartialEq, Decodable, Encodable, Hash, HashStable_Generic)]
 #[rustc_pass_by_value]
 pub enum Variance {
     Covariant,     // T<A> <: T<B> iff A <: B -- e.g., function return type
@@ -666,30 +670,6 @@ impl Variance {
     }
 }
 
-impl<CTX> HashStable<CTX> for DebruijnIndex {
-    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
-        self.as_u32().hash_stable(ctx, hasher);
-    }
-}
-
-impl<CTX> HashStable<CTX> for IntTy {
-    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
-        discriminant(self).hash_stable(ctx, hasher);
-    }
-}
-
-impl<CTX> HashStable<CTX> for UintTy {
-    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
-        discriminant(self).hash_stable(ctx, hasher);
-    }
-}
-
-impl<CTX> HashStable<CTX> for FloatTy {
-    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
-        discriminant(self).hash_stable(ctx, hasher);
-    }
-}
-
 impl<CTX> HashStable<CTX> for InferTy {
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
         use InferTy::*;
@@ -703,12 +683,6 @@ impl<CTX> HashStable<CTX> for InferTy {
     }
 }
 
-impl<CTX> HashStable<CTX> for Variance {
-    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
-        discriminant(self).hash_stable(ctx, hasher);
-    }
-}
-
 impl fmt::Debug for IntVarValue {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
@@ -811,6 +785,7 @@ rustc_index::newtype_index! {
     /// declared, but a type name in a non-zero universe is a placeholder
     /// type -- an idealized representative of "types in general" that we
     /// use for checking generic functions.
+    #[derive(HashStable_Generic)]
     pub struct UniverseIndex {
         DEBUG_FORMAT = "U{}",
     }
@@ -850,9 +825,3 @@ impl UniverseIndex {
         self.private < other.private
     }
 }
-
-impl<CTX> HashStable<CTX> for UniverseIndex {
-    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
-        self.private.hash_stable(ctx, hasher);
-    }
-}
diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs
index 74737e30bb4..26e48d2d214 100644
--- a/compiler/rustc_type_ir/src/sty.rs
+++ b/compiler/rustc_type_ir/src/sty.rs
@@ -3,7 +3,6 @@
 use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
 use std::{fmt, hash};
 
-use crate::DebruijnIndex;
 use crate::FloatTy;
 use crate::IntTy;
 use crate::Interner;
@@ -11,6 +10,7 @@ use crate::TyDecoder;
 use crate::TyEncoder;
 use crate::UintTy;
 use crate::UniverseIndex;
+use crate::{DebruijnIndex, HashStableContext};
 
 use self::RegionKind::*;
 use self::TyKind::*;
@@ -774,7 +774,7 @@ where
 
 // This is not a derived impl because a derive would require `I: HashStable`
 #[allow(rustc::usage_of_ty_tykind)]
-impl<CTX, I: Interner> HashStable<CTX> for TyKind<I>
+impl<CTX: HashStableContext, I: Interner> HashStable<CTX> for TyKind<I>
 where
     I::AdtDef: HashStable<CTX>,
     I::DefId: HashStable<CTX>,
@@ -1286,7 +1286,7 @@ where
 }
 
 // This is not a derived impl because a derive would require `I: HashStable`
-impl<CTX, I: Interner> HashStable<CTX> for RegionKind<I>
+impl<CTX: HashStableContext, I: Interner> HashStable<CTX> for RegionKind<I>
 where
     I::EarlyBoundRegion: HashStable<CTX>,
     I::BoundRegion: HashStable<CTX>,
diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs
index ff39bf36129..a9152bdc597 100644
--- a/compiler/rustc_typeck/src/astconv/errors.rs
+++ b/compiler/rustc_typeck/src/astconv/errors.rs
@@ -29,6 +29,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         self.tcx().sess.emit_err(MissingTypeParams {
             span,
             def_span: self.tcx().def_span(def_id),
+            span_snippet: self.tcx().sess.source_map().span_to_snippet(span).ok(),
             missing_type_params,
             empty_generic_args,
         });
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 28e4f8ad0ef..d66cf6d099a 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -1113,8 +1113,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             let ident = Ident::new(assoc_item.name, binding.item_name.span);
             let item_segment = hir::PathSegment {
                 ident,
-                hir_id: Some(binding.hir_id),
-                res: None,
+                hir_id: binding.hir_id,
+                res: Res::Err,
                 args: Some(binding.gen_args),
                 infer_args: false,
             };
@@ -1183,11 +1183,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 // `<T as Iterator>::Item = u32`
                 let assoc_item_def_id = projection_ty.skip_binder().item_def_id;
                 let def_kind = tcx.def_kind(assoc_item_def_id);
-                match (def_kind, term) {
-                    (hir::def::DefKind::AssocTy, ty::Term::Ty(_))
-                    | (hir::def::DefKind::AssocConst, ty::Term::Const(_)) => (),
+                match (def_kind, term.unpack()) {
+                    (hir::def::DefKind::AssocTy, ty::TermKind::Ty(_))
+                    | (hir::def::DefKind::AssocConst, ty::TermKind::Const(_)) => (),
                     (_, _) => {
-                        let got = if let ty::Term::Ty(_) = term { "type" } else { "constant" };
+                        let got = if let Some(_) = term.ty() { "type" } else { "constant" };
                         let expected = def_kind.descr(assoc_item_def_id);
                         tcx.sess
                             .struct_span_err(
@@ -1375,9 +1375,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                         let pred = bound_predicate.rebind(pred);
                         // A `Self` within the original bound will be substituted with a
                         // `trait_object_dummy_self`, so check for that.
-                        let references_self = match pred.skip_binder().term {
-                            ty::Term::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
-                            ty::Term::Const(c) => c.ty().walk().any(|arg| arg == dummy_self.into()),
+                        let references_self = match pred.skip_binder().term.unpack() {
+                            ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
+                            ty::TermKind::Const(c) => {
+                                c.ty().walk().any(|arg| arg == dummy_self.into())
+                            }
                         };
 
                         // If the projection output contains `Self`, force the user to
@@ -1845,7 +1847,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                                     [.., hir::PathSegment {
                                         ident,
                                         args,
-                                        res: Some(Res::Def(DefKind::Enum, _)),
+                                        res: Res::Def(DefKind::Enum, _),
                                         ..
                                     }, _] => (
                                         // We need to include the `::` in `Type::Variant::<Args>`
@@ -2127,24 +2129,22 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             let types_and_spans: Vec<_> = segments
                 .clone()
                 .flat_map(|segment| {
-                    segment.res.and_then(|res| {
-                        if segment.args().args.is_empty() {
-                            None
-                        } else {
-                            Some((
-                            match res {
-                                Res::PrimTy(ty) => format!("{} `{}`", res.descr(), ty.name()),
+                    if segment.args().args.is_empty() {
+                        None
+                    } else {
+                        Some((
+                            match segment.res {
+                                Res::PrimTy(ty) => format!("{} `{}`", segment.res.descr(), ty.name()),
                                 Res::Def(_, def_id)
                                 if let Some(name) = self.tcx().opt_item_name(def_id) => {
-                                    format!("{} `{name}`", res.descr())
+                                    format!("{} `{name}`", segment.res.descr())
                                 }
                                 Res::Err => "this type".to_string(),
-                                _ => res.descr().to_string(),
+                                _ => segment.res.descr().to_string(),
                             },
                             segment.ident.span,
                         ))
-                        }
-                    })
+                    }
                 })
                 .collect();
             let this_type = match &types_and_spans[..] {
@@ -2697,6 +2697,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         result_ty
     }
 
+    #[instrument(level = "debug", skip(self), ret)]
     fn impl_trait_ty_to_ty(
         &self,
         def_id: DefId,
@@ -2745,9 +2746,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         });
         debug!("impl_trait_ty_to_ty: substs={:?}", substs);
 
-        let ty = tcx.mk_opaque(def_id, substs);
-        debug!("impl_trait_ty_to_ty: {}", ty);
-        ty
+        tcx.mk_opaque(def_id, substs)
     }
 
     pub fn ty_of_arg(&self, ty: &hir::Ty<'_>, expected_ty: Option<Ty<'tcx>>) -> Ty<'tcx> {
@@ -2941,8 +2940,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 // though we can easily give a hint that ought to be
                 // relevant.
                 err.note(
-                    "lifetimes appearing in an associated type are not considered constrained",
+                    "lifetimes appearing in an associated or opaque type are not considered constrained",
                 );
+                err.note("consider introducing a named lifetime parameter");
             }
 
             err.emit();
diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs
index 75f5aced855..0d35c2479dd 100644
--- a/compiler/rustc_typeck/src/check/callee.rs
+++ b/compiler/rustc_typeck/src/check/callee.rs
@@ -1,5 +1,5 @@
 use super::method::MethodCallee;
-use super::{Expectation, FnCtxt, TupleArgumentsFlag};
+use super::{DefIdOrName, Expectation, FnCtxt, TupleArgumentsFlag};
 use crate::type_error_struct;
 
 use rustc_errors::{struct_span_err, Applicability, Diagnostic};
@@ -24,7 +24,8 @@ use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 use rustc_target::spec::abi;
 use rustc_trait_selection::autoderef::Autoderef;
-use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
+use rustc_trait_selection::infer::InferCtxtExt as _;
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 
 use std::iter;
 
@@ -471,7 +472,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 };
 
                 if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) {
-                    err.span_label(call_expr.span, "call expression requires function");
+                    if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_expr, callee_ty)
+                        && !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span)
+                    {
+                        let descr = match maybe_def {
+                            DefIdOrName::DefId(def_id) => self.tcx.def_kind(def_id).descr(def_id),
+                            DefIdOrName::Name(name) => name,
+                        };
+                        err.span_label(
+                            callee_expr.span,
+                            format!("this {descr} returns an unsized value `{output_ty}`, so it cannot be called")
+                        );
+                        if let DefIdOrName::DefId(def_id) = maybe_def
+                            && let Some(def_span) = self.tcx.hir().span_if_local(def_id)
+                        {
+                            err.span_label(def_span, "the callable type is defined here");
+                        }
+                    } else {
+                        err.span_label(call_expr.span, "call expression requires function");
+                    }
                 }
 
                 if let Some(span) = self.tcx.hir().res_span(def) {
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index 6c7b2a2889f..a3fcda5864b 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -35,7 +35,6 @@ use crate::type_error_struct;
 use hir::def_id::LOCAL_CRATE;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
-use rustc_hir::lang_items::LangItem;
 use rustc_middle::mir::Mutability;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::cast::{CastKind, CastTy};
@@ -47,7 +46,6 @@ use rustc_session::Session;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_trait_selection::infer::InferCtxtExt;
-use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
 
 /// Reifies a cast check to be checked once we have full type information for
@@ -97,7 +95,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return Err(reported);
         }
 
-        if self.type_is_known_to_be_sized_modulo_regions(t, span) {
+        if self.type_is_sized_modulo_regions(self.param_env, t, span) {
             return Ok(Some(PointerKind::Thin));
         }
 
@@ -705,7 +703,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
 
         debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty);
 
-        if !fcx.type_is_known_to_be_sized_modulo_regions(self.cast_ty, self.span)
+        if !fcx.type_is_sized_modulo_regions(fcx.param_env, self.cast_ty, self.span)
             && !self.cast_ty.has_infer_types()
         {
             self.report_cast_to_unsized_type(fcx);
@@ -1084,10 +1082,3 @@ impl<'a, 'tcx> CastCheck<'tcx> {
         );
     }
 }
-
-impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
-    fn type_is_known_to_be_sized_modulo_regions(&self, ty: Ty<'tcx>, span: Span) -> bool {
-        let lang_item = self.tcx.require_lang_item(LangItem::Sized, None);
-        traits::type_known_to_meet_bound_modulo_regions(self, self.param_env, ty, lang_item, span)
-    }
-}
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index 29a128f27b8..43893263be1 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -610,12 +610,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
         fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
             match arg.kind {
                 hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
-                    [
-                        PathSegment {
-                            res: Some(Res::SelfTy { trait_: _, alias_to: impl_ref }),
-                            ..
-                        },
-                    ] => {
+                    [PathSegment { res: Res::SelfTy { trait_: _, alias_to: impl_ref }, .. }] => {
                         let impl_ty_name =
                             impl_ref.map(|(def_id, _)| self.tcx.def_path_str(def_id));
                         self.selftys.push((path.span, impl_ty_name));
@@ -1464,7 +1459,7 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L
     def.destructor(tcx); // force the destructor to be evaluated
 
     if vs.is_empty() {
-        if let Some(attr) = tcx.get_attr(def_id.to_def_id(), sym::repr) {
+        if let Some(attr) = tcx.get_attrs(def_id.to_def_id(), sym::repr).next() {
             struct_span_err!(
                 tcx.sess,
                 attr.span,
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index 4a3d69f5b6c..e1d55ff82cb 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -375,7 +375,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                     let field_is_local = sole_field.did.is_local();
                     let field_is_accessible =
-                        sole_field.vis.is_accessible_from(expr.hir_id.owner.to_def_id(), self.tcx)
+                        sole_field.vis.is_accessible_from(expr.hir_id.owner, self.tcx)
                         // Skip suggestions for unstable public fields (for example `Pin::pointer`)
                         && matches!(self.tcx.eval_stability(sole_field.did, None, expr.span, None), EvalResult::Allow | EvalResult::Unmarked);
 
@@ -590,7 +590,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let closure_params_len = closure_fn_decl.inputs.len();
         let (
             Some(Node::Expr(hir::Expr {
-                kind: hir::ExprKind::MethodCall(method_path, method_expr, _),
+                kind: hir::ExprKind::MethodCall(method_path, receiver, ..),
                 ..
             })),
             1,
@@ -598,7 +598,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return None;
         };
 
-        let self_ty = self.typeck_results.borrow().expr_ty(&method_expr[0]);
+        let self_ty = self.typeck_results.borrow().expr_ty(receiver);
         let name = method_path.ident.name;
         let is_as_ref_able = match self_ty.peel_refs().kind() {
             ty::Adt(def, _) => {
@@ -767,22 +767,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 };
                 if self.can_coerce(ref_ty, expected) {
                     let mut sugg_sp = sp;
-                    if let hir::ExprKind::MethodCall(ref segment, ref args, _) = expr.kind {
+                    if let hir::ExprKind::MethodCall(ref segment, receiver, args, _) = expr.kind {
                         let clone_trait =
                             self.tcx.require_lang_item(LangItem::Clone, Some(segment.ident.span));
-                        if let ([arg], Some(true), sym::clone) = (
-                            &args[..],
-                            self.typeck_results.borrow().type_dependent_def_id(expr.hir_id).map(
+                        if args.is_empty()
+                            && self.typeck_results.borrow().type_dependent_def_id(expr.hir_id).map(
                                 |did| {
                                     let ai = self.tcx.associated_item(did);
                                     ai.trait_container(self.tcx) == Some(clone_trait)
                                 },
-                            ),
-                            segment.ident.name,
-                        ) {
+                            ) == Some(true)
+                            && segment.ident.name == sym::clone
+                        {
                             // If this expression had a clone call when suggesting borrowing
                             // we want to suggest removing it because it'd now be unnecessary.
-                            sugg_sp = arg.span;
+                            sugg_sp = receiver.span;
                         }
                     }
                     if let Ok(src) = sm.span_to_snippet(sugg_sp) {
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 17ec8afc737..0e6a8ef8265 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -324,8 +324,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             ExprKind::Block(body, _) => self.check_block_with_expected(&body, expected),
             ExprKind::Call(callee, args) => self.check_call(expr, &callee, args, expected),
-            ExprKind::MethodCall(segment, args, _) => {
-                self.check_method_call(expr, segment, args, expected)
+            ExprKind::MethodCall(segment, receiver, args, _) => {
+                self.check_method_call(expr, segment, receiver, args, expected)
             }
             ExprKind::Cast(e, t) => self.check_expr_cast(e, t, expr),
             ExprKind::Type(e, t) => {
@@ -1195,13 +1195,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         segment: &hir::PathSegment<'_>,
+        rcvr: &'tcx hir::Expr<'tcx>,
         args: &'tcx [hir::Expr<'tcx>],
         expected: Expectation<'tcx>,
     ) -> Ty<'tcx> {
-        let rcvr = &args[0];
         let rcvr_t = self.check_expr(&rcvr);
         // no need to check for bot/err -- callee does that
-        let rcvr_t = self.structurally_resolved_type(args[0].span, rcvr_t);
+        let rcvr_t = self.structurally_resolved_type(rcvr.span, rcvr_t);
         let span = segment.ident.span;
 
         let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr, args) {
@@ -1218,9 +1218,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         span,
                         rcvr_t,
                         segment.ident,
-                        SelfSource::MethodCall(&args[0]),
+                        SelfSource::MethodCall(rcvr),
                         error,
-                        Some(args),
+                        Some((rcvr, args)),
                     ) {
                         err.emit();
                     }
@@ -1230,14 +1230,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         // Call the generic checker.
-        self.check_method_argument_types(
-            span,
-            expr,
-            method,
-            &args[1..],
-            DontTupleArguments,
-            expected,
-        )
+        self.check_method_argument_types(span, expr, method, &args, DontTupleArguments, expected)
     }
 
     fn check_expr_cast(
@@ -1736,9 +1729,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let private_fields: Vec<&ty::FieldDef> = variant
                 .fields
                 .iter()
-                .filter(|field| {
-                    !field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx)
-                })
+                .filter(|field| !field.vis.is_accessible_from(tcx.parent_module(expr_id), tcx))
                 .collect();
 
             if !private_fields.is_empty() {
@@ -2350,7 +2341,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if let ty::Adt(def, _) = output_ty.kind() && !def.is_enum() {
                 def.non_enum_variant().fields.iter().any(|field| {
                     field.ident(self.tcx) == ident
-                        && field.vis.is_accessible_from(expr.hir_id.owner.to_def_id(), self.tcx)
+                        && field.vis.is_accessible_from(expr.hir_id.owner, self.tcx)
                 })
             } else if let ty::Tuple(tys) = output_ty.kind()
                 && let Ok(idx) = ident.as_str().parse::<usize>()
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index 7e746b7387a..a40478db969 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -409,7 +409,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     rhs_span: opt_input_expr.map(|expr| expr.span),
                     is_lit: opt_input_expr
                         .map_or(false, |expr| matches!(expr.kind, ExprKind::Lit(_))),
-                    output_pred: None,
+                    output_ty: None,
                 },
             ),
             self.param_env,
@@ -495,13 +495,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     pub fn to_const(&self, ast_c: &hir::AnonConst) -> ty::Const<'tcx> {
         let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id);
+        let span = self.tcx.hir().span(ast_c.hir_id);
         let c = ty::Const::from_anon_const(self.tcx, const_def_id);
-        self.register_wf_obligation(
-            c.into(),
-            self.tcx.hir().span(ast_c.hir_id),
-            ObligationCauseCode::WellFormed(None),
-        );
-        c
+        self.register_wf_obligation(c.into(), span, ObligationCauseCode::WellFormed(None));
+        self.normalize_associated_types_in(span, c)
     }
 
     pub fn const_arg_to_const(
@@ -987,7 +984,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         if found != self.tcx.types.unit {
             return;
         }
-        if let ExprKind::MethodCall(path_segment, [rcvr, ..], _) = expr.kind {
+        if let ExprKind::MethodCall(path_segment, rcvr, ..) = expr.kind {
             if self
                 .typeck_results
                 .borrow()
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index d1d27db9131..311fcaadaa9 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -478,7 +478,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
             }
             hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, None, false),
-            hir::ExprKind::MethodCall(path_segment, _, span) => {
+            hir::ExprKind::MethodCall(path_segment, _, _, span) => {
                 let ident_span = path_segment.ident.span;
                 let ident_span = if let Some(args) = path_segment.args {
                     ident_span.with_hi(args.span_ext.hi())
@@ -530,13 +530,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             .collect();
         let callee_expr = match &call_expr.peel_blocks().kind {
             hir::ExprKind::Call(callee, _) => Some(*callee),
-            hir::ExprKind::MethodCall(_, callee, _) => {
+            hir::ExprKind::MethodCall(_, receiver, ..) => {
                 if let Some((DefKind::AssocFn, def_id)) =
                     self.typeck_results.borrow().type_dependent_def(call_expr.hir_id)
                     && let Some(assoc) = tcx.opt_associated_item(def_id)
                     && assoc.fn_has_self_parameter
                 {
-                    Some(&callee[0])
+                    Some(*receiver)
                 } else {
                     None
                 }
@@ -1805,25 +1805,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 param,
                                 *call_hir_id,
                                 callee.span,
+                                None,
                                 args,
                             )
                         {
                             return true;
                         }
                     }
-                    // Notably, we only point to params that are local to the
-                    // item we're checking, since those are the ones we are able
-                    // to look in the final `hir::PathSegment` for. Everything else
-                    // would require a deeper search into the `qpath` than I think
-                    // is worthwhile.
-                    if let Some(param_to_point_at) = param_to_point_at
-                        && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath)
-                    {
-                        return true;
-                    }
+                }
+                // Notably, we only point to params that are local to the
+                // item we're checking, since those are the ones we are able
+                // to look in the final `hir::PathSegment` for. Everything else
+                // would require a deeper search into the `qpath` than I think
+                // is worthwhile.
+                if let Some(param_to_point_at) = param_to_point_at
+                    && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath)
+                {
+                    return true;
                 }
             }
-            hir::ExprKind::MethodCall(segment, args, ..) => {
+            hir::ExprKind::MethodCall(segment, receiver, args, ..) => {
                 for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
                     .into_iter()
                     .flatten()
@@ -1834,6 +1835,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         param,
                         hir_id,
                         segment.ident.span,
+                        Some(receiver),
                         args,
                     ) {
                         return true;
@@ -1901,7 +1903,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         param_to_point_at: ty::GenericArg<'tcx>,
         call_hir_id: hir::HirId,
         callee_span: Span,
-        args: &[hir::Expr<'tcx>],
+        receiver: Option<&'tcx hir::Expr<'tcx>>,
+        args: &'tcx [hir::Expr<'tcx>],
     ) -> bool {
         let sig = self.tcx.fn_sig(def_id).skip_binder();
         let args_referencing_param: Vec<_> = sig
@@ -1910,9 +1913,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             .enumerate()
             .filter(|(_, ty)| find_param_in_ty(**ty, param_to_point_at))
             .collect();
-
         // If there's one field that references the given generic, great!
-        if let [(idx, _)] = args_referencing_param.as_slice() && let Some(arg) = args.get(*idx) {
+        if let [(idx, _)] = args_referencing_param.as_slice()
+            && let Some(arg) = receiver
+                .map_or(args.get(*idx), |rcvr| if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) }) {
             error.obligation.cause.span = arg.span.find_ancestor_in_same_ctxt(error.obligation.cause.span).unwrap_or(arg.span);
             error.obligation.cause.map_code(|parent_code| {
                 ObligationCauseCode::FunctionArgumentObligation {
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
index d8527b9267e..2bfee9a5364 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
@@ -144,7 +144,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         false
     }
 
-    fn extract_callable_info(
+    /// Extracts information about a callable type for diagnostics. This is a
+    /// heuristic -- it doesn't necessarily mean that a type is always callable,
+    /// because the callable type must also be well-formed to be called.
+    pub(in super::super) fn extract_callable_info(
         &self,
         expr: &Expr<'_>,
         found: Ty<'tcx>,
@@ -1049,7 +1052,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         found_ty: Ty<'tcx>,
         expr: &hir::Expr<'_>,
     ) {
-        let hir::ExprKind::MethodCall(segment, &[ref callee_expr], _) = expr.kind else { return; };
+        let hir::ExprKind::MethodCall(segment, callee_expr, &[], _) = expr.kind else { return; };
         let Some(clone_trait_did) = self.tcx.lang_items().clone_trait() else { return; };
         let ty::Ref(_, pointee_ty, _) = found_ty.kind() else { return };
         let results = self.typeck_results.borrow();
@@ -1130,7 +1133,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 }
 
-enum DefIdOrName {
+pub enum DefIdOrName {
     DefId(DefId),
     Name(&'static str),
 }
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs
index 3e96b3ffb09..016f4056bd9 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs
@@ -434,7 +434,8 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> {
 
                 self.handle_uninhabited_return(expr);
             }
-            ExprKind::MethodCall(_, exprs, _) => {
+            ExprKind::MethodCall(_, receiver, exprs, _) => {
+                self.visit_expr(receiver);
                 for expr in exprs {
                     self.visit_expr(expr);
                 }
diff --git a/compiler/rustc_typeck/src/check/intrinsicck.rs b/compiler/rustc_typeck/src/check/intrinsicck.rs
index 721ebba6514..d8fe63dbf08 100644
--- a/compiler/rustc_typeck/src/check/intrinsicck.rs
+++ b/compiler/rustc_typeck/src/check/intrinsicck.rs
@@ -333,10 +333,10 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                         let mut err = lint.build(msg);
                         err.span_label(expr.span, "for this argument");
                         err.help(&format!(
-                            "use the `{suggested_modifier}` modifier to have the register formatted as `{suggested_result}`",
+                            "use `{{{idx}:{suggested_modifier}}}` to have the register formatted as `{suggested_result}`",
                         ));
                         err.help(&format!(
-                            "or use the `{default_modifier}` modifier to keep the default formatting of `{default_result}`",
+                            "or use `{{{idx}:{default_modifier}}}` to keep the default formatting of `{default_result}`",
                         ));
                         err.emit();
                     },
diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs
index a9071cd1fd9..249e9c66ba7 100644
--- a/compiler/rustc_typeck/src/check/method/mod.rs
+++ b/compiler/rustc_typeck/src/check/method/mod.rs
@@ -20,10 +20,7 @@ use rustc_hir::def_id::DefId;
 use rustc_infer::infer::{self, InferOk};
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
-use rustc_middle::ty::{
-    self, AssocKind, DefIdTree, GenericParamDefKind, ProjectionPredicate, ProjectionTy, Term,
-    ToPredicate, Ty, TypeVisitable,
-};
+use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, ToPredicate, Ty, TypeVisitable};
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 use rustc_trait_selection::traits;
@@ -337,22 +334,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Construct an obligation
         let poly_trait_ref = ty::Binder::dummy(trait_ref);
-        let opt_output_ty =
-            expected.only_has_type(self).and_then(|ty| (!ty.needs_infer()).then(|| ty));
-        let opt_output_assoc_item = self.tcx.associated_items(trait_def_id).find_by_name_and_kind(
-            self.tcx,
-            Ident::from_str("Output"),
-            AssocKind::Type,
-            trait_def_id,
-        );
-        let output_pred =
-            opt_output_ty.zip(opt_output_assoc_item).map(|(output_ty, output_assoc_item)| {
-                ty::Binder::dummy(ty::PredicateKind::Projection(ProjectionPredicate {
-                    projection_ty: ProjectionTy { substs, item_def_id: output_assoc_item.def_id },
-                    term: Term::Ty(output_ty),
-                }))
-                .to_predicate(self.tcx)
-            });
+        let output_ty = expected.only_has_type(self).and_then(|ty| (!ty.needs_infer()).then(|| ty));
 
         (
             traits::Obligation::new(
@@ -363,7 +345,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         rhs_span: opt_input_expr.map(|expr| expr.span),
                         is_lit: opt_input_expr
                             .map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))),
-                        output_pred,
+                        output_ty,
                     },
                 ),
                 self.param_env,
@@ -518,7 +500,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     rhs_span: opt_input_expr.map(|expr| expr.span),
                     is_lit: opt_input_expr
                         .map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))),
-                    output_pred: None,
+                    output_ty: None,
                 },
             )
         } else {
diff --git a/compiler/rustc_typeck/src/check/method/prelude2021.rs b/compiler/rustc_typeck/src/check/method/prelude2021.rs
index 7c68d930405..392695cca68 100644
--- a/compiler/rustc_typeck/src/check/method/prelude2021.rs
+++ b/compiler/rustc_typeck/src/check/method/prelude2021.rs
@@ -160,7 +160,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     if precise {
                         let args = args
                             .iter()
-                            .skip(1)
                             .map(|arg| {
                                 let span = arg.span.find_ancestor_inside(sp).unwrap_or_default();
                                 format!(
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index 998405bcbe1..8065b848ad6 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -95,7 +95,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         item_name: Ident,
         source: SelfSource<'tcx>,
         error: MethodError<'tcx>,
-        args: Option<&'tcx [hir::Expr<'tcx>]>,
+        args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
     ) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
         // Avoid suggestions when we don't know what's going on.
         if rcvr_ty.references_error() {
@@ -998,7 +998,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         span,
                         rcvr_ty,
                         item_name,
-                        args.map(|args| args.len()),
+                        args.map(|(_, args)| args.len() + 1),
                         source,
                         out_of_scope_traits,
                         &unsatisfied_predicates,
@@ -1161,7 +1161,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             _ => None,
         });
         if let Some((field, field_ty)) = field_receiver {
-            let scope = tcx.parent_module(self.body_id).to_def_id();
+            let scope = tcx.parent_module(self.body_id);
             let is_accessible = field.vis.is_accessible_from(scope, tcx);
 
             if is_accessible {
@@ -2310,7 +2310,7 @@ pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
 
 fn print_disambiguation_help<'tcx>(
     item_name: Ident,
-    args: Option<&'tcx [hir::Expr<'tcx>]>,
+    args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
     err: &mut Diagnostic,
     trait_name: String,
     rcvr_ty: Ty<'_>,
@@ -2322,7 +2322,7 @@ fn print_disambiguation_help<'tcx>(
     fn_has_self_parameter: bool,
 ) {
     let mut applicability = Applicability::MachineApplicable;
-    let (span, sugg) = if let (ty::AssocKind::Fn, Some(args)) = (kind, args) {
+    let (span, sugg) = if let (ty::AssocKind::Fn, Some((receiver, args))) = (kind, args) {
         let args = format!(
             "({}{})",
             if rcvr_ty.is_region_ptr() {
@@ -2330,7 +2330,8 @@ fn print_disambiguation_help<'tcx>(
             } else {
                 ""
             },
-            args.iter()
+            std::iter::once(receiver)
+                .chain(args.iter())
                 .map(|arg| source_map.span_to_snippet(arg.span).unwrap_or_else(|_| {
                     applicability = Applicability::HasPlaceholders;
                     "_".to_owned()
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs
index 0d9dbb5bc11..4754717c29a 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_typeck/src/check/op.rs
@@ -11,9 +11,8 @@ use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
 };
-use rustc_middle::ty::{
-    self, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor,
-};
+use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable};
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
@@ -22,8 +21,6 @@ use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt as
 use rustc_trait_selection::traits::{FulfillmentError, TraitEngine, TraitEngineExt};
 use rustc_type_ir::sty::TyKind::*;
 
-use std::ops::ControlFlow;
-
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Checks a `a <op>= b`
     pub fn check_binop_assign(
@@ -313,8 +310,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // error types are considered "builtin"
             Err(_) if lhs_ty.references_error() || rhs_ty.references_error() => self.tcx.ty_error(),
             Err(errors) => {
-                let source_map = self.tcx.sess.source_map();
-                let (mut err, missing_trait, use_output) = match is_assign {
+                let (_, trait_def_id) =
+                    lang_item_for_op(self.tcx, Op::Binary(op, is_assign), op.span);
+                let missing_trait = trait_def_id
+                    .map(|def_id| with_no_trimmed_paths!(self.tcx.def_path_str(def_id)));
+                let (mut err, output_def_id) = match is_assign {
                     IsAssign::Yes => {
                         let mut err = struct_span_err!(
                             self.tcx.sess,
@@ -328,112 +328,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             lhs_expr.span,
                             format!("cannot use `{}=` on type `{}`", op.node.as_str(), lhs_ty),
                         );
-                        let missing_trait = match op.node {
-                            hir::BinOpKind::Add => Some("std::ops::AddAssign"),
-                            hir::BinOpKind::Sub => Some("std::ops::SubAssign"),
-                            hir::BinOpKind::Mul => Some("std::ops::MulAssign"),
-                            hir::BinOpKind::Div => Some("std::ops::DivAssign"),
-                            hir::BinOpKind::Rem => Some("std::ops::RemAssign"),
-                            hir::BinOpKind::BitAnd => Some("std::ops::BitAndAssign"),
-                            hir::BinOpKind::BitXor => Some("std::ops::BitXorAssign"),
-                            hir::BinOpKind::BitOr => Some("std::ops::BitOrAssign"),
-                            hir::BinOpKind::Shl => Some("std::ops::ShlAssign"),
-                            hir::BinOpKind::Shr => Some("std::ops::ShrAssign"),
-                            _ => None,
-                        };
                         self.note_unmet_impls_on_type(&mut err, errors);
-                        (err, missing_trait, false)
+                        (err, None)
                     }
                     IsAssign::No => {
-                        let (message, missing_trait, use_output) = match op.node {
-                            hir::BinOpKind::Add => (
-                                format!("cannot add `{rhs_ty}` to `{lhs_ty}`"),
-                                Some("std::ops::Add"),
-                                true,
-                            ),
-                            hir::BinOpKind::Sub => (
-                                format!("cannot subtract `{rhs_ty}` from `{lhs_ty}`"),
-                                Some("std::ops::Sub"),
-                                true,
-                            ),
-                            hir::BinOpKind::Mul => (
-                                format!("cannot multiply `{lhs_ty}` by `{rhs_ty}`"),
-                                Some("std::ops::Mul"),
-                                true,
-                            ),
-                            hir::BinOpKind::Div => (
-                                format!("cannot divide `{lhs_ty}` by `{rhs_ty}`"),
-                                Some("std::ops::Div"),
-                                true,
-                            ),
-                            hir::BinOpKind::Rem => (
-                                format!("cannot mod `{lhs_ty}` by `{rhs_ty}`"),
-                                Some("std::ops::Rem"),
-                                true,
-                            ),
-                            hir::BinOpKind::BitAnd => (
-                                format!("no implementation for `{lhs_ty} & {rhs_ty}`"),
-                                Some("std::ops::BitAnd"),
-                                true,
-                            ),
-                            hir::BinOpKind::BitXor => (
-                                format!("no implementation for `{lhs_ty} ^ {rhs_ty}`"),
-                                Some("std::ops::BitXor"),
-                                true,
-                            ),
-                            hir::BinOpKind::BitOr => (
-                                format!("no implementation for `{lhs_ty} | {rhs_ty}`"),
-                                Some("std::ops::BitOr"),
-                                true,
-                            ),
-                            hir::BinOpKind::Shl => (
-                                format!("no implementation for `{lhs_ty} << {rhs_ty}`"),
-                                Some("std::ops::Shl"),
-                                true,
-                            ),
-                            hir::BinOpKind::Shr => (
-                                format!("no implementation for `{lhs_ty} >> {rhs_ty}`"),
-                                Some("std::ops::Shr"),
-                                true,
-                            ),
-                            hir::BinOpKind::Eq | hir::BinOpKind::Ne => (
-                                format!(
-                                    "binary operation `{}` cannot be applied to type `{}`",
-                                    op.node.as_str(),
-                                    lhs_ty
-                                ),
-                                Some("std::cmp::PartialEq"),
-                                false,
-                            ),
-                            hir::BinOpKind::Lt
-                            | hir::BinOpKind::Le
-                            | hir::BinOpKind::Gt
-                            | hir::BinOpKind::Ge => (
-                                format!(
-                                    "binary operation `{}` cannot be applied to type `{}`",
-                                    op.node.as_str(),
-                                    lhs_ty
-                                ),
-                                Some("std::cmp::PartialOrd"),
-                                false,
-                            ),
-                            _ => (
-                                format!(
-                                    "binary operation `{}` cannot be applied to type `{}`",
-                                    op.node.as_str(),
-                                    lhs_ty
-                                ),
-                                None,
-                                false,
+                        let message = match op.node {
+                            hir::BinOpKind::Add => {
+                                format!("cannot add `{rhs_ty}` to `{lhs_ty}`")
+                            }
+                            hir::BinOpKind::Sub => {
+                                format!("cannot subtract `{rhs_ty}` from `{lhs_ty}`")
+                            }
+                            hir::BinOpKind::Mul => {
+                                format!("cannot multiply `{lhs_ty}` by `{rhs_ty}`")
+                            }
+                            hir::BinOpKind::Div => {
+                                format!("cannot divide `{lhs_ty}` by `{rhs_ty}`")
+                            }
+                            hir::BinOpKind::Rem => {
+                                format!("cannot mod `{lhs_ty}` by `{rhs_ty}`")
+                            }
+                            hir::BinOpKind::BitAnd => {
+                                format!("no implementation for `{lhs_ty} & {rhs_ty}`")
+                            }
+                            hir::BinOpKind::BitXor => {
+                                format!("no implementation for `{lhs_ty} ^ {rhs_ty}`")
+                            }
+                            hir::BinOpKind::BitOr => {
+                                format!("no implementation for `{lhs_ty} | {rhs_ty}`")
+                            }
+                            hir::BinOpKind::Shl => {
+                                format!("no implementation for `{lhs_ty} << {rhs_ty}`")
+                            }
+                            hir::BinOpKind::Shr => {
+                                format!("no implementation for `{lhs_ty} >> {rhs_ty}`")
+                            }
+                            _ => format!(
+                                "binary operation `{}` cannot be applied to type `{}`",
+                                op.node.as_str(),
+                                lhs_ty
                             ),
                         };
+                        let output_def_id = trait_def_id.and_then(|def_id| {
+                            self.tcx
+                                .associated_item_def_ids(def_id)
+                                .iter()
+                                .find(|item_def_id| {
+                                    self.tcx.associated_item(*item_def_id).name == sym::Output
+                                })
+                                .cloned()
+                        });
                         let mut err = struct_span_err!(self.tcx.sess, op.span, E0369, "{message}");
                         if !lhs_expr.span.eq(&rhs_expr.span) {
                             err.span_label(lhs_expr.span, lhs_ty.to_string());
                             err.span_label(rhs_expr.span, rhs_ty.to_string());
                         }
                         self.note_unmet_impls_on_type(&mut err, errors);
-                        (err, missing_trait, use_output)
+                        (err, output_def_id)
                     }
                 };
 
@@ -448,24 +399,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         )
                         .is_ok()
                     {
-                        if let Ok(lstring) = source_map.span_to_snippet(lhs_expr.span) {
-                            let msg = &format!(
-                                "`{}{}` can be used on `{}`, you can dereference `{}`",
-                                op.node.as_str(),
-                                match is_assign {
-                                    IsAssign::Yes => "=",
-                                    IsAssign::No => "",
-                                },
-                                lhs_deref_ty.peel_refs(),
-                                lstring,
-                            );
-                            err.span_suggestion_verbose(
-                                lhs_expr.span.shrink_to_lo(),
-                                msg,
-                                "*",
-                                rustc_errors::Applicability::MachineApplicable,
-                            );
-                        }
+                        let msg = &format!(
+                            "`{}{}` can be used on `{}` if you dereference the left-hand side",
+                            op.node.as_str(),
+                            match is_assign {
+                                IsAssign::Yes => "=",
+                                IsAssign::No => "",
+                            },
+                            lhs_deref_ty,
+                        );
+                        err.span_suggestion_verbose(
+                            lhs_expr.span.shrink_to_lo(),
+                            msg,
+                            "*",
+                            rustc_errors::Applicability::MachineApplicable,
+                        );
                     }
                 };
 
@@ -514,9 +462,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
 
                 if let Some(missing_trait) = missing_trait {
-                    let mut visitor = TypeParamVisitor(vec![]);
-                    visitor.visit_ty(lhs_ty);
-
                     if op.node == hir::BinOpKind::Add
                         && self.check_str_addition(
                             lhs_expr, rhs_expr, lhs_ty, rhs_ty, &mut err, is_assign, op,
@@ -525,7 +470,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         // This has nothing here because it means we did string
                         // concatenation (e.g., "Hello " + "World!"). This means
                         // we don't want the note in the else clause to be emitted
-                    } else if let [ty] = &visitor.0[..] {
+                    } else if lhs_ty.has_param_types_or_consts() {
                         // Look for a TraitPredicate in the Fulfillment errors,
                         // and use it to generate a suggestion.
                         //
@@ -547,12 +492,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 if let Some(trait_pred) =
                                     error.obligation.predicate.to_opt_poly_trait_pred()
                                 {
-                                    let proj_pred = match error.obligation.cause.code() {
+                                    let output_associated_item = match error.obligation.cause.code()
+                                    {
                                         ObligationCauseCode::BinOp {
-                                            output_pred: Some(output_pred),
+                                            output_ty: Some(output_ty),
                                             ..
-                                        } if use_output => {
-                                            output_pred.to_opt_poly_projection_pred()
+                                        } => {
+                                            // Make sure that we're attaching `Output = ..` to the right trait predicate
+                                            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
+                                            {
+                                                Some(("Output", *output_ty))
+                                            } else {
+                                                None
+                                            }
                                         }
                                         _ => None,
                                     };
@@ -560,12 +514,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                     self.suggest_restricting_param_bound(
                                         &mut err,
                                         trait_pred,
-                                        proj_pred,
+                                        output_associated_item,
                                         self.body_id,
                                     );
                                 }
                             }
-                        } else if *ty != lhs_ty {
+                        } else {
                             // When we know that a missing bound is responsible, we don't show
                             // this note as it is redundant.
                             err.note(&format!(
@@ -702,14 +656,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         format!("cannot apply unary operator `{}`", op.as_str()),
                     );
 
-                    let mut visitor = TypeParamVisitor(vec![]);
-                    visitor.visit_ty(operand_ty);
-                    if let [_] = &visitor.0[..] && let ty::Param(_) = *operand_ty.kind() {
-                        let predicates = errors
-                            .iter()
-                            .filter_map(|error| {
-                                error.obligation.predicate.to_opt_poly_trait_pred()
-                            });
+                    if operand_ty.has_param_types_or_consts() {
+                        let predicates = errors.iter().filter_map(|error| {
+                            error.obligation.predicate.to_opt_poly_trait_pred()
+                        });
                         for pred in predicates {
                             self.suggest_restricting_param_bound(
                                 &mut err,
@@ -777,64 +727,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         op: Op,
         expected: Expectation<'tcx>,
     ) -> Result<MethodCallee<'tcx>, Vec<FulfillmentError<'tcx>>> {
-        let lang = self.tcx.lang_items();
-
         let span = match op {
             Op::Binary(op, _) => op.span,
             Op::Unary(_, span) => span,
         };
-        let (opname, trait_did) = if let Op::Binary(op, IsAssign::Yes) = op {
-            match op.node {
-                hir::BinOpKind::Add => (sym::add_assign, lang.add_assign_trait()),
-                hir::BinOpKind::Sub => (sym::sub_assign, lang.sub_assign_trait()),
-                hir::BinOpKind::Mul => (sym::mul_assign, lang.mul_assign_trait()),
-                hir::BinOpKind::Div => (sym::div_assign, lang.div_assign_trait()),
-                hir::BinOpKind::Rem => (sym::rem_assign, lang.rem_assign_trait()),
-                hir::BinOpKind::BitXor => (sym::bitxor_assign, lang.bitxor_assign_trait()),
-                hir::BinOpKind::BitAnd => (sym::bitand_assign, lang.bitand_assign_trait()),
-                hir::BinOpKind::BitOr => (sym::bitor_assign, lang.bitor_assign_trait()),
-                hir::BinOpKind::Shl => (sym::shl_assign, lang.shl_assign_trait()),
-                hir::BinOpKind::Shr => (sym::shr_assign, lang.shr_assign_trait()),
-                hir::BinOpKind::Lt
-                | hir::BinOpKind::Le
-                | hir::BinOpKind::Ge
-                | hir::BinOpKind::Gt
-                | hir::BinOpKind::Eq
-                | hir::BinOpKind::Ne
-                | hir::BinOpKind::And
-                | hir::BinOpKind::Or => {
-                    span_bug!(span, "impossible assignment operation: {}=", op.node.as_str())
-                }
-            }
-        } else if let Op::Binary(op, IsAssign::No) = op {
-            match op.node {
-                hir::BinOpKind::Add => (sym::add, lang.add_trait()),
-                hir::BinOpKind::Sub => (sym::sub, lang.sub_trait()),
-                hir::BinOpKind::Mul => (sym::mul, lang.mul_trait()),
-                hir::BinOpKind::Div => (sym::div, lang.div_trait()),
-                hir::BinOpKind::Rem => (sym::rem, lang.rem_trait()),
-                hir::BinOpKind::BitXor => (sym::bitxor, lang.bitxor_trait()),
-                hir::BinOpKind::BitAnd => (sym::bitand, lang.bitand_trait()),
-                hir::BinOpKind::BitOr => (sym::bitor, lang.bitor_trait()),
-                hir::BinOpKind::Shl => (sym::shl, lang.shl_trait()),
-                hir::BinOpKind::Shr => (sym::shr, lang.shr_trait()),
-                hir::BinOpKind::Lt => (sym::lt, lang.partial_ord_trait()),
-                hir::BinOpKind::Le => (sym::le, lang.partial_ord_trait()),
-                hir::BinOpKind::Ge => (sym::ge, lang.partial_ord_trait()),
-                hir::BinOpKind::Gt => (sym::gt, lang.partial_ord_trait()),
-                hir::BinOpKind::Eq => (sym::eq, lang.eq_trait()),
-                hir::BinOpKind::Ne => (sym::ne, lang.eq_trait()),
-                hir::BinOpKind::And | hir::BinOpKind::Or => {
-                    span_bug!(span, "&& and || are not overloadable")
-                }
-            }
-        } else if let Op::Unary(hir::UnOp::Not, _) = op {
-            (sym::not, lang.not_trait())
-        } else if let Op::Unary(hir::UnOp::Neg, _) = op {
-            (sym::neg, lang.neg_trait())
-        } else {
-            bug!("lookup_op_method: op not supported: {:?}", op)
-        };
+        let (opname, trait_did) = lang_item_for_op(self.tcx, op, span);
 
         debug!(
             "lookup_op_method(lhs_ty={:?}, op={:?}, opname={:?}, trait_did={:?})",
@@ -895,6 +792,66 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 }
 
+fn lang_item_for_op(
+    tcx: TyCtxt<'_>,
+    op: Op,
+    span: Span,
+) -> (rustc_span::Symbol, Option<hir::def_id::DefId>) {
+    let lang = tcx.lang_items();
+    if let Op::Binary(op, IsAssign::Yes) = op {
+        match op.node {
+            hir::BinOpKind::Add => (sym::add_assign, lang.add_assign_trait()),
+            hir::BinOpKind::Sub => (sym::sub_assign, lang.sub_assign_trait()),
+            hir::BinOpKind::Mul => (sym::mul_assign, lang.mul_assign_trait()),
+            hir::BinOpKind::Div => (sym::div_assign, lang.div_assign_trait()),
+            hir::BinOpKind::Rem => (sym::rem_assign, lang.rem_assign_trait()),
+            hir::BinOpKind::BitXor => (sym::bitxor_assign, lang.bitxor_assign_trait()),
+            hir::BinOpKind::BitAnd => (sym::bitand_assign, lang.bitand_assign_trait()),
+            hir::BinOpKind::BitOr => (sym::bitor_assign, lang.bitor_assign_trait()),
+            hir::BinOpKind::Shl => (sym::shl_assign, lang.shl_assign_trait()),
+            hir::BinOpKind::Shr => (sym::shr_assign, lang.shr_assign_trait()),
+            hir::BinOpKind::Lt
+            | hir::BinOpKind::Le
+            | hir::BinOpKind::Ge
+            | hir::BinOpKind::Gt
+            | hir::BinOpKind::Eq
+            | hir::BinOpKind::Ne
+            | hir::BinOpKind::And
+            | hir::BinOpKind::Or => {
+                span_bug!(span, "impossible assignment operation: {}=", op.node.as_str())
+            }
+        }
+    } else if let Op::Binary(op, IsAssign::No) = op {
+        match op.node {
+            hir::BinOpKind::Add => (sym::add, lang.add_trait()),
+            hir::BinOpKind::Sub => (sym::sub, lang.sub_trait()),
+            hir::BinOpKind::Mul => (sym::mul, lang.mul_trait()),
+            hir::BinOpKind::Div => (sym::div, lang.div_trait()),
+            hir::BinOpKind::Rem => (sym::rem, lang.rem_trait()),
+            hir::BinOpKind::BitXor => (sym::bitxor, lang.bitxor_trait()),
+            hir::BinOpKind::BitAnd => (sym::bitand, lang.bitand_trait()),
+            hir::BinOpKind::BitOr => (sym::bitor, lang.bitor_trait()),
+            hir::BinOpKind::Shl => (sym::shl, lang.shl_trait()),
+            hir::BinOpKind::Shr => (sym::shr, lang.shr_trait()),
+            hir::BinOpKind::Lt => (sym::lt, lang.partial_ord_trait()),
+            hir::BinOpKind::Le => (sym::le, lang.partial_ord_trait()),
+            hir::BinOpKind::Ge => (sym::ge, lang.partial_ord_trait()),
+            hir::BinOpKind::Gt => (sym::gt, lang.partial_ord_trait()),
+            hir::BinOpKind::Eq => (sym::eq, lang.eq_trait()),
+            hir::BinOpKind::Ne => (sym::ne, lang.eq_trait()),
+            hir::BinOpKind::And | hir::BinOpKind::Or => {
+                span_bug!(span, "&& and || are not overloadable")
+            }
+        }
+    } else if let Op::Unary(hir::UnOp::Not, _) = op {
+        (sym::not, lang.not_trait())
+    } else if let Op::Unary(hir::UnOp::Neg, _) = op {
+        (sym::neg, lang.neg_trait())
+    } else {
+        bug!("lookup_op_method: op not supported: {:?}", op)
+    }
+}
+
 // Binary operator categories. These categories summarize the behavior
 // with respect to the builtin operations supported.
 enum BinOpCategory {
@@ -1017,17 +974,6 @@ fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>, rhs: Ty<'tcx>, op: hir::BinOp) -> bool
     }
 }
 
-struct TypeParamVisitor<'tcx>(Vec<Ty<'tcx>>);
-
-impl<'tcx> TypeVisitor<'tcx> for TypeParamVisitor<'tcx> {
-    fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-        if let ty::Param(_) = ty.kind() {
-            self.0.push(ty);
-        }
-        ty.super_visit_with(self)
-    }
-}
-
 struct TypeParamEraser<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, Span);
 
 impl<'tcx> TypeFolder<'tcx> for TypeParamEraser<'_, 'tcx> {
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index 6dcc364bb50..8906b622b68 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -569,7 +569,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) -> Ty<'tcx> {
         // Determine the binding mode...
         let bm = match ba {
-            hir::BindingAnnotation::Unannotated => def_bm,
+            hir::BindingAnnotation::NONE => def_bm,
             _ => BindingMode::convert(ba),
         };
         // ...and store it in a side table:
@@ -655,7 +655,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ba: hir::BindingAnnotation,
     ) {
         match (expected.kind(), actual.kind(), ba) {
-            (ty::Ref(_, inner_ty, _), _, hir::BindingAnnotation::Unannotated)
+            (ty::Ref(_, inner_ty, _), _, hir::BindingAnnotation::NONE)
                 if self.can_eq(self.param_env, *inner_ty, actual).is_ok() =>
             {
                 err.span_suggestion_verbose(
@@ -665,7 +665,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     Applicability::MaybeIncorrect,
                 );
             }
-            (_, ty::Ref(_, inner_ty, _), hir::BindingAnnotation::Ref)
+            (_, ty::Ref(_, inner_ty, _), hir::BindingAnnotation::REF)
                 if self.can_eq(self.param_env, expected, *inner_ty).is_ok() =>
             {
                 err.span_suggestion_verbose(
@@ -981,7 +981,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         pat: &'tcx Pat<'tcx>,
         qpath: &'tcx hir::QPath<'tcx>,
         subpats: &'tcx [Pat<'tcx>],
-        ddpos: Option<usize>,
+        ddpos: hir::DotDotPos,
         expected: Ty<'tcx>,
         def_bm: BindingMode,
         ti: TopInfo<'tcx>,
@@ -1066,7 +1066,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Type-check subpatterns.
         if subpats.len() == variant.fields.len()
-            || subpats.len() < variant.fields.len() && ddpos.is_some()
+            || subpats.len() < variant.fields.len() && ddpos.as_opt_usize().is_some()
         {
             let ty::Adt(_, substs) = pat_ty.kind() else {
                 bug!("unexpected pattern type {:?}", pat_ty);
@@ -1254,14 +1254,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         span: Span,
         elements: &'tcx [Pat<'tcx>],
-        ddpos: Option<usize>,
+        ddpos: hir::DotDotPos,
         expected: Ty<'tcx>,
         def_bm: BindingMode,
         ti: TopInfo<'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
         let mut expected_len = elements.len();
-        if ddpos.is_some() {
+        if ddpos.as_opt_usize().is_some() {
             // Require known type only when `..` is present.
             if let ty::Tuple(tys) = self.structurally_resolved_type(span, expected).kind() {
                 expected_len = tys.len();
@@ -1397,7 +1397,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .iter()
                 .copied()
                 .filter(|(field, _)| {
-                    field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx)
+                    field.vis.is_accessible_from(tcx.parent_module(pat.hir_id), tcx)
                         && !matches!(
                             tcx.eval_stability(field.did, None, DUMMY_SP, None),
                             EvalResult::Deny { .. }
diff --git a/compiler/rustc_typeck/src/check/region.rs b/compiler/rustc_typeck/src/check/region.rs
index 0081e9049ee..b779713482e 100644
--- a/compiler/rustc_typeck/src/check/region.rs
+++ b/compiler/rustc_typeck/src/check/region.rs
@@ -587,8 +587,7 @@ fn resolve_local<'tcx>(
         // & expression, and its lifetime would be extended to the end of the block (due
         // to a different rule, not the below code).
         match pat.kind {
-            PatKind::Binding(hir::BindingAnnotation::Ref, ..)
-            | PatKind::Binding(hir::BindingAnnotation::RefMut, ..) => true,
+            PatKind::Binding(hir::BindingAnnotation(hir::ByRef::Yes, _), ..) => true,
 
             PatKind::Struct(_, ref field_pats, _) => {
                 field_pats.iter().any(|fp| is_binding_pat(&fp.pat))
@@ -607,10 +606,7 @@ fn resolve_local<'tcx>(
             PatKind::Box(ref subpat) => is_binding_pat(&subpat),
 
             PatKind::Ref(_, _)
-            | PatKind::Binding(
-                hir::BindingAnnotation::Unannotated | hir::BindingAnnotation::Mutable,
-                ..,
-            )
+            | PatKind::Binding(hir::BindingAnnotation(hir::ByRef::No, _), ..)
             | PatKind::Wild
             | PatKind::Path(_)
             | PatKind::Lit(_)
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 86cf12d2240..5c6c8aca173 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -768,7 +768,7 @@ impl<'tcx> TypeVisitor<'tcx> for GATSubstCollector<'tcx> {
 fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool {
     match ty.kind {
         hir::TyKind::TraitObject([trait_ref], ..) => match trait_ref.trait_ref.path.segments {
-            [s] => s.res.and_then(|r| r.opt_def_id()) == Some(trait_def_id.to_def_id()),
+            [s] => s.res.opt_def_id() == Some(trait_def_id.to_def_id()),
             _ => false,
         },
         _ => false,
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index 6236ad370df..e70f728d7dc 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -573,6 +573,7 @@ fn get_new_lifetime_name<'tcx>(
 
 /// Returns the predicates defined on `item_def_id` of the form
 /// `X: Foo` where `X` is the type parameter `def_id`.
+#[instrument(level = "trace", skip(tcx))]
 fn type_param_predicates(
     tcx: TyCtxt<'_>,
     (item_def_id, def_id, assoc_name): (DefId, LocalDefId, Ident),
@@ -679,7 +680,7 @@ impl<'tcx> ItemCtxt<'tcx> {
         assoc_name: Option<Ident>,
     ) -> Vec<(ty::Predicate<'tcx>, Span)> {
         let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id();
-        debug!(?param_def_id);
+        trace!(?param_def_id);
         ast_generics
             .predicates
             .iter()
@@ -708,9 +709,8 @@ impl<'tcx> ItemCtxt<'tcx> {
             .collect()
     }
 
+    #[instrument(level = "trace", skip(self))]
     fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool {
-        debug!("bound_defines_assoc_item(b={:?}, assoc_name={:?})", b, assoc_name);
-
         match b {
             hir::GenericBound::Trait(poly_trait_ref, _) => {
                 let trait_ref = &poly_trait_ref.trait_ref;
@@ -2105,11 +2105,10 @@ fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
 
 /// Returns a list of user-specified type predicates for the definition with ID `def_id`.
 /// N.B., this does not include any implied/inferred constraints.
+#[instrument(level = "trace", skip(tcx), ret)]
 fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
     use rustc_hir::*;
 
-    debug!("explicit_predicates_of(def_id={:?})", def_id);
-
     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
     let node = tcx.hir().get(hir_id);
 
@@ -2224,6 +2223,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
         + has_own_self as u32
         + early_bound_lifetimes_from_generics(tcx, ast_generics).count() as u32;
 
+    trace!(?predicates);
+    trace!(?ast_generics);
+
     // Collect the predicates that were written inline by the user on each
     // type parameter (e.g., `<T: Foo>`).
     for param in ast_generics.params {
@@ -2244,7 +2246,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
                     Some((param.hir_id, ast_generics.predicates)),
                     param.span,
                 );
+                trace!(?bounds);
                 predicates.extend(bounds.predicates(tcx, param_ty));
+                trace!(?predicates);
             }
             GenericParamKind::Const { .. } => {
                 // Bounds on const parameters are currently not possible.
@@ -2253,6 +2257,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
         }
     }
 
+    trace!(?predicates);
     // Add in the bounds that appear in the where-clause.
     for predicate in ast_generics.predicates {
         match predicate {
@@ -2338,12 +2343,10 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
         );
     }
 
-    let result = ty::GenericPredicates {
+    ty::GenericPredicates {
         parent: generics.parent,
         predicates: tcx.arena.alloc_from_iter(predicates),
-    };
-    debug!("explicit_predicates_of(def_id={:?}) = {:?}", def_id, result);
-    result
+    }
 }
 
 fn const_evaluatable_predicates_of<'tcx>(
diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_typeck/src/collect/item_bounds.rs
index 0d2b75d3328..318e8f581f7 100644
--- a/compiler/rustc_typeck/src/collect/item_bounds.rs
+++ b/compiler/rustc_typeck/src/collect/item_bounds.rs
@@ -53,6 +53,7 @@ fn associated_type_bounds<'tcx>(
 /// impl trait it isn't possible to write a suitable predicate on the
 /// containing function and for type-alias impl trait we don't have a backwards
 /// compatibility issue.
+#[instrument(level = "trace", skip(tcx), ret)]
 fn opaque_type_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
     opaque_def_id: DefId,
@@ -67,6 +68,8 @@ fn opaque_type_bounds<'tcx>(
         let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, ast_bounds);
         // Opaque types are implicitly sized unless a `?Sized` bound is found
         <dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span);
+        debug!(?bounds);
+
         tcx.arena.alloc_from_iter(bounds.predicates(tcx, item_ty))
     })
 }
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs
index 2435426873b..a0280ddca4b 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_typeck/src/collect/type_of.rs
@@ -1,6 +1,5 @@
 use rustc_errors::{Applicability, StashKey};
 use rustc_hir as hir;
-use rustc_hir::def::Res;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit;
 use rustc_hir::intravisit::Visitor;
@@ -179,15 +178,12 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
                 return None;
             };
 
-            // Try to use the segment resolution if it is valid, otherwise we
-            // default to the path resolution.
-            let res = segment.res.filter(|&r| r != Res::Err).unwrap_or(path.res);
-            let generics = match tcx.res_generics_def_id(res) {
+            let generics = match tcx.res_generics_def_id(segment.res) {
                 Some(def_id) => tcx.generics_of(def_id),
                 None => {
                     tcx.sess.delay_span_bug(
                         tcx.def_span(def_id),
-                        &format!("unexpected anon const res {:?} in path: {:?}", res, path),
+                        &format!("unexpected anon const res {:?} in path: {:?}", segment.res, path),
                     );
                     return None;
                 }
diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs
index 14c0558cdde..0d2e6674585 100644
--- a/compiler/rustc_typeck/src/errors.rs
+++ b/compiler/rustc_typeck/src/errors.rs
@@ -1,8 +1,8 @@
 //! Errors emitted by typeck.
-use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler};
 use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic};
 use rustc_middle::ty::Ty;
-use rustc_session::{parse::ParseSess, SessionDiagnostic};
+use rustc_session::SessionDiagnostic;
 use rustc_span::{symbol::Ident, Span, Symbol};
 
 #[derive(SessionDiagnostic)]
@@ -244,14 +244,15 @@ pub struct UnconstrainedOpaqueType {
 pub struct MissingTypeParams {
     pub span: Span,
     pub def_span: Span,
+    pub span_snippet: Option<String>,
     pub missing_type_params: Vec<Symbol>,
     pub empty_generic_args: bool,
 }
 
 // Manual implementation of `SessionDiagnostic` to be able to call `span_to_snippet`.
 impl<'a> SessionDiagnostic<'a> for MissingTypeParams {
-    fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
-        let mut err = sess.span_diagnostic.struct_span_err_with_code(
+    fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
+        let mut err = handler.struct_span_err_with_code(
             self.span,
             rustc_errors::fluent::typeck::missing_type_params,
             error_code!(E0393),
@@ -269,12 +270,9 @@ impl<'a> SessionDiagnostic<'a> for MissingTypeParams {
         err.span_label(self.def_span, rustc_errors::fluent::typeck::label);
 
         let mut suggested = false;
-        if let (Ok(snippet), true) = (
-            sess.source_map().span_to_snippet(self.span),
-            // Don't suggest setting the type params if there are some already: the order is
-            // tricky to get right and the user will already know what the syntax is.
-            self.empty_generic_args,
-        ) {
+        // Don't suggest setting the type params if there are some already: the order is
+        // tricky to get right and the user will already know what the syntax is.
+        if let Some(snippet) = self.span_snippet && self.empty_generic_args {
             if snippet.ends_with('>') {
                 // The user wrote `Trait<'a, T>` or similar. To provide an accurate suggestion
                 // we would have to preserve the right order. For now, as clearly the user is
diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs
index bfc4f061b70..f483342b445 100644
--- a/compiler/rustc_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_typeck/src/expr_use_visitor.rs
@@ -233,8 +233,9 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
                 self.consume_exprs(args);
             }
 
-            hir::ExprKind::MethodCall(.., args, _) => {
+            hir::ExprKind::MethodCall(.., receiver, args, _) => {
                 // callee.m(args)
+                self.consume_expr(receiver);
                 self.consume_exprs(args);
             }
 
diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
index d4b5e5e2fe4..4359124646d 100644
--- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
@@ -291,62 +291,60 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
     // Creates lifetime name suggestions from the lifetime parameter names
     fn get_lifetime_args_suggestions_from_param_names(
         &self,
-        path_hir_id: Option<hir::HirId>,
+        path_hir_id: hir::HirId,
         num_params_to_take: usize,
     ) -> String {
         debug!(?path_hir_id);
 
-        if let Some(path_hir_id) = path_hir_id {
-            let mut ret = Vec::new();
-            for (id, node) in self.tcx.hir().parent_iter(path_hir_id) {
-                debug!(?id);
-                let params = if let Some(generics) = node.generics() {
-                    generics.params
-                } else if let hir::Node::Ty(ty) = node
-                    && let hir::TyKind::BareFn(bare_fn) = ty.kind
-                {
-                    bare_fn.generic_params
-                } else {
-                    &[]
-                };
-                ret.extend(params.iter().filter_map(|p| {
-                    let hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }
-                        = p.kind
-                    else { return None };
-                    let hir::ParamName::Plain(name) = p.name else { return None };
-                    Some(name.to_string())
-                }));
-                // Suggest `'static` when in const/static item-like.
-                if let hir::Node::Item(hir::Item {
-                    kind: hir::ItemKind::Static { .. } | hir::ItemKind::Const { .. },
-                    ..
-                })
-                | hir::Node::TraitItem(hir::TraitItem {
-                    kind: hir::TraitItemKind::Const { .. },
-                    ..
-                })
-                | hir::Node::ImplItem(hir::ImplItem {
-                    kind: hir::ImplItemKind::Const { .. },
-                    ..
-                })
-                | hir::Node::ForeignItem(hir::ForeignItem {
-                    kind: hir::ForeignItemKind::Static { .. },
-                    ..
-                })
-                | hir::Node::AnonConst(..) = node
-                {
-                    ret.extend(
-                        std::iter::repeat("'static".to_owned())
-                            .take(num_params_to_take.saturating_sub(ret.len())),
-                    );
-                }
-                if ret.len() >= num_params_to_take {
-                    return ret[..num_params_to_take].join(", ");
-                }
-                // We cannot refer to lifetimes defined in an outer function.
-                if let hir::Node::Item(_) = node {
-                    break;
-                }
+        let mut ret = Vec::new();
+        for (id, node) in self.tcx.hir().parent_iter(path_hir_id) {
+            debug!(?id);
+            let params = if let Some(generics) = node.generics() {
+                generics.params
+            } else if let hir::Node::Ty(ty) = node
+                && let hir::TyKind::BareFn(bare_fn) = ty.kind
+            {
+                bare_fn.generic_params
+            } else {
+                &[]
+            };
+            ret.extend(params.iter().filter_map(|p| {
+                let hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }
+                    = p.kind
+                else { return None };
+                let hir::ParamName::Plain(name) = p.name else { return None };
+                Some(name.to_string())
+            }));
+            // Suggest `'static` when in const/static item-like.
+            if let hir::Node::Item(hir::Item {
+                kind: hir::ItemKind::Static { .. } | hir::ItemKind::Const { .. },
+                ..
+            })
+            | hir::Node::TraitItem(hir::TraitItem {
+                kind: hir::TraitItemKind::Const { .. },
+                ..
+            })
+            | hir::Node::ImplItem(hir::ImplItem {
+                kind: hir::ImplItemKind::Const { .. },
+                ..
+            })
+            | hir::Node::ForeignItem(hir::ForeignItem {
+                kind: hir::ForeignItemKind::Static { .. },
+                ..
+            })
+            | hir::Node::AnonConst(..) = node
+            {
+                ret.extend(
+                    std::iter::repeat("'static".to_owned())
+                        .take(num_params_to_take.saturating_sub(ret.len())),
+                );
+            }
+            if ret.len() >= num_params_to_take {
+                return ret[..num_params_to_take].join(", ");
+            }
+            // We cannot refer to lifetimes defined in an outer function.
+            if let hir::Node::Item(_) = node {
+                break;
             }
         }
 
@@ -690,8 +688,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
             num = num_trait_generics_except_self,
         );
 
-        if let Some(hir_id) = self.path_segment.hir_id
-        && let Some(parent_node) = self.tcx.hir().find_parent_node(hir_id)
+        if let Some(parent_node) = self.tcx.hir().find_parent_node(self.path_segment.hir_id)
         && let Some(parent_node) = self.tcx.hir().find(parent_node)
         && let hir::Node::Expr(expr) = parent_node {
             match expr.kind {
@@ -752,23 +749,45 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
     fn suggest_moving_args_from_assoc_fn_to_trait_for_method_call(
         &self,
         err: &mut Diagnostic,
-        trait_: DefId,
+        trait_def_id: DefId,
         expr: &'tcx hir::Expr<'tcx>,
         msg: String,
         num_assoc_fn_excess_args: usize,
         num_trait_generics_except_self: usize,
     ) {
-        if let hir::ExprKind::MethodCall(_, args, _) = expr.kind {
-            assert_eq!(args.len(), 1);
-            if num_assoc_fn_excess_args == num_trait_generics_except_self {
-                if let Some(gen_args) = self.gen_args.span_ext()
-                && let Ok(gen_args) = self.tcx.sess.source_map().span_to_snippet(gen_args)
-                && let Ok(args) = self.tcx.sess.source_map().span_to_snippet(args[0].span) {
-                    let sugg = format!("{}::{}::{}({})", self.tcx.item_name(trait_), gen_args, self.tcx.item_name(self.def_id), args);
-                    err.span_suggestion(expr.span, msg, sugg, Applicability::MaybeIncorrect);
-                }
-            }
+        let sm = self.tcx.sess.source_map();
+        let hir::ExprKind::MethodCall(_, rcvr, args, _) = expr.kind else { return; };
+        if num_assoc_fn_excess_args != num_trait_generics_except_self {
+            return;
         }
+        let Some(gen_args) = self.gen_args.span_ext() else { return; };
+        let Ok(generics) = sm.span_to_snippet(gen_args) else { return; };
+        let Ok(rcvr) = sm.span_to_snippet(
+            rcvr.span.find_ancestor_inside(expr.span).unwrap_or(rcvr.span)
+        ) else { return; };
+        let Ok(rest) =
+            (match args {
+                [] => Ok(String::new()),
+                [arg] => sm.span_to_snippet(
+                    arg.span.find_ancestor_inside(expr.span).unwrap_or(arg.span),
+                ),
+                [first, .., last] => {
+                    let first_span =
+                        first.span.find_ancestor_inside(expr.span).unwrap_or(first.span);
+                    let last_span =
+                        last.span.find_ancestor_inside(expr.span).unwrap_or(last.span);
+                    sm.span_to_snippet(first_span.to(last_span))
+                }
+            }) else { return; };
+        let comma = if args.len() > 0 { ", " } else { "" };
+        let trait_path = self.tcx.def_path_str(trait_def_id);
+        let method_name = self.tcx.item_name(self.def_id);
+        err.span_suggestion(
+            expr.span,
+            msg,
+            format!("{trait_path}::{generics}::{method_name}({rcvr}{comma}{rest})"),
+            Applicability::MaybeIncorrect,
+        );
     }
 
     /// Suggests to remove redundant argument(s):
diff --git a/compiler/rustc_typeck/src/variance/constraints.rs b/compiler/rustc_typeck/src/variance/constraints.rs
index d79450e1ae7..4fe213ffeea 100644
--- a/compiler/rustc_typeck/src/variance/constraints.rs
+++ b/compiler/rustc_typeck/src/variance/constraints.rs
@@ -271,11 +271,11 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 }
 
                 for projection in data.projection_bounds() {
-                    match projection.skip_binder().term {
-                        ty::Term::Ty(ty) => {
+                    match projection.skip_binder().term.unpack() {
+                        ty::TermKind::Ty(ty) => {
                             self.add_constraints_from_ty(current, ty, self.invariant);
                         }
-                        ty::Term::Const(c) => {
+                        ty::TermKind::Const(c) => {
                             self.add_constraints_from_const(current, c, self.invariant)
                         }
                     }
diff --git a/library/core/src/bool.rs b/library/core/src/bool.rs
index f7a8aa0d921..7667a650837 100644
--- a/library/core/src/bool.rs
+++ b/library/core/src/bool.rs
@@ -6,6 +6,12 @@ impl bool {
     /// Returns `Some(t)` if the `bool` is [`true`](../std/keyword.true.html),
     /// or `None` otherwise.
     ///
+    /// Arguments passed to `then_some` are eagerly evaluated; if you are
+    /// passing the result of a function call, it is recommended to use
+    /// [`then`], which is lazily evaluated.
+    ///
+    /// [`then`]: bool::then
+    ///
     /// # Examples
     ///
     /// ```
diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs
index 5bddfd1a413..05637c16622 100644
--- a/library/core/src/convert/mod.rs
+++ b/library/core/src/convert/mod.rs
@@ -558,6 +558,7 @@ where
 #[rustc_const_unstable(feature = "const_convert", issue = "88674")]
 impl<T> const From<T> for T {
     /// Returns the argument unchanged.
+    #[inline(always)]
     fn from(t: T) -> T {
         t
     }
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 92b12ed3352..e7deb728d15 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -1518,6 +1518,51 @@ macro_rules! int_impl {
             (a as Self, b)
         }
 
+        /// Calculates `self + rhs + carry` without the ability to overflow.
+        ///
+        /// Performs "signed ternary addition" which takes in an extra bit to add, and may return an
+        /// additional bit of overflow. This signed function is used only on the highest-ordered data,
+        /// for which the signed overflow result indicates whether the big integer overflowed or not.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(bigint_helper_methods)]
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, false), (7, false));")]
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, true), (8, false));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), (", stringify!($SelfT), "::MIN, true));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(0, true), (", stringify!($SelfT), "::MIN, true));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, true), (", stringify!($SelfT), "::MIN + 1, true));")]
+        #[doc = concat!("assert_eq!(",
+            stringify!($SelfT), "::MAX.carrying_add(", stringify!($SelfT), "::MAX, true), ",
+            "(-1, true));"
+        )]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.carrying_add(-1, true), (", stringify!($SelfT), "::MIN, false));")]
+        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".carrying_add(", stringify!($SelfT), "::MAX, true), (", stringify!($SelfT), "::MIN, true));")]
+        /// ```
+        ///
+        /// If `carry` is false, this method is equivalent to [`overflowing_add`](Self::overflowing_add):
+        ///
+        /// ```
+        /// #![feature(bigint_helper_methods)]
+        #[doc = concat!("assert_eq!(5_", stringify!($SelfT), ".carrying_add(2, false), 5_", stringify!($SelfT), ".overflowing_add(2));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), ", stringify!($SelfT), "::MAX.overflowing_add(1));")]
+        /// ```
+        #[unstable(feature = "bigint_helper_methods", issue = "85532")]
+        #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn carrying_add(self, rhs: Self, carry: bool) -> (Self, bool) {
+            // note: longer-term this should be done via an intrinsic.
+            // note: no intermediate overflow is required (https://github.com/rust-lang/rust/issues/85532#issuecomment-1032214946).
+            let (a, b) = self.overflowing_add(rhs);
+            let (c, d) = a.overflowing_add(carry as $SelfT);
+            (c, b != d)
+        }
+
         /// Calculates `self` + `rhs` with an unsigned `rhs`
         ///
         /// Returns a tuple of the addition along with a boolean indicating
@@ -1569,6 +1614,39 @@ macro_rules! int_impl {
             (a as Self, b)
         }
 
+        /// Calculates `self - rhs - borrow` without the ability to overflow.
+        ///
+        /// Performs "signed ternary subtraction" which takes in an extra bit to subtract, and may return an
+        /// additional bit of overflow. This signed function is used only on the highest-ordered data,
+        /// for which the signed overflow result indicates whether the big integer overflowed or not.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(bigint_helper_methods)]
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, false), (3, false));")]
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, true), (2, false));")]
+        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".borrowing_sub(1, false), (-1, false));")]
+        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".borrowing_sub(1, true), (-2, false));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.borrowing_sub(1, true), (", stringify!($SelfT), "::MAX - 1, true));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.borrowing_sub(-1, false), (", stringify!($SelfT), "::MIN, true));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.borrowing_sub(-1, true), (", stringify!($SelfT), "::MAX, false));")]
+        /// ```
+        #[unstable(feature = "bigint_helper_methods", issue = "85532")]
+        #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn borrowing_sub(self, rhs: Self, borrow: bool) -> (Self, bool) {
+            // note: longer-term this should be done via an intrinsic.
+            // note: no intermediate overflow is required (https://github.com/rust-lang/rust/issues/85532#issuecomment-1032214946).
+            let (a, b) = self.overflowing_sub(rhs);
+            let (c, d) = a.overflowing_sub(borrow as $SelfT);
+            (c, b != d)
+        }
+
         /// Calculates `self` - `rhs` with an unsigned `rhs`
         ///
         /// Returns a tuple of the subtraction along with a boolean indicating
diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs
index 47455760a4b..6c9e7574e17 100644
--- a/library/core/src/slice/iter/macros.rs
+++ b/library/core/src/slice/iter/macros.rs
@@ -64,7 +64,7 @@ macro_rules! iterator {
         // backwards by `n`. `n` must not exceed `self.len()`.
         macro_rules! zst_shrink {
             ($self: ident, $n: ident) => {
-                $self.end = $self.end.wrapping_byte_offset(-$n);
+                $self.end = $self.end.wrapping_byte_sub($n);
             }
         }
 
@@ -82,7 +82,7 @@ macro_rules! iterator {
             // returning the old start.
             // Unsafe because the offset must not exceed `self.len()`.
             #[inline(always)]
-            unsafe fn post_inc_start(&mut self, offset: isize) -> * $raw_mut T {
+            unsafe fn post_inc_start(&mut self, offset: usize) -> * $raw_mut T {
                 if mem::size_of::<T>() == 0 {
                     zst_shrink!(self, offset);
                     self.ptr.as_ptr()
@@ -90,7 +90,7 @@ macro_rules! iterator {
                     let old = self.ptr.as_ptr();
                     // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`,
                     // so this new pointer is inside `self` and thus guaranteed to be non-null.
-                    self.ptr = unsafe { NonNull::new_unchecked(self.ptr.as_ptr().offset(offset)) };
+                    self.ptr = unsafe { NonNull::new_unchecked(self.ptr.as_ptr().add(offset)) };
                     old
                 }
             }
@@ -99,7 +99,7 @@ macro_rules! iterator {
             // returning the new end.
             // Unsafe because the offset must not exceed `self.len()`.
             #[inline(always)]
-            unsafe fn pre_dec_end(&mut self, offset: isize) -> * $raw_mut T {
+            unsafe fn pre_dec_end(&mut self, offset: usize) -> * $raw_mut T {
                 if mem::size_of::<T>() == 0 {
                     zst_shrink!(self, offset);
                     self.ptr.as_ptr()
@@ -107,7 +107,7 @@ macro_rules! iterator {
                     // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`,
                     // which is guaranteed to not overflow an `isize`. Also, the resulting pointer
                     // is in bounds of `slice`, which fulfills the other requirements for `offset`.
-                    self.end = unsafe { self.end.offset(-offset) };
+                    self.end = unsafe { self.end.sub(offset) };
                     self.end
                 }
             }
@@ -180,7 +180,7 @@ macro_rules! iterator {
                 }
                 // SAFETY: We are in bounds. `post_inc_start` does the right thing even for ZSTs.
                 unsafe {
-                    self.post_inc_start(n as isize);
+                    self.post_inc_start(n);
                     Some(next_unchecked!(self))
                 }
             }
@@ -189,7 +189,7 @@ macro_rules! iterator {
             fn advance_by(&mut self, n: usize) -> Result<(), usize> {
                 let advance = cmp::min(len!(self), n);
                 // SAFETY: By construction, `advance` does not exceed `self.len()`.
-                unsafe { self.post_inc_start(advance as isize) };
+                unsafe { self.post_inc_start(advance) };
                 if advance == n { Ok(()) } else { Err(advance) }
             }
 
@@ -375,7 +375,7 @@ macro_rules! iterator {
                 }
                 // SAFETY: We are in bounds. `pre_dec_end` does the right thing even for ZSTs.
                 unsafe {
-                    self.pre_dec_end(n as isize);
+                    self.pre_dec_end(n);
                     Some(next_back_unchecked!(self))
                 }
             }
@@ -384,7 +384,7 @@ macro_rules! iterator {
             fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
                 let advance = cmp::min(len!(self), n);
                 // SAFETY: By construction, `advance` does not exceed `self.len()`.
-                unsafe { self.pre_dec_end(advance as isize) };
+                unsafe { self.pre_dec_end(advance) };
                 if advance == n { Ok(()) } else { Err(advance) }
             }
         }
diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs
index 8b025da2a46..c6c03c0b0db 100644
--- a/library/core/src/slice/sort.rs
+++ b/library/core/src/slice/sort.rs
@@ -365,12 +365,12 @@ where
         if count > 0 {
             macro_rules! left {
                 () => {
-                    l.add(*start_l as usize)
+                    l.add(usize::from(*start_l))
                 };
             }
             macro_rules! right {
                 () => {
-                    r.sub((*start_r as usize) + 1)
+                    r.sub(usize::from(*start_r) + 1)
                 };
             }
 
@@ -458,7 +458,7 @@ where
             //    the last block, so the `l.offset` calls are valid.
             unsafe {
                 end_l = end_l.sub(1);
-                ptr::swap(l.add(*end_l as usize), r.sub(1));
+                ptr::swap(l.add(usize::from(*end_l)), r.sub(1));
                 r = r.sub(1);
             }
         }
@@ -471,7 +471,7 @@ where
             // SAFETY: See the reasoning in [remaining-elements-safety].
             unsafe {
                 end_r = end_r.sub(1);
-                ptr::swap(l, r.sub((*end_r as usize) + 1));
+                ptr::swap(l, r.sub(usize::from(*end_r) + 1));
                 l = l.add(1);
             }
         }
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index c315f3a7975..4a0e162bc4a 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -3,6 +3,7 @@
 #![feature(array_methods)]
 #![feature(array_windows)]
 #![feature(bench_black_box)]
+#![feature(bigint_helper_methods)]
 #![feature(cell_update)]
 #![feature(const_assume)]
 #![feature(const_black_box)]
diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs
index 8b84a78e6be..18c55e43aac 100644
--- a/library/core/tests/num/int_macros.rs
+++ b/library/core/tests/num/int_macros.rs
@@ -338,6 +338,32 @@ macro_rules! int_module {
                 assert_eq!(MIN.checked_next_multiple_of(-3), None);
                 assert_eq!(MIN.checked_next_multiple_of(-1), Some(MIN));
             }
+
+            #[test]
+            fn test_carrying_add() {
+                assert_eq!($T::MAX.carrying_add(1, false), ($T::MIN, true));
+                assert_eq!($T::MAX.carrying_add(0, true), ($T::MIN, true));
+                assert_eq!($T::MAX.carrying_add(1, true), ($T::MIN + 1, true));
+                assert_eq!($T::MAX.carrying_add(-1, false), ($T::MAX - 1, false));
+                assert_eq!($T::MAX.carrying_add(-1, true), ($T::MAX, false)); // no intermediate overflow
+                assert_eq!($T::MIN.carrying_add(-1, false), ($T::MAX, true));
+                assert_eq!($T::MIN.carrying_add(-1, true), ($T::MIN, false)); // no intermediate overflow
+                assert_eq!((0 as $T).carrying_add($T::MAX, true), ($T::MIN, true));
+                assert_eq!((0 as $T).carrying_add($T::MIN, true), ($T::MIN + 1, false));
+            }
+
+            #[test]
+            fn test_borrowing_sub() {
+                assert_eq!($T::MIN.borrowing_sub(1, false), ($T::MAX, true));
+                assert_eq!($T::MIN.borrowing_sub(0, true), ($T::MAX, true));
+                assert_eq!($T::MIN.borrowing_sub(1, true), ($T::MAX - 1, true));
+                assert_eq!($T::MIN.borrowing_sub(-1, false), ($T::MIN + 1, false));
+                assert_eq!($T::MIN.borrowing_sub(-1, true), ($T::MIN, false)); // no intermediate overflow
+                assert_eq!($T::MAX.borrowing_sub(-1, false), ($T::MIN, true));
+                assert_eq!($T::MAX.borrowing_sub(-1, true), ($T::MAX, false)); // no intermediate overflow
+                assert_eq!((0 as $T).borrowing_sub($T::MIN, false), ($T::MIN, true));
+                assert_eq!((0 as $T).borrowing_sub($T::MIN, true), ($T::MAX, false));
+            }
         }
     };
 }
diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs
index 93ae620c233..15ae9f2324f 100644
--- a/library/core/tests/num/uint_macros.rs
+++ b/library/core/tests/num/uint_macros.rs
@@ -230,6 +230,28 @@ macro_rules! uint_module {
                 assert_eq!((1 as $T).checked_next_multiple_of(0), None);
                 assert_eq!(MAX.checked_next_multiple_of(2), None);
             }
+
+            #[test]
+            fn test_carrying_add() {
+                assert_eq!($T::MAX.carrying_add(1, false), (0, true));
+                assert_eq!($T::MAX.carrying_add(0, true), (0, true));
+                assert_eq!($T::MAX.carrying_add(1, true), (1, true));
+
+                assert_eq!($T::MIN.carrying_add($T::MAX, false), ($T::MAX, false));
+                assert_eq!($T::MIN.carrying_add(0, true), (1, false));
+                assert_eq!($T::MIN.carrying_add($T::MAX, true), (0, true));
+            }
+
+            #[test]
+            fn test_borrowing_sub() {
+                assert_eq!($T::MIN.borrowing_sub(1, false), ($T::MAX, true));
+                assert_eq!($T::MIN.borrowing_sub(0, true), ($T::MAX, true));
+                assert_eq!($T::MIN.borrowing_sub(1, true), ($T::MAX - 1, true));
+
+                assert_eq!($T::MAX.borrowing_sub($T::MAX, false), (0, false));
+                assert_eq!($T::MAX.borrowing_sub(0, true), ($T::MAX - 1, false));
+                assert_eq!($T::MAX.borrowing_sub($T::MAX, true), ($T::MAX, true));
+            }
         }
     };
 }
diff --git a/library/portable-simd/crates/std_float/src/lib.rs b/library/portable-simd/crates/std_float/src/lib.rs
index 4bd4d4c05e3..4ac60b10c92 100644
--- a/library/portable-simd/crates/std_float/src/lib.rs
+++ b/library/portable-simd/crates/std_float/src/lib.rs
@@ -1,9 +1,5 @@
 #![cfg_attr(feature = "as_crate", no_std)] // We are std!
-#![cfg_attr(
-    feature = "as_crate",
-    feature(platform_intrinsics),
-    feature(portable_simd)
-)]
+#![cfg_attr(feature = "as_crate", feature(platform_intrinsics), feature(portable_simd))]
 #[cfg(not(feature = "as_crate"))]
 use core::simd;
 #[cfg(feature = "as_crate")]
diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index dd4ff4952fd..2dc12a18a8a 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -607,15 +607,24 @@ pub fn stdout() -> Stdout {
     }
 }
 
+// Flush the data and disable buffering during shutdown
+// by replacing the line writer by one with zero
+// buffering capacity.
 pub fn cleanup() {
-    // Flush the data and disable buffering during shutdown
-    // by replacing the line writer by one with zero
-    // buffering capacity.
-    // We use try_lock() instead of lock(), because someone
-    // might have leaked a StdoutLock, which would
-    // otherwise cause a deadlock here.
-    if let Some(lock) = STDOUT.get().and_then(ReentrantMutex::try_lock) {
-        *lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw());
+    let mut initialized = false;
+    let stdout = STDOUT.get_or_init(|| {
+        initialized = true;
+        ReentrantMutex::new(RefCell::new(LineWriter::with_capacity(0, stdout_raw())))
+    });
+
+    if !initialized {
+        // The buffer was previously initialized, overwrite it here.
+        // We use try_lock() instead of lock(), because someone
+        // might have leaked a StdoutLock, which would
+        // otherwise cause a deadlock here.
+        if let Some(lock) = stdout.try_lock() {
+            *lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw());
+        }
     }
 }
 
@@ -983,6 +992,9 @@ pub fn set_output_capture(sink: Option<LocalStream>) -> Option<LocalStream> {
 /// the global stream.
 ///
 /// However, if the actual I/O causes an error, this function does panic.
+///
+/// Writing to non-blocking stdout/stderr can cause an error, which will lead
+/// this function to panic.
 fn print_to<T>(args: fmt::Arguments<'_>, global_s: fn() -> T, label: &str)
 where
     T: Write,
diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs
index a5003c66fca..6e4ba1404e5 100644
--- a/library/std/src/macros.rs
+++ b/library/std/src/macros.rs
@@ -49,6 +49,9 @@ macro_rules! panic {
 ///
 /// Panics if writing to `io::stdout()` fails.
 ///
+/// Writing to non-blocking stdout can cause an error, which will lead
+/// this macro to panic.
+///
 /// # Examples
 ///
 /// ```
@@ -107,6 +110,9 @@ macro_rules! print {
 ///
 /// Panics if writing to [`io::stdout`] fails.
 ///
+/// Writing to non-blocking stdout can cause an error, which will lead
+/// this macro to panic.
+///
 /// [`io::stdout`]: crate::io::stdout
 ///
 /// # Examples
@@ -147,6 +153,9 @@ macro_rules! println {
 ///
 /// Panics if writing to `io::stderr` fails.
 ///
+/// Writing to non-blocking stdout can cause an error, which will lead
+/// this macro to panic.
+///
 /// # Examples
 ///
 /// ```
@@ -179,6 +188,9 @@ macro_rules! eprint {
 ///
 /// Panics if writing to `io::stderr` fails.
 ///
+/// Writing to non-blocking stdout can cause an error, which will lead
+/// this macro to panic.
+///
 /// # Examples
 ///
 /// ```
diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs
index a463bc41db7..71e33fb9ed8 100644
--- a/library/std/src/os/fd/owned.rs
+++ b/library/std/src/os/fd/owned.rs
@@ -104,7 +104,8 @@ impl BorrowedFd<'_> {
         #[cfg(target_os = "espidf")]
         let cmd = libc::F_DUPFD;
 
-        let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) })?;
+        // Avoid using file descriptors below 3 as they are used for stdio
+        let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 3) })?;
         Ok(unsafe { OwnedFd::from_raw_fd(fd) })
     }
 
diff --git a/library/std/src/sys/hermit/fs.rs b/library/std/src/sys/hermit/fs.rs
index 1c5efa94bd3..f921839cf52 100644
--- a/library/std/src/sys/hermit/fs.rs
+++ b/library/std/src/sys/hermit/fs.rs
@@ -41,6 +41,9 @@ pub struct OpenOptions {
     mode: i32,
 }
 
+#[derive(Copy, Clone, Debug, Default)]
+pub struct FileTimes {}
+
 pub struct FilePermissions(!);
 
 pub struct FileType(!);
@@ -110,6 +113,11 @@ impl fmt::Debug for FilePermissions {
     }
 }
 
+impl FileTimes {
+    pub fn set_accessed(&mut self, _t: SystemTime) {}
+    pub fn set_modified(&mut self, _t: SystemTime) {}
+}
+
 impl FileType {
     pub fn is_dir(&self) -> bool {
         self.0
@@ -344,6 +352,10 @@ impl File {
     pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
         Err(Error::from_raw_os_error(22))
     }
+
+    pub fn set_times(&self, _times: FileTimes) -> io::Result<()> {
+        Err(Error::from_raw_os_error(22))
+    }
 }
 
 impl DirBuilder {
diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs
index e0184eb5baf..30c8fc4562d 100644
--- a/library/std/src/sys/hermit/mutex.rs
+++ b/library/std/src/sys/hermit/mutex.rs
@@ -2,7 +2,6 @@ use crate::cell::UnsafeCell;
 use crate::collections::VecDeque;
 use crate::hint;
 use crate::ops::{Deref, DerefMut, Drop};
-use crate::ptr;
 use crate::sync::atomic::{AtomicUsize, Ordering};
 use crate::sys::hermit::abi;
 
diff --git a/library/std/src/sys/hermit/net.rs b/library/std/src/sys/hermit/net.rs
index 74547617150..8a13879d8cc 100644
--- a/library/std/src/sys/hermit/net.rs
+++ b/library/std/src/sys/hermit/net.rs
@@ -487,6 +487,4 @@ pub mod netc {
 
     #[derive(Copy, Clone)]
     pub struct sockaddr {}
-
-    pub type socklen_t = usize;
 }
diff --git a/library/std/src/sys/hermit/rwlock.rs b/library/std/src/sys/hermit/rwlock.rs
index 9701bab1f66..1adf0b2be6b 100644
--- a/library/std/src/sys/hermit/rwlock.rs
+++ b/library/std/src/sys/hermit/rwlock.rs
@@ -1,6 +1,5 @@
 use crate::cell::UnsafeCell;
 use crate::sys::locks::{MovableCondvar, Mutex};
-use crate::sys_common::lazy_box::{LazyBox, LazyInit};
 
 pub struct RwLock {
     lock: Mutex,
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index 78d6ce3eff4..89d0ab59be8 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -66,6 +66,7 @@ pub type LPSYSTEM_INFO = *mut SYSTEM_INFO;
 pub type LPWSABUF = *mut WSABUF;
 pub type LPWSAOVERLAPPED = *mut c_void;
 pub type LPWSAOVERLAPPED_COMPLETION_ROUTINE = *mut c_void;
+pub type BCRYPT_ALG_HANDLE = LPVOID;
 
 pub type PCONDITION_VARIABLE = *mut CONDITION_VARIABLE;
 pub type PLARGE_INTEGER = *mut c_longlong;
@@ -278,6 +279,7 @@ pub const STATUS_INVALID_PARAMETER: NTSTATUS = 0xc000000d_u32 as _;
 pub const STATUS_PENDING: NTSTATUS = 0x103 as _;
 pub const STATUS_END_OF_FILE: NTSTATUS = 0xC0000011_u32 as _;
 pub const STATUS_NOT_IMPLEMENTED: NTSTATUS = 0xC0000002_u32 as _;
+pub const STATUS_NOT_SUPPORTED: NTSTATUS = 0xC00000BB_u32 as _;
 
 // Equivalent to the `NT_SUCCESS` C preprocessor macro.
 // See: https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values
@@ -285,7 +287,8 @@ pub fn nt_success(status: NTSTATUS) -> bool {
     status >= 0
 }
 
-pub const BCRYPT_RNG_ALG_HANDLE: usize = 0x81;
+// "RNG\0"
+pub const BCRYPT_RNG_ALGORITHM: &[u16] = &[b'R' as u16, b'N' as u16, b'G' as u16, 0];
 
 #[repr(C)]
 pub struct UNICODE_STRING {
@@ -1229,11 +1232,18 @@ extern "system" {
     // >= Vista / Server 2008
     // https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
     pub fn BCryptGenRandom(
-        hAlgorithm: LPVOID,
+        hAlgorithm: BCRYPT_ALG_HANDLE,
         pBuffer: *mut u8,
         cbBuffer: ULONG,
         dwFlags: ULONG,
     ) -> NTSTATUS;
+    pub fn BCryptOpenAlgorithmProvider(
+        phalgorithm: *mut BCRYPT_ALG_HANDLE,
+        pszAlgId: LPCWSTR,
+        pszimplementation: LPCWSTR,
+        dwflags: ULONG,
+    ) -> NTSTATUS;
+    pub fn BCryptCloseAlgorithmProvider(hAlgorithm: BCRYPT_ALG_HANDLE, dwFlags: ULONG) -> NTSTATUS;
 }
 
 // Functions that aren't available on every version of Windows that we support,
diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs
index c2ad592dfea..155d0297e49 100644
--- a/library/std/src/sys/windows/fs.rs
+++ b/library/std/src/sys/windows/fs.rs
@@ -403,7 +403,7 @@ impl File {
                     mem::size_of::<c::FILE_ATTRIBUTE_TAG_INFO>().try_into().unwrap(),
                 ))?;
                 if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
-                    reparse_tag = attr_tag.ReparseTag;
+                    attr.reparse_tag = attr_tag.ReparseTag;
                 }
             }
             Ok(attr)
diff --git a/library/std/src/sys/windows/rand.rs b/library/std/src/sys/windows/rand.rs
index 8b969788436..d6cd8f80271 100644
--- a/library/std/src/sys/windows/rand.rs
+++ b/library/std/src/sys/windows/rand.rs
@@ -22,7 +22,6 @@
 //! [`RtlGenRandom`]: https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom
 //! [`BCryptGenRandom`]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
 //! [Pseudo-handle]: https://docs.microsoft.com/en-us/windows/win32/seccng/cng-algorithm-pseudo-handles
-use crate::io;
 use crate::mem;
 use crate::ptr;
 use crate::sys::c;
@@ -34,35 +33,94 @@ use crate::sys::c;
 /// [`HashMap`]: crate::collections::HashMap
 /// [`RandomState`]: crate::collections::hash_map::RandomState
 pub fn hashmap_random_keys() -> (u64, u64) {
-    let mut v = (0, 0);
-    let ret = unsafe {
-        let size = mem::size_of_val(&v).try_into().unwrap();
-        c::BCryptGenRandom(
-            // BCRYPT_RNG_ALG_HANDLE is only supported in Windows 10+.
-            // So for Windows 8.1 and Windows 7 we'll need a fallback when this fails.
-            ptr::invalid_mut(c::BCRYPT_RNG_ALG_HANDLE),
-            ptr::addr_of_mut!(v).cast(),
-            size,
-            0,
-        )
-    };
-    if ret != 0 { fallback_rng() } else { v }
+    Rng::open().and_then(|rng| rng.gen_random_keys()).unwrap_or_else(fallback_rng)
+}
+
+struct Rng(c::BCRYPT_ALG_HANDLE);
+impl Rng {
+    #[cfg(miri)]
+    fn open() -> Result<Self, c::NTSTATUS> {
+        const BCRYPT_RNG_ALG_HANDLE: c::BCRYPT_ALG_HANDLE = ptr::invalid_mut(0x81);
+        let _ = (
+            c::BCryptOpenAlgorithmProvider,
+            c::BCryptCloseAlgorithmProvider,
+            c::BCRYPT_RNG_ALGORITHM,
+            c::STATUS_NOT_SUPPORTED,
+        );
+        Ok(Self(BCRYPT_RNG_ALG_HANDLE))
+    }
+    #[cfg(not(miri))]
+    // Open a handle to the RNG algorithm.
+    fn open() -> Result<Self, c::NTSTATUS> {
+        use crate::sync::atomic::AtomicPtr;
+        use crate::sync::atomic::Ordering::{Acquire, Release};
+        const ERROR_VALUE: c::LPVOID = ptr::invalid_mut(usize::MAX);
+
+        // An atomic is used so we don't need to reopen the handle every time.
+        static HANDLE: AtomicPtr<crate::ffi::c_void> = AtomicPtr::new(ptr::null_mut());
+
+        let mut handle = HANDLE.load(Acquire);
+        // We use a sentinel value to designate an error occurred last time.
+        if handle == ERROR_VALUE {
+            Err(c::STATUS_NOT_SUPPORTED)
+        } else if handle.is_null() {
+            let status = unsafe {
+                c::BCryptOpenAlgorithmProvider(
+                    &mut handle,
+                    c::BCRYPT_RNG_ALGORITHM.as_ptr(),
+                    ptr::null(),
+                    0,
+                )
+            };
+            if c::nt_success(status) {
+                // If another thread opens a handle first then use that handle instead.
+                let result = HANDLE.compare_exchange(ptr::null_mut(), handle, Release, Acquire);
+                if let Err(previous_handle) = result {
+                    // Close our handle and return the previous one.
+                    unsafe { c::BCryptCloseAlgorithmProvider(handle, 0) };
+                    handle = previous_handle;
+                }
+                Ok(Self(handle))
+            } else {
+                HANDLE.store(ERROR_VALUE, Release);
+                Err(status)
+            }
+        } else {
+            Ok(Self(handle))
+        }
+    }
+
+    fn gen_random_keys(self) -> Result<(u64, u64), c::NTSTATUS> {
+        let mut v = (0, 0);
+        let status = unsafe {
+            let size = mem::size_of_val(&v).try_into().unwrap();
+            c::BCryptGenRandom(self.0, ptr::addr_of_mut!(v).cast(), size, 0)
+        };
+        if c::nt_success(status) { Ok(v) } else { Err(status) }
+    }
 }
 
 /// Generate random numbers using the fallback RNG function (RtlGenRandom)
 #[cfg(not(target_vendor = "uwp"))]
 #[inline(never)]
-fn fallback_rng() -> (u64, u64) {
+fn fallback_rng(rng_status: c::NTSTATUS) -> (u64, u64) {
     let mut v = (0, 0);
     let ret =
         unsafe { c::RtlGenRandom(&mut v as *mut _ as *mut u8, mem::size_of_val(&v) as c::ULONG) };
 
-    if ret != 0 { v } else { panic!("fallback RNG broken: {}", io::Error::last_os_error()) }
+    if ret != 0 {
+        v
+    } else {
+        panic!(
+            "RNG broken: {rng_status:#x}, fallback RNG broken: {}",
+            crate::io::Error::last_os_error()
+        )
+    }
 }
 
 /// We can't use RtlGenRandom with UWP, so there is no fallback
 #[cfg(target_vendor = "uwp")]
 #[inline(never)]
-fn fallback_rng() -> (u64, u64) {
-    panic!("fallback RNG broken: RtlGenRandom() not supported on UWP");
+fn fallback_rng(rng_status: c::NTSTATUS) -> (u64, u64) {
+    panic!("RNG broken: {rng_status:#x} fallback RNG broken: RtlGenRandom() not supported on UWP");
 }
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index 2dad41bb18f..95e71173773 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -67,6 +67,7 @@ features = [
     "psapi",
     "impl-default",
     "timezoneapi",
+    "winbase",
 ]
 
 [dev-dependencies]
diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs
index 3a00e258e00..0ebabbd5ca5 100644
--- a/src/bootstrap/util.rs
+++ b/src/bootstrap/util.rs
@@ -197,9 +197,11 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> {
                 ptr::null_mut(),
             );
 
-            let mut data = [0u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize];
-            let db = data.as_mut_ptr() as *mut REPARSE_MOUNTPOINT_DATA_BUFFER;
-            let buf = &mut (*db).ReparseTarget as *mut u16;
+            #[repr(C, align(8))]
+            struct Align8<T>(T);
+            let mut data = Align8([0u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize]);
+            let db = data.0.as_mut_ptr() as *mut REPARSE_MOUNTPOINT_DATA_BUFFER;
+            let buf = core::ptr::addr_of_mut!((*db).ReparseTarget) as *mut u16;
             let mut i = 0;
             // FIXME: this conversion is very hacky
             let v = br"\??\";
@@ -219,7 +221,7 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> {
             let res = DeviceIoControl(
                 h as *mut _,
                 FSCTL_SET_REPARSE_POINT,
-                data.as_ptr() as *mut _,
+                db.cast(),
                 (*db).ReparseDataLength + 8,
                 ptr::null_mut(),
                 0,
diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md
index 3c9eecbe128..1d5ad3cce18 100644
--- a/src/doc/rustc/src/platform-support/fuchsia.md
+++ b/src/doc/rustc/src/platform-support/fuchsia.md
@@ -422,6 +422,7 @@ Next, we'll build a package manifest as defined by our manifest:
 
 ```sh
 ${SDK_PATH}/tools/${ARCH}/pm \
+    -api-level $(${SDK_PATH}/tools/${ARCH}/ffx version -v | grep "api-level" | head -1 |  awk -F ' ' '{print $2}') \
     -o pkg/hello_fuchsia_manifest \
     -m pkg/hello_fuchsia.manifest \
     build \
diff --git a/src/etc/check_missing_items.py b/src/etc/check_missing_items.py
index 025f320e3a1..991c881bae1 100644
--- a/src/etc/check_missing_items.py
+++ b/src/etc/check_missing_items.py
@@ -132,9 +132,11 @@ while work_list:
         work_list |= set(item["inner"]["items"]) - visited
     elif item["kind"] == "struct":
         check_generics(item["inner"]["generics"])
-        work_list |= (
-            set(item["inner"]["fields"]) | set(item["inner"]["impls"])
-        ) - visited
+        work_list |= set(item["inner"]["impls"]) - visited
+        if "tuple" in item["inner"]["kind"]:
+            work_list |= set(filter(None, item["inner"]["kind"]["tuple"])) - visited
+        elif "plain" in item["inner"]["kind"]:
+            work_list |= set(item["inner"]["kind"]["plain"]["fields"]) - visited
     elif item["kind"] == "struct_field":
         check_type(item["inner"])
     elif item["kind"] == "enum":
@@ -144,10 +146,10 @@ while work_list:
         ) - visited
     elif item["kind"] == "variant":
         if item["inner"]["variant_kind"] == "tuple":
-            for ty in item["inner"]["variant_inner"]:
-                check_type(ty)
+            for field_id in filter(None, item["inner"]["variant_inner"]):
+                work_list.add(field_id)
         elif item["inner"]["variant_kind"] == "struct":
-            work_list |= set(item["inner"]["variant_inner"]) - visited
+            work_list |= set(item["inner"]["variant_inner"]["fields"]) - visited
     elif item["kind"] in ("function", "method"):
         check_generics(item["inner"]["generics"])
         check_decl(item["inner"]["decl"])
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index be2227f47af..66f766bfbe8 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -190,7 +190,7 @@ fn clean_poly_trait_ref_with_bindings<'tcx>(
     )
 }
 
-fn clean_lifetime<'tcx>(lifetime: hir::Lifetime, cx: &mut DocContext<'tcx>) -> Lifetime {
+fn clean_lifetime<'tcx>(lifetime: &hir::Lifetime, cx: &mut DocContext<'tcx>) -> Lifetime {
     let def = cx.tcx.named_region(lifetime.hir_id);
     if let Some(
         rl::Region::EarlyBound(node_id)
@@ -370,9 +370,9 @@ fn clean_type_outlives_predicate<'tcx>(
 }
 
 fn clean_middle_term<'tcx>(term: ty::Term<'tcx>, cx: &mut DocContext<'tcx>) -> Term {
-    match term {
-        ty::Term::Ty(ty) => Term::Type(clean_middle_ty(ty, cx, None)),
-        ty::Term::Const(c) => Term::Constant(clean_middle_const(c, cx)),
+    match term.unpack() {
+        ty::TermKind::Ty(ty) => Term::Type(clean_middle_ty(ty, cx, None)),
+        ty::TermKind::Const(c) => Term::Constant(clean_middle_const(c, cx)),
     }
 }
 
@@ -495,7 +495,7 @@ fn clean_generic_param<'tcx>(
                     .filter(|bp| !bp.in_where_clause)
                     .flat_map(|bp| bp.bounds)
                     .map(|bound| match bound {
-                        hir::GenericBound::Outlives(lt) => clean_lifetime(*lt, cx),
+                        hir::GenericBound::Outlives(lt) => clean_lifetime(lt, cx),
                         _ => panic!(),
                     })
                     .collect()
@@ -1392,7 +1392,7 @@ fn maybe_expand_private_type_alias<'tcx>(
                     }
                     _ => None,
                 });
-                if let Some(lt) = lifetime.cloned() {
+                if let Some(lt) = lifetime {
                     let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id);
                     let cleaned =
                         if !lt.is_elided() { clean_lifetime(lt, cx) } else { Lifetime::elided() };
@@ -1777,7 +1777,7 @@ fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
     }
 }
 
-pub(crate) fn clean_visibility(vis: ty::Visibility) -> Visibility {
+pub(crate) fn clean_visibility(vis: ty::Visibility<DefId>) -> Visibility {
     match vis {
         ty::Visibility::Public => Visibility::Public,
         ty::Visibility::Restricted(module) => Visibility::Restricted(module),
@@ -2111,8 +2111,8 @@ fn clean_use_statement<'tcx>(
     // `pub(super)` or higher. If the current module is the top level
     // module, there isn't really a parent module, which makes the results
     // meaningless. In this case, we make sure the answer is `false`.
-    let is_visible_from_parent_mod = visibility.is_accessible_from(parent_mod.to_def_id(), cx.tcx)
-        && !current_mod.is_top_level_module();
+    let is_visible_from_parent_mod =
+        visibility.is_accessible_from(parent_mod, cx.tcx) && !current_mod.is_top_level_module();
 
     if pub_underscore {
         if let Some(ref inline) = inline_attr {
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index d6bb7c6c4fc..2077cf71b2e 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -2532,7 +2532,8 @@ mod size_asserts {
     // These are in alphabetical order, which is easy to maintain.
     static_assert_size!(Crate, 72); // frequently moved by-value
     static_assert_size!(DocFragment, 32);
-    static_assert_size!(GenericArg, 64);
+    #[cfg(not(bootstrap))]
+    static_assert_size!(GenericArg, 56);
     static_assert_size!(GenericArgs, 32);
     static_assert_size!(GenericParamDef, 56);
     static_assert_size!(Item, 56);
diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs
index 34d590fb244..151ec2b28ad 100644
--- a/src/librustdoc/html/render/span_map.rs
+++ b/src/librustdoc/html/render/span_map.rs
@@ -166,25 +166,23 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
 
     fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) {
         if let ExprKind::MethodCall(segment, ..) = expr.kind {
-            if let Some(hir_id) = segment.hir_id {
-                let hir = self.tcx.hir();
-                let body_id = hir.enclosing_body_owner(hir_id);
-                // FIXME: this is showing error messages for parts of the code that are not
-                // compiled (because of cfg)!
-                //
-                // See discussion in https://github.com/rust-lang/rust/issues/69426#issuecomment-1019412352
-                let typeck_results = self.tcx.typeck_body(
-                    hir.maybe_body_owned_by(body_id).expect("a body which isn't a body"),
+            let hir = self.tcx.hir();
+            let body_id = hir.enclosing_body_owner(segment.hir_id);
+            // FIXME: this is showing error messages for parts of the code that are not
+            // compiled (because of cfg)!
+            //
+            // See discussion in https://github.com/rust-lang/rust/issues/69426#issuecomment-1019412352
+            let typeck_results = self
+                .tcx
+                .typeck_body(hir.maybe_body_owned_by(body_id).expect("a body which isn't a body"));
+            if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) {
+                self.matches.insert(
+                    segment.ident.span,
+                    match hir.span_if_local(def_id) {
+                        Some(span) => LinkFromSrc::Local(clean::Span::new(span)),
+                        None => LinkFromSrc::External(def_id),
+                    },
                 );
-                if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) {
-                    self.matches.insert(
-                        segment.ident.span,
-                        match hir.span_if_local(def_id) {
-                            Some(span) => LinkFromSrc::Local(clean::Span::new(span)),
-                            None => LinkFromSrc::External(def_id),
-                        },
-                    );
-                }
             }
         } else if self.handle_macro(expr.span) {
             // We don't want to go deeper into the macro.
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 3502d97d470..2f31a0bb72e 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -197,10 +197,6 @@ h4.code-header {
 	position: relative;
 }
 
-div.impl-items > div {
-	padding-left: 0;
-}
-
 h1, h2, h3, h4, h5, h6,
 .sidebar,
 .mobile-topbar,
@@ -212,7 +208,6 @@ a.source,
 span.since,
 #source-sidebar, #sidebar-toggle,
 details.rustdoc-toggle > summary::before,
-div.impl-items > div:not(.docblock):not(.item-info),
 .content ul.crate a.crate,
 a.srclink,
 #help-button > button,
@@ -609,11 +604,6 @@ h2.location a {
 	text-align: center;
 }
 
-#results > table {
-	width: 100%;
-	table-layout: fixed;
-}
-
 .content > .example-wrap pre.line-numbers {
 	position: relative;
 	-webkit-user-select: none;
@@ -704,9 +694,6 @@ pre, .rustdoc.source .example-wrap {
 #main-content {
 	position: relative;
 }
-#main-content > .since {
-	top: inherit;
-}
 
 .content table {
 	border-spacing: 0 5px;
@@ -752,11 +739,6 @@ pre, .rustdoc.source .example-wrap {
 	font-size: 0.875rem;
 }
 
-.content .methods > div:not(.notable-traits):not(.method) {
-	margin-left: 40px;
-	margin-bottom: 15px;
-}
-
 .item-info {
 	display: block;
 }
@@ -770,10 +752,6 @@ pre, .rustdoc.source .example-wrap {
 	margin-left: 24px;
 }
 
-.sub-variant > div > .item-info {
-	margin-top: initial;
-}
-
 .content .impl-items .docblock, .content .impl-items .item-info {
 	margin-bottom: .6em;
 }
@@ -1466,9 +1444,7 @@ pre.rust {
 	border-radius: 2px;
 	cursor: pointer;
 }
-#settings-menu {
-	padding: 0;
-}
+
 #settings-menu > a, #help-button > button {
 	padding: 5px;
 	height: 100%;
@@ -1545,10 +1521,6 @@ kbd {
 	cursor: default;
 }
 
-#implementations-list > h3 > span.in-band {
-	width: 100%;
-}
-
 #main-content > ul {
 	padding-left: 10px;
 }
@@ -1760,7 +1732,6 @@ in storage.js plus the media query with (min-width: 701px)
 		padding-top: 0px;
 	}
 
-	.rustdoc,
 	.main-heading {
 		flex-direction: column;
 	}
@@ -2047,11 +2018,6 @@ in storage.js plus the media query with (min-width: 701px)
 		height: 73px;
 	}
 
-	#main-content > table td {
-		word-break: break-word;
-		width: 50%;
-	}
-
 	#crate-search {
 		border-radius: 4px;
 	}
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 4d009316730..1177d482ac0 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -304,11 +304,19 @@ impl FromWithTcx<clean::Struct> for Struct {
     fn from_tcx(struct_: clean::Struct, tcx: TyCtxt<'_>) -> Self {
         let fields_stripped = struct_.has_stripped_entries();
         let clean::Struct { struct_type, generics, fields } = struct_;
+
+        let kind = match struct_type {
+            CtorKind::Fn => StructKind::Tuple(ids_keeping_stripped(fields, tcx)),
+            CtorKind::Const => {
+                assert!(fields.is_empty());
+                StructKind::Unit
+            }
+            CtorKind::Fictive => StructKind::Plain { fields: ids(fields, tcx), fields_stripped },
+        };
+
         Struct {
-            struct_type: from_ctor_kind(struct_type),
+            kind,
             generics: generics.into_tcx(tcx),
-            fields_stripped,
-            fields: ids(fields, tcx),
             impls: Vec::new(), // Added in JsonRenderer::item
         }
     }
@@ -327,14 +335,6 @@ impl FromWithTcx<clean::Union> for Union {
     }
 }
 
-pub(crate) fn from_ctor_kind(struct_type: CtorKind) -> StructType {
-    match struct_type {
-        CtorKind::Fictive => StructType::Plain,
-        CtorKind::Fn => StructType::Tuple,
-        CtorKind::Const => StructType::Unit,
-    }
-}
-
 pub(crate) fn from_fn_header(header: &rustc_hir::FnHeader) -> Header {
     Header {
         async_: header.is_async(),
@@ -644,36 +644,16 @@ impl FromWithTcx<clean::Enum> for Enum {
     }
 }
 
-impl FromWithTcx<clean::VariantStruct> for Struct {
-    fn from_tcx(struct_: clean::VariantStruct, tcx: TyCtxt<'_>) -> Self {
-        let fields_stripped = struct_.has_stripped_entries();
-        let clean::VariantStruct { struct_type, fields } = struct_;
-        Struct {
-            struct_type: from_ctor_kind(struct_type),
-            generics: Generics { params: vec![], where_predicates: vec![] },
-            fields_stripped,
-            fields: ids(fields, tcx),
-            impls: Vec::new(),
-        }
-    }
-}
-
 impl FromWithTcx<clean::Variant> for Variant {
     fn from_tcx(variant: clean::Variant, tcx: TyCtxt<'_>) -> Self {
         use clean::Variant::*;
         match variant {
             CLike(disr) => Variant::Plain(disr.map(|disr| disr.into_tcx(tcx))),
-            Tuple(fields) => Variant::Tuple(
-                fields
-                    .into_iter()
-                    .filter_map(|f| match *f.kind {
-                        clean::StructFieldItem(ty) => Some(ty.into_tcx(tcx)),
-                        clean::StrippedItem(_) => None,
-                        _ => unreachable!(),
-                    })
-                    .collect(),
-            ),
-            Struct(s) => Variant::Struct(ids(s.fields, tcx)),
+            Tuple(fields) => Variant::Tuple(ids_keeping_stripped(fields, tcx)),
+            Struct(s) => Variant::Struct {
+                fields_stripped: s.has_stripped_entries(),
+                fields: ids(s.fields, tcx),
+            },
         }
     }
 }
@@ -796,3 +776,19 @@ fn ids(items: impl IntoIterator<Item = clean::Item>, tcx: TyCtxt<'_>) -> Vec<Id>
         .map(|i| from_item_id_with_name(i.item_id, tcx, i.name))
         .collect()
 }
+
+fn ids_keeping_stripped(
+    items: impl IntoIterator<Item = clean::Item>,
+    tcx: TyCtxt<'_>,
+) -> Vec<Option<Id>> {
+    items
+        .into_iter()
+        .map(|i| {
+            if !i.is_stripped() && !i.is_keyword() {
+                Some(from_item_id_with_name(i.item_id, tcx, i.name))
+            } else {
+                None
+            }
+        })
+        .collect()
+}
diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs
index 0d968402503..ca86ac89e85 100644
--- a/src/librustdoc/scrape_examples.rs
+++ b/src/librustdoc/scrape_examples.rs
@@ -159,7 +159,7 @@ where
                     return;
                 }
             }
-            hir::ExprKind::MethodCall(path, _, call_span) => {
+            hir::ExprKind::MethodCall(path, _, _, call_span) => {
                 let types = tcx.typeck(ex.hir_id.owner);
                 let Some(def_id) = types.type_dependent_def_id(ex.hir_id) else {
                     trace!("type_dependent_def_id({}) = None", ex.hir_id);
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index d25f68b3743..13bafa506e4 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -9,7 +9,7 @@ use std::path::PathBuf;
 use serde::{Deserialize, Serialize};
 
 /// rustdoc format-version.
-pub const FORMAT_VERSION: u32 = 19;
+pub const FORMAT_VERSION: u32 = 21;
 
 /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
 /// about the language items in the local crate, as well as info about external items to allow
@@ -289,14 +289,40 @@ pub struct Union {
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Struct {
-    pub struct_type: StructType,
+    pub kind: StructKind,
     pub generics: Generics,
-    pub fields_stripped: bool,
-    pub fields: Vec<Id>,
     pub impls: Vec<Id>,
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
+#[serde(rename_all = "snake_case")]
+pub enum StructKind {
+    /// A struct with no fields and no parentheses.
+    ///
+    /// ```rust
+    /// pub struct Unit;
+    /// ```
+    Unit,
+    /// A struct with unnamed fields.
+    ///
+    /// ```rust
+    /// pub struct TupleStruct(i32);
+    /// pub struct EmptyTupleStruct();
+    /// ```
+    ///
+    /// All [`Id`]'s will point to [`ItemEnum::StructField`]. Private and
+    /// `#[doc(hidden)]` fields will be given as `None`
+    Tuple(Vec<Option<Id>>),
+    /// A struct with nammed fields.
+    ///
+    /// ```rust
+    /// pub struct PlainStruct { x: i32 }
+    /// pub struct EmptyPlainStruct {}
+    /// ```
+    Plain { fields: Vec<Id>, fields_stripped: bool },
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Enum {
     pub generics: Generics,
     pub variants_stripped: bool,
@@ -308,9 +334,36 @@ pub struct Enum {
 #[serde(rename_all = "snake_case")]
 #[serde(tag = "variant_kind", content = "variant_inner")]
 pub enum Variant {
+    /// A variant with no parentheses, and possible discriminant.
+    ///
+    /// ```rust
+    /// enum Demo {
+    ///     PlainVariant,
+    ///     PlainWithDiscriminant = 1,
+    /// }
+    /// ```
     Plain(Option<Discriminant>),
-    Tuple(Vec<Type>),
-    Struct(Vec<Id>),
+    /// A variant with unnamed fields.
+    ///
+    /// Unlike most of json, `#[doc(hidden)]` fields will be given as `None`
+    /// instead of being ommited, because order matters.
+    ///
+    /// ```rust
+    /// enum Demo {
+    ///     TupleVariant(i32),
+    ///     EmptyTupleVariant(),
+    /// }
+    /// ```
+    Tuple(Vec<Option<Id>>),
+    /// A variant with named fields.
+    ///
+    /// ```rust
+    /// enum Demo {
+    ///     StructVariant { x: i32 },
+    ///     EmptyStructVariant {},
+    /// }
+    /// ```
+    Struct { fields: Vec<Id>, fields_stripped: bool },
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
@@ -331,14 +384,6 @@ pub struct Discriminant {
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
-#[serde(rename_all = "snake_case")]
-pub enum StructType {
-    Plain,
-    Tuple,
-    Unit,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Header {
     #[serde(rename = "const")]
     pub const_: bool,
diff --git a/src/rustdoc-json-types/tests.rs b/src/rustdoc-json-types/tests.rs
index e7f6447ed87..399ff54b294 100644
--- a/src/rustdoc-json-types/tests.rs
+++ b/src/rustdoc-json-types/tests.rs
@@ -3,10 +3,8 @@ use super::*;
 #[test]
 fn test_struct_info_roundtrip() {
     let s = ItemEnum::Struct(Struct {
-        struct_type: StructType::Plain,
         generics: Generics { params: vec![], where_predicates: vec![] },
-        fields_stripped: false,
-        fields: vec![],
+        kind: StructKind::Plain { fields: vec![], fields_stripped: false },
         impls: vec![],
     });
 
diff --git a/src/test/codegen/issue-98294-get-mut-copy-from-slice-opt.rs b/src/test/codegen/issue-98294-get-mut-copy-from-slice-opt.rs
new file mode 100644
index 00000000000..7da29cd7952
--- /dev/null
+++ b/src/test/codegen/issue-98294-get-mut-copy-from-slice-opt.rs
@@ -0,0 +1,19 @@
+// min-llvm-version: 15.0.0
+// ignore-debug: The debug assertions get in the way
+// compile-flags: -O
+
+#![crate_type = "lib"]
+
+// There should be no calls to panic / len_mismatch_fail.
+
+#[no_mangle]
+pub fn test(a: &mut [u8], offset: usize, bytes: &[u8]) {
+    // CHECK-LABEL: @test(
+    // CHECK-NOT: call
+    // CHECK: call void @llvm.memcpy
+    // CHECK-NOT: call
+    // CHECK: }
+    if let Some(dst) = a.get_mut(offset..offset + bytes.len()) {
+        dst.copy_from_slice(bytes);
+    }
+}
diff --git a/src/test/debuginfo/msvc-pretty-enums.rs b/src/test/debuginfo/msvc-pretty-enums.rs
index 45d5ddf5c0e..7f1be6f2784 100644
--- a/src/test/debuginfo/msvc-pretty-enums.rs
+++ b/src/test/debuginfo/msvc-pretty-enums.rs
@@ -53,8 +53,8 @@
 // cdb-command: dx niche128_none
 // cdb-check: niche128_none    : None [Type: enum2$<core::option::Option<core::num::nonzero::NonZeroI128> >]
 
-// cdb-command: dx wrapping_niche128_dataful
-// cdb-check: wrapping_niche128_dataful : X [Type: enum2$<msvc_pretty_enums::Wrapping128Niche>]
+// cdb-command: dx wrapping_niche128_untagged
+// cdb-check: wrapping_niche128_untagged : X [Type: enum2$<msvc_pretty_enums::Wrapping128Niche>]
 // cdb-check:    [+0x[...]] __0              [Type: msvc_pretty_enums::Wrapping128]
 
 // cdb-command: dx wrapping_niche128_none1
@@ -213,7 +213,7 @@ fn main() {
     let niche128_some = Some(NonZeroI128::new(123456).unwrap());
     let niche128_none: Option<NonZeroI128> = None;
 
-    let wrapping_niche128_dataful =
+    let wrapping_niche128_untagged =
         unsafe { Wrapping128Niche::X(Wrapping128(340282366920938463463374607431768211454)) };
     let wrapping_niche128_none1 = Wrapping128Niche::Y;
     let wrapping_niche128_none2 = Wrapping128Niche::Z;
diff --git a/src/test/incremental/issue-100521-change-struct-name-assocty.rs b/src/test/incremental/issue-100521-change-struct-name-assocty.rs
new file mode 100644
index 00000000000..7f8d1e60881
--- /dev/null
+++ b/src/test/incremental/issue-100521-change-struct-name-assocty.rs
@@ -0,0 +1,65 @@
+// revisions: rpass1 rpass2
+
+pub fn foo() {
+    bar();
+    baz::<()>();
+}
+
+fn bar()
+where
+    <() as Table>::AllColumns:,
+{
+}
+
+fn baz<W>()
+where
+    W: AsQuery,
+    <W as AsQuery>::Query:,
+{
+}
+
+trait AsQuery {
+    type Query;
+}
+
+trait UnimplementedTrait {}
+
+impl<T> AsQuery for T
+where
+    T: UnimplementedTrait,
+{
+    type Query = ();
+}
+
+struct Wrapper<Expr>(Expr);
+
+impl<Ret> AsQuery for Wrapper<Ret> {
+    type Query = ();
+}
+
+impl AsQuery for ()
+where
+    Wrapper<<() as Table>::AllColumns>: AsQuery,
+{
+    type Query = ();
+}
+
+trait Table {
+    type AllColumns;
+}
+
+#[cfg(rpass1)]
+impl Table for () {
+    type AllColumns = Checksum1;
+}
+#[cfg(rpass1)]
+struct Checksum1;
+
+#[cfg(rpass2)]
+impl Table for () {
+    type AllColumns = Checksum2;
+}
+#[cfg(rpass2)]
+struct Checksum2;
+
+fn main() {}
diff --git a/src/test/mir-opt/array-index-is-temporary.rs b/src/test/mir-opt/array-index-is-temporary.rs
index 0e4c486e464..e7bde81d4ca 100644
--- a/src/test/mir-opt/array-index-is-temporary.rs
+++ b/src/test/mir-opt/array-index-is-temporary.rs
@@ -7,7 +7,7 @@ unsafe fn foo(z: *mut usize) -> u32 {
     99
 }
 
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
 // EMIT_MIR array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir
 fn main() {
     let mut x = [42, 43, 44];
diff --git a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir
deleted file mode 100644
index 27f883ed321..00000000000
--- a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir
+++ /dev/null
@@ -1,64 +0,0 @@
-// MIR for `main` after SimplifyCfg-elaborate-drops
-
-fn main() -> () {
-    let mut _0: ();                      // return place in scope 0 at $DIR/array-index-is-temporary.rs:+0:11: +0:11
-    let mut _1: [u32; 3];                // in scope 0 at $DIR/array-index-is-temporary.rs:+1:9: +1:14
-    let mut _4: &mut usize;              // in scope 0 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
-    let mut _5: u32;                     // in scope 0 at $DIR/array-index-is-temporary.rs:+4:12: +4:29
-    let mut _6: *mut usize;              // in scope 0 at $DIR/array-index-is-temporary.rs:+4:25: +4:26
-    let _7: usize;                       // in scope 0 at $DIR/array-index-is-temporary.rs:+4:7: +4:8
-    let mut _8: usize;                   // in scope 0 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
-    let mut _9: bool;                    // in scope 0 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
-    scope 1 {
-        debug x => _1;                   // in scope 1 at $DIR/array-index-is-temporary.rs:+1:9: +1:14
-        let mut _2: usize;               // in scope 1 at $DIR/array-index-is-temporary.rs:+2:9: +2:14
-        scope 2 {
-            debug y => _2;               // in scope 2 at $DIR/array-index-is-temporary.rs:+2:9: +2:14
-            let _3: *mut usize;          // in scope 2 at $DIR/array-index-is-temporary.rs:+3:9: +3:10
-            scope 3 {
-                debug z => _3;           // in scope 3 at $DIR/array-index-is-temporary.rs:+3:9: +3:10
-                scope 4 {
-                }
-            }
-        }
-    }
-
-    bb0: {
-        StorageLive(_1);                 // scope 0 at $DIR/array-index-is-temporary.rs:+1:9: +1:14
-        _1 = [const 42_u32, const 43_u32, const 44_u32]; // scope 0 at $DIR/array-index-is-temporary.rs:+1:17: +1:29
-        StorageLive(_2);                 // scope 1 at $DIR/array-index-is-temporary.rs:+2:9: +2:14
-        _2 = const 1_usize;              // scope 1 at $DIR/array-index-is-temporary.rs:+2:17: +2:18
-        StorageLive(_3);                 // scope 2 at $DIR/array-index-is-temporary.rs:+3:9: +3:10
-        StorageLive(_4);                 // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
-        _4 = &mut _2;                    // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
-        _3 = &raw mut (*_4);             // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
-        StorageDead(_4);                 // scope 2 at $DIR/array-index-is-temporary.rs:+3:31: +3:32
-        StorageLive(_5);                 // scope 3 at $DIR/array-index-is-temporary.rs:+4:12: +4:29
-        StorageLive(_6);                 // scope 4 at $DIR/array-index-is-temporary.rs:+4:25: +4:26
-        _6 = _3;                         // scope 4 at $DIR/array-index-is-temporary.rs:+4:25: +4:26
-        _5 = foo(move _6) -> bb1;        // scope 4 at $DIR/array-index-is-temporary.rs:+4:21: +4:27
-                                         // mir::Constant
-                                         // + span: $DIR/array-index-is-temporary.rs:16:21: 16:24
-                                         // + literal: Const { ty: unsafe fn(*mut usize) -> u32 {foo}, val: Value(<ZST>) }
-    }
-
-    bb1: {
-        StorageDead(_6);                 // scope 4 at $DIR/array-index-is-temporary.rs:+4:26: +4:27
-        StorageLive(_7);                 // scope 3 at $DIR/array-index-is-temporary.rs:+4:7: +4:8
-        _7 = _2;                         // scope 3 at $DIR/array-index-is-temporary.rs:+4:7: +4:8
-        _8 = Len(_1);                    // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
-        _9 = Lt(_7, _8);                 // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
-        assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
-    }
-
-    bb2: {
-        _1[_7] = move _5;                // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:29
-        StorageDead(_5);                 // scope 3 at $DIR/array-index-is-temporary.rs:+4:28: +4:29
-        StorageDead(_7);                 // scope 3 at $DIR/array-index-is-temporary.rs:+4:29: +4:30
-        _0 = const ();                   // scope 0 at $DIR/array-index-is-temporary.rs:+0:11: +5:2
-        StorageDead(_3);                 // scope 2 at $DIR/array-index-is-temporary.rs:+5:1: +5:2
-        StorageDead(_2);                 // scope 1 at $DIR/array-index-is-temporary.rs:+5:1: +5:2
-        StorageDead(_1);                 // scope 0 at $DIR/array-index-is-temporary.rs:+5:1: +5:2
-        return;                          // scope 0 at $DIR/array-index-is-temporary.rs:+5:2: +5:2
-    }
-}
diff --git a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir
index 27f883ed321..27f883ed321 100644
--- a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir
+++ b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir
diff --git a/src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir b/src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir
index d3914597362..96716a39a2b 100644
--- a/src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir
+++ b/src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir
@@ -8,13 +8,13 @@ fn match_tuple(_1: (u32, bool, Option<i32>, u32)) -> u32 {
     let mut _4: bool;                    // in scope 0 at $DIR/exponential-or.rs:+2:70: +2:77
     let mut _5: bool;                    // in scope 0 at $DIR/exponential-or.rs:+2:62: +2:67
     let mut _6: bool;                    // in scope 0 at $DIR/exponential-or.rs:+2:62: +2:67
-    let _7: u32;                         // in scope 0 at $DIR/exponential-or.rs:+2:10: +2:21
-    let _8: u32;                         // in scope 0 at $DIR/exponential-or.rs:+2:57: +2:78
+    let _7: u32;                         // in scope 0 at $DIR/exponential-or.rs:+2:10: +2:11
+    let _8: u32;                         // in scope 0 at $DIR/exponential-or.rs:+2:57: +2:58
     let mut _9: u32;                     // in scope 0 at $DIR/exponential-or.rs:+2:83: +2:84
     let mut _10: u32;                    // in scope 0 at $DIR/exponential-or.rs:+2:87: +2:88
     scope 1 {
-        debug y => _7;                   // in scope 1 at $DIR/exponential-or.rs:+2:10: +2:21
-        debug z => _8;                   // in scope 1 at $DIR/exponential-or.rs:+2:57: +2:78
+        debug y => _7;                   // in scope 1 at $DIR/exponential-or.rs:+2:10: +2:11
+        debug z => _8;                   // in scope 1 at $DIR/exponential-or.rs:+2:57: +2:58
     }
 
     bb0: {
@@ -61,10 +61,10 @@ fn match_tuple(_1: (u32, bool, Option<i32>, u32)) -> u32 {
     }
 
     bb9: {
-        StorageLive(_7);                 // scope 0 at $DIR/exponential-or.rs:+2:10: +2:21
-        _7 = (_1.0: u32);                // scope 0 at $DIR/exponential-or.rs:+2:10: +2:21
-        StorageLive(_8);                 // scope 0 at $DIR/exponential-or.rs:+2:57: +2:78
-        _8 = (_1.3: u32);                // scope 0 at $DIR/exponential-or.rs:+2:57: +2:78
+        StorageLive(_7);                 // scope 0 at $DIR/exponential-or.rs:+2:10: +2:11
+        _7 = (_1.0: u32);                // scope 0 at $DIR/exponential-or.rs:+2:10: +2:11
+        StorageLive(_8);                 // scope 0 at $DIR/exponential-or.rs:+2:57: +2:58
+        _8 = (_1.3: u32);                // scope 0 at $DIR/exponential-or.rs:+2:57: +2:58
         StorageLive(_9);                 // scope 1 at $DIR/exponential-or.rs:+2:83: +2:84
         _9 = _7;                         // scope 1 at $DIR/exponential-or.rs:+2:83: +2:84
         StorageLive(_10);                // scope 1 at $DIR/exponential-or.rs:+2:87: +2:88
diff --git a/src/test/mir-opt/inline/inline-into-box-place.rs b/src/test/mir-opt/inline/inline-into-box-place.rs
index 049a97816f6..232bcc7b27d 100644
--- a/src/test/mir-opt/inline/inline-into-box-place.rs
+++ b/src/test/mir-opt/inline/inline-into-box-place.rs
@@ -1,7 +1,7 @@
 // ignore-endian-big
 // ignore-wasm32-bare compiled with panic=abort by default
 // compile-flags: -Z mir-opt-level=4
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
 #![feature(box_syntax)]
 // EMIT_MIR inline_into_box_place.main.Inline.diff
 fn main() {
diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff
deleted file mode 100644
index 7017413ad38..00000000000
--- a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff
+++ /dev/null
@@ -1,82 +0,0 @@
-- // MIR for `main` before Inline
-+ // MIR for `main` after Inline
-  
-  fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/inline-into-box-place.rs:+0:11: +0:11
-      let _1: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:9: +1:11
-      let mut _2: usize;                   // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-      let mut _3: usize;                   // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-      let mut _4: *mut u8;                 // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-      let mut _5: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-      let mut _6: ();                      // in scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
-      let mut _7: *const std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-+     let mut _8: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-      scope 1 {
-          debug _x => _1;                  // in scope 1 at $DIR/inline-into-box-place.rs:+1:9: +1:11
-      }
-      scope 2 {
-      }
-+     scope 3 (inlined Vec::<u32>::new) {  // at $DIR/inline-into-box-place.rs:8:33: 8:43
-+         let mut _9: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+     }
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:9: +1:11
-          _2 = SizeOf(std::vec::Vec<u32>); // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-          _3 = AlignOf(std::vec::Vec<u32>); // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-          _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-                                           // mir::Constant
-                                           // + span: $DIR/inline-into-box-place.rs:8:29: 8:43
-                                           // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
-      }
-  
-      bb1: {
-          StorageLive(_5);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-          _5 = ShallowInitBox(move _4, std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-          _7 = (((_5.0: std::ptr::Unique<std::vec::Vec<u32>>).0: std::ptr::NonNull<std::vec::Vec<u32>>).0: *const std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
--         (*_7) = Vec::<u32>::new() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+         StorageLive(_8);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+         _8 = &mut (*_7);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+         StorageLive(_9);                 // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         _9 = const alloc::raw_vec::RawVec::<u32>::NEW; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-                                           // mir::Constant
--                                          // + span: $DIR/inline-into-box-place.rs:8:33: 8:41
--                                          // + user_ty: UserType(1)
--                                          // + literal: Const { ty: fn() -> Vec<u32> {Vec::<u32>::new}, val: Value(<ZST>) }
--     }
-- 
--     bb2: {
-+                                          // + span: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+                                          // + user_ty: UserType(0)
-+                                          // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Unevaluated(alloc::raw_vec::RawVec::<T>::NEW, [u32], None) }
-+         Deinit((*_8));                   // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         ((*_8).0: alloc::raw_vec::RawVec<u32>) = move _9; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         ((*_8).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         StorageDead(_9);                 // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         StorageDead(_8);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-          _1 = move _5;                    // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-          StorageDead(_5);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
-          _0 = const ();                   // scope 0 at $DIR/inline-into-box-place.rs:+0:11: +2:2
--         drop(_1) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2
-+         drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2
-      }
-  
--     bb3: {
-+     bb2: {
-          StorageDead(_1);                 // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2
-          return;                          // scope 0 at $DIR/inline-into-box-place.rs:+2:2: +2:2
-      }
-  
--     bb4 (cleanup): {
-+     bb3 (cleanup): {
-          resume;                          // scope 0 at $DIR/inline-into-box-place.rs:+0:1: +2:2
--     }
-- 
--     bb5 (cleanup): {
--         _6 = alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>(move (_5.0: std::ptr::Unique<std::vec::Vec<u32>>), move (_5.1: std::alloc::Global)) -> bb4; // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
--                                          // mir::Constant
--                                          // + span: $DIR/inline-into-box-place.rs:8:42: 8:43
--                                          // + literal: Const { ty: unsafe fn(Unique<Vec<u32>>, std::alloc::Global) {alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>}, val: Value(<ZST>) }
-      }
-  }
-  
diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff
index 7017413ad38..7017413ad38 100644
--- a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff
+++ b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff
diff --git a/src/test/mir-opt/issue-41697.rs b/src/test/mir-opt/issue-41697.rs
index 5c34d8e68d0..cbd8633a345 100644
--- a/src/test/mir-opt/issue-41697.rs
+++ b/src/test/mir-opt/issue-41697.rs
@@ -13,7 +13,7 @@ trait Foo {
     fn get(&self) -> [u8; 2];
 }
 
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
 // EMIT_MIR issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.mir
 impl Foo for [u8; 1+1] {
     fn get(&self) -> [u8; 2] {
diff --git a/src/test/mir-opt/issue-72181.rs b/src/test/mir-opt/issue-72181.rs
index 844d53a4b2b..ebb5f5042fc 100644
--- a/src/test/mir-opt/issue-72181.rs
+++ b/src/test/mir-opt/issue-72181.rs
@@ -11,14 +11,14 @@ union Foo {
     b: Never
 }
 
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
 // EMIT_MIR issue_72181.foo.mir_map.0.mir
 fn foo(xs: [(Never, u32); 1]) -> u32 { xs[0].1 }
 
 // EMIT_MIR issue_72181.bar.mir_map.0.mir
 fn bar([(_, x)]: [(Never, u32); 1]) -> u32 { x }
 
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
 // EMIT_MIR issue_72181.main.mir_map.0.mir
 fn main() {
     let _ = mem::size_of::<Foo>();
diff --git a/src/test/mir-opt/issue-73223.rs b/src/test/mir-opt/issue-73223.rs
index 9e731c40908..be114cab719 100644
--- a/src/test/mir-opt/issue-73223.rs
+++ b/src/test/mir-opt/issue-73223.rs
@@ -8,5 +8,5 @@ fn main() {
     assert_eq!(split, 1);
 }
 
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
 // EMIT_MIR issue_73223.main.SimplifyArmIdentity.diff
diff --git a/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir b/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir
deleted file mode 100644
index 047b24db466..00000000000
--- a/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir
+++ /dev/null
@@ -1,20 +0,0 @@
-// MIR for `<impl at $DIR/issue-41697.rs:18:1: 18:23>::{constant#0}` after SimplifyCfg-promote-consts
-
-<impl at $DIR/issue-41697.rs:18:1: 18:23>::{constant#0}: usize = {
-    let mut _0: usize;                   // return place in scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
-    let mut _1: (usize, bool);           // in scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
-
-    bb0: {
-        _1 = CheckedAdd(const 1_usize, const 1_usize); // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
-        assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_usize, const 1_usize) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
-    }
-
-    bb1: {
-        _0 = move (_1.0: usize);         // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
-        return;                          // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
-    }
-
-    bb2 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
-    }
-}
diff --git a/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.32bit.mir b/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.mir
index 047b24db466..047b24db466 100644
--- a/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.32bit.mir
+++ b/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.mir
diff --git a/src/test/mir-opt/issue_72181.bar.mir_map.0.64bit.mir b/src/test/mir-opt/issue_72181.bar.mir_map.0.64bit.mir
deleted file mode 100644
index 972ce1d5078..00000000000
--- a/src/test/mir-opt/issue_72181.bar.mir_map.0.64bit.mir
+++ /dev/null
@@ -1,17 +0,0 @@
-// MIR for `bar` 0 mir_map
-
-fn bar(_1: [(Never, u32); 1]) -> u32 {
-    let mut _0: u32;                     // return place in scope 0 at $DIR/issue-72181.rs:+0:40: +0:43
-    let _2: u32;                         // in scope 0 at $DIR/issue-72181.rs:+0:13: +0:14
-    scope 1 {
-        debug x => _2;                   // in scope 1 at $DIR/issue-72181.rs:+0:13: +0:14
-    }
-
-    bb0: {
-        StorageLive(_2);                 // scope 0 at $DIR/issue-72181.rs:+0:13: +0:14
-        _2 = (_1[0 of 1].1: u32);        // scope 0 at $DIR/issue-72181.rs:+0:13: +0:14
-        _0 = _2;                         // scope 1 at $DIR/issue-72181.rs:+0:46: +0:47
-        StorageDead(_2);                 // scope 0 at $DIR/issue-72181.rs:+0:48: +0:49
-        return;                          // scope 0 at $DIR/issue-72181.rs:+0:49: +0:49
-    }
-}
diff --git a/src/test/mir-opt/issue_72181.bar.mir_map.0.32bit.mir b/src/test/mir-opt/issue_72181.bar.mir_map.0.mir
index 972ce1d5078..972ce1d5078 100644
--- a/src/test/mir-opt/issue_72181.bar.mir_map.0.32bit.mir
+++ b/src/test/mir-opt/issue_72181.bar.mir_map.0.mir
diff --git a/src/test/mir-opt/issue_72181.foo.mir_map.0.64bit.mir b/src/test/mir-opt/issue_72181.foo.mir_map.0.64bit.mir
deleted file mode 100644
index 534f131ea93..00000000000
--- a/src/test/mir-opt/issue_72181.foo.mir_map.0.64bit.mir
+++ /dev/null
@@ -1,27 +0,0 @@
-// MIR for `foo` 0 mir_map
-
-fn foo(_1: [(Never, u32); 1]) -> u32 {
-    debug xs => _1;                      // in scope 0 at $DIR/issue-72181.rs:+0:8: +0:10
-    let mut _0: u32;                     // return place in scope 0 at $DIR/issue-72181.rs:+0:34: +0:37
-    let _2: usize;                       // in scope 0 at $DIR/issue-72181.rs:+0:43: +0:44
-    let mut _3: usize;                   // in scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
-    let mut _4: bool;                    // in scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
-
-    bb0: {
-        StorageLive(_2);                 // scope 0 at $DIR/issue-72181.rs:+0:43: +0:44
-        _2 = const 0_usize;              // scope 0 at $DIR/issue-72181.rs:+0:43: +0:44
-        _3 = Len(_1);                    // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
-        _4 = Lt(_2, _3);                 // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
-        assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, _2) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
-    }
-
-    bb1: {
-        _0 = (_1[_2].1: u32);            // scope 0 at $DIR/issue-72181.rs:+0:40: +0:47
-        StorageDead(_2);                 // scope 0 at $DIR/issue-72181.rs:+0:48: +0:49
-        return;                          // scope 0 at $DIR/issue-72181.rs:+0:49: +0:49
-    }
-
-    bb2 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-72181.rs:+0:1: +0:49
-    }
-}
diff --git a/src/test/mir-opt/issue_72181.foo.mir_map.0.32bit.mir b/src/test/mir-opt/issue_72181.foo.mir_map.0.mir
index 534f131ea93..534f131ea93 100644
--- a/src/test/mir-opt/issue_72181.foo.mir_map.0.32bit.mir
+++ b/src/test/mir-opt/issue_72181.foo.mir_map.0.mir
diff --git a/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir b/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir
deleted file mode 100644
index 425906f84fc..00000000000
--- a/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir
+++ /dev/null
@@ -1,62 +0,0 @@
-// MIR for `main` 0 mir_map
-
-fn main() -> () {
-    let mut _0: ();                      // return place in scope 0 at $DIR/issue-72181.rs:+0:11: +0:11
-    let mut _1: usize;                   // in scope 0 at $DIR/issue-72181.rs:+1:13: +1:34
-    let mut _3: Foo;                     // in scope 0 at $DIR/issue-72181.rs:+3:14: +3:27
-    let mut _4: Foo;                     // in scope 0 at $DIR/issue-72181.rs:+3:29: +3:42
-    let mut _5: u64;                     // in scope 0 at $DIR/issue-72181.rs:+4:13: +4:30
-    let _6: usize;                       // in scope 0 at $DIR/issue-72181.rs:+4:24: +4:25
-    let mut _7: usize;                   // in scope 0 at $DIR/issue-72181.rs:+4:22: +4:26
-    let mut _8: bool;                    // in scope 0 at $DIR/issue-72181.rs:+4:22: +4:26
-    scope 1 {
-        let _2: [Foo; 2];                // in scope 1 at $DIR/issue-72181.rs:+3:9: +3:10
-        scope 2 {
-            debug f => _2;               // in scope 2 at $DIR/issue-72181.rs:+3:9: +3:10
-            scope 3 {
-            }
-            scope 4 {
-            }
-        }
-    }
-
-    bb0: {
-        StorageLive(_1);                 // scope 0 at $DIR/issue-72181.rs:+1:13: +1:34
-        _1 = std::mem::size_of::<Foo>() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-72181.rs:+1:13: +1:34
-                                         // mir::Constant
-                                         // + span: $DIR/issue-72181.rs:24:13: 24:32
-                                         // + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(<ZST>) }
-    }
-
-    bb1: {
-        StorageDead(_1);                 // scope 0 at $DIR/issue-72181.rs:+1:34: +1:35
-        StorageLive(_2);                 // scope 1 at $DIR/issue-72181.rs:+3:9: +3:10
-        StorageLive(_3);                 // scope 1 at $DIR/issue-72181.rs:+3:14: +3:27
-        _3 = Foo { a: const 42_u64 };    // scope 1 at $DIR/issue-72181.rs:+3:14: +3:27
-        StorageLive(_4);                 // scope 1 at $DIR/issue-72181.rs:+3:29: +3:42
-        _4 = Foo { a: const 10_u64 };    // scope 1 at $DIR/issue-72181.rs:+3:29: +3:42
-        _2 = [move _3, move _4];         // scope 1 at $DIR/issue-72181.rs:+3:13: +3:43
-        StorageDead(_4);                 // scope 1 at $DIR/issue-72181.rs:+3:42: +3:43
-        StorageDead(_3);                 // scope 1 at $DIR/issue-72181.rs:+3:42: +3:43
-        FakeRead(ForLet(None), _2);      // scope 1 at $DIR/issue-72181.rs:+3:9: +3:10
-        StorageLive(_5);                 // scope 2 at $DIR/issue-72181.rs:+4:13: +4:30
-        StorageLive(_6);                 // scope 4 at $DIR/issue-72181.rs:+4:24: +4:25
-        _6 = const 0_usize;              // scope 4 at $DIR/issue-72181.rs:+4:24: +4:25
-        _7 = Len(_2);                    // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26
-        _8 = Lt(_6, _7);                 // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26
-        assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb2, unwind: bb3]; // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26
-    }
-
-    bb2: {
-        _5 = (_2[_6].0: u64);            // scope 4 at $DIR/issue-72181.rs:+4:22: +4:28
-        StorageDead(_6);                 // scope 2 at $DIR/issue-72181.rs:+4:30: +4:31
-        StorageDead(_5);                 // scope 2 at $DIR/issue-72181.rs:+4:30: +4:31
-        _0 = const ();                   // scope 0 at $DIR/issue-72181.rs:+0:11: +5:2
-        StorageDead(_2);                 // scope 1 at $DIR/issue-72181.rs:+5:1: +5:2
-        return;                          // scope 0 at $DIR/issue-72181.rs:+5:2: +5:2
-    }
-
-    bb3 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-72181.rs:+0:1: +5:2
-    }
-}
diff --git a/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir b/src/test/mir-opt/issue_72181.main.mir_map.0.mir
index 425906f84fc..425906f84fc 100644
--- a/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir
+++ b/src/test/mir-opt/issue_72181.main.mir_map.0.mir
diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff
deleted file mode 100644
index ac7fe31f3b3..00000000000
--- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff
+++ /dev/null
@@ -1,161 +0,0 @@
-- // MIR for `main` before SimplifyArmIdentity
-+ // MIR for `main` after SimplifyArmIdentity
-  
-  fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/issue-73223.rs:+0:11: +0:11
-      let _1: i32;                         // in scope 0 at $DIR/issue-73223.rs:+1:9: +1:14
-      let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
-      let mut _3: isize;                   // in scope 0 at $DIR/issue-73223.rs:+2:9: +2:16
-      let _4: i32;                         // in scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
-      let mut _5: !;                       // in scope 0 at $DIR/issue-73223.rs:+3:17: +3:23
-      let mut _7: i32;                     // in scope 0 at $DIR/issue-73223.rs:+6:22: +6:27
-      let _8: ();                          // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _9: (&i32, &i32);            // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _10: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _11: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _12: i32;                        // in scope 0 at $DIR/issue-73223.rs:+7:23: +7:24
-      let mut _15: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _16: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _17: i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _18: i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _19: !;                      // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _21: !;                          // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _22: core::panicking::AssertKind; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _23: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _24: &i32;                       // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _25: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _26: &i32;                       // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _27: std::option::Option<std::fmt::Arguments>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      scope 1 {
-          debug split => _1;               // in scope 1 at $DIR/issue-73223.rs:+1:9: +1:14
-          let _6: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:+6:9: +6:14
-          scope 3 {
-              debug _prev => _6;           // in scope 3 at $DIR/issue-73223.rs:+6:9: +6:14
-              let _13: &i32;               // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-              let _14: &i32;               // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-              let mut _28: &i32;           // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-              scope 4 {
-                  debug left_val => _13;   // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  debug right_val => _14;  // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  let _20: core::panicking::AssertKind; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  scope 5 {
-                      debug kind => _20;   // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                  }
-              }
-          }
-      }
-      scope 2 {
-          debug v => _4;                   // in scope 2 at $DIR/issue-73223.rs:+2:14: +2:15
-      }
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/issue-73223.rs:+1:9: +1:14
-          StorageLive(_2);                 // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
-          Deinit(_2);                      // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
-          ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
-          discriminant(_2) = 1;            // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
-          _3 = const 1_isize;              // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
-          goto -> bb3;                     // scope 0 at $DIR/issue-73223.rs:+1:17: +1:30
-      }
-  
-      bb1: {
-          nop;                             // scope 0 at $DIR/issue-73223.rs:+3:17: +3:23
-          StorageDead(_2);                 // scope 0 at $DIR/issue-73223.rs:+4:6: +4:7
-          StorageDead(_1);                 // scope 0 at $DIR/issue-73223.rs:+8:1: +8:2
-          return;                          // scope 0 at $DIR/issue-73223.rs:+8:2: +8:2
-      }
-  
-      bb2: {
-          unreachable;                     // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
-      }
-  
-      bb3: {
-          StorageLive(_4);                 // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
-          _4 = ((_2 as Some).0: i32);      // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
-          _1 = _4;                         // scope 2 at $DIR/issue-73223.rs:+2:20: +2:21
-          StorageDead(_4);                 // scope 0 at $DIR/issue-73223.rs:+2:20: +2:21
-          StorageDead(_2);                 // scope 0 at $DIR/issue-73223.rs:+4:6: +4:7
-          StorageLive(_6);                 // scope 1 at $DIR/issue-73223.rs:+6:9: +6:14
-          StorageLive(_7);                 // scope 1 at $DIR/issue-73223.rs:+6:22: +6:27
-          _7 = _1;                         // scope 1 at $DIR/issue-73223.rs:+6:22: +6:27
-          Deinit(_6);                      // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28
-          ((_6 as Some).0: i32) = move _7; // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28
-          discriminant(_6) = 1;            // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28
-          StorageDead(_7);                 // scope 1 at $DIR/issue-73223.rs:+6:27: +6:28
-          StorageLive(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_9);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_10);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _10 = &_1;                       // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_11);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _28 = const main::promoted[0];   // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // mir::Constant
-                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
-          _11 = _28;                       // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          Deinit(_9);                      // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          (_9.0: &i32) = move _10;         // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          (_9.1: &i32) = move _11;         // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_11);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_10);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_13);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _13 = (_9.0: &i32);              // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_14);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _14 = (_9.1: &i32);              // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_15);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_16);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_17);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _17 = (*_13);                    // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_18);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _18 = const 1_i32;               // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _16 = Eq(move _17, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_18);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_17);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _15 = Not(move _16);             // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_16);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          switchInt(move _15) -> [false: bb5, otherwise: bb4]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      }
-  
-      bb4: {
-          StorageLive(_20);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          Deinit(_20);                     // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          discriminant(_20) = 0;           // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_21);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_22);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _22 = const core::panicking::AssertKind::Eq; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // mir::Constant
-                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) }
-          StorageLive(_23);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_24);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _24 = _13;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _23 = _24;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_25);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_26);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _26 = _14;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _25 = _26;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageLive(_27);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          Deinit(_27);                     // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          discriminant(_27) = 0;           // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _21 = core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _23, move _25, move _27); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // mir::Constant
-                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(<ZST>) }
-                                           // mir::Constant
-                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) }
-      }
-  
-      bb5: {
-          nop;                             // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_15);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_14);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_13);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_9);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          StorageDead(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          nop;                             // scope 0 at $DIR/issue-73223.rs:+0:11: +8:2
-          StorageDead(_6);                 // scope 1 at $DIR/issue-73223.rs:+8:1: +8:2
-          StorageDead(_1);                 // scope 0 at $DIR/issue-73223.rs:+8:1: +8:2
-          return;                          // scope 0 at $DIR/issue-73223.rs:+8:2: +8:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff
index ac7fe31f3b3..ac7fe31f3b3 100644
--- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff
+++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff
diff --git a/src/test/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff
new file mode 100644
index 00000000000..d9898d8e0f0
--- /dev/null
+++ b/src/test/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff
@@ -0,0 +1,26 @@
+- // MIR for `assume` before LowerIntrinsics
++ // MIR for `assume` after LowerIntrinsics
+  
+  fn assume() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:17: +0:17
+      let _1: ();                          // in scope 0 at $DIR/lower_intrinsics.rs:+2:9: +2:38
+      scope 1 {
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
+-         _1 = std::intrinsics::assume(const true) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
+-                                          // mir::Constant
+-                                          // + span: $DIR/lower_intrinsics.rs:72:9: 72:32
+-                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(bool) {std::intrinsics::assume}, val: Value(<ZST>) }
++         assume(const true);              // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
++         goto -> bb1;                     // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
+      }
+  
+      bb1: {
+          StorageDead(_1);                 // scope 1 at $DIR/lower_intrinsics.rs:+2:38: +2:39
+          _0 = const ();                   // scope 1 at $DIR/lower_intrinsics.rs:+1:5: +3:6
+          return;                          // scope 0 at $DIR/lower_intrinsics.rs:+4:2: +4:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff
new file mode 100644
index 00000000000..4fb6752b619
--- /dev/null
+++ b/src/test/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff
@@ -0,0 +1,72 @@
+- // MIR for `f_copy_nonoverlapping` before LowerIntrinsics
++ // MIR for `f_copy_nonoverlapping` after LowerIntrinsics
+  
+  fn f_copy_nonoverlapping() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:32: +0:32
+      let _1: ();                          // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:12
+      let _3: ();                          // in scope 0 at $DIR/lower_intrinsics.rs:+4:9: +4:95
+      let mut _4: *const i32;              // in scope 0 at $DIR/lower_intrinsics.rs:+4:29: +4:59
+      let mut _5: *const ();               // in scope 0 at $DIR/lower_intrinsics.rs:+4:29: +4:45
+      let mut _6: *const ();               // in scope 0 at $DIR/lower_intrinsics.rs:+4:29: +4:45
+      let _7: &();                         // in scope 0 at $DIR/lower_intrinsics.rs:+4:29: +4:33
+      let mut _8: *mut i32;                // in scope 0 at $DIR/lower_intrinsics.rs:+4:61: +4:91
+      let mut _9: *mut ();                 // in scope 0 at $DIR/lower_intrinsics.rs:+4:61: +4:79
+      let mut _10: *mut ();                // in scope 0 at $DIR/lower_intrinsics.rs:+4:61: +4:79
+      let mut _11: &mut ();                // in scope 0 at $DIR/lower_intrinsics.rs:+4:61: +4:69
+      scope 1 {
+          debug src => _1;                 // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:12
+          let mut _2: ();                  // in scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:16
+          scope 2 {
+              debug dst => _2;             // in scope 2 at $DIR/lower_intrinsics.rs:+2:9: +2:16
+              scope 3 {
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:12
+          Deinit(_1);                      // scope 0 at $DIR/lower_intrinsics.rs:+1:15: +1:17
+          StorageLive(_2);                 // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:16
+          Deinit(_2);                      // scope 1 at $DIR/lower_intrinsics.rs:+2:19: +2:21
+          StorageLive(_3);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95
+          StorageLive(_4);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:59
+          StorageLive(_5);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:45
+          StorageLive(_6);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:45
+          StorageLive(_7);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:33
+          _7 = &_1;                        // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:33
+          _6 = &raw const (*_7);           // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:33
+          _5 = _6;                         // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:45
+          _4 = move _5 as *const i32 (Misc); // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:59
+          StorageDead(_5);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:58: +4:59
+          StorageLive(_8);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:91
+          StorageLive(_9);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:79
+          StorageLive(_10);                // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:79
+          StorageLive(_11);                // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:69
+          _11 = &mut _2;                   // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:69
+          _10 = &raw mut (*_11);           // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:69
+          _9 = _10;                        // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:79
+          _8 = move _9 as *mut i32 (Misc); // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:91
+          StorageDead(_9);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:90: +4:91
+-         _3 = copy_nonoverlapping::<i32>(move _4, move _8, const 0_usize) -> bb1; // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95
+-                                          // mir::Constant
+-                                          // + span: $DIR/lower_intrinsics.rs:65:9: 65:28
+-                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32, *mut i32, usize) {copy_nonoverlapping::<i32>}, val: Value(<ZST>) }
++         copy_nonoverlapping(dst = move _8, src = move _4, count = const 0_usize); // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95
++         goto -> bb1;                     // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95
+      }
+  
+      bb1: {
+          StorageDead(_8);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:94: +4:95
+          StorageDead(_4);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:94: +4:95
+          StorageDead(_11);                // scope 3 at $DIR/lower_intrinsics.rs:+4:95: +4:96
+          StorageDead(_10);                // scope 3 at $DIR/lower_intrinsics.rs:+4:95: +4:96
+          StorageDead(_7);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:95: +4:96
+          StorageDead(_6);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:95: +4:96
+          StorageDead(_3);                 // scope 3 at $DIR/lower_intrinsics.rs:+4:95: +4:96
+          _0 = const ();                   // scope 3 at $DIR/lower_intrinsics.rs:+3:5: +5:6
+          StorageDead(_2);                 // scope 1 at $DIR/lower_intrinsics.rs:+6:1: +6:2
+          StorageDead(_1);                 // scope 0 at $DIR/lower_intrinsics.rs:+6:1: +6:2
+          return;                          // scope 0 at $DIR/lower_intrinsics.rs:+6:2: +6:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/lower_intrinsics.rs b/src/test/mir-opt/lower_intrinsics.rs
index 195543d42bb..66dae0e46b9 100644
--- a/src/test/mir-opt/lower_intrinsics.rs
+++ b/src/test/mir-opt/lower_intrinsics.rs
@@ -1,7 +1,7 @@
 // unit-test: LowerIntrinsics
 // ignore-wasm32 compiled with panic=abort by default
 
-#![feature(core_intrinsics)]
+#![feature(core_intrinsics, intrinsics)]
 #![crate_type = "lib"]
 
 // EMIT_MIR lower_intrinsics.wrapping.LowerIntrinsics.diff
@@ -51,3 +51,24 @@ pub fn discriminant<T>(t: T) {
     core::intrinsics::discriminant_value(&());
     core::intrinsics::discriminant_value(&E::B);
 }
+
+extern "rust-intrinsic" {
+    // Cannot use `std::intrinsics::copy_nonoverlapping` as that is a wrapper function
+    fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
+}
+
+// EMIT_MIR lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff
+pub fn f_copy_nonoverlapping() {
+    let src = ();
+    let mut dst = ();
+    unsafe {
+        copy_nonoverlapping(&src as *const _ as *const i32, &mut dst as *mut _ as *mut i32, 0);
+    }
+}
+
+// EMIT_MIR lower_intrinsics.assume.LowerIntrinsics.diff
+pub fn assume() {
+    unsafe {
+        std::intrinsics::assume(true);
+    }
+}
diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff
deleted file mode 100644
index f9eeb1ea5b9..00000000000
--- a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff
+++ /dev/null
@@ -1,88 +0,0 @@
-- // MIR for `bar` before MatchBranchSimplification
-+ // MIR for `bar` after MatchBranchSimplification
-  
-  fn bar(_1: i32) -> (bool, bool, bool, bool) {
-      debug i => _1;                       // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:9
-      let mut _0: (bool, bool, bool, bool); // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:19: +0:43
-      let _2: bool;                        // in scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:10
-      let _6: ();                          // in scope 0 at $DIR/matches_reduce_branches.rs:+6:5: +21:6
-      let mut _7: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+23:6: +23:7
-      let mut _8: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+23:9: +23:10
-      let mut _9: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+23:12: +23:13
-      let mut _10: bool;                   // in scope 0 at $DIR/matches_reduce_branches.rs:+23:15: +23:16
-+     let mut _11: i32;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
-      scope 1 {
-          debug a => _2;                   // in scope 1 at $DIR/matches_reduce_branches.rs:+1:9: +1:10
-          let _3: bool;                    // in scope 1 at $DIR/matches_reduce_branches.rs:+2:9: +2:10
-          scope 2 {
-              debug b => _3;               // in scope 2 at $DIR/matches_reduce_branches.rs:+2:9: +2:10
-              let _4: bool;                // in scope 2 at $DIR/matches_reduce_branches.rs:+3:9: +3:10
-              scope 3 {
-                  debug c => _4;           // in scope 3 at $DIR/matches_reduce_branches.rs:+3:9: +3:10
-                  let _5: bool;            // in scope 3 at $DIR/matches_reduce_branches.rs:+4:9: +4:10
-                  scope 4 {
-                      debug d => _5;       // in scope 4 at $DIR/matches_reduce_branches.rs:+4:9: +4:10
-                  }
-              }
-          }
-      }
-  
-      bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:10
-          StorageLive(_3);                 // scope 1 at $DIR/matches_reduce_branches.rs:+2:9: +2:10
-          StorageLive(_4);                 // scope 2 at $DIR/matches_reduce_branches.rs:+3:9: +3:10
-          StorageLive(_5);                 // scope 3 at $DIR/matches_reduce_branches.rs:+4:9: +4:10
-          StorageLive(_6);                 // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +21:6
--         switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
--     }
-- 
--     bb1: {
--         _2 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:+15:13: +15:21
--         _3 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:+16:13: +16:22
--         _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:+17:13: +17:22
--         _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:+18:13: +18:21
--         Deinit(_6);                      // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15
--         goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15
--     }
-- 
--     bb2: {
--         _2 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:+8:13: +8:22
--         _3 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:+9:13: +9:21
-+         StorageLive(_11);                // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
-+         _11 = _1;                        // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
-+         _2 = Ne(_11, const 7_i32);       // scope 4 at $DIR/matches_reduce_branches.rs:+8:13: +8:22
-+         _3 = Eq(_11, const 7_i32);       // scope 4 at $DIR/matches_reduce_branches.rs:+9:13: +9:21
-          _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:+10:13: +10:22
-          _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:+11:13: +11:21
-          Deinit(_6);                      // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15
--         goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15
--     }
-- 
--     bb3: {
-+         StorageDead(_11);                // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12
-          StorageDead(_6);                 // scope 4 at $DIR/matches_reduce_branches.rs:+21:6: +21:7
-          StorageLive(_7);                 // scope 4 at $DIR/matches_reduce_branches.rs:+23:6: +23:7
-          _7 = _2;                         // scope 4 at $DIR/matches_reduce_branches.rs:+23:6: +23:7
-          StorageLive(_8);                 // scope 4 at $DIR/matches_reduce_branches.rs:+23:9: +23:10
-          _8 = _3;                         // scope 4 at $DIR/matches_reduce_branches.rs:+23:9: +23:10
-          StorageLive(_9);                 // scope 4 at $DIR/matches_reduce_branches.rs:+23:12: +23:13
-          _9 = _4;                         // scope 4 at $DIR/matches_reduce_branches.rs:+23:12: +23:13
-          StorageLive(_10);                // scope 4 at $DIR/matches_reduce_branches.rs:+23:15: +23:16
-          _10 = _5;                        // scope 4 at $DIR/matches_reduce_branches.rs:+23:15: +23:16
-          Deinit(_0);                      // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
-          (_0.0: bool) = move _7;          // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
-          (_0.1: bool) = move _8;          // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
-          (_0.2: bool) = move _9;          // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
-          (_0.3: bool) = move _10;         // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17
-          StorageDead(_10);                // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
-          StorageDead(_9);                 // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
-          StorageDead(_8);                 // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
-          StorageDead(_7);                 // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17
-          StorageDead(_5);                 // scope 3 at $DIR/matches_reduce_branches.rs:+24:1: +24:2
-          StorageDead(_4);                 // scope 2 at $DIR/matches_reduce_branches.rs:+24:1: +24:2
-          StorageDead(_3);                 // scope 1 at $DIR/matches_reduce_branches.rs:+24:1: +24:2
-          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:+24:1: +24:2
-          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:+24:2: +24:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff
index f9eeb1ea5b9..f9eeb1ea5b9 100644
--- a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff
+++ b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff
diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff
deleted file mode 100644
index 0b40b3be8bd..00000000000
--- a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff
+++ /dev/null
@@ -1,55 +0,0 @@
-- // MIR for `foo` before MatchBranchSimplification
-+ // MIR for `foo` after MatchBranchSimplification
-  
-  fn foo(_1: Option<()>) -> () {
-      debug bar => _1;                     // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:11
-      let mut _0: ();                      // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:25
-      let mut _2: bool;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let mut _3: isize;                   // in scope 0 at $DIR/matches_reduce_branches.rs:+1:22: +1:26
-+     let mut _4: isize;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-  
-      bb0: {
-          StorageLive(_2);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _3 = discriminant(_1);           // scope 0 at $DIR/matches_reduce_branches.rs:+1:17: +1:20
--         switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+         StorageLive(_4);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+         _4 = move _3;                    // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+         _2 = Eq(_4, const 0_isize);      // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+         StorageDead(_4);                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-+         switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      }
-  
-      bb1: {
--         _2 = const false;                // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
--         goto -> bb3;                     // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
--     }
-- 
--     bb2: {
--         _2 = const true;                 // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
--         goto -> bb3;                     // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
--     }
-- 
--     bb3: {
--         switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
--     }
-- 
--     bb4: {
-          Deinit(_0);                      // scope 0 at $DIR/matches_reduce_branches.rs:+2:9: +2:11
--         goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
-+         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
-      }
-  
--     bb5: {
-+     bb2: {
-          _0 = const ();                   // scope 0 at $DIR/matches_reduce_branches.rs:+3:6: +3:6
--         goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
-+         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6
-      }
-  
--     bb6: {
-+     bb3: {
-          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:+3:5: +3:6
-          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:+4:2: +4:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff
index 0b40b3be8bd..0b40b3be8bd 100644
--- a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff
+++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff
diff --git a/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff
deleted file mode 100644
index b8c7722cd37..00000000000
--- a/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff
+++ /dev/null
@@ -1,113 +0,0 @@
-- // MIR for `match_nested_if` before MatchBranchSimplification
-+ // MIR for `match_nested_if` after MatchBranchSimplification
-  
-  fn match_nested_if() -> bool {
-      let mut _0: bool;                    // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:29
-      let _1: bool;                        // in scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:12
-      let mut _2: ();                      // in scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
-      let mut _3: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
-      let mut _4: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-      let mut _5: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-      let mut _6: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-+     let mut _7: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-+     let mut _8: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-+     let mut _9: bool;                    // in scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-+     let mut _10: bool;                   // in scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
-      scope 1 {
-          debug val => _1;                 // in scope 1 at $DIR/matches_reduce_branches.rs:+1:9: +1:12
-      }
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:12
-          StorageLive(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
-          Deinit(_2);                      // scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23
-          StorageLive(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
-          StorageLive(_4);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-          StorageLive(_5);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-          StorageLive(_6);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-          _6 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
--         switchInt(move _6) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
--     }
-- 
--     bb1: {
--         _5 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:31: +2:35
--         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
--     }
-- 
--     bb2: {
--         _5 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:+2:45: +2:50
--         goto -> bb3;                     // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
--     }
-- 
--     bb3: {
-+         StorageLive(_7);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-+         _7 = move _6;                    // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-+         _5 = Ne(_7, const false);        // scope 0 at $DIR/matches_reduce_branches.rs:+2:45: +2:50
-+         StorageDead(_7);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28
-          StorageDead(_6);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:51: +2:52
--         switchInt(move _5) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
--     }
-- 
--     bb4: {
--         _4 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:55: +2:59
--         goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
--     }
-- 
--     bb5: {
--         _4 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:+2:69: +2:74
--         goto -> bb6;                     // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
--     }
-- 
--     bb6: {
-+         StorageLive(_8);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-+         _8 = move _5;                    // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-+         _4 = Ne(_8, const false);        // scope 0 at $DIR/matches_reduce_branches.rs:+2:69: +2:74
-+         StorageDead(_8);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52
-          StorageDead(_5);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:75: +2:76
--         switchInt(move _4) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
--     }
-- 
--     bb7: {
--         _3 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:+3:13: +3:17
--         goto -> bb9;                     // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
--     }
-- 
--     bb8: {
--         _3 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:+5:13: +5:18
--         goto -> bb9;                     // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
--     }
-- 
--     bb9: {
--         switchInt(move _3) -> [false: bb11, otherwise: bb10]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
--     }
-- 
--     bb10: {
-+         StorageLive(_9);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-+         _9 = move _4;                    // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-+         _3 = Ne(_9, const false);        // scope 0 at $DIR/matches_reduce_branches.rs:+5:13: +5:18
-+         StorageDead(_9);                 // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76
-+         StorageLive(_10);                // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
-+         _10 = move _3;                   // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
-          StorageDead(_4);                 // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
-          StorageDead(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
--         _1 = const true;                 // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17
--         goto -> bb12;                    // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17
--     }
-- 
--     bb11: {
--         StorageDead(_4);                 // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
--         StorageDead(_3);                 // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10
--         _1 = const false;                // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
--         goto -> bb12;                    // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
--     }
-- 
--     bb12: {
-+         _1 = Ne(_10, const false);       // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19
-+         StorageDead(_10);                // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10
-          StorageDead(_2);                 // scope 0 at $DIR/matches_reduce_branches.rs:+11:6: +11:7
-          _0 = _1;                         // scope 1 at $DIR/matches_reduce_branches.rs:+12:5: +12:8
-          StorageDead(_1);                 // scope 0 at $DIR/matches_reduce_branches.rs:+13:1: +13:2
-          return;                          // scope 0 at $DIR/matches_reduce_branches.rs:+13:2: +13:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.diff
index b8c7722cd37..b8c7722cd37 100644
--- a/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff
+++ b/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.diff
diff --git a/src/test/mir-opt/matches_reduce_branches.rs b/src/test/mir-opt/matches_reduce_branches.rs
index c122b4c69d1..a81d5f7b4e8 100644
--- a/src/test/mir-opt/matches_reduce_branches.rs
+++ b/src/test/mir-opt/matches_reduce_branches.rs
@@ -1,6 +1,6 @@
 // unit-test: MatchBranchSimplification
 
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
 // EMIT_MIR matches_reduce_branches.foo.MatchBranchSimplification.diff
 // EMIT_MIR matches_reduce_branches.bar.MatchBranchSimplification.diff
 // EMIT_MIR matches_reduce_branches.match_nested_if.MatchBranchSimplification.diff
diff --git a/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.64bit.diff
deleted file mode 100644
index 1b4dddc1d43..00000000000
--- a/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.64bit.diff
+++ /dev/null
@@ -1,32 +0,0 @@
-- // MIR for `exhaustive_match` before MatchBranchSimplification
-+ // MIR for `exhaustive_match` after MatchBranchSimplification
-  
-  fn exhaustive_match(_1: E) -> u8 {
-      debug e => _1;                       // in scope 0 at $DIR/matches_u8.rs:+0:25: +0:26
-      let mut _0: u8;                      // return place in scope 0 at $DIR/matches_u8.rs:+0:34: +0:36
-      let mut _2: isize;                   // in scope 0 at $DIR/matches_u8.rs:+2:9: +2:13
-  
-      bb0: {
-          _2 = discriminant(_1);           // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
-          switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/matches_u8.rs:+1:5: +1:12
-      }
-  
-      bb1: {
-          _0 = const 1_u8;                 // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18
-          goto -> bb4;                     // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18
-      }
-  
-      bb2: {
-          unreachable;                     // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
-      }
-  
-      bb3: {
-          _0 = const 0_u8;                 // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18
-          goto -> bb4;                     // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18
-      }
-  
-      bb4: {
-          return;                          // scope 0 at $DIR/matches_u8.rs:+5:2: +5:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff
index 1b4dddc1d43..1b4dddc1d43 100644
--- a/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.32bit.diff
+++ b/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff
diff --git a/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.64bit.diff
deleted file mode 100644
index 6e734852e1a..00000000000
--- a/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.64bit.diff
+++ /dev/null
@@ -1,32 +0,0 @@
-- // MIR for `exhaustive_match_i8` before MatchBranchSimplification
-+ // MIR for `exhaustive_match_i8` after MatchBranchSimplification
-  
-  fn exhaustive_match_i8(_1: E) -> i8 {
-      debug e => _1;                       // in scope 0 at $DIR/matches_u8.rs:+0:28: +0:29
-      let mut _0: i8;                      // return place in scope 0 at $DIR/matches_u8.rs:+0:37: +0:39
-      let mut _2: isize;                   // in scope 0 at $DIR/matches_u8.rs:+2:9: +2:13
-  
-      bb0: {
-          _2 = discriminant(_1);           // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
-          switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/matches_u8.rs:+1:5: +1:12
-      }
-  
-      bb1: {
-          _0 = const 1_i8;                 // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18
-          goto -> bb4;                     // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18
-      }
-  
-      bb2: {
-          unreachable;                     // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12
-      }
-  
-      bb3: {
-          _0 = const 0_i8;                 // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18
-          goto -> bb4;                     // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18
-      }
-  
-      bb4: {
-          return;                          // scope 0 at $DIR/matches_u8.rs:+5:2: +5:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff
index 6e734852e1a..6e734852e1a 100644
--- a/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.32bit.diff
+++ b/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff
diff --git a/src/test/mir-opt/matches_u8.rs b/src/test/mir-opt/matches_u8.rs
index 2c748b02a8b..422c3a95e8e 100644
--- a/src/test/mir-opt/matches_u8.rs
+++ b/src/test/mir-opt/matches_u8.rs
@@ -1,6 +1,6 @@
 // unit-test: MatchBranchSimplification
 
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
 // EMIT_MIR matches_u8.exhaustive_match.MatchBranchSimplification.diff
 // EMIT_MIR matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff
 
diff --git a/src/test/mir-opt/packed-struct-drop-aligned.rs b/src/test/mir-opt/packed-struct-drop-aligned.rs
index 6c2e265d514..cb652426090 100644
--- a/src/test/mir-opt/packed-struct-drop-aligned.rs
+++ b/src/test/mir-opt/packed-struct-drop-aligned.rs
@@ -1,6 +1,6 @@
 // ignore-wasm32-bare compiled with panic=abort by default
 
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
 // EMIT_MIR packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir
 fn main() {
     let mut x = Packed(Aligned(Droppy(0)));
diff --git a/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.64bit.mir b/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.64bit.mir
deleted file mode 100644
index f9ed1036f00..00000000000
--- a/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.64bit.mir
+++ /dev/null
@@ -1,60 +0,0 @@
-// MIR for `main` after SimplifyCfg-elaborate-drops
-
-fn main() -> () {
-    let mut _0: ();                      // return place in scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:11: +0:11
-    let mut _1: Packed;                  // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14
-    let mut _2: Aligned;                 // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
-    let mut _3: Droppy;                  // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
-    let mut _4: Aligned;                 // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
-    let mut _5: Droppy;                  // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
-    let mut _6: Aligned;                 // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
-    scope 1 {
-        debug x => _1;                   // in scope 1 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14
-    }
-
-    bb0: {
-        StorageLive(_1);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14
-        StorageLive(_2);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
-        StorageLive(_3);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
-        Deinit(_3);                      // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
-        (_3.0: usize) = const 0_usize;   // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
-        Deinit(_2);                      // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
-        (_2.0: Droppy) = move _3;        // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
-        StorageDead(_3);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:41: +1:42
-        Deinit(_1);                      // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:17: +1:43
-        (_1.0: Aligned) = move _2;       // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:17: +1:43
-        StorageDead(_2);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:42: +1:43
-        StorageLive(_4);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
-        StorageLive(_5);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
-        Deinit(_5);                      // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
-        (_5.0: usize) = const 0_usize;   // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
-        Deinit(_4);                      // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
-        (_4.0: Droppy) = move _5;        // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
-        StorageDead(_5);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:28: +2:29
-        StorageLive(_6);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
-        _6 = move (_1.0: Aligned);       // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
-        drop(_6) -> [return: bb4, unwind: bb3]; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
-    }
-
-    bb1: {
-        StorageDead(_1);                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2
-        return;                          // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:2: +3:2
-    }
-
-    bb2 (cleanup): {
-        resume;                          // scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:1: +3:2
-    }
-
-    bb3 (cleanup): {
-        (_1.0: Aligned) = move _4;       // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
-        drop(_1) -> bb2;                 // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2
-    }
-
-    bb4: {
-        StorageDead(_6);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
-        (_1.0: Aligned) = move _4;       // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
-        StorageDead(_4);                 // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:28: +2:29
-        _0 = const ();                   // scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:11: +3:2
-        drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2
-    }
-}
diff --git a/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.32bit.mir b/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir
index f9ed1036f00..f9ed1036f00 100644
--- a/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.32bit.mir
+++ b/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir
diff --git a/src/test/mir-opt/separate_const_switch.identity.ConstProp.diff b/src/test/mir-opt/separate_const_switch.identity.ConstProp.diff
deleted file mode 100644
index 28536dc28a7..00000000000
--- a/src/test/mir-opt/separate_const_switch.identity.ConstProp.diff
+++ /dev/null
@@ -1,146 +0,0 @@
-- // MIR for `identity` before ConstProp
-+ // MIR for `identity` after ConstProp
-  
-  fn identity(_1: Result<i32, i32>) -> Result<i32, i32> {
-      debug x => _1;                       // in scope 0 at $DIR/separate_const_switch.rs:+0:13: +0:14
-      let mut _0: std::result::Result<i32, i32>; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:37: +0:53
-      let mut _2: i32;                     // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-      let mut _3: std::ops::ControlFlow<std::result::Result<std::convert::Infallible, i32>, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-      let mut _4: std::result::Result<i32, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
-      let mut _5: isize;                   // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-      let _6: std::result::Result<std::convert::Infallible, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-      let mut _7: !;                       // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-      let mut _8: std::result::Result<std::convert::Infallible, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-      let _9: i32;                         // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-      scope 1 {
-          debug residual => _6;            // in scope 1 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          scope 2 {
-              scope 8 (inlined #[track_caller] <Result<i32, i32> as FromResidual<Result<Infallible, i32>>>::from_residual) { // at $DIR/separate_const_switch.rs:29:8: 29:10
-                  debug residual => _8;    // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-                  let _16: i32;            // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-                  let mut _17: i32;        // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-                  let mut _18: i32;        // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-                  scope 9 {
-                      debug e => _16;      // in scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-                      scope 10 (inlined <i32 as From<i32>>::from) { // at $SRC_DIR/core/src/result.rs:LL:COL
-                          debug t => _18;  // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
-                      }
-                  }
-              }
-          }
-      }
-      scope 3 {
-          debug val => _9;                 // in scope 3 at $DIR/separate_const_switch.rs:+1:8: +1:10
-          scope 4 {
-          }
-      }
-      scope 5 (inlined <Result<i32, i32> as Try>::branch) { // at $DIR/separate_const_switch.rs:29:8: 29:10
-          debug self => _4;                // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          let mut _10: isize;              // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          let _11: i32;                    // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          let mut _12: i32;                // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          let _13: i32;                    // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          let mut _14: std::result::Result<std::convert::Infallible, i32>; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          let mut _15: i32;                // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          scope 6 {
-              debug v => _11;              // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-          }
-          scope 7 {
-              debug e => _13;              // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          }
-      }
-  
-      bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-          StorageLive(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-          StorageLive(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
-          _4 = _1;                         // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
-          _10 = discriminant(_4);          // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          switchInt(move _10) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-      }
-  
-      bb1: {
-          StorageLive(_9);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-          _9 = ((_3 as Continue).0: i32);  // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-          _2 = _9;                         // scope 4 at $DIR/separate_const_switch.rs:+1:8: +1:10
-          StorageDead(_9);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          Deinit(_0);                      // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
-          ((_0 as Ok).0: i32) = move _2;   // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
-          discriminant(_0) = 0;            // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
-          StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
-          StorageDead(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
-          return;                          // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
-      }
-  
-      bb2: {
-          unreachable;                     // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-      }
-  
-      bb3: {
-          StorageLive(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          _6 = ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          StorageLive(_8);                 // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          _8 = _6;                         // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          StorageLive(_16);                // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-          _16 = move ((_8 as Err).0: i32); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageLive(_17);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageLive(_18);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          _18 = move _16;                  // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          _17 = move _18;                  // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
-          StorageDead(_18);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          Deinit(_0);                      // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          ((_0 as Err).0: i32) = move _17; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          discriminant(_0) = 1;            // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_17);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_16);                // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_8);                 // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          StorageDead(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-          StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
-          StorageDead(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
-          return;                          // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
-      }
-  
-      bb4: {
-          StorageLive(_13);                // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          _13 = move ((_4 as Err).0: i32); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageLive(_14);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageLive(_15);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          _15 = move _13;                  // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          Deinit(_14);                     // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          ((_14 as Err).0: i32) = move _15; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          discriminant(_14) = 1;           // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_15);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          Deinit(_3);                      // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>) = move _14; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          discriminant(_3) = 1;            // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_14);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_13);                // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
--         _5 = discriminant(_3);           // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
--         switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-+         _5 = const 1_isize;              // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-+         switchInt(const 1_isize) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-      }
-  
-      bb5: {
-          unreachable;                     // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-      }
-  
-      bb6: {
-          StorageLive(_11);                // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          _11 = move ((_4 as Ok).0: i32);  // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageLive(_12);                // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-          _12 = move _11;                  // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-          Deinit(_3);                      // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-          ((_3 as Continue).0: i32) = move _12; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-          discriminant(_3) = 0;            // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_12);                // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_11);                // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-          StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
--         _5 = discriminant(_3);           // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
--         switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-+         _5 = const 0_isize;              // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-+         switchInt(const 0_isize) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-      }
-  }
-  
diff --git a/src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir b/src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir
deleted file mode 100644
index df20f0ed36b..00000000000
--- a/src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir
+++ /dev/null
@@ -1,124 +0,0 @@
-// MIR for `identity` after PreCodegen
-
-fn identity(_1: Result<i32, i32>) -> Result<i32, i32> {
-    debug x => _1;                       // in scope 0 at $DIR/separate_const_switch.rs:+0:13: +0:14
-    let mut _0: std::result::Result<i32, i32>; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:37: +0:53
-    let mut _2: i32;                     // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-    let mut _3: std::ops::ControlFlow<std::result::Result<std::convert::Infallible, i32>, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-    let mut _4: std::result::Result<i32, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
-    let _5: std::result::Result<std::convert::Infallible, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-    let mut _6: std::result::Result<std::convert::Infallible, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-    let _7: i32;                         // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-    scope 1 {
-        debug residual => _5;            // in scope 1 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        scope 2 {
-            scope 8 (inlined #[track_caller] <Result<i32, i32> as FromResidual<Result<Infallible, i32>>>::from_residual) { // at $DIR/separate_const_switch.rs:29:8: 29:10
-                debug residual => _6;    // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-                let _14: i32;            // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-                let mut _15: i32;        // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-                let mut _16: i32;        // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-                scope 9 {
-                    debug e => _14;      // in scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-                    scope 10 (inlined <i32 as From<i32>>::from) { // at $SRC_DIR/core/src/result.rs:LL:COL
-                        debug t => _16;  // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
-                    }
-                }
-            }
-        }
-    }
-    scope 3 {
-        debug val => _7;                 // in scope 3 at $DIR/separate_const_switch.rs:+1:8: +1:10
-        scope 4 {
-        }
-    }
-    scope 5 (inlined <Result<i32, i32> as Try>::branch) { // at $DIR/separate_const_switch.rs:29:8: 29:10
-        debug self => _4;                // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        let mut _8: isize;               // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        let _9: i32;                     // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        let mut _10: i32;                // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        let _11: i32;                    // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        let mut _12: std::result::Result<std::convert::Infallible, i32>; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        let mut _13: i32;                // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        scope 6 {
-            debug v => _9;               // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-        }
-        scope 7 {
-            debug e => _11;              // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        }
-    }
-
-    bb0: {
-        StorageLive(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-        StorageLive(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-        StorageLive(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
-        _4 = _1;                         // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
-        _8 = discriminant(_4);           // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        switchInt(move _8) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-    }
-
-    bb1: {
-        StorageLive(_11);                // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        _11 = move ((_4 as Err).0: i32); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageLive(_12);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageLive(_13);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        _13 = move _11;                  // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        Deinit(_12);                     // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        ((_12 as Err).0: i32) = move _13; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        discriminant(_12) = 1;           // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_13);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        Deinit(_3);                      // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>) = move _12; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        discriminant(_3) = 1;            // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_12);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_11);                // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        StorageLive(_5);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        _5 = ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        StorageLive(_6);                 // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        _6 = _5;                         // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        StorageLive(_14);                // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-        _14 = move ((_6 as Err).0: i32); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageLive(_15);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageLive(_16);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-        _16 = move _14;                  // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-        _15 = move _16;                  // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
-        StorageDead(_16);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-        Deinit(_0);                      // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-        ((_0 as Err).0: i32) = move _15; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-        discriminant(_0) = 1;            // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_15);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_14);                // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_6);                 // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        StorageDead(_5);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
-        StorageDead(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
-        return;                          // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
-    }
-
-    bb2: {
-        unreachable;                     // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-    }
-
-    bb3: {
-        StorageLive(_9);                 // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        _9 = move ((_4 as Ok).0: i32);   // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageLive(_10);                // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-        _10 = move _9;                   // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-        Deinit(_3);                      // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-        ((_3 as Continue).0: i32) = move _10; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-        discriminant(_3) = 0;            // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_10);                // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_9);                 // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
-        StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        StorageLive(_7);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-        _7 = ((_3 as Continue).0: i32);  // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
-        _2 = _7;                         // scope 4 at $DIR/separate_const_switch.rs:+1:8: +1:10
-        StorageDead(_7);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
-        Deinit(_0);                      // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
-        ((_0 as Ok).0: i32) = move _2;   // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
-        discriminant(_0) = 0;            // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
-        StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
-        StorageDead(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
-        return;                          // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
-    }
-}
diff --git a/src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff b/src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff
deleted file mode 100644
index 28269165e1c..00000000000
--- a/src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff
+++ /dev/null
@@ -1,103 +0,0 @@
-- // MIR for `too_complex` before ConstProp
-+ // MIR for `too_complex` after ConstProp
-  
-  fn too_complex(_1: Result<i32, usize>) -> Option<i32> {
-      debug x => _1;                       // in scope 0 at $DIR/separate_const_switch.rs:+0:16: +0:17
-      let mut _0: std::option::Option<i32>; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:42: +0:53
-      let mut _2: std::ops::ControlFlow<usize, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
-      let mut _3: isize;                   // in scope 0 at $DIR/separate_const_switch.rs:+7:13: +7:18
-      let _4: i32;                         // in scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
-      let mut _5: i32;                     // in scope 0 at $DIR/separate_const_switch.rs:+7:44: +7:45
-      let _6: usize;                       // in scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18
-      let mut _7: usize;                   // in scope 0 at $DIR/separate_const_switch.rs:+8:42: +8:43
-      let mut _8: isize;                   // in scope 0 at $DIR/separate_const_switch.rs:+11:9: +11:33
-      let _9: i32;                         // in scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
-      let mut _10: i32;                    // in scope 0 at $DIR/separate_const_switch.rs:+11:42: +11:43
-      let _11: usize;                      // in scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29
-      scope 1 {
-          debug v => _4;                   // in scope 1 at $DIR/separate_const_switch.rs:+7:16: +7:17
-      }
-      scope 2 {
-          debug r => _6;                   // in scope 2 at $DIR/separate_const_switch.rs:+8:17: +8:18
-      }
-      scope 3 {
-          debug v => _9;                   // in scope 3 at $DIR/separate_const_switch.rs:+11:31: +11:32
-      }
-      scope 4 {
-          debug r => _11;                  // in scope 4 at $DIR/separate_const_switch.rs:+12:28: +12:29
-      }
-  
-      bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
-          _3 = discriminant(_1);           // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16
-          switchInt(move _3) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+6:9: +6:16
-      }
-  
-      bb1: {
-          StorageLive(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18
-          _6 = ((_1 as Err).0: usize);     // scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18
-          StorageLive(_7);                 // scope 2 at $DIR/separate_const_switch.rs:+8:42: +8:43
-          _7 = _6;                         // scope 2 at $DIR/separate_const_switch.rs:+8:42: +8:43
-          Deinit(_2);                      // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44
-          ((_2 as Break).0: usize) = move _7; // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44
-          discriminant(_2) = 1;            // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44
-          StorageDead(_7);                 // scope 2 at $DIR/separate_const_switch.rs:+8:43: +8:44
-          StorageDead(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+8:43: +8:44
--         _8 = discriminant(_2);           // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
--         switchInt(move _8) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
-+         _8 = const 1_isize;              // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
-+         switchInt(const 1_isize) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
-      }
-  
-      bb2: {
-          unreachable;                     // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16
-      }
-  
-      bb3: {
-          StorageLive(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
-          _4 = ((_1 as Ok).0: i32);        // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
-          StorageLive(_5);                 // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45
-          _5 = _4;                         // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45
-          Deinit(_2);                      // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
-          ((_2 as Continue).0: i32) = move _5; // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
-          discriminant(_2) = 0;            // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
-          StorageDead(_5);                 // scope 1 at $DIR/separate_const_switch.rs:+7:45: +7:46
-          StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+7:45: +7:46
--         _8 = discriminant(_2);           // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
--         switchInt(move _8) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
-+         _8 = const 0_isize;              // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
-+         switchInt(const 0_isize) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
-      }
-  
-      bb4: {
-          StorageLive(_11);                // scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29
-          _11 = ((_2 as Break).0: usize);  // scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29
-          Deinit(_0);                      // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38
-          discriminant(_0) = 0;            // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38
-          StorageDead(_11);                // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38
-          goto -> bb7;                     // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38
-      }
-  
-      bb5: {
-          unreachable;                     // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
-      }
-  
-      bb6: {
-          StorageLive(_9);                 // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
-          _9 = ((_2 as Continue).0: i32);  // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
-          StorageLive(_10);                // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43
-          _10 = _9;                        // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43
-          Deinit(_0);                      // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
-          ((_0 as Some).0: i32) = move _10; // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
-          discriminant(_0) = 1;            // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
-          StorageDead(_10);                // scope 3 at $DIR/separate_const_switch.rs:+11:43: +11:44
-          StorageDead(_9);                 // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44
-          goto -> bb7;                     // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44
-      }
-  
-      bb7: {
-          StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+14:1: +14:2
-          return;                          // scope 0 at $DIR/separate_const_switch.rs:+14:2: +14:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir b/src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir
deleted file mode 100644
index 0ee070619e7..00000000000
--- a/src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir
+++ /dev/null
@@ -1,73 +0,0 @@
-// MIR for `too_complex` after PreCodegen
-
-fn too_complex(_1: Result<i32, usize>) -> Option<i32> {
-    debug x => _1;                       // in scope 0 at $DIR/separate_const_switch.rs:+0:16: +0:17
-    let mut _0: std::option::Option<i32>; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:42: +0:53
-    let mut _2: std::ops::ControlFlow<usize, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
-    let mut _3: isize;                   // in scope 0 at $DIR/separate_const_switch.rs:+7:13: +7:18
-    let _4: i32;                         // in scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
-    let mut _5: i32;                     // in scope 0 at $DIR/separate_const_switch.rs:+7:44: +7:45
-    let _6: usize;                       // in scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18
-    let _7: i32;                         // in scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
-    let mut _8: i32;                     // in scope 0 at $DIR/separate_const_switch.rs:+11:42: +11:43
-    let _9: usize;                       // in scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29
-    scope 1 {
-        debug v => _4;                   // in scope 1 at $DIR/separate_const_switch.rs:+7:16: +7:17
-    }
-    scope 2 {
-        debug r => _6;                   // in scope 2 at $DIR/separate_const_switch.rs:+8:17: +8:18
-    }
-    scope 3 {
-        debug v => _7;                   // in scope 3 at $DIR/separate_const_switch.rs:+11:31: +11:32
-    }
-    scope 4 {
-        debug r => _9;                   // in scope 4 at $DIR/separate_const_switch.rs:+12:28: +12:29
-    }
-
-    bb0: {
-        StorageLive(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
-        _3 = discriminant(_1);           // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16
-        switchInt(move _3) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+6:9: +6:16
-    }
-
-    bb1: {
-        StorageLive(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18
-        StorageDead(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+8:43: +8:44
-        StorageLive(_9);                 // scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29
-        Deinit(_0);                      // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38
-        discriminant(_0) = 0;            // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38
-        StorageDead(_9);                 // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38
-        goto -> bb4;                     // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38
-    }
-
-    bb2: {
-        unreachable;                     // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16
-    }
-
-    bb3: {
-        StorageLive(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
-        _4 = ((_1 as Ok).0: i32);        // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
-        StorageLive(_5);                 // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45
-        _5 = _4;                         // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45
-        Deinit(_2);                      // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
-        ((_2 as Continue).0: i32) = move _5; // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
-        discriminant(_2) = 0;            // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
-        StorageDead(_5);                 // scope 1 at $DIR/separate_const_switch.rs:+7:45: +7:46
-        StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+7:45: +7:46
-        StorageLive(_7);                 // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
-        _7 = ((_2 as Continue).0: i32);  // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
-        StorageLive(_8);                 // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43
-        _8 = _7;                         // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43
-        Deinit(_0);                      // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
-        ((_0 as Some).0: i32) = move _8; // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
-        discriminant(_0) = 1;            // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
-        StorageDead(_8);                 // scope 3 at $DIR/separate_const_switch.rs:+11:43: +11:44
-        StorageDead(_7);                 // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44
-        goto -> bb4;                     // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44
-    }
-
-    bb4: {
-        StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+14:1: +14:2
-        return;                          // scope 0 at $DIR/separate_const_switch.rs:+14:2: +14:2
-    }
-}
diff --git a/src/test/mir-opt/simple-match.rs b/src/test/mir-opt/simple-match.rs
index 44adc55b6f7..103033c4e2b 100644
--- a/src/test/mir-opt/simple-match.rs
+++ b/src/test/mir-opt/simple-match.rs
@@ -1,6 +1,6 @@
 // Test that we don't generate unnecessarily large MIR for very simple matches
 
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
 // EMIT_MIR simple_match.match_bool.mir_map.0.mir
 fn match_bool(x: bool) -> usize {
     match x {
diff --git a/src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir b/src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir
deleted file mode 100644
index 3bef6aa0579..00000000000
--- a/src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir
+++ /dev/null
@@ -1,29 +0,0 @@
-// MIR for `match_bool` 0 mir_map
-
-fn match_bool(_1: bool) -> usize {
-    debug x => _1;                       // in scope 0 at $DIR/simple-match.rs:+0:15: +0:16
-    let mut _0: usize;                   // return place in scope 0 at $DIR/simple-match.rs:+0:27: +0:32
-
-    bb0: {
-        FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/simple-match.rs:+1:11: +1:12
-        switchInt(_1) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/simple-match.rs:+1:5: +1:12
-    }
-
-    bb1: {
-        falseEdge -> [real: bb3, imaginary: bb2]; // scope 0 at $DIR/simple-match.rs:+2:9: +2:13
-    }
-
-    bb2: {
-        _0 = const 20_usize;             // scope 0 at $DIR/simple-match.rs:+3:14: +3:16
-        goto -> bb4;                     // scope 0 at $DIR/simple-match.rs:+3:14: +3:16
-    }
-
-    bb3: {
-        _0 = const 10_usize;             // scope 0 at $DIR/simple-match.rs:+2:17: +2:19
-        goto -> bb4;                     // scope 0 at $DIR/simple-match.rs:+2:17: +2:19
-    }
-
-    bb4: {
-        return;                          // scope 0 at $DIR/simple-match.rs:+5:2: +5:2
-    }
-}
diff --git a/src/test/mir-opt/simple_match.match_bool.mir_map.0.32bit.mir b/src/test/mir-opt/simple_match.match_bool.mir_map.0.mir
index 3bef6aa0579..3bef6aa0579 100644
--- a/src/test/mir-opt/simple_match.match_bool.mir_map.0.32bit.mir
+++ b/src/test/mir-opt/simple_match.match_bool.mir_map.0.mir
diff --git a/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs b/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs
index 62a15df04b1..d09bd92c4e8 100644
--- a/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs
+++ b/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs
@@ -11,5 +11,4 @@ fn main() {
     map(None);
 }
 
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
 // EMIT_MIR simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff
diff --git a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff
deleted file mode 100644
index 51d26b08b2a..00000000000
--- a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff
+++ /dev/null
@@ -1,52 +0,0 @@
-- // MIR for `map` before SimplifyLocals
-+ // MIR for `map` after SimplifyLocals
-  
-  fn map(_1: Option<Box<()>>) -> Option<Box<()>> {
-      debug x => _1;                       // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:8: +0:9
-      let mut _0: std::option::Option<std::boxed::Box<()>>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:31: +0:46
-      let mut _2: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:9: +2:13
-      let _3: std::boxed::Box<()>;         // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
-      let mut _4: std::boxed::Box<()>;     // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
--     let mut _5: bool;                    // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
--     let mut _6: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
--     let mut _7: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
-      scope 1 {
-          debug x => _3;                   // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
-      }
-  
-      bb0: {
--         _5 = const false;                // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
--         _5 = const true;                 // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
-          _2 = discriminant(_1);           // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
-          switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:5: +1:12
-      }
-  
-      bb1: {
-          StorageLive(_3);                 // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
-          _3 = move ((_1 as Some).0: std::boxed::Box<()>); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
-          StorageLive(_4);                 // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
-          _4 = move _3;                    // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
-          Deinit(_0);                      // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
-          ((_0 as Some).0: std::boxed::Box<()>) = move _4; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
-          discriminant(_0) = 1;            // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
-          StorageDead(_4);                 // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
-          StorageDead(_3);                 // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
-          goto -> bb4;                     // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
-      }
-  
-      bb2: {
-          unreachable;                     // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
-      }
-  
-      bb3: {
-          Deinit(_0);                      // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21
-          discriminant(_0) = 0;            // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21
-          goto -> bb4;                     // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21
-      }
-  
-      bb4: {
--         _6 = discriminant(_1);           // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
-          return;                          // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:2: +5:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff
index 51d26b08b2a..51d26b08b2a 100644
--- a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff
+++ b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff
diff --git a/src/test/mir-opt/slice-drop-shim.rs b/src/test/mir-opt/slice-drop-shim.rs
index 0fd32906db6..344c1af2c91 100644
--- a/src/test/mir-opt/slice-drop-shim.rs
+++ b/src/test/mir-opt/slice-drop-shim.rs
@@ -1,6 +1,6 @@
 // compile-flags: -Zmir-opt-level=0
 
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
 // EMIT_MIR core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir
 fn main() {
     let _fn = std::ptr::drop_in_place::<[String]> as unsafe fn(_);
diff --git a/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.64bit.mir b/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.64bit.mir
deleted file mode 100644
index b4b317e84af..00000000000
--- a/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.64bit.mir
+++ /dev/null
@@ -1,101 +0,0 @@
-// MIR for `std::ptr::drop_in_place` before AddMovesForPackedDrops
-
-fn std::ptr::drop_in_place(_1: *mut [String]) -> () {
-    let mut _0: ();                      // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _2: usize;                   // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _3: usize;                   // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _4: usize;                   // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _5: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _6: bool;                    // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _7: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _8: bool;                    // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _9: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _10: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _11: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _12: bool;                   // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _13: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _14: bool;                   // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _15: *mut [std::string::String]; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-
-    bb0: {
-        goto -> bb15;                    // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb1: {
-        return;                          // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb2 (cleanup): {
-        resume;                          // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb3 (cleanup): {
-        _5 = &raw mut (*_1)[_4];         // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        drop((*_5)) -> bb4;              // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb4 (cleanup): {
-        _6 = Eq(_4, _3);                 // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        switchInt(move _6) -> [false: bb3, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb5: {
-        _7 = &raw mut (*_1)[_4];         // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        drop((*_7)) -> [return: bb6, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb6: {
-        _8 = Eq(_4, _3);                 // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        switchInt(move _8) -> [false: bb5, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb7: {
-        _4 = const 0_usize;              // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        goto -> bb6;                     // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb8: {
-        goto -> bb7;                     // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb9 (cleanup): {
-        _11 = _9;                        // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        drop((*_11)) -> bb10;            // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb10 (cleanup): {
-        _12 = Eq(_9, _10);               // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        switchInt(move _12) -> [false: bb9, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb11: {
-        _13 = _9;                        // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        drop((*_13)) -> [return: bb12, unwind: bb10]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb12: {
-        _14 = Eq(_9, _10);               // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        switchInt(move _14) -> [false: bb11, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb13: {
-        _15 = &raw mut (*_1);            // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _9 = move _15 as *mut std::string::String (Misc); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _10 = Offset(_9, move _3);       // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        goto -> bb12;                    // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb14: {
-        goto -> bb13;                    // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb15: {
-        _2 = SizeOf(std::string::String); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _3 = Len((*_1));                 // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        switchInt(move _2) -> [0_usize: bb8, otherwise: bb14]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-}
diff --git a/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.32bit.mir b/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir
index b4b317e84af..b4b317e84af 100644
--- a/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.32bit.mir
+++ b/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir
diff --git a/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir b/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir
index 6e9a8b4d975..6a5021139cf 100644
--- a/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir
+++ b/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir
@@ -15,9 +15,9 @@ fn move_out_by_subslice() -> () {
     let mut _11: std::boxed::Box<i32>;   // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
     scope 1 {
         debug a => _1;                   // in scope 1 at $DIR/uniform_array_move_out.rs:+1:9: +1:10
-        let _12: [std::boxed::Box<i32>; 2]; // in scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:17
+        let _12: [std::boxed::Box<i32>; 2]; // in scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:12
         scope 4 {
-            debug _y => _12;             // in scope 4 at $DIR/uniform_array_move_out.rs:+2:10: +2:17
+            debug _y => _12;             // in scope 4 at $DIR/uniform_array_move_out.rs:+2:10: +2:12
         }
     }
     scope 2 {
@@ -77,8 +77,8 @@ fn move_out_by_subslice() -> () {
     bb6: {
         StorageDead(_2);                 // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27
         FakeRead(ForLet(None), _1);      // scope 0 at $DIR/uniform_array_move_out.rs:+1:9: +1:10
-        StorageLive(_12);                // scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:17
-        _12 = move _1[0..2];             // scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:17
+        StorageLive(_12);                // scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:12
+        _12 = move _1[0..2];             // scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:12
         _0 = const ();                   // scope 0 at $DIR/uniform_array_move_out.rs:+0:27: +3:2
         drop(_12) -> [return: bb7, unwind: bb9]; // scope 1 at $DIR/uniform_array_move_out.rs:+3:1: +3:2
     }
diff --git a/src/test/mir-opt/unusual-item-types.rs b/src/test/mir-opt/unusual-item-types.rs
index 670f61cd5ce..9ef3d86472d 100644
--- a/src/test/mir-opt/unusual-item-types.rs
+++ b/src/test/mir-opt/unusual-item-types.rs
@@ -1,7 +1,7 @@
 // Test that we don't ICE when trying to dump MIR for unusual item types and
 // that we don't create filenames containing `<` and `>`
 // compile-flags: -Zmir-opt-level=0
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
 
 struct A;
 
diff --git a/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.64bit.mir b/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.64bit.mir
deleted file mode 100644
index a72e00ecde7..00000000000
--- a/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.64bit.mir
+++ /dev/null
@@ -1,10 +0,0 @@
-// MIR for `E::V::{constant#0}` 0 mir_map
-
-E::V::{constant#0}: isize = {
-    let mut _0: isize;                   // return place in scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10
-
-    bb0: {
-        _0 = const 5_isize;              // scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10
-        return;                          // scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10
-    }
-}
diff --git a/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.32bit.mir b/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.mir
index a72e00ecde7..a72e00ecde7 100644
--- a/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.32bit.mir
+++ b/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.mir
diff --git a/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir
deleted file mode 100644
index 0686af46ed5..00000000000
--- a/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir
+++ /dev/null
@@ -1,12 +0,0 @@
-// MIR for `Test::X` 0 mir_map
-
-fn Test::X(_1: usize) -> Test {
-    let mut _0: Test;                    // return place in scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
-
-    bb0: {
-        Deinit(_0);                      // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
-        ((_0 as X).0: usize) = move _1;  // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
-        discriminant(_0) = 0;            // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
-        return;                          // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
-    }
-}
diff --git a/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.mir
index 0686af46ed5..0686af46ed5 100644
--- a/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir
+++ b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.mir
diff --git a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir
deleted file mode 100644
index 7ffd242e0dc..00000000000
--- a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir
+++ /dev/null
@@ -1,39 +0,0 @@
-// MIR for `std::ptr::drop_in_place` before AddMovesForPackedDrops
-
-fn std::ptr::drop_in_place(_1: *mut Vec<i32>) -> () {
-    let mut _0: ();                      // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _2: &mut std::vec::Vec<i32>; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    let mut _3: ();                      // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-
-    bb0: {
-        goto -> bb6;                     // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb1: {
-        return;                          // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb2 (cleanup): {
-        resume;                          // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb3: {
-        goto -> bb1;                     // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb4 (cleanup): {
-        drop(((*_1).0: alloc::raw_vec::RawVec<i32>)) -> bb2; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb5: {
-        drop(((*_1).0: alloc::raw_vec::RawVec<i32>)) -> [return: bb3, unwind: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-    }
-
-    bb6: {
-        _2 = &mut (*_1);                 // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-        _3 = <Vec<i32> as Drop>::drop(move _2) -> [return: bb5, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56
-                                         // mir::Constant
-                                         // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-                                         // + literal: Const { ty: for<'r> fn(&'r mut Vec<i32>) {<Vec<i32> as Drop>::drop}, val: Value(<ZST>) }
-    }
-}
diff --git a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir
index 7ffd242e0dc..7ffd242e0dc 100644
--- a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir
+++ b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir
diff --git a/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir b/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir
deleted file mode 100644
index e2633f61b5f..00000000000
--- a/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir
+++ /dev/null
@@ -1,10 +0,0 @@
-// MIR for `<impl at $DIR/unusual-item-types.rs:9:1: 9:7>::ASSOCIATED_CONSTANT` 0 mir_map
-
-const <impl at $DIR/unusual-item-types.rs:9:1: 9:7>::ASSOCIATED_CONSTANT: i32 = {
-    let mut _0: i32;                     // return place in scope 0 at $DIR/unusual-item-types.rs:+0:32: +0:35
-
-    bb0: {
-        _0 = const 2_i32;                // scope 0 at $DIR/unusual-item-types.rs:+0:38: +0:39
-        return;                          // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:39
-    }
-}
diff --git a/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir b/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.mir
index e2633f61b5f..e2633f61b5f 100644
--- a/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir
+++ b/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.mir
diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.64bit.diff b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.64bit.diff
deleted file mode 100644
index eef7011149d..00000000000
--- a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.64bit.diff
+++ /dev/null
@@ -1,55 +0,0 @@
-- // MIR for `change_loop_body` before ConstProp
-+ // MIR for `change_loop_body` after ConstProp
-  
-  fn change_loop_body() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/while_let_loops.rs:+0:27: +0:27
-      let mut _1: i32;                     // in scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
-      let mut _2: ();                      // in scope 0 at $DIR/while_let_loops.rs:+0:1: +6:2
-      let mut _3: std::option::Option<u32>; // in scope 0 at $DIR/while_let_loops.rs:+2:28: +2:32
-      let mut _4: isize;                   // in scope 0 at $DIR/while_let_loops.rs:+2:15: +2:25
-      let mut _5: !;                       // in scope 0 at $DIR/while_let_loops.rs:+2:33: +5:6
-      let mut _6: !;                       // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
-      let _7: ();                          // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
-      let mut _8: !;                       // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
-      scope 1 {
-          debug _x => _1;                  // in scope 1 at $DIR/while_let_loops.rs:+1:9: +1:15
-          scope 2 {
-          }
-      }
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
-          _1 = const 0_i32;                // scope 0 at $DIR/while_let_loops.rs:+1:18: +1:19
-          StorageLive(_3);                 // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
-          Deinit(_3);                      // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
-          discriminant(_3) = 0;            // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
--         _4 = discriminant(_3);           // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
--         switchInt(move _4) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
-+         _4 = const 0_isize;              // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
-+         switchInt(const 0_isize) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
-      }
-  
-      bb1: {
-          switchInt(((_3 as Some).0: u32)) -> [0_u32: bb2, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
-      }
-  
-      bb2: {
-          _1 = const 1_i32;                // scope 2 at $DIR/while_let_loops.rs:+3:9: +3:15
-          nop;                             // scope 2 at $DIR/while_let_loops.rs:+4:9: +4:14
-          goto -> bb4;                     // scope 2 at $DIR/while_let_loops.rs:+4:9: +4:14
-      }
-  
-      bb3: {
-          StorageLive(_7);                 // scope 1 at $DIR/while_let_loops.rs:+2:5: +5:6
-          nop;                             // scope 1 at $DIR/while_let_loops.rs:+2:5: +5:6
-          StorageDead(_7);                 // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6
-          goto -> bb4;                     // scope 1 at no-location
-      }
-  
-      bb4: {
-          StorageDead(_3);                 // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6
-          StorageDead(_1);                 // scope 0 at $DIR/while_let_loops.rs:+6:1: +6:2
-          return;                          // scope 0 at $DIR/while_let_loops.rs:+6:2: +6:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.32bit.diff b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff
index eef7011149d..eef7011149d 100644
--- a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.32bit.diff
+++ b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff
diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir
deleted file mode 100644
index 15b0aece8f5..00000000000
--- a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir
+++ /dev/null
@@ -1,17 +0,0 @@
-// MIR for `change_loop_body` after PreCodegen
-
-fn change_loop_body() -> () {
-    let mut _0: ();                      // return place in scope 0 at $DIR/while_let_loops.rs:+0:27: +0:27
-    let mut _1: i32;                     // in scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
-    scope 1 {
-        debug _x => _1;                  // in scope 1 at $DIR/while_let_loops.rs:+1:9: +1:15
-        scope 2 {
-        }
-    }
-
-    bb0: {
-        StorageLive(_1);                 // scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
-        StorageDead(_1);                 // scope 0 at $DIR/while_let_loops.rs:+6:1: +6:2
-        return;                          // scope 0 at $DIR/while_let_loops.rs:+6:2: +6:2
-    }
-}
diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.32bit.mir b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir
index 15b0aece8f5..15b0aece8f5 100644
--- a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.32bit.mir
+++ b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir
diff --git a/src/test/mir-opt/while_let_loops.rs b/src/test/mir-opt/while_let_loops.rs
index f320a218c85..fc56cd6985d 100644
--- a/src/test/mir-opt/while_let_loops.rs
+++ b/src/test/mir-opt/while_let_loops.rs
@@ -1,6 +1,5 @@
 // EMIT_MIR while_let_loops.change_loop_body.ConstProp.diff
 // EMIT_MIR while_let_loops.change_loop_body.PreCodegen.after.mir
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
 
 pub fn change_loop_body() {
     let mut _x = 0;
diff --git a/src/test/run-make/issue-71519/Makefile b/src/test/run-make/issue-71519/Makefile
index 4475649ca92..16d9a56e6bf 100644
--- a/src/test/run-make/issue-71519/Makefile
+++ b/src/test/run-make/issue-71519/Makefile
@@ -1,5 +1,6 @@
 include ../../run-make-fulldeps/tools.mk
 
+# ignore-msvc
 # needs-rust-lld
 all:
 	RUSTC_LOG=rustc_codegen_ssa::back::link=info $(RUSTC) -Z gcc-ld=lld -C link-args=-Wl,-v main.rs 2> $(TMPDIR)/output.txt
diff --git a/src/test/run-make/track-pgo-dep-info/Makefile b/src/test/run-make/track-pgo-dep-info/Makefile
new file mode 100644
index 00000000000..60b59c04aa9
--- /dev/null
+++ b/src/test/run-make/track-pgo-dep-info/Makefile
@@ -0,0 +1,26 @@
+# needs-profiler-support
+# ignore-windows-gnu
+
+-include ../../run-make-fulldeps/tools.mk
+
+# FIXME(eddyb) provide `HOST_RUSTC` and `TARGET_RUSTC`
+# instead of hardcoding them everywhere they're needed.
+ifeq ($(IS_MUSL_HOST),1)
+ADDITIONAL_ARGS := $(RUSTFLAGS)
+endif
+
+all:
+	# Generate PGO profiles
+	$(BARE_RUSTC) $(ADDITIONAL_ARGS) -Cprofile-generate=$(TMPDIR)/profiles --out-dir $(TMPDIR) main.rs
+	$(TMPDIR)/main
+
+	# Merge profiles
+	"$(LLVM_BIN_DIR)/llvm-profdata" merge \
+		-o "$(TMPDIR)/merged.profdata" \
+		"$(TMPDIR)/profiles" || exit 1
+
+	# Use the profile
+	$(RUSTC) -Cprofile-use=$(TMPDIR)/merged.profdata --emit dep-info main.rs
+
+	# Check that profile file is in depinfo
+	$(CGREP) "merged.profdata" < $(TMPDIR)/main.d
diff --git a/src/test/run-make/track-pgo-dep-info/main.rs b/src/test/run-make/track-pgo-dep-info/main.rs
new file mode 100644
index 00000000000..f328e4d9d04
--- /dev/null
+++ b/src/test/run-make/track-pgo-dep-info/main.rs
@@ -0,0 +1 @@
+fn main() {}
diff --git a/src/test/rustdoc-json/enum_variant_hidden.rs b/src/test/rustdoc-json/enums/field_hidden.rs
index c5e063a055c..e6310cc3b99 100644
--- a/src/test/rustdoc-json/enum_variant_hidden.rs
+++ b/src/test/rustdoc-json/enums/field_hidden.rs
@@ -6,7 +6,7 @@
 // @has "$.index[*][?(@.name=='ParseError')]"
 // @has "$.index[*][?(@.name=='UnexpectedEndTag')]"
 // @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.variant_kind" '"tuple"'
-// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.variant_inner" []
+// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.variant_inner" [null]
 
 pub enum ParseError {
     UnexpectedEndTag(#[doc(hidden)] u32),
diff --git a/src/test/rustdoc-json/enums/kind.rs b/src/test/rustdoc-json/enums/kind.rs
new file mode 100644
index 00000000000..e9ea3ae23c2
--- /dev/null
+++ b/src/test/rustdoc-json/enums/kind.rs
@@ -0,0 +1,37 @@
+// ignore-tidy-linelength
+
+#![feature(no_core)]
+#![no_core]
+
+pub enum Foo {
+    // @set Unit = "$.index[*][?(@.name=='Unit')].id"
+    // @is "$.index[*][?(@.name=='Unit')].inner.variant_kind" '"plain"'
+    // @is "$.index[*][?(@.name=='Unit')].inner.variant_inner" null
+    Unit,
+    // @set Named = "$.index[*][?(@.name=='Named')].id"
+    // @is "$.index[*][?(@.name=='Named')].inner.variant_kind" '"struct"'
+    // @is "$.index[*][?(@.name=='Named')].inner.variant_inner" '{"fields": [], "fields_stripped": false}'
+    Named {},
+    // @set Tuple = "$.index[*][?(@.name=='Tuple')].id"
+    // @is "$.index[*][?(@.name=='Tuple')].inner.variant_kind" '"tuple"'
+    // @is "$.index[*][?(@.name=='Tuple')].inner.variant_inner" []
+    Tuple(),
+    // @set NamedField = "$.index[*][?(@.name=='NamedField')].id"
+    // @set x = "$.index[*][?(@.name=='x' && @.kind=='struct_field')].id"
+    // @is "$.index[*][?(@.name=='NamedField')].inner.variant_kind" '"struct"'
+    // @is "$.index[*][?(@.name=='NamedField')].inner.variant_inner.fields[*]" $x
+    // @is "$.index[*][?(@.name=='NamedField')].inner.variant_inner.fields_stripped" false
+    NamedField { x: i32 },
+    // @set TupleField = "$.index[*][?(@.name=='TupleField')].id"
+    // @is "$.index[*][?(@.name=='TupleField')].inner.variant_kind" '"tuple"'
+    // @set tup_field = "$.index[*][?(@.name=='0' && @.kind=='struct_field')].id"
+    // @is "$.index[*][?(@.name=='TupleField')].inner.variant_inner[*]" $tup_field
+    TupleField(i32),
+}
+
+// @is    "$.index[*][?(@.name=='Foo')].inner.variants[0]" $Unit
+// @is    "$.index[*][?(@.name=='Foo')].inner.variants[1]" $Named
+// @is    "$.index[*][?(@.name=='Foo')].inner.variants[2]" $Tuple
+// @is    "$.index[*][?(@.name=='Foo')].inner.variants[3]" $NamedField
+// @is    "$.index[*][?(@.name=='Foo')].inner.variants[4]" $TupleField
+// @count "$.index[*][?(@.name=='Foo')].inner.variants[*]" 5
diff --git a/src/test/rustdoc-json/enums/struct_field_hidden.rs b/src/test/rustdoc-json/enums/struct_field_hidden.rs
new file mode 100644
index 00000000000..f612a34a492
--- /dev/null
+++ b/src/test/rustdoc-json/enums/struct_field_hidden.rs
@@ -0,0 +1,17 @@
+pub enum Foo {
+    Variant {
+        #[doc(hidden)]
+        a: i32,
+        // @set b = "$.index[*][?(@.name=='b')].id"
+        b: i32,
+        #[doc(hidden)]
+        x: i32,
+        // @set y = "$.index[*][?(@.name=='y')].id"
+        y: i32,
+    },
+    // @is "$.index[*][?(@.name=='Variant')].inner.variant_kind" '"struct"'
+    // @is "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields_stripped" true
+    // @is "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields[0]" $b
+    // @is "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields[1]" $y
+    // @count "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields[*]" 2
+}
diff --git a/src/test/rustdoc-json/enums/tuple_fields_hidden.rs b/src/test/rustdoc-json/enums/tuple_fields_hidden.rs
new file mode 100644
index 00000000000..f546eaa0d17
--- /dev/null
+++ b/src/test/rustdoc-json/enums/tuple_fields_hidden.rs
@@ -0,0 +1,94 @@
+#![feature(no_core)]
+#![no_core]
+
+// @set 1.1.0 = "$.index[*][?(@.docs=='1.1.0')].id"
+// @set 2.1.0 = "$.index[*][?(@.docs=='2.1.0')].id"
+// @set 2.1.1 = "$.index[*][?(@.docs=='2.1.1')].id"
+// @set 2.2.1 = "$.index[*][?(@.docs=='2.2.1')].id"
+// @set 2.3.0 = "$.index[*][?(@.docs=='2.3.0')].id"
+// @set 3.1.1 = "$.index[*][?(@.docs=='3.1.1')].id"
+// @set 3.1.2 = "$.index[*][?(@.docs=='3.1.2')].id"
+// @set 3.2.0 = "$.index[*][?(@.docs=='3.2.0')].id"
+// @set 3.2.2 = "$.index[*][?(@.docs=='3.2.2')].id"
+// @set 3.3.0 = "$.index[*][?(@.docs=='3.3.0')].id"
+// @set 3.3.1 = "$.index[*][?(@.docs=='3.3.1')].id"
+
+pub enum EnumWithStrippedTupleVariants {
+    // @is    "$.index[*][?(@.name=='None')].inner.variant_kind" '"tuple"'
+    // @count "$.index[*][?(@.name=='None')].inner.variant_inner[*]" 0
+    None(),
+
+    // @is    "$.index[*][?(@.name=='One')].inner.variant_kind" '"tuple"'
+    // @count "$.index[*][?(@.name=='One')].inner.variant_inner[*]" 1
+    // @is    "$.index[*][?(@.name=='One')].inner.variant_inner[0]" $1.1.0
+    One(/** 1.1.0*/ bool),
+    // @is    "$.index[*][?(@.name=='OneHidden')].inner.variant_kind" '"tuple"'
+    // @count "$.index[*][?(@.name=='OneHidden')].inner.variant_inner[*]" 1
+    // @is    "$.index[*][?(@.name=='OneHidden')].inner.variant_inner[0]" null
+    OneHidden(#[doc(hidden)] bool),
+
+    // @is    "$.index[*][?(@.name=='Two')].inner.variant_kind" '"tuple"'
+    // @count "$.index[*][?(@.name=='Two')].inner.variant_inner[*]" 2
+    // @is    "$.index[*][?(@.name=='Two')].inner.variant_inner[0]" $2.1.0
+    // @is    "$.index[*][?(@.name=='Two')].inner.variant_inner[1]" $2.1.1
+    Two(/** 2.1.0*/ bool, /** 2.1.1*/ bool),
+    // @is    "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_kind" '"tuple"'
+    // @count "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_inner[*]" 2
+    // @is    "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_inner[0]" null
+    // @is    "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_inner[1]" $2.2.1
+    TwoLeftHidden(#[doc(hidden)] bool, /** 2.2.1*/ bool),
+    // @is    "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_kind" '"tuple"'
+    // @count "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_inner[*]" 2
+    // @is    "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_inner[0]" $2.3.0
+    // @is    "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_inner[1]" null
+    TwoRightHidden(/** 2.3.0*/ bool, #[doc(hidden)] bool),
+    // @is    "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_kind" '"tuple"'
+    // @count "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_inner[*]" 2
+    // @is    "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_inner[0]" null
+    // @is    "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_inner[1]" null
+    TwoBothHidden(#[doc(hidden)] bool, #[doc(hidden)] bool),
+
+    // @is    "$.index[*][?(@.name=='Three1')].inner.variant_kind" '"tuple"'
+    // @count "$.index[*][?(@.name=='Three1')].inner.variant_inner[*]" 3
+    // @is    "$.index[*][?(@.name=='Three1')].inner.variant_inner[0]" null
+    // @is    "$.index[*][?(@.name=='Three1')].inner.variant_inner[1]" $3.1.1
+    // @is    "$.index[*][?(@.name=='Three1')].inner.variant_inner[2]" $3.1.2
+    Three1(#[doc(hidden)] bool, /** 3.1.1*/ bool, /** 3.1.2*/ bool),
+    // @is    "$.index[*][?(@.name=='Three2')].inner.variant_kind" '"tuple"'
+    // @count "$.index[*][?(@.name=='Three2')].inner.variant_inner[*]" 3
+    // @is    "$.index[*][?(@.name=='Three2')].inner.variant_inner[0]" $3.2.0
+    // @is    "$.index[*][?(@.name=='Three2')].inner.variant_inner[1]" null
+    // @is    "$.index[*][?(@.name=='Three2')].inner.variant_inner[2]" $3.2.2
+    Three2(/** 3.2.0*/ bool, #[doc(hidden)] bool, /** 3.2.2*/ bool),
+    // @is    "$.index[*][?(@.name=='Three3')].inner.variant_kind" '"tuple"'
+    // @count "$.index[*][?(@.name=='Three3')].inner.variant_inner[*]" 3
+    // @is    "$.index[*][?(@.name=='Three3')].inner.variant_inner[0]" $3.3.0
+    // @is    "$.index[*][?(@.name=='Three3')].inner.variant_inner[1]" $3.3.1
+    // @is    "$.index[*][?(@.name=='Three3')].inner.variant_inner[2]" null
+    Three3(/** 3.3.0*/ bool, /** 3.3.1*/ bool, #[doc(hidden)] bool),
+}
+
+
+// @is "$.index[*][?(@.docs=='1.1.0')].name" '"0"'
+// @is "$.index[*][?(@.docs=='2.1.0')].name" '"0"'
+// @is "$.index[*][?(@.docs=='2.1.1')].name" '"1"'
+// @is "$.index[*][?(@.docs=='2.2.1')].name" '"1"'
+// @is "$.index[*][?(@.docs=='2.3.0')].name" '"0"'
+// @is "$.index[*][?(@.docs=='3.1.1')].name" '"1"'
+// @is "$.index[*][?(@.docs=='3.1.2')].name" '"2"'
+// @is "$.index[*][?(@.docs=='3.2.0')].name" '"0"'
+// @is "$.index[*][?(@.docs=='3.2.2')].name" '"2"'
+// @is "$.index[*][?(@.docs=='3.3.0')].name" '"0"'
+// @is "$.index[*][?(@.docs=='3.3.1')].name" '"1"'
+
+// @is "$.index[*][?(@.docs=='1.1.0')].inner" '{"kind": "primitive", "inner": "bool"}'
+// @is "$.index[*][?(@.docs=='2.1.0')].inner" '{"kind": "primitive", "inner": "bool"}'
+// @is "$.index[*][?(@.docs=='2.1.1')].inner" '{"kind": "primitive", "inner": "bool"}'
+// @is "$.index[*][?(@.docs=='2.2.1')].inner" '{"kind": "primitive", "inner": "bool"}'
+// @is "$.index[*][?(@.docs=='2.3.0')].inner" '{"kind": "primitive", "inner": "bool"}'
+// @is "$.index[*][?(@.docs=='3.1.1')].inner" '{"kind": "primitive", "inner": "bool"}'
+// @is "$.index[*][?(@.docs=='3.1.2')].inner" '{"kind": "primitive", "inner": "bool"}'
+// @is "$.index[*][?(@.docs=='3.2.0')].inner" '{"kind": "primitive", "inner": "bool"}'
+// @is "$.index[*][?(@.docs=='3.2.2')].inner" '{"kind": "primitive", "inner": "bool"}'
+// @is "$.index[*][?(@.docs=='3.3.0')].inner" '{"kind": "primitive", "inner": "bool"}'
+// @is "$.index[*][?(@.docs=='3.3.1')].inner" '{"kind": "primitive", "inner": "bool"}'
diff --git a/src/test/rustdoc-json/nested.rs b/src/test/rustdoc-json/nested.rs
index 73ec9392ce9..ee2d2efa960 100644
--- a/src/test/rustdoc-json/nested.rs
+++ b/src/test/rustdoc-json/nested.rs
@@ -17,7 +17,7 @@ pub mod l1 {
     pub mod l3 {
 
         // @is "$.index[*][?(@.name=='L4')].kind" \"struct\"
-        // @is "$.index[*][?(@.name=='L4')].inner.struct_type" \"unit\"
+        // @is "$.index[*][?(@.name=='L4')].inner.kind" \"unit\"
         // @set l4_id = "$.index[*][?(@.name=='L4')].id"
         // @ismany "$.index[*][?(@.name=='l3')].inner.items[*]" $l4_id
         pub struct L4;
diff --git a/src/test/rustdoc-json/structs/plain_all_pub.rs b/src/test/rustdoc-json/structs/plain_all_pub.rs
new file mode 100644
index 00000000000..b86ab93c264
--- /dev/null
+++ b/src/test/rustdoc-json/structs/plain_all_pub.rs
@@ -0,0 +1,11 @@
+pub struct Demo {
+    pub x: i32,
+    pub y: i32,
+}
+
+// @set x = "$.index[*][?(@.name=='x')].id"
+// @set y = "$.index[*][?(@.name=='y')].id"
+// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[0]" $x
+// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[1]" $y
+// @count "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[*]" 2
+// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields_stripped" false
diff --git a/src/test/rustdoc-json/structs/plain_doc_hidden.rs b/src/test/rustdoc-json/structs/plain_doc_hidden.rs
new file mode 100644
index 00000000000..7800b55a481
--- /dev/null
+++ b/src/test/rustdoc-json/structs/plain_doc_hidden.rs
@@ -0,0 +1,11 @@
+pub struct Demo {
+    pub x: i32,
+    #[doc(hidden)]
+    pub y: i32,
+}
+
+// @set x = "$.index[*][?(@.name=='x')].id"
+// @!has "$.index[*][?(@.name=='y')].id"
+// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[0]" $x
+// @count "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[*]" 1
+// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields_stripped" true
diff --git a/src/test/rustdoc-json/structs/plain_empty.rs b/src/test/rustdoc-json/structs/plain_empty.rs
index 2ad9e86096c..1d01b8bc14a 100644
--- a/src/test/rustdoc-json/structs/plain_empty.rs
+++ b/src/test/rustdoc-json/structs/plain_empty.rs
@@ -1,6 +1,5 @@
-// @has "$.index[*][?(@.name=='PlainEmpty')].visibility" \"public\"
-// @has "$.index[*][?(@.name=='PlainEmpty')].kind" \"struct\"
-// @has "$.index[*][?(@.name=='PlainEmpty')].inner.struct_type" \"plain\"
-// @has "$.index[*][?(@.name=='PlainEmpty')].inner.fields_stripped" false
-// @has "$.index[*][?(@.name=='PlainEmpty')].inner.fields" []
+// @is "$.index[*][?(@.name=='PlainEmpty')].visibility" \"public\"
+// @is "$.index[*][?(@.name=='PlainEmpty')].kind" \"struct\"
+// @is "$.index[*][?(@.name=='PlainEmpty')].inner.kind.plain.fields_stripped" false
+// @is "$.index[*][?(@.name=='PlainEmpty')].inner.kind.plain.fields" []
 pub struct PlainEmpty {}
diff --git a/src/test/rustdoc-json/structs/plain_pub_priv.rs b/src/test/rustdoc-json/structs/plain_pub_priv.rs
new file mode 100644
index 00000000000..9b771224d97
--- /dev/null
+++ b/src/test/rustdoc-json/structs/plain_pub_priv.rs
@@ -0,0 +1,9 @@
+pub struct Demo {
+    pub x: i32,
+    y: i32,
+}
+
+// @set x = "$.index[*][?(@.name=='x')].id"
+// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[0]" $x
+// @count "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[*]" 1
+// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields_stripped" true
diff --git a/src/test/rustdoc-json/structs/tuple.rs b/src/test/rustdoc-json/structs/tuple.rs
index 91fac359422..6bdb753ee01 100644
--- a/src/test/rustdoc-json/structs/tuple.rs
+++ b/src/test/rustdoc-json/structs/tuple.rs
@@ -1,5 +1,4 @@
-// @has "$.index[*][?(@.name=='Tuple')].visibility" \"public\"
-// @has "$.index[*][?(@.name=='Tuple')].kind" \"struct\"
-// @has "$.index[*][?(@.name=='Tuple')].inner.struct_type" \"tuple\"
-// @has "$.index[*][?(@.name=='Tuple')].inner.fields_stripped" true
+// @is "$.index[*][?(@.name=='Tuple')].visibility" \"public\"
+// @is "$.index[*][?(@.name=='Tuple')].kind" \"struct\"
+// @is "$.index[*][?(@.name=='Tuple')].inner.kind.tuple" '[null, null]'
 pub struct Tuple(u32, String);
diff --git a/src/test/rustdoc-json/structs/tuple_empty.rs b/src/test/rustdoc-json/structs/tuple_empty.rs
new file mode 100644
index 00000000000..0ad6a89547f
--- /dev/null
+++ b/src/test/rustdoc-json/structs/tuple_empty.rs
@@ -0,0 +1,2 @@
+// @is "$.index[*][?(@.name=='TupleUnit')].inner.kind.tuple" []
+pub struct TupleUnit();
diff --git a/src/test/rustdoc-json/structs/tuple_pub_priv.rs b/src/test/rustdoc-json/structs/tuple_pub_priv.rs
new file mode 100644
index 00000000000..9d5a1d1c8be
--- /dev/null
+++ b/src/test/rustdoc-json/structs/tuple_pub_priv.rs
@@ -0,0 +1,13 @@
+pub struct Demo(
+    i32,
+    /// field
+    pub i32,
+    #[doc(hidden)] i32,
+);
+
+// @set field = "$.index[*][?(@.docs=='field')].id"
+
+// @is    "$.index[*][?(@.name=='Demo')].inner.kind.tuple[0]" null
+// @is    "$.index[*][?(@.name=='Demo')].inner.kind.tuple[1]" $field
+// @is    "$.index[*][?(@.name=='Demo')].inner.kind.tuple[2]" null
+// @count "$.index[*][?(@.name=='Demo')].inner.kind.tuple[*]" 3
diff --git a/src/test/rustdoc-json/structs/unit.rs b/src/test/rustdoc-json/structs/unit.rs
index 85a515b5e78..26570971721 100644
--- a/src/test/rustdoc-json/structs/unit.rs
+++ b/src/test/rustdoc-json/structs/unit.rs
@@ -1,5 +1,4 @@
-// @has "$.index[*][?(@.name=='Unit')].visibility" \"public\"
-// @has "$.index[*][?(@.name=='Unit')].kind" \"struct\"
-// @has "$.index[*][?(@.name=='Unit')].inner.struct_type" \"unit\"
-// @has "$.index[*][?(@.name=='Unit')].inner.fields" []
+// @is "$.index[*][?(@.name=='Unit')].visibility" \"public\"
+// @is "$.index[*][?(@.name=='Unit')].kind" \"struct\"
+// @is "$.index[*][?(@.name=='Unit')].inner.kind" \"unit\"
 pub struct Unit;
diff --git a/src/test/rustdoc-json/structs/with_generics.rs b/src/test/rustdoc-json/structs/with_generics.rs
index b0ad1883f8a..00474800a0e 100644
--- a/src/test/rustdoc-json/structs/with_generics.rs
+++ b/src/test/rustdoc-json/structs/with_generics.rs
@@ -1,13 +1,13 @@
 use std::collections::HashMap;
 
-// @has "$.index[*][?(@.name=='WithGenerics')].visibility" \"public\"
-// @has "$.index[*][?(@.name=='WithGenerics')].kind" \"struct\"
-// @has "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[0].name" \"T\"
-// @has "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[0].kind.type"
-// @has "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[1].name" \"U\"
-// @has "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[1].kind.type"
-// @has "$.index[*][?(@.name=='WithGenerics')].inner.struct_type" \"plain\"
-// @has "$.index[*][?(@.name=='WithGenerics')].inner.fields_stripped" true
+// @is "$.index[*][?(@.name=='WithGenerics')].visibility" \"public\"
+// @is "$.index[*][?(@.name=='WithGenerics')].kind" \"struct\"
+// @is "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[0].name" \"T\"
+// @is "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[0].kind.type.bounds" []
+// @is "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[1].name" \"U\"
+// @is "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[1].kind.type.bounds" []
+// @is "$.index[*][?(@.name=='WithGenerics')].inner.kind.plain.fields_stripped" true
+// @is "$.index[*][?(@.name=='WithGenerics')].inner.kind.plain.fields" []
 pub struct WithGenerics<T, U> {
     stuff: Vec<T>,
     things: HashMap<U, U>,
diff --git a/src/test/rustdoc-json/structs/with_primitives.rs b/src/test/rustdoc-json/structs/with_primitives.rs
index b74050dde78..9c5a37f3957 100644
--- a/src/test/rustdoc-json/structs/with_primitives.rs
+++ b/src/test/rustdoc-json/structs/with_primitives.rs
@@ -1,9 +1,9 @@
-// @has "$.index[*][?(@.name=='WithPrimitives')].visibility" \"public\"
-// @has "$.index[*][?(@.name=='WithPrimitives')].kind" \"struct\"
-// @has "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].name" \"\'a\"
-// @has "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].kind.lifetime.outlives" []
-// @has "$.index[*][?(@.name=='WithPrimitives')].inner.struct_type" \"plain\"
-// @has "$.index[*][?(@.name=='WithPrimitives')].inner.fields_stripped" true
+// @is "$.index[*][?(@.name=='WithPrimitives')].visibility" \"public\"
+// @is "$.index[*][?(@.name=='WithPrimitives')].kind" \"struct\"
+// @is "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].name" \"\'a\"
+// @is "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].kind.lifetime.outlives" []
+// @is "$.index[*][?(@.name=='WithPrimitives')].inner.kind.plain.fields_stripped" true
+// @is "$.index[*][?(@.name=='WithPrimitives')].inner.kind.plain.fields" []
 pub struct WithPrimitives<'a> {
     num: u32,
     s: &'a str,
diff --git a/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs b/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs
index 802b867a301..03ad3ca8261 100644
--- a/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs
+++ b/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs
@@ -21,7 +21,7 @@ use rustc_span::source_map;
 #[no_mangle]
 fn __rustc_plugin_registrar(reg: &mut Registry) {
     reg.lint_store.register_lints(&[&MISSING_ALLOWED_ATTR]);
-    reg.lint_store.register_late_pass(|| Box::new(MissingAllowedAttrPass));
+    reg.lint_store.register_late_pass(|_| Box::new(MissingAllowedAttrPass));
 }
 
 declare_lint! {
diff --git a/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs b/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs
index bc153faa892..a3b570ad8c4 100644
--- a/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs
+++ b/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs
@@ -74,7 +74,7 @@ fn __rustc_plugin_registrar(reg: &mut Registry) {
         &CRATE_NOT_GREY,
         &CRATE_NOT_GREEN,
     ]);
-    reg.lint_store.register_late_pass(|| Box::new(PassOkay));
-    reg.lint_store.register_late_pass(|| Box::new(PassRedBlue));
-    reg.lint_store.register_late_pass(|| Box::new(PassGreyGreen));
+    reg.lint_store.register_late_pass(|_| Box::new(PassOkay));
+    reg.lint_store.register_late_pass(|_| Box::new(PassRedBlue));
+    reg.lint_store.register_late_pass(|_| Box::new(PassGreyGreen));
 }
diff --git a/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs
index 29d0abfbe53..0b1534939b7 100644
--- a/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs
+++ b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs
@@ -39,5 +39,5 @@ impl<'tcx> LateLintPass<'tcx> for Pass {
 #[no_mangle]
 fn __rustc_plugin_registrar(reg: &mut Registry) {
     reg.lint_store.register_lints(&[&CRATE_NOT_OKAY]);
-    reg.lint_store.register_late_pass(|| Box::new(Pass));
+    reg.lint_store.register_late_pass(|_| Box::new(Pass));
 }
diff --git a/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs b/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs
index 691cfb97d92..2d41b5f30e9 100644
--- a/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs
+++ b/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs
@@ -36,7 +36,7 @@ impl<'tcx> LateLintPass<'tcx> for Pass {
 #[no_mangle]
 fn __rustc_plugin_registrar(reg: &mut Registry) {
     reg.lint_store.register_lints(&[&TEST_LINT, &PLEASE_LINT]);
-    reg.lint_store.register_late_pass(|| Box::new(Pass));
+    reg.lint_store.register_late_pass(|_| Box::new(Pass));
     reg.lint_store.register_group(
         true,
         "lint_me",
diff --git a/src/test/ui-fulldeps/internal-lints/diagnostics.rs b/src/test/ui-fulldeps/internal-lints/diagnostics.rs
index 0e449256153..e9e809fa416 100644
--- a/src/test/ui-fulldeps/internal-lints/diagnostics.rs
+++ b/src/test/ui-fulldeps/internal-lints/diagnostics.rs
@@ -11,9 +11,11 @@ extern crate rustc_macros;
 extern crate rustc_session;
 extern crate rustc_span;
 
-use rustc_errors::{AddSubdiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, fluent};
+use rustc_errors::{
+    AddSubdiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, Handler, fluent
+};
 use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
-use rustc_session::{parse::ParseSess, SessionDiagnostic};
+use rustc_session::SessionDiagnostic;
 use rustc_span::Span;
 
 #[derive(SessionDiagnostic)]
@@ -33,8 +35,8 @@ struct Note {
 pub struct UntranslatableInSessionDiagnostic;
 
 impl<'a> SessionDiagnostic<'a, ErrorGuaranteed> for UntranslatableInSessionDiagnostic {
-    fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
-        sess.struct_err("untranslatable diagnostic")
+    fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
+        handler.struct_err("untranslatable diagnostic")
         //~^ ERROR diagnostics should be created using translatable messages
     }
 }
@@ -42,8 +44,8 @@ impl<'a> SessionDiagnostic<'a, ErrorGuaranteed> for UntranslatableInSessionDiagn
 pub struct TranslatableInSessionDiagnostic;
 
 impl<'a> SessionDiagnostic<'a, ErrorGuaranteed> for TranslatableInSessionDiagnostic {
-    fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
-        sess.struct_err(fluent::parser::expect_path)
+    fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
+        handler.struct_err(fluent::parser::expect_path)
     }
 }
 
@@ -64,11 +66,11 @@ impl AddSubdiagnostic for TranslatableInAddSubdiagnostic {
     }
 }
 
-pub fn make_diagnostics<'a>(sess: &'a ParseSess) {
-    let _diag = sess.struct_err(fluent::parser::expect_path);
+pub fn make_diagnostics<'a>(handler: &'a Handler) {
+    let _diag = handler.struct_err(fluent::parser::expect_path);
     //~^ ERROR diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls
 
-    let _diag = sess.struct_err("untranslatable diagnostic");
+    let _diag = handler.struct_err("untranslatable diagnostic");
     //~^ ERROR diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls
     //~^^ ERROR diagnostics should be created using translatable messages
 }
@@ -76,6 +78,6 @@ pub fn make_diagnostics<'a>(sess: &'a ParseSess) {
 // Check that `rustc_lint_diagnostics`-annotated functions aren't themselves linted.
 
 #[rustc_lint_diagnostics]
-pub fn skipped_because_of_annotation<'a>(sess: &'a ParseSess) {
-    let _diag = sess.struct_err("untranslatable diagnostic"); // okay!
+pub fn skipped_because_of_annotation<'a>(handler: &'a Handler) {
+    let _diag = handler.struct_err("untranslatable diagnostic"); // okay!
 }
diff --git a/src/test/ui-fulldeps/internal-lints/diagnostics.stderr b/src/test/ui-fulldeps/internal-lints/diagnostics.stderr
index ed5105dabcd..e5c5bc2e998 100644
--- a/src/test/ui-fulldeps/internal-lints/diagnostics.stderr
+++ b/src/test/ui-fulldeps/internal-lints/diagnostics.stderr
@@ -1,8 +1,8 @@
 error: diagnostics should be created using translatable messages
-  --> $DIR/diagnostics.rs:37:14
+  --> $DIR/diagnostics.rs:39:17
    |
-LL |         sess.struct_err("untranslatable diagnostic")
-   |              ^^^^^^^^^^
+LL |         handler.struct_err("untranslatable diagnostic")
+   |                 ^^^^^^^^^^
    |
 note: the lint level is defined here
   --> $DIR/diagnostics.rs:6:9
@@ -11,16 +11,16 @@ LL | #![deny(rustc::untranslatable_diagnostic)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostics should be created using translatable messages
-  --> $DIR/diagnostics.rs:54:14
+  --> $DIR/diagnostics.rs:56:14
    |
 LL |         diag.note("untranslatable diagnostic");
    |              ^^^^
 
 error: diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls
-  --> $DIR/diagnostics.rs:68:22
+  --> $DIR/diagnostics.rs:70:25
    |
-LL |     let _diag = sess.struct_err(fluent::parser::expect_path);
-   |                      ^^^^^^^^^^
+LL |     let _diag = handler.struct_err(fluent::parser::expect_path);
+   |                         ^^^^^^^^^^
    |
 note: the lint level is defined here
   --> $DIR/diagnostics.rs:7:9
@@ -29,16 +29,16 @@ LL | #![deny(rustc::diagnostic_outside_of_impl)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls
-  --> $DIR/diagnostics.rs:71:22
+  --> $DIR/diagnostics.rs:73:25
    |
-LL |     let _diag = sess.struct_err("untranslatable diagnostic");
-   |                      ^^^^^^^^^^
+LL |     let _diag = handler.struct_err("untranslatable diagnostic");
+   |                         ^^^^^^^^^^
 
 error: diagnostics should be created using translatable messages
-  --> $DIR/diagnostics.rs:71:22
+  --> $DIR/diagnostics.rs:73:25
    |
-LL |     let _diag = sess.struct_err("untranslatable diagnostic");
-   |                      ^^^^^^^^^^
+LL |     let _diag = handler.struct_err("untranslatable diagnostic");
+   |                         ^^^^^^^^^^
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/asm/aarch64/type-check-3.stderr b/src/test/ui/asm/aarch64/type-check-3.stderr
index b320abdc01b..49292982eec 100644
--- a/src/test/ui/asm/aarch64/type-check-3.stderr
+++ b/src/test/ui/asm/aarch64/type-check-3.stderr
@@ -5,8 +5,8 @@ LL |         asm!("{}", in(reg) 0u8);
    |               ^^           --- for this argument
    |
    = note: `#[warn(asm_sub_register)]` on by default
-   = help: use the `w` modifier to have the register formatted as `w0`
-   = help: or use the `x` modifier to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0`
+   = help: or use `{0:x}` to keep the default formatting of `x0`
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:50:15
@@ -14,8 +14,8 @@ warning: formatting may not be suitable for sub-register argument
 LL |         asm!("{}", in(reg) 0u16);
    |               ^^           ---- for this argument
    |
-   = help: use the `w` modifier to have the register formatted as `w0`
-   = help: or use the `x` modifier to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0`
+   = help: or use `{0:x}` to keep the default formatting of `x0`
 
 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 the `w` modifier to have the register formatted as `w0`
-   = help: or use the `x` modifier to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0`
+   = help: or use `{0:x}` to keep the default formatting of `x0`
 
 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 the `w` modifier to have the register formatted as `w0`
-   = help: or use the `x` modifier to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0`
+   = help: or use `{0:x}` to keep the default formatting of `x0`
 
 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 the `h` modifier to have the register formatted as `h0`
-   = help: or use the `v` modifier to keep the default formatting of `v0`
+   = help: use `{0:h}` to have the register formatted as `h0`
+   = help: or use `{0:v}` to keep the default formatting of `v0`
 
 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 the `s` modifier to have the register formatted as `s0`
-   = help: or use the `v` modifier to keep the default formatting of `v0`
+   = help: use `{0:s}` to have the register formatted as `s0`
+   = help: or use `{0:v}` to keep the default formatting of `v0`
 
 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 the `d` modifier to have the register formatted as `d0`
-   = help: or use the `v` modifier to keep the default formatting of `v0`
+   = help: use `{0:d}` to have the register formatted as `d0`
+   = help: or use `{0:v}` to keep the default formatting of `v0`
 
 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 the `d` modifier to have the register formatted as `d0`
-   = help: or use the `v` modifier to keep the default formatting of `v0`
+   = help: use `{0:d}` to have the register formatted as `d0`
+   = help: or use `{0:v}` to keep the default formatting of `v0`
 
 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 the `w` modifier to have the register formatted as `w0`
-   = help: or use the `x` modifier to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0`
+   = help: or use `{0:x}` to keep the default formatting of `x0`
 
 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 the `w` modifier to have the register formatted as `w0`
-   = help: or use the `x` modifier to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0`
+   = help: or use `{0:x}` to keep the default formatting of `x0`
 
 error: type `i128` cannot be used with this register class
   --> $DIR/type-check-3.rs:73:28
diff --git a/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr b/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr
index 7ef93e15f5b..5dac693cc27 100644
--- a/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr
+++ b/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr
@@ -190,8 +190,8 @@ LL |         asm!("{:foo}", in(reg) foo);
    |               ^^^^^^           --- for this argument
    |
    = note: `#[warn(asm_sub_register)]` on by default
-   = help: use the `w` modifier to have the register formatted as `w0`
-   = help: or use the `x` modifier to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0`
+   = help: or use `{0:x}` to keep the default formatting of `x0`
 
 error: aborting due to 21 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr b/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr
index 7ef93e15f5b..5dac693cc27 100644
--- a/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr
+++ b/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr
@@ -190,8 +190,8 @@ LL |         asm!("{:foo}", in(reg) foo);
    |               ^^^^^^           --- for this argument
    |
    = note: `#[warn(asm_sub_register)]` on by default
-   = help: use the `w` modifier to have the register formatted as `w0`
-   = help: or use the `x` modifier to keep the default formatting of `x0`
+   = help: use `{0:w}` to have the register formatted as `w0`
+   = help: or use `{0:x}` to keep the default formatting of `x0`
 
 error: aborting due to 21 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr b/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr
index 250bc3be42e..b29b74bac80 100644
--- a/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr
+++ b/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr
@@ -190,8 +190,8 @@ LL |         asm!("{:foo}", in(reg) foo);
    |               ^^^^^^           --- for this argument
    |
    = note: `#[warn(asm_sub_register)]` on by default
-   = help: use the `e` modifier to have the register formatted as `eax`
-   = help: or use the `r` modifier to keep the default formatting of `rax`
+   = help: use `{0:e}` to have the register formatted as `eax`
+   = help: or use `{0:r}` to keep the default formatting of `rax`
 
 error: aborting due to 21 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr b/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr
index 250bc3be42e..b29b74bac80 100644
--- a/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr
+++ b/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr
@@ -190,8 +190,8 @@ LL |         asm!("{:foo}", in(reg) foo);
    |               ^^^^^^           --- for this argument
    |
    = note: `#[warn(asm_sub_register)]` on by default
-   = help: use the `e` modifier to have the register formatted as `eax`
-   = help: or use the `r` modifier to keep the default formatting of `rax`
+   = help: use `{0:e}` to have the register formatted as `eax`
+   = help: or use `{0:r}` to keep the default formatting of `rax`
 
 error: aborting due to 21 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/asm/x86_64/type-check-3.stderr b/src/test/ui/asm/x86_64/type-check-3.stderr
index b38ea8cc4d8..366038fea23 100644
--- a/src/test/ui/asm/x86_64/type-check-3.stderr
+++ b/src/test/ui/asm/x86_64/type-check-3.stderr
@@ -45,8 +45,8 @@ LL |         asm!("{0} {0}", in(reg) 0i16);
    |               ^^^ ^^^           ---- for this argument
    |
    = note: `#[warn(asm_sub_register)]` on by default
-   = help: use the `x` modifier to have the register formatted as `ax`
-   = help: or use the `r` modifier to keep the default formatting of `rax`
+   = help: use `{0:x}` to have the register formatted as `ax`
+   = help: or use `{0:r}` to keep the default formatting of `rax`
 
 warning: formatting may not be suitable for sub-register argument
   --> $DIR/type-check-3.rs:36:15
@@ -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 the `x` modifier to have the register formatted as `ax`
-   = help: or use the `r` modifier to keep the default formatting of `rax`
+   = help: use `{0:x}` to have the register formatted as `ax`
+   = help: or use `{0:r}` to keep the default formatting of `rax`
 
 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 the `e` modifier to have the register formatted as `eax`
-   = help: or use the `r` modifier to keep the default formatting of `rax`
+   = help: use `{0:e}` to have the register formatted as `eax`
+   = help: or use `{0:r}` to keep the default formatting of `rax`
 
 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 the `x` modifier to have the register formatted as `xmm0`
-   = help: or use the `y` modifier to keep the default formatting of `ymm0`
+   = help: use `{0:x}` to have the register formatted as `xmm0`
+   = help: or use `{0:y}` to keep the default formatting of `ymm0`
 
 error: type `i8` cannot be used with this register class
   --> $DIR/type-check-3.rs:52:28
diff --git a/src/test/ui/associated-types/issue-62200.rs b/src/test/ui/associated-types/issue-62200.rs
index 9d18690e960..499bbd6b6fa 100644
--- a/src/test/ui/associated-types/issue-62200.rs
+++ b/src/test/ui/associated-types/issue-62200.rs
@@ -10,6 +10,7 @@ impl T<'_> for S {
 
 fn foo(x: impl Fn(<S as T<'_>>::A) -> <S as T<'_>>::A) {}
 //~^ ERROR binding for associated type `Output` references an anonymous lifetime
-//~^^ NOTE lifetimes appearing in an associated type are not considered constrained
+//~| NOTE lifetimes appearing in an associated or opaque type are not considered constrained
+//~| NOTE consider introducing a named lifetime parameter
 
 fn main() {}
diff --git a/src/test/ui/associated-types/issue-62200.stderr b/src/test/ui/associated-types/issue-62200.stderr
index f14cd81fdfe..04f0728f58e 100644
--- a/src/test/ui/associated-types/issue-62200.stderr
+++ b/src/test/ui/associated-types/issue-62200.stderr
@@ -4,7 +4,8 @@ error[E0582]: binding for associated type `Output` references an anonymous lifet
 LL | fn foo(x: impl Fn(<S as T<'_>>::A) -> <S as T<'_>>::A) {}
    |                                       ^^^^^^^^^^^^^^^
    |
-   = note: lifetimes appearing in an associated type are not considered constrained
+   = note: lifetimes appearing in an associated or opaque type are not considered constrained
+   = note: consider introducing a named lifetime parameter
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/attributes/issue-100631.rs b/src/test/ui/attributes/issue-100631.rs
new file mode 100644
index 00000000000..0fefcf83fd5
--- /dev/null
+++ b/src/test/ui/attributes/issue-100631.rs
@@ -0,0 +1,8 @@
+// issue #100631, make sure `TyCtxt::get_attr` only called by case that compiler
+// can reasonably deal with multiple attributes.
+// `repr` will use `TyCtxt::get_attrs` since it's `DuplicatesOk`.
+#[repr(C)] //~ ERROR: unsupported representation for zero-variant enum [E0084]
+#[repr(C)]
+enum Foo {}
+
+fn main() {}
diff --git a/src/test/ui/attributes/issue-100631.stderr b/src/test/ui/attributes/issue-100631.stderr
new file mode 100644
index 00000000000..caa5351ddc7
--- /dev/null
+++ b/src/test/ui/attributes/issue-100631.stderr
@@ -0,0 +1,12 @@
+error[E0084]: unsupported representation for zero-variant enum
+  --> $DIR/issue-100631.rs:4:1
+   |
+LL | #[repr(C)]
+   | ^^^^^^^^^^
+LL | #[repr(C)]
+LL | enum Foo {}
+   | -------- zero-variant enum
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0084`.
diff --git a/src/test/ui/binop/binary-op-on-double-ref.stderr b/src/test/ui/binop/binary-op-on-double-ref.stderr
index 1651f70d5cd..34826d2f4bf 100644
--- a/src/test/ui/binop/binary-op-on-double-ref.stderr
+++ b/src/test/ui/binop/binary-op-on-double-ref.stderr
@@ -6,7 +6,7 @@ LL |         x % 2 == 0
    |         |
    |         &&{integer}
    |
-help: `%` can be used on `{integer}`, you can dereference `x`
+help: `%` can be used on `&{integer}` if you dereference the left-hand side
    |
 LL |         *x % 2 == 0
    |         +
diff --git a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr
index d4f81930843..1fd1eb12851 100644
--- a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr
+++ b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr
@@ -23,7 +23,7 @@ LL | fn bindings_after_at_slice_patterns_move_binding(x: [String; 4]) {
    |                                                  - move occurs because `x` has type `[String; 4]`, which does not implement the `Copy` trait
 LL |     match x {
 LL |         a @ [.., _] => (),
-   |         ----------- value moved here
+   |         - value moved here
 ...
 LL |     &x;
    |     ^^ value borrowed here after move
@@ -32,7 +32,7 @@ error[E0502]: cannot borrow `x` as immutable because it is also borrowed as muta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:28:5
    |
 LL |         ref mut foo @ [.., _] => Some(foo),
-   |         --------------------- mutable borrow occurs here
+   |         ----------- mutable borrow occurs here
 ...
 LL |     &x;
    |     ^^ immutable borrow occurs here
@@ -44,7 +44,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:50:5
    |
 LL |         [ref foo @ .., ref bar] => Some(foo),
-   |          ------------ immutable borrow occurs here
+   |          ------- immutable borrow occurs here
 ...
 LL |     &mut x;
    |     ^^^^^^ mutable borrow occurs here
@@ -56,7 +56,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:62:5
    |
 LL |         ref foo @ [.., ref bar] => Some(foo),
-   |         ----------------------- immutable borrow occurs here
+   |         ------- immutable borrow occurs here
 ...
 LL |     &mut x;
    |     ^^^^^^ mutable borrow occurs here
@@ -71,7 +71,7 @@ LL | fn bindings_after_at_or_patterns_move(x: Option<Test>) {
    |                                       - move occurs because `x` has type `Option<Test>`, which does not implement the `Copy` trait
 LL |     match x {
 LL |         foo @ Some(Test::Foo | Test::Bar) => (),
-   |         ---------------------------------
+   |         ---
    |         |
    |         value moved here
    |         value moved here
@@ -83,7 +83,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:86:5
    |
 LL |         ref foo @ Some(Test::Foo | Test::Bar) => Some(foo),
-   |         ------------------------------------- immutable borrow occurs here
+   |         ------- immutable borrow occurs here
 ...
 LL |     &mut x;
    |     ^^^^^^ mutable borrow occurs here
@@ -95,7 +95,7 @@ error[E0502]: cannot borrow `x` as immutable because it is also borrowed as muta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:98:5
    |
 LL |         ref mut foo @ Some(Test::Foo | Test::Bar) => Some(foo),
-   |         ----------------------------------------- mutable borrow occurs here
+   |         ----------- mutable borrow occurs here
 ...
 LL |     &x;
    |     ^^ immutable borrow occurs here
@@ -107,7 +107,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:112:5
    |
 LL |         ref foo @ Some(box ref s) => Some(foo),
-   |         ------------------------- immutable borrow occurs here
+   |         ------- immutable borrow occurs here
 ...
 LL |     &mut x;
    |     ^^^^^^ mutable borrow occurs here
@@ -122,7 +122,7 @@ LL | fn bindings_after_at_slice_patterns_or_patterns_moves(x: [Option<Test>; 4])
    |                                                       - move occurs because `x` has type `[Option<Test>; 4]`, which does not implement the `Copy` trait
 LL |     match x {
 LL |         a @ [.., Some(Test::Foo | Test::Bar)] => (),
-   |         -------------------------------------
+   |         -
    |         |
    |         value moved here
    |         value moved here
@@ -134,7 +134,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:144:5
    |
 LL |         ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(a),
-   |         ------------------------------------------------- immutable borrow occurs here
+   |         ----- immutable borrow occurs here
 ...
 LL |     &mut x;
    |     ^^^^^^ mutable borrow occurs here
@@ -146,7 +146,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:156:5
    |
 LL |         ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(b),
-   |                  ---------- immutable borrow occurs here
+   |                  ----- immutable borrow occurs here
 ...
 LL |     &mut x;
    |     ^^^^^^ mutable borrow occurs here
@@ -158,7 +158,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:170:5
    |
 LL |         [_, ref a @ Some(box ref b), ..] => Some(a),
-   |             ----------------------- immutable borrow occurs here
+   |             ----- immutable borrow occurs here
 ...
 LL |     &mut x;
    |     ^^^^^^ mutable borrow occurs here
@@ -170,7 +170,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:186:5
    |
 LL |         [_, ref a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a),
-   |             ------------------------------------------- immutable borrow occurs here
+   |             ----- immutable borrow occurs here
 ...
 LL |     &mut x;
    |     ^^^^^^ mutable borrow occurs here
@@ -182,7 +182,7 @@ error[E0502]: cannot borrow `x` as immutable because it is also borrowed as muta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:200:5
    |
 LL |         [_, ref mut a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a),
-   |             ----------------------------------------------- mutable borrow occurs here
+   |             --------- mutable borrow occurs here
 ...
 LL |     &x;
    |     ^^ immutable borrow occurs here
@@ -194,7 +194,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:214:5
    |
 LL |         ref a @ [_, ref b @ Some(box Test::Foo | box Test::Bar), ..] => Some(a),
-   |         ------------------------------------------------------------ immutable borrow occurs here
+   |         ----- immutable borrow occurs here
 ...
 LL |     &mut x;
    |     ^^^^^^ mutable borrow occurs here
diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.stderr b/src/test/ui/borrowck/borrowck-describe-lvalue.stderr
index cfcc62de438..2c1b9c10d46 100644
--- a/src/test/ui/borrowck/borrowck-describe-lvalue.stderr
+++ b/src/test/ui/borrowck/borrowck-describe-lvalue.stderr
@@ -200,7 +200,7 @@ LL |         let x = &mut v;
    |                 ------ borrow of `v` occurs here
 LL |         match v {
 LL |             &[x @ ..] => println!("{:?}", x),
-   |               ^^^^^^ use of borrowed `v`
+   |               ^ use of borrowed `v`
 ...
 LL |         drop(x);
    |              - borrow later used here
@@ -212,7 +212,7 @@ LL |         let x = &mut v;
    |                 ------ borrow of `v` occurs here
 ...
 LL |             &[_, x @ ..] => println!("{:?}", x),
-   |                  ^^^^^^ use of borrowed `v`
+   |                  ^ use of borrowed `v`
 ...
 LL |         drop(x);
    |              - borrow later used here
@@ -224,7 +224,7 @@ LL |         let x = &mut v;
    |                 ------ borrow of `v` occurs here
 ...
 LL |             &[x @ .., _] => println!("{:?}", x),
-   |               ^^^^^^ use of borrowed `v`
+   |               ^ use of borrowed `v`
 ...
 LL |         drop(x);
    |              - borrow later used here
@@ -236,7 +236,7 @@ LL |         let x = &mut v;
    |                 ------ borrow of `v` occurs here
 ...
 LL |             &[_, x @ .., _] => println!("{:?}", x),
-   |                  ^^^^^^ use of borrowed `v`
+   |                  ^ use of borrowed `v`
 ...
 LL |         drop(x);
    |              - borrow later used here
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr
index 3249aae8f44..346b82a2666 100644
--- a/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr
@@ -79,7 +79,7 @@ error[E0382]: use of moved value: `a[..].0`
   --> $DIR/borrowck-move-out-from-array-match.rs:89:11
    |
 LL |         [_y @ .., _, _] => {}
-   |          ------- value moved here
+   |          -- value moved here
 ...
 LL |         [(_x, _), _, _] => {}
    |           ^^ value used here after move
@@ -90,7 +90,7 @@ error[E0382]: use of moved value: `a[..].0`
   --> $DIR/borrowck-move-out-from-array-match.rs:99:15
    |
 LL |         [_, _, _y @ ..] => {}
-   |                ------- value moved here
+   |                -- value moved here
 ...
 LL |         [.., (_x, _)] => {}
    |               ^^ value used here after move
@@ -101,7 +101,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-match.rs:110:11
    |
 LL |         [x @ .., _] => {}
-   |          ------ value partially moved here
+   |          - value partially moved here
 LL |     }
 LL |     match a {
    |           ^ value used here after partial move
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr
index c198002265b..6c6a25c251e 100644
--- a/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr
@@ -68,7 +68,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:85:11
    |
 LL |         [_, _y @ ..] => {}
-   |             ------- value partially moved here
+   |             -- value partially moved here
 LL |     }
 LL |     match a {
    |           ^ value used here after partial move
@@ -79,7 +79,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:96:11
    |
 LL |         [_y @ .., _] => {}
-   |          ------- value partially moved here
+   |          -- value partially moved here
 LL |     }
 LL |     match a {
    |           ^ value used here after partial move
@@ -90,7 +90,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:109:11
    |
 LL |         [x @ .., _, _] => {}
-   |          ------ value partially moved here
+   |          - value partially moved here
 LL |     }
 LL |     match a {
    |           ^ value used here after partial move
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr
index 8f2da9d203b..77702e145df 100644
--- a/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr
@@ -79,7 +79,7 @@ error[E0382]: borrow of moved value: `a[..]`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:89:11
    |
 LL |         [_y @ .., _, _] => {}
-   |          ------- value moved here
+   |          -- value moved here
 ...
 LL |         [(ref _x, _), _, _] => {}
    |           ^^^^^^ value borrowed here after move
@@ -90,7 +90,7 @@ error[E0382]: borrow of moved value: `a[..]`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:99:15
    |
 LL |         [_, _, _y @ ..] => {}
-   |                ------- value moved here
+   |                -- value moved here
 ...
 LL |         [.., (ref _x, _)] => {}
    |               ^^^^^^ value borrowed here after move
@@ -101,7 +101,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:110:11
    |
 LL |         [x @ .., _] => {}
-   |          ------ value partially moved here
+   |          - value partially moved here
 LL |     }
 LL |     match a {
    |           ^ value used here after partial move
@@ -134,7 +134,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:139:5
    |
 LL |         [_, _, _x @ ..] => {}
-   |                ------- value partially moved here
+   |                -- value partially moved here
 LL |     }
 LL |     a[0] = Default::default();
    |     ^^^^ value used here after partial move
@@ -145,7 +145,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:147:5
    |
 LL |         [_, _, _x @ ..] => {}
-   |                ------- value partially moved here
+   |                -- value partially moved here
 LL |     }
 LL |     a[0].1 = Default::default();
    |     ^^^^ value used here after partial move
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr
index 4b27f03dc45..6cc2c2f7a98 100644
--- a/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr
@@ -68,7 +68,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:85:11
    |
 LL |         [_, _y @ ..] => {}
-   |             ------- value partially moved here
+   |             -- value partially moved here
 LL |     }
 LL |     match a {
    |           ^ value used here after partial move
@@ -79,7 +79,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:96:11
    |
 LL |         [_y @ .., _] => {}
-   |          ------- value partially moved here
+   |          -- value partially moved here
 LL |     }
 LL |     match a {
    |           ^ value used here after partial move
@@ -90,7 +90,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:109:11
    |
 LL |         [x @ .., _, _] => {}
-   |          ------ value partially moved here
+   |          - value partially moved here
 LL |     }
 LL |     match a {
    |           ^ value used here after partial move
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr
index b0bad6e9978..9add7553afa 100644
--- a/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr
@@ -34,7 +34,7 @@ error[E0382]: borrow of partially moved value: `a`
 LL |     let [_x, _, _] = a;
    |          -- value partially moved here
 LL |     let [ref _y @ .., _, _] = a;
-   |          ^^^^^^^^^^^ value borrowed here after partial move
+   |          ^^^^^^ value borrowed here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
 
@@ -44,7 +44,7 @@ error[E0382]: borrow of partially moved value: `a`
 LL |     let [.., _x] = a;
    |              -- value partially moved here
 LL |     let [_, _, ref _y @ ..] = a;
-   |                ^^^^^^^^^^^ value borrowed here after partial move
+   |                ^^^^^^ value borrowed here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
 
@@ -54,7 +54,7 @@ error[E0382]: borrow of partially moved value: `a`
 LL |     let [(_x, _), _, _] = a;
    |           -- value partially moved here
 LL |     let [ref _y @ .., _, _] = a;
-   |          ^^^^^^^^^^^ value borrowed here after partial move
+   |          ^^^^^^ value borrowed here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
 
@@ -64,7 +64,7 @@ error[E0382]: borrow of partially moved value: `a`
 LL |     let [.., (_x, _)] = a;
    |               -- value partially moved here
 LL |     let [_, _, ref _y @ ..] = a;
-   |                ^^^^^^^^^^^ value borrowed here after partial move
+   |                ^^^^^^ value borrowed here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
 
@@ -72,7 +72,7 @@ error[E0382]: borrow of moved value: `a[..]`
   --> $DIR/borrowck-move-out-from-array-use.rs:54:11
    |
 LL |     let [_y @ .., _, _] = a;
-   |          ------- value moved here
+   |          -- value moved here
 LL |     let [(ref _x, _), _, _] = a;
    |           ^^^^^^ value borrowed here after move
    |
@@ -82,7 +82,7 @@ error[E0382]: borrow of moved value: `a[..]`
   --> $DIR/borrowck-move-out-from-array-use.rs:60:15
    |
 LL |     let [_, _, _y @ ..] = a;
-   |                ------- value moved here
+   |                -- value moved here
 LL |     let [.., (ref _x, _)] = a;
    |               ^^^^^^ value borrowed here after move
    |
@@ -92,9 +92,9 @@ error[E0382]: borrow of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use.rs:68:13
    |
 LL |     let [x @ .., _] = a;
-   |          ------ value partially moved here
+   |          - value partially moved here
 LL |     let [_, ref _y @ ..] = a;
-   |             ^^^^^^^^^^^ value borrowed here after partial move
+   |             ^^^^^^ value borrowed here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
 
@@ -122,7 +122,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use.rs:88:5
    |
 LL |     let [_, _, _x @ ..] = a;
-   |                ------- value partially moved here
+   |                -- value partially moved here
 LL |     a[0] = Default::default();
    |     ^^^^ value used here after partial move
    |
@@ -132,7 +132,7 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use.rs:94:5
    |
 LL |     let [_, _, _x @ ..] = a;
-   |                ------- value partially moved here
+   |                -- value partially moved here
 LL |     a[0].1 = Default::default();
    |     ^^^^ value used here after partial move
    |
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array.stderr
index 1fc2b292b84..363effcfe53 100644
--- a/src/test/ui/borrowck/borrowck-move-out-from-array.stderr
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array.stderr
@@ -34,7 +34,7 @@ error[E0382]: use of partially moved value: `a`
 LL |     let [_x, _, _] = a;
    |          -- value partially moved here
 LL |     let [_y @ .., _, _] = a;
-   |          ^^^^^^^ value used here after partial move
+   |          ^^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
 
@@ -44,7 +44,7 @@ error[E0382]: use of partially moved value: `a`
 LL |     let [.., _x] = a;
    |              -- value partially moved here
 LL |     let [_, _, _y @ ..] = a;
-   |                ^^^^^^^ value used here after partial move
+   |                ^^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
 
@@ -54,7 +54,7 @@ error[E0382]: use of partially moved value: `a`
 LL |     let [(_x, _), _, _] = a;
    |           -- value partially moved here
 LL |     let [_y @ .., _, _] = a;
-   |          ^^^^^^^ value used here after partial move
+   |          ^^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
 
@@ -64,7 +64,7 @@ error[E0382]: use of partially moved value: `a`
 LL |     let [.., (_x, _)] = a;
    |               -- value partially moved here
 LL |     let [_, _, _y @ ..] = a;
-   |                ^^^^^^^ value used here after partial move
+   |                ^^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
 
@@ -72,7 +72,7 @@ error[E0382]: use of moved value: `a[..].0`
   --> $DIR/borrowck-move-out-from-array.rs:54:11
    |
 LL |     let [_y @ .., _, _] = a;
-   |          ------- value moved here
+   |          -- value moved here
 LL |     let [(_x, _), _, _] = a;
    |           ^^ value used here after move
    |
@@ -82,7 +82,7 @@ error[E0382]: use of moved value: `a[..].0`
   --> $DIR/borrowck-move-out-from-array.rs:60:15
    |
 LL |     let [_, _, _y @ ..] = a;
-   |                ------- value moved here
+   |                -- value moved here
 LL |     let [.., (_x, _)] = a;
    |               ^^ value used here after move
    |
@@ -92,9 +92,9 @@ error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array.rs:68:13
    |
 LL |     let [x @ .., _] = a;
-   |          ------ value partially moved here
+   |          - value partially moved here
 LL |     let [_, _y @ ..] = a;
-   |             ^^^^^^^ value used here after partial move
+   |             ^^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
 
diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr
index b8ac7a3a446..f4324110ccb 100644
--- a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr
+++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr
@@ -57,7 +57,7 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im
 LL |     let [ref first, ref second, ..] = *s;
    |                     ---------- immutable borrow occurs here
 LL |     let [_, ref mut tail @ ..] = *s;
-   |             ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+   |             ^^^^^^^^^^^^ mutable borrow occurs here
 LL |     nop(&[first, second]);
    |                  ------ immutable borrow later used here
 
@@ -67,7 +67,7 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im
 LL |     let [.., ref second, ref first] = *s;
    |              ---------- immutable borrow occurs here
 LL |     let [ref mut tail @ .., _] = *s;
-   |          ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+   |          ^^^^^^^^^^^^ mutable borrow occurs here
 LL |     nop(&[first, second]);
    |                  ------ immutable borrow later used here
 
@@ -75,9 +75,9 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im
   --> $DIR/borrowck-slice-pattern-element-loan-array.rs:46:10
    |
 LL |     let [_,  ref s1 @ ..] = *s;
-   |              ----------- immutable borrow occurs here
+   |              ------ immutable borrow occurs here
 LL |     let [ref mut s2 @ .., _, _] = *s;
-   |          ^^^^^^^^^^^^^^^ mutable borrow occurs here
+   |          ^^^^^^^^^^ mutable borrow occurs here
 LL |     nop_subslice(s1);
    |                  -- immutable borrow later used here
 
diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr
index d3388e071aa..f9a63bd49dd 100644
--- a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr
+++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr
@@ -88,7 +88,7 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im
 LL |     if let [ref first, ref second, ..] = *s {
    |                        ---------- immutable borrow occurs here
 LL |         if let [_, ref mut tail @ ..] = *s {
-   |                    ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+   |                    ^^^^^^^^^^^^ mutable borrow occurs here
 LL |             nop(&[first, second]);
    |                          ------ immutable borrow later used here
 
@@ -98,7 +98,7 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im
 LL |     if let [.., ref second, ref first] = *s {
    |                 ---------- immutable borrow occurs here
 LL |         if let [ref mut tail @ .., _] = *s {
-   |                 ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
+   |                 ^^^^^^^^^^^^ mutable borrow occurs here
 LL |             nop(&[first, second]);
    |                          ------ immutable borrow later used here
 
@@ -106,9 +106,9 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im
   --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:65:17
    |
 LL |     if let [_, _, _, ref s1 @ ..] = *s {
-   |                      ----------- immutable borrow occurs here
+   |                      ------ immutable borrow occurs here
 LL |         if let [ref mut s2 @ .., _, _, _] = *s {
-   |                 ^^^^^^^^^^^^^^^ mutable borrow occurs here
+   |                 ^^^^^^^^^^ mutable borrow occurs here
 LL |             nop_subslice(s1);
    |                          -- immutable borrow later used here
 
diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.stderr b/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.stderr
index ff70ba9fcca..0ac7df944d7 100644
--- a/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.stderr
+++ b/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.stderr
@@ -2,7 +2,7 @@ error[E0506]: cannot assign to `a[_]` because it is borrowed
   --> $DIR/borrowck-vec-pattern-move-tail.rs:8:5
    |
 LL |         [1, 2, ref tail @ ..] => tail,
-   |                ------------- borrow of `a[_]` occurs here
+   |                -------- borrow of `a[_]` occurs here
 ...
 LL |     a[2] = 0;
    |     ^^^^^^^^ assignment to borrowed `a[_]` occurs here
diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr
index ddd89afe5bf..c3bcb7de65d 100644
--- a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr
+++ b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr
@@ -14,7 +14,7 @@ error[E0506]: cannot assign to `vec[_]` because it is borrowed
   --> $DIR/borrowck-vec-pattern-nesting.rs:23:13
    |
 LL |         &mut [ref _b @ ..] => {
-   |               ----------- borrow of `vec[_]` occurs here
+   |               ------ borrow of `vec[_]` occurs here
 LL |
 LL |             vec[0] = Box::new(4);
    |             ^^^^^^ assignment to borrowed `vec[_]` occurs here
diff --git a/src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.rs b/src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.rs
index 318673ef847..972c24c23b0 100644
--- a/src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.rs
+++ b/src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.rs
@@ -24,7 +24,7 @@ fn main() {
     let _a = || { match l1 { L1::A => (), L1::B => () } };
     // (except if the match is already non-exhaustive)
     let _b = || { match l1 { L1::A => () } };
-    //~^ ERROR: non-exhaustive patterns: `B` not covered [E0004]
+    //~^ ERROR: non-exhaustive patterns: `L1::B` not covered [E0004]
 
     // l2 should not be captured as it is a non-exhaustive SingleVariant
     // defined in this crate
diff --git a/src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr b/src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr
index e0678bc718f..3a5fad15421 100644
--- a/src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: `B` not covered
+error[E0004]: non-exhaustive patterns: `L1::B` not covered
   --> $DIR/non-exhaustive-match.rs:26:25
    |
 LL |     let _b = || { match l1 { L1::A => () } };
-   |                         ^^ pattern `B` not covered
+   |                         ^^ pattern `L1::B` not covered
    |
 note: `L1` defined here
   --> $DIR/non-exhaustive-match.rs:12:14
@@ -12,8 +12,8 @@ LL | enum L1 { A, B }
    = note: the matched value is of type `L1`
 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 |     let _b = || { match l1 { L1::A => (), B => todo!() } };
-   |                                         ++++++++++++++
+LL |     let _b = || { match l1 { L1::A => (), L1::B => todo!() } };
+   |                                         ++++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: type `E1` is non-empty
   --> $DIR/non-exhaustive-match.rs:37:25
diff --git a/src/test/ui/closures/issue-52437.rs b/src/test/ui/closures/issue-52437.rs
index f79a0bd3548..6ac5380a5aa 100644
--- a/src/test/ui/closures/issue-52437.rs
+++ b/src/test/ui/closures/issue-52437.rs
@@ -2,5 +2,4 @@ fn main() {
     [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
     //~^ ERROR: invalid label name `'static`
     //~| ERROR: type annotations needed
-    //~| ERROR mismatched types
 }
diff --git a/src/test/ui/closures/issue-52437.stderr b/src/test/ui/closures/issue-52437.stderr
index 38d9d08ce36..4c24a54bbbe 100644
--- a/src/test/ui/closures/issue-52437.stderr
+++ b/src/test/ui/closures/issue-52437.stderr
@@ -15,15 +15,6 @@ help: consider giving this closure parameter an explicit type
 LL |     [(); &(&'static: loop { |x: _| {}; }) as *const _ as usize]
    |                               +++
 
-error[E0308]: mismatched types
-  --> $DIR/issue-52437.rs:2:5
-   |
-LL | fn main() {
-   |           - expected `()` because of default return type
-LL |     [(); &(&'static: loop { |x| {}; }) as *const _ as usize]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found array `[(); _]`
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0282, E0308.
-For more information about an error, try `rustc --explain E0282`.
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/empty/empty-never-array.rs b/src/test/ui/empty/empty-never-array.rs
index 01b99134a44..3de2b1a78a3 100644
--- a/src/test/ui/empty/empty-never-array.rs
+++ b/src/test/ui/empty/empty-never-array.rs
@@ -8,7 +8,7 @@ enum Helper<T, U> {
 
 fn transmute<T, U>(t: T) -> U {
     let Helper::U(u) = Helper::T(t, []);
-    //~^ ERROR refutable pattern in local binding: `T(_, _)` not covered
+    //~^ ERROR refutable pattern in local binding: `Helper::T(_, _)` not covered
     u
 }
 
diff --git a/src/test/ui/empty/empty-never-array.stderr b/src/test/ui/empty/empty-never-array.stderr
index 909aa73a74a..8c80b05ee3a 100644
--- a/src/test/ui/empty/empty-never-array.stderr
+++ b/src/test/ui/empty/empty-never-array.stderr
@@ -1,8 +1,8 @@
-error[E0005]: refutable pattern in local binding: `T(_, _)` not covered
+error[E0005]: refutable pattern in local binding: `Helper::T(_, _)` not covered
   --> $DIR/empty-never-array.rs:10:9
    |
 LL |     let Helper::U(u) = Helper::T(t, []);
-   |         ^^^^^^^^^^^^ pattern `T(_, _)` not covered
+   |         ^^^^^^^^^^^^ pattern `Helper::T(_, _)` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
diff --git a/src/test/ui/error-codes/E0004.stderr b/src/test/ui/error-codes/E0004.stderr
index 8ba151d9e65..4ac8c904f05 100644
--- a/src/test/ui/error-codes/E0004.stderr
+++ b/src/test/ui/error-codes/E0004.stderr
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: `HastaLaVistaBaby` not covered
+error[E0004]: non-exhaustive patterns: `Terminator::HastaLaVistaBaby` not covered
   --> $DIR/E0004.rs:9:11
    |
 LL |     match x {
-   |           ^ pattern `HastaLaVistaBaby` not covered
+   |           ^ pattern `Terminator::HastaLaVistaBaby` not covered
    |
 note: `Terminator` defined here
   --> $DIR/E0004.rs:2:5
@@ -15,7 +15,7 @@ LL |     HastaLaVistaBaby,
 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 ~         Terminator::TalkToMyHand => {}
-LL +         HastaLaVistaBaby => todo!()
+LL +         Terminator::HastaLaVistaBaby => todo!()
    |
 
 error: aborting due to previous error
diff --git a/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs b/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs
index 29a6e1f8a01..9b646060adf 100644
--- a/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs
+++ b/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs
@@ -21,7 +21,7 @@ fn main() {
         Foo::A => {}
         Foo::B => {}
     }
-    //~^^^^ ERROR non-exhaustive patterns: `C` not covered
+    //~^^^^ ERROR non-exhaustive patterns: `Foo::C` not covered
 
     match Foo::A {
         Foo::A => {}
diff --git a/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr b/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr
index dbeef6c2d2a..3de08e215da 100644
--- a/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr
+++ b/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr
@@ -99,11 +99,11 @@ LL |         #[warn(non_exhaustive_omitted_patterns)]
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error[E0004]: non-exhaustive patterns: `C` not covered
+error[E0004]: non-exhaustive patterns: `Foo::C` not covered
   --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:20:11
    |
 LL |     match Foo::A {
-   |           ^^^^^^ pattern `C` not covered
+   |           ^^^^^^ pattern `Foo::C` not covered
    |
 note: `Foo` defined here
   --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:12:15
@@ -116,7 +116,7 @@ LL |         A, B, C,
 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 ~         Foo::B => {}
-LL +         C => todo!()
+LL +         Foo::C => todo!()
    |
 
 error: aborting due to previous error; 10 warnings emitted
diff --git a/src/test/ui/generic-associated-types/missing-bounds.fixed b/src/test/ui/generic-associated-types/missing-bounds.fixed
index 2315810a47a..ee758f19ec1 100644
--- a/src/test/ui/generic-associated-types/missing-bounds.fixed
+++ b/src/test/ui/generic-associated-types/missing-bounds.fixed
@@ -24,7 +24,7 @@ impl<B: Add + Add<Output = B>> Add for C<B> {
 
 struct D<B>(B);
 
-impl<B: std::ops::Add<Output=B>> Add for D<B> {
+impl<B: std::ops::Add<Output = B>> Add for D<B> {
     type Output = Self;
 
     fn add(self, rhs: Self) -> Self {
diff --git a/src/test/ui/generic-associated-types/missing-bounds.stderr b/src/test/ui/generic-associated-types/missing-bounds.stderr
index 138c642dd79..c913483a874 100644
--- a/src/test/ui/generic-associated-types/missing-bounds.stderr
+++ b/src/test/ui/generic-associated-types/missing-bounds.stderr
@@ -66,8 +66,8 @@ LL |         Self(self.0 + rhs.0)
    |
 help: consider restricting type parameter `B`
    |
-LL | impl<B: std::ops::Add<Output=B>> Add for D<B> {
-   |       +++++++++++++++++++++++++
+LL | impl<B: std::ops::Add<Output = B>> Add for D<B> {
+   |       +++++++++++++++++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/missing-bounds.rs:42:14
diff --git a/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2015.stderr b/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2015.stderr
new file mode 100644
index 00000000000..fd2e454e7e4
--- /dev/null
+++ b/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2015.stderr
@@ -0,0 +1,9 @@
+error[E0277]: the trait bound `(): AsRef<(dyn for<'r> Fn(&'r ()) + 'static)>` is not satisfied
+  --> $DIR/generic-with-implicit-hrtb-without-dyn.rs:6:13
+   |
+LL | fn ice() -> impl AsRef<Fn(&())> {
+   |             ^^^^^^^^^^^^^^^^^^^ the trait `AsRef<(dyn for<'r> Fn(&'r ()) + 'static)>` is not implemented for `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr b/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr
new file mode 100644
index 00000000000..c01c33a8931
--- /dev/null
+++ b/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr
@@ -0,0 +1,22 @@
+error[E0782]: trait objects must include the `dyn` keyword
+  --> $DIR/generic-with-implicit-hrtb-without-dyn.rs:6:24
+   |
+LL | fn ice() -> impl AsRef<Fn(&())> {
+   |                        ^^^^^^^
+   |
+help: add `dyn` keyword before this trait
+   |
+LL - fn ice() -> impl AsRef<Fn(&())> {
+LL + fn ice() -> impl AsRef<dyn Fn(&())> {
+   |
+
+error[E0277]: the trait bound `(): AsRef<(dyn for<'r> Fn(&'r ()) + 'static)>` is not satisfied
+  --> $DIR/generic-with-implicit-hrtb-without-dyn.rs:6:13
+   |
+LL | fn ice() -> impl AsRef<Fn(&())> {
+   |             ^^^^^^^^^^^^^^^^^^^ the trait `AsRef<(dyn for<'r> Fn(&'r ()) + 'static)>` is not implemented for `()`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0782.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs b/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs
new file mode 100644
index 00000000000..856dc7a3f5a
--- /dev/null
+++ b/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs
@@ -0,0 +1,12 @@
+// revisions: edition2015 edition2021
+//[edition2021]edition:2021
+
+#![allow(warnings)]
+
+fn ice() -> impl AsRef<Fn(&())> {
+    //~^ ERROR: the trait bound `(): AsRef<(dyn for<'r> Fn(&'r ()) + 'static)>` is not satisfied [E0277]
+    //[edition2021]~| ERROR: trait objects must include the `dyn` keyword [E0782]
+    todo!()
+}
+
+fn main() {}
diff --git a/src/test/ui/issue-94866.stderr b/src/test/ui/issue-94866.stderr
index 5477d83f449..b3c17ce8974 100644
--- a/src/test/ui/issue-94866.stderr
+++ b/src/test/ui/issue-94866.stderr
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: `B` not covered
+error[E0004]: non-exhaustive patterns: `Enum::B` not covered
   --> $DIR/issue-94866.rs:10:11
    |
 LL |     match Enum::A {
-   |           ^^^^^^^ pattern `B` not covered
+   |           ^^^^^^^ pattern `Enum::B` not covered
    |
 note: `Enum` defined here
   --> $DIR/issue-94866.rs:7:16
@@ -13,7 +13,7 @@ LL | enum Enum { A, B }
 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 ~     Enum::A => m!(),
-LL +     B => todo!()
+LL +     Enum::B => todo!()
    |
 
 error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-41139.stderr b/src/test/ui/issues/issue-41139.stderr
index 48b22bca20f..97492e6e0fa 100644
--- a/src/test/ui/issues/issue-41139.stderr
+++ b/src/test/ui/issues/issue-41139.stderr
@@ -5,9 +5,7 @@ LL | fn get_function<'a>() -> &'a dyn Fn() -> dyn Trait {
    | -------------------------------------------------- `get_function` defined here returns `&dyn Fn() -> (dyn Trait + 'static)`
 ...
 LL |     let t: &dyn Trait = &get_function()();
-   |                          ^^^^^^^^^^^^^^--
-   |                          |
-   |                          call expression requires function
+   |                          ^^^^^^^^^^^^^^ this trait object returns an unsized value `(dyn Trait + 'static)`, so it cannot be called
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-43988.stderr b/src/test/ui/issues/issue-43988.stderr
index 03aa37f5207..02c5dd5bfb7 100644
--- a/src/test/ui/issues/issue-43988.stderr
+++ b/src/test/ui/issues/issue-43988.stderr
@@ -31,12 +31,16 @@ error[E0552]: unrecognized representation hint
    |
 LL |     #[repr(nothing)]
    |            ^^^^^^^
+   |
+   = help: valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
 
 error[E0552]: unrecognized representation hint
   --> $DIR/issue-43988.rs:18:12
    |
 LL |     #[repr(something_not_real)]
    |            ^^^^^^^^^^^^^^^^^^
+   |
+   = help: valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
 
 error[E0518]: attribute should be applied to function or closure
   --> $DIR/issue-43988.rs:30:5
diff --git a/src/test/ui/issues/issue-47511.stderr b/src/test/ui/issues/issue-47511.stderr
index 5b84f7ed62c..9998ee0e8d0 100644
--- a/src/test/ui/issues/issue-47511.stderr
+++ b/src/test/ui/issues/issue-47511.stderr
@@ -4,7 +4,8 @@ error[E0581]: return type references an anonymous lifetime, which is not constra
 LL | fn f(_: X) -> X {
    |               ^
    |
-   = note: lifetimes appearing in an associated type are not considered constrained
+   = note: lifetimes appearing in an associated or opaque type are not considered constrained
+   = note: consider introducing a named lifetime parameter
 
 error[E0581]: return type references lifetime `'a`, which is not constrained by the fn input types
   --> $DIR/issue-47511.rs:12:23
diff --git a/src/test/ui/issues/issue-66706.rs b/src/test/ui/issues/issue-66706.rs
index 4585bcc8cd5..835fdfae86c 100644
--- a/src/test/ui/issues/issue-66706.rs
+++ b/src/test/ui/issues/issue-66706.rs
@@ -2,7 +2,6 @@ fn a() {
     [0; [|_: _ &_| ()].len()]
     //~^ ERROR expected `,`, found `&`
     //~| ERROR type annotations needed
-    //~| ERROR mismatched types
 }
 
 fn b() {
@@ -13,13 +12,11 @@ fn b() {
 fn c() {
     [0; [|&_: _ &_| {}; 0 ].len()]
     //~^ ERROR expected `,`, found `&`
-    //~| ERROR mismatched types
 }
 
 fn d() {
     [0; match [|f @ &ref _| () ] {} ]
     //~^ ERROR expected identifier, found reserved identifier `_`
-    //~| ERROR mismatched types
 }
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-66706.stderr b/src/test/ui/issues/issue-66706.stderr
index 1c55560cb7c..8a30c0cad39 100644
--- a/src/test/ui/issues/issue-66706.stderr
+++ b/src/test/ui/issues/issue-66706.stderr
@@ -7,13 +7,13 @@ LL |     [0; [|_: _ &_| ()].len()]
    |               help: missing `,`
 
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/issue-66706.rs:9:20
+  --> $DIR/issue-66706.rs:8:20
    |
 LL |     [0; [|f @ &ref _| {} ; 0 ].len() ];
    |                    ^ expected identifier, found reserved identifier
 
 error: expected `,`, found `&`
-  --> $DIR/issue-66706.rs:14:17
+  --> $DIR/issue-66706.rs:13:17
    |
 LL |     [0; [|&_: _ &_| {}; 0 ].len()]
    |                -^ expected `,`
@@ -21,7 +21,7 @@ LL |     [0; [|&_: _ &_| {}; 0 ].len()]
    |                help: missing `,`
 
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/issue-66706.rs:20:26
+  --> $DIR/issue-66706.rs:18:26
    |
 LL |     [0; match [|f @ &ref _| () ] {} ]
    |                          ^ expected identifier, found reserved identifier
@@ -32,31 +32,6 @@ error[E0282]: type annotations needed
 LL |     [0; [|_: _ &_| ()].len()]
    |           ^ cannot infer type
 
-error[E0308]: mismatched types
-  --> $DIR/issue-66706.rs:2:5
-   |
-LL | fn a() {
-   |        - help: try adding a return type: `-> [i32; _]`
-LL |     [0; [|_: _ &_| ()].len()]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found array `[{integer}; _]`
-
-error[E0308]: mismatched types
-  --> $DIR/issue-66706.rs:14:5
-   |
-LL | fn c() {
-   |        - help: try adding a return type: `-> [i32; _]`
-LL |     [0; [|&_: _ &_| {}; 0 ].len()]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found array `[{integer}; _]`
-
-error[E0308]: mismatched types
-  --> $DIR/issue-66706.rs:20:5
-   |
-LL | fn d() {
-   |        - help: try adding a return type: `-> [i32; _]`
-LL |     [0; match [|f @ &ref _| () ] {} ]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found array `[{integer}; _]`
-
-error: aborting due to 8 previous errors
+error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0282, E0308.
-For more information about an error, try `rustc --explain E0282`.
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr b/src/test/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr
index 6deb1f271a7..bfabe2d12f7 100644
--- a/src/test/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr
+++ b/src/test/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr
@@ -411,7 +411,7 @@ error: layout_of(NicheFirst) = Layout {
                    valid_range: 0..=4,
                },
                tag_encoding: Niche {
-                   dataful_variant: 0,
+                   untagged_variant: 0,
                    niche_variants: 1..=2,
                    niche_start: 3,
                },
@@ -555,7 +555,7 @@ error: layout_of(NicheSecond) = Layout {
                    valid_range: 0..=4,
                },
                tag_encoding: Niche {
-                   dataful_variant: 0,
+                   untagged_variant: 0,
                    niche_variants: 1..=2,
                    niche_start: 3,
                },
diff --git a/src/test/ui/layout/zero-sized-array-enum-niche.stderr b/src/test/ui/layout/zero-sized-array-enum-niche.stderr
index 56d3a52bb7f..a3e82070e0f 100644
--- a/src/test/ui/layout/zero-sized-array-enum-niche.stderr
+++ b/src/test/ui/layout/zero-sized-array-enum-niche.stderr
@@ -353,7 +353,7 @@ error: layout_of(std::result::Result<[u32; 0], Packed<U16IsZero>>) = Layout {
                    valid_range: 0..=1,
                },
                tag_encoding: Niche {
-                   dataful_variant: 1,
+                   untagged_variant: 1,
                    niche_variants: 0..=0,
                    niche_start: 1,
                },
diff --git a/src/test/ui/let-else/let-else-drop-order.rs b/src/test/ui/let-else/let-else-drop-order.rs
new file mode 100644
index 00000000000..0054f3d4182
--- /dev/null
+++ b/src/test/ui/let-else/let-else-drop-order.rs
@@ -0,0 +1,270 @@
+// run-pass
+// edition:2021
+// check-run-results
+//
+// Drop order tests for let else
+//
+// Mostly this ensures two things:
+// 1. That let and let else temporary drop order is the same.
+//    This is a specific design request: https://github.com/rust-lang/rust/pull/93628#issuecomment-1047140316
+// 2. That the else block truly only runs after the
+//    temporaries have dropped.
+//
+// We also print some nice tables for an overview by humans.
+// Changes in those tables are considered breakages, but the
+// important properties 1 and 2 are also enforced by the code.
+// This is important as it's easy to update the stdout file
+// with a --bless and miss the impact of that change.
+
+#![feature(let_else)]
+#![allow(irrefutable_let_patterns)]
+
+use std::cell::RefCell;
+use std::rc::Rc;
+
+#[derive(Clone)]
+struct DropAccountant(Rc<RefCell<Vec<Vec<String>>>>);
+
+impl DropAccountant {
+    fn new() -> Self {
+        Self(Default::default())
+    }
+    fn build_droppy(&self, v: u32) -> Droppy<u32> {
+        Droppy(self.clone(), v)
+    }
+    fn build_droppy_enum_none(&self, _v: u32) -> ((), DroppyEnum<u32>) {
+        ((), DroppyEnum::None(self.clone()))
+    }
+    fn new_list(&self, s: impl ToString) {
+        self.0.borrow_mut().push(vec![s.to_string()]);
+    }
+    fn push(&self, s: impl ToString) {
+        let s = s.to_string();
+        let mut accounts = self.0.borrow_mut();
+        accounts.last_mut().unwrap().push(s);
+    }
+    fn print_table(&self) {
+        println!();
+
+        let accounts = self.0.borrow();
+        let before_last = &accounts[accounts.len() - 2];
+        let last = &accounts[accounts.len() - 1];
+        let before_last = get_comma_list(before_last);
+        let last = get_comma_list(last);
+        const LINES: &[&str] = &[
+            "vanilla",
+            "&",
+            "&mut",
+            "move",
+            "fn(this)",
+            "tuple",
+            "array",
+            "ref &",
+            "ref mut &mut",
+        ];
+        let max_len = LINES.iter().map(|v| v.len()).max().unwrap();
+        let max_len_before = before_last.iter().map(|v| v.len()).max().unwrap();
+        let max_len_last = last.iter().map(|v| v.len()).max().unwrap();
+
+        println!(
+            "| {: <max_len$} | {: <max_len_before$} | {: <max_len_last$} |",
+            "construct", before_last[0], last[0]
+        );
+        println!("| {:-<max_len$} | {:-<max_len_before$} | {:-<max_len_last$} |", "", "", "");
+
+        for ((l, l_before), l_last) in
+            LINES.iter().zip(before_last[1..].iter()).zip(last[1..].iter())
+        {
+            println!(
+                "| {: <max_len$} | {: <max_len_before$} | {: <max_len_last$} |",
+                l, l_before, l_last,
+            );
+        }
+    }
+    #[track_caller]
+    fn assert_all_equal_to(&self, st: &str) {
+        let accounts = self.0.borrow();
+        let last = &accounts[accounts.len() - 1];
+        let last = get_comma_list(last);
+        for line in last[1..].iter() {
+            assert_eq!(line.trim(), st.trim());
+        }
+    }
+    #[track_caller]
+    fn assert_equality_last_two_lists(&self) {
+        let accounts = self.0.borrow();
+        let last = &accounts[accounts.len() - 1];
+        let before_last = &accounts[accounts.len() - 2];
+        for (l, b) in last[1..].iter().zip(before_last[1..].iter()) {
+            if !(l == b || l == "n/a" || b == "n/a") {
+                panic!("not equal: '{last:?}' != '{before_last:?}'");
+            }
+        }
+    }
+}
+
+fn get_comma_list(sl: &[String]) -> Vec<String> {
+    std::iter::once(sl[0].clone())
+        .chain(sl[1..].chunks(2).map(|c| c.join(",")))
+        .collect::<Vec<String>>()
+}
+
+struct Droppy<T>(DropAccountant, T);
+
+impl<T> Drop for Droppy<T> {
+    fn drop(&mut self) {
+        self.0.push("drop");
+    }
+}
+
+#[allow(dead_code)]
+enum DroppyEnum<T> {
+    Some(DropAccountant, T),
+    None(DropAccountant),
+}
+
+impl<T> Drop for DroppyEnum<T> {
+    fn drop(&mut self) {
+        match self {
+            DroppyEnum::Some(acc, _inner) => acc,
+            DroppyEnum::None(acc) => acc,
+        }
+        .push("drop");
+    }
+}
+
+macro_rules! nestings_with {
+    ($construct:ident, $binding:pat, $exp:expr) => {
+        // vanilla:
+        $construct!($binding, $exp.1);
+
+        // &:
+        $construct!(&$binding, &$exp.1);
+
+        // &mut:
+        $construct!(&mut $binding, &mut ($exp.1));
+
+        {
+            // move:
+            let w = $exp;
+            $construct!(
+                $binding,
+                {
+                    let w = w;
+                    w
+                }
+                .1
+            );
+        }
+
+        // fn(this):
+        $construct!($binding, std::convert::identity($exp).1);
+    };
+}
+
+macro_rules! nestings {
+    ($construct:ident, $binding:pat, $exp:expr) => {
+        nestings_with!($construct, $binding, $exp);
+
+        // tuple:
+        $construct!(($binding, 77), ($exp.1, 77));
+
+        // array:
+        $construct!([$binding], [$exp.1]);
+    };
+}
+
+macro_rules! let_else {
+    ($acc:expr, $v:expr, $binding:pat, $build:ident) => {
+        let acc = $acc;
+        let v = $v;
+
+        macro_rules! let_else_construct {
+            ($arg:pat, $exp:expr) => {
+                loop {
+                    let $arg = $exp else {
+                        acc.push("else");
+                        break;
+                    };
+                    acc.push("body");
+                    break;
+                }
+            };
+        }
+        nestings!(let_else_construct, $binding, acc.$build(v));
+        // ref &:
+        let_else_construct!($binding, &acc.$build(v).1);
+
+        // ref mut &mut:
+        let_else_construct!($binding, &mut acc.$build(v).1);
+    };
+}
+
+macro_rules! let_ {
+    ($acc:expr, $binding:tt) => {
+        let acc = $acc;
+
+        macro_rules! let_construct {
+            ($arg:pat, $exp:expr) => {{
+                let $arg = $exp;
+                acc.push("body");
+            }};
+        }
+        let v = 0;
+        {
+            nestings_with!(let_construct, $binding, acc.build_droppy(v));
+        }
+        acc.push("n/a");
+        acc.push("n/a");
+        acc.push("n/a");
+        acc.push("n/a");
+
+        // ref &:
+        let_construct!($binding, &acc.build_droppy(v).1);
+
+        // ref mut &mut:
+        let_construct!($binding, &mut acc.build_droppy(v).1);
+    };
+}
+
+fn main() {
+    let acc = DropAccountant::new();
+
+    println!(" --- matching cases ---");
+
+    // Ensure that let and let else have the same behaviour
+    acc.new_list("let _");
+    let_!(&acc, _);
+    acc.new_list("let else _");
+    let_else!(&acc, 0, _, build_droppy);
+    acc.assert_equality_last_two_lists();
+    acc.print_table();
+
+    // Ensure that let and let else have the same behaviour
+    acc.new_list("let _v");
+    let_!(&acc, _v);
+    acc.new_list("let else _v");
+    let_else!(&acc, 0, _v, build_droppy);
+    acc.assert_equality_last_two_lists();
+    acc.print_table();
+
+    println!();
+
+    println!(" --- mismatching cases ---");
+
+    acc.new_list("let else _ mismatch");
+    let_else!(&acc, 1, DroppyEnum::Some(_, _), build_droppy_enum_none);
+    acc.new_list("let else _v mismatch");
+    let_else!(&acc, 1, DroppyEnum::Some(_, _v), build_droppy_enum_none);
+    acc.print_table();
+    // This ensures that we always drop before visiting the else case
+    acc.assert_all_equal_to("drop,else");
+
+    acc.new_list("let else 0 mismatch");
+    let_else!(&acc, 1, 0, build_droppy);
+    acc.new_list("let else 0 mismatch");
+    let_else!(&acc, 1, 0, build_droppy);
+    acc.print_table();
+    // This ensures that we always drop before visiting the else case
+    acc.assert_all_equal_to("drop,else");
+}
diff --git a/src/test/ui/let-else/let-else-drop-order.run.stdout b/src/test/ui/let-else/let-else-drop-order.run.stdout
new file mode 100644
index 00000000000..01cf2f73e17
--- /dev/null
+++ b/src/test/ui/let-else/let-else-drop-order.run.stdout
@@ -0,0 +1,51 @@
+ --- matching cases ---
+
+| construct    | let _     | let else _ |
+| ------------ | --------- | ---------- |
+| vanilla      | drop,body | drop,body  |
+| &            | body,drop | body,drop  |
+| &mut         | body,drop | body,drop  |
+| move         | drop,body | drop,body  |
+| fn(this)     | drop,body | drop,body  |
+| tuple        | n/a,n/a   | drop,body  |
+| array        | n/a,n/a   | drop,body  |
+| ref &        | body,drop | body,drop  |
+| ref mut &mut | body,drop | body,drop  |
+
+| construct    | let _v    | let else _v |
+| ------------ | --------- | ----------- |
+| vanilla      | drop,body | drop,body   |
+| &            | body,drop | body,drop   |
+| &mut         | body,drop | body,drop   |
+| move         | drop,body | drop,body   |
+| fn(this)     | drop,body | drop,body   |
+| tuple        | n/a,n/a   | drop,body   |
+| array        | n/a,n/a   | drop,body   |
+| ref &        | body,drop | body,drop   |
+| ref mut &mut | body,drop | body,drop   |
+
+ --- mismatching cases ---
+
+| construct    | let else _ mismatch | let else _v mismatch |
+| ------------ | ------------------- | -------------------- |
+| vanilla      | drop,else           | drop,else            |
+| &            | drop,else           | drop,else            |
+| &mut         | drop,else           | drop,else            |
+| move         | drop,else           | drop,else            |
+| fn(this)     | drop,else           | drop,else            |
+| tuple        | drop,else           | drop,else            |
+| array        | drop,else           | drop,else            |
+| ref &        | drop,else           | drop,else            |
+| ref mut &mut | drop,else           | drop,else            |
+
+| construct    | let else 0 mismatch | let else 0 mismatch |
+| ------------ | ------------------- | ------------------- |
+| vanilla      | drop,else           | drop,else           |
+| &            | drop,else           | drop,else           |
+| &mut         | drop,else           | drop,else           |
+| move         | drop,else           | drop,else           |
+| fn(this)     | drop,else           | drop,else           |
+| tuple        | drop,else           | drop,else           |
+| array        | drop,else           | drop,else           |
+| ref &        | drop,else           | drop,else           |
+| ref mut &mut | drop,else           | drop,else           |
diff --git a/src/test/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.rs b/src/test/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.rs
new file mode 100644
index 00000000000..645bc7db0dd
--- /dev/null
+++ b/src/test/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.rs
@@ -0,0 +1,9 @@
+fn no_restriction<T>(x: &()) -> &() {
+    with_restriction::<T>(x) //~ ERROR the parameter type `T` may not live long enough
+}
+
+fn with_restriction<'b, T: 'b>(x: &'b ()) -> &'b () {
+    x
+}
+
+fn main() {}
diff --git a/src/test/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.stderr b/src/test/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.stderr
new file mode 100644
index 00000000000..a8b0996d8b0
--- /dev/null
+++ b/src/test/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.stderr
@@ -0,0 +1,23 @@
+error[E0311]: the parameter type `T` may not live long enough
+  --> $DIR/suggest-introducing-and-adding-missing-lifetime.rs:2:5
+   |
+LL |     with_restriction::<T>(x)
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the parameter type `T` must be valid for the anonymous lifetime defined here...
+  --> $DIR/suggest-introducing-and-adding-missing-lifetime.rs:1:25
+   |
+LL | fn no_restriction<T>(x: &()) -> &() {
+   |                         ^^^
+note: ...so that the type `T` will meet its required lifetime bounds
+  --> $DIR/suggest-introducing-and-adding-missing-lifetime.rs:2:5
+   |
+LL |     with_restriction::<T>(x)
+   |     ^^^^^^^^^^^^^^^^^^^^^
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn no_restriction<'a, T: 'a>(x: &()) -> &() {
+   |                   +++  ++++
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/match/match_non_exhaustive.rs b/src/test/ui/match/match_non_exhaustive.rs
index 8219f0eb135..f162dd60f50 100644
--- a/src/test/ui/match/match_non_exhaustive.rs
+++ b/src/test/ui/match/match_non_exhaustive.rs
@@ -21,7 +21,7 @@ fn main() {
     match l { L::A => (), L::B => () };
     // (except if the match is already non-exhaustive)
     match l { L::A => () };
-    //~^ ERROR: non-exhaustive patterns: `B` not covered [E0004]
+    //~^ ERROR: non-exhaustive patterns: `L::B` not covered [E0004]
 
     // E1 is not visibly uninhabited from here
     let (e1, e2) = bar();
diff --git a/src/test/ui/match/match_non_exhaustive.stderr b/src/test/ui/match/match_non_exhaustive.stderr
index 9d92f8fdbb4..46ee8d5179e 100644
--- a/src/test/ui/match/match_non_exhaustive.stderr
+++ b/src/test/ui/match/match_non_exhaustive.stderr
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: `B` not covered
+error[E0004]: non-exhaustive patterns: `L::B` not covered
   --> $DIR/match_non_exhaustive.rs:23:11
    |
 LL |     match l { L::A => () };
-   |           ^ pattern `B` not covered
+   |           ^ pattern `L::B` not covered
    |
 note: `L` defined here
   --> $DIR/match_non_exhaustive.rs:10:13
@@ -12,8 +12,8 @@ LL | enum L { A, B }
    = note: the matched value is of type `L`
 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 |     match l { L::A => (), B => todo!() };
-   |                         ++++++++++++++
+LL |     match l { L::A => (), L::B => todo!() };
+   |                         +++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: type `E1` is non-empty
   --> $DIR/match_non_exhaustive.rs:28:11
diff --git a/src/test/ui/moves/move-out-of-array-ref.stderr b/src/test/ui/moves/move-out-of-array-ref.stderr
index fd682e56ae1..0caa0b83a4c 100644
--- a/src/test/ui/moves/move-out-of-array-ref.stderr
+++ b/src/test/ui/moves/move-out-of-array-ref.stderr
@@ -13,7 +13,7 @@ error[E0508]: cannot move out of type `[D; 4]`, a non-copy array
   --> $DIR/move-out-of-array-ref.rs:13:27
    |
 LL |     let [_, s @ .. , _] = *a;
-   |             ------        ^^
+   |             -             ^^
    |             |             |
    |             |             cannot move out of here
    |             |             help: consider borrowing here: `&*a`
@@ -35,7 +35,7 @@ error[E0508]: cannot move out of type `[D; 4]`, a non-copy array
   --> $DIR/move-out-of-array-ref.rs:23:27
    |
 LL |     let [_, s @ .. , _] = *a;
-   |             ------        ^^
+   |             -             ^^
    |             |             |
    |             |             cannot move out of here
    |             |             help: consider borrowing here: `&*a`
diff --git a/src/test/ui/moves/move-out-of-slice-2.stderr b/src/test/ui/moves/move-out-of-slice-2.stderr
index 9a863bf31a7..93b0dcfc2d1 100644
--- a/src/test/ui/moves/move-out-of-slice-2.stderr
+++ b/src/test/ui/moves/move-out-of-slice-2.stderr
@@ -14,7 +14,7 @@ LL |     match *a {
    |           ^^ cannot move out of here
 LL |
 LL |         [a @ ..] => {}
-   |          ------
+   |          -
    |          |
    |          data moved here
    |          move occurs because `a` has type `[A]`, which does not implement the `Copy` trait
@@ -26,7 +26,7 @@ LL |     match *b {
    |           ^^ cannot move out of here
 LL |
 LL |         [_, _, b @ .., _] => {}
-   |                ------
+   |                -
    |                |
    |                data moved here
    |                move occurs because `b` has type `[A]`, which does not implement the `Copy` trait
@@ -38,7 +38,7 @@ LL |     match *c {
    |           ^^ cannot move out of here
 LL |
 LL |         [c @ ..] => {}
-   |          ------
+   |          -
    |          |
    |          data moved here
    |          move occurs because `c` has type `[C]`, which does not implement the `Copy` trait
@@ -50,7 +50,7 @@ LL |     match *d {
    |           ^^ cannot move out of here
 LL |
 LL |         [_, _, d @ .., _] => {}
-   |                ------
+   |                -
    |                |
    |                data moved here
    |                move occurs because `d` has type `[C]`, which does not implement the `Copy` trait
diff --git a/src/test/ui/nll/issue-51244.stderr b/src/test/ui/nll/issue-51244.stderr
index 19f0223a357..dcb6f9fec18 100644
--- a/src/test/ui/nll/issue-51244.stderr
+++ b/src/test/ui/nll/issue-51244.stderr
@@ -2,7 +2,7 @@ error[E0594]: cannot assign to `*my_ref`, which is behind a `&` reference
   --> $DIR/issue-51244.rs:3:5
    |
 LL |     let ref my_ref @ _ = 0;
-   |         -------------- help: consider changing this to be a mutable reference: `ref mut my_ref @ _`
+   |         ---------- help: consider changing this to be a mutable reference: `ref mut my_ref`
 LL |     *my_ref = 0;
    |     ^^^^^^^^^^^ `my_ref` is a `&` reference, so the data it refers to cannot be written
 
diff --git a/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.rs b/src/test/ui/parser/do-not-suggest-semicolon-before-array.rs
index 7ebf3f6b0d8..7ebf3f6b0d8 100644
--- a/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.rs
+++ b/src/test/ui/parser/do-not-suggest-semicolon-before-array.rs
diff --git a/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.stderr b/src/test/ui/parser/do-not-suggest-semicolon-before-array.stderr
index d6e8db80329..a9dd526321f 100644
--- a/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.stderr
+++ b/src/test/ui/parser/do-not-suggest-semicolon-before-array.stderr
@@ -1,5 +1,5 @@
 error: expected one of `.`, `?`, `]`, or an operator, found `,`
-  --> $DIR/do-not-suggest-suggest-semicolon-before-array.rs:5:5
+  --> $DIR/do-not-suggest-semicolon-before-array.rs:5:5
    |
 LL |     [1, 3)
    |     ^ ^ help: `]` may belong here
diff --git a/src/test/ui/parser/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.rs b/src/test/ui/parser/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.rs
new file mode 100644
index 00000000000..d6f7981813f
--- /dev/null
+++ b/src/test/ui/parser/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.rs
@@ -0,0 +1,3 @@
+fn main() {
+    let _x = vec[1, 2, 3]; //~ ERROR expected one of `.`, `?`, `]`, or an operator
+}
diff --git a/src/test/ui/parser/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.stderr b/src/test/ui/parser/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.stderr
new file mode 100644
index 00000000000..2fe6a28eeb4
--- /dev/null
+++ b/src/test/ui/parser/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.stderr
@@ -0,0 +1,8 @@
+error: expected one of `.`, `?`, `]`, or an operator, found `,`
+  --> $DIR/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.rs:2:19
+   |
+LL |     let _x = vec[1, 2, 3];
+   |                   ^ expected one of `.`, `?`, `]`, or an operator
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/issue-101477-enum.fixed b/src/test/ui/parser/issue-101477-enum.fixed
new file mode 100644
index 00000000000..1dfeae22aea
--- /dev/null
+++ b/src/test/ui/parser/issue-101477-enum.fixed
@@ -0,0 +1,10 @@
+// run-rustfix
+
+#[allow(dead_code)]
+enum Demo {
+    A = 1,
+    B = 2 //~ ERROR unexpected `==`
+    //~^ expected item, found `==`
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/issue-101477-enum.rs b/src/test/ui/parser/issue-101477-enum.rs
new file mode 100644
index 00000000000..ea7051d69a4
--- /dev/null
+++ b/src/test/ui/parser/issue-101477-enum.rs
@@ -0,0 +1,10 @@
+// run-rustfix
+
+#[allow(dead_code)]
+enum Demo {
+    A = 1,
+    B == 2 //~ ERROR unexpected `==`
+    //~^ expected item, found `==`
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/issue-101477-enum.stderr b/src/test/ui/parser/issue-101477-enum.stderr
new file mode 100644
index 00000000000..bffc881bdc8
--- /dev/null
+++ b/src/test/ui/parser/issue-101477-enum.stderr
@@ -0,0 +1,14 @@
+error: unexpected `==`
+  --> $DIR/issue-101477-enum.rs:6:7
+   |
+LL |     B == 2
+   |       ^^ help: try using `=` instead
+
+error: expected item, found `==`
+  --> $DIR/issue-101477-enum.rs:6:7
+   |
+LL |     B == 2
+   |       ^^ expected item
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/parser/issue-101477-let.fixed b/src/test/ui/parser/issue-101477-let.fixed
new file mode 100644
index 00000000000..9989ad81524
--- /dev/null
+++ b/src/test/ui/parser/issue-101477-let.fixed
@@ -0,0 +1,6 @@
+// run-rustfix
+
+fn main() {
+    let x = 2; //~ ERROR unexpected `==`
+    println!("x: {}", x)
+}
diff --git a/src/test/ui/parser/issue-101477-let.rs b/src/test/ui/parser/issue-101477-let.rs
new file mode 100644
index 00000000000..8b0e8bee179
--- /dev/null
+++ b/src/test/ui/parser/issue-101477-let.rs
@@ -0,0 +1,6 @@
+// run-rustfix
+
+fn main() {
+    let x == 2; //~ ERROR unexpected `==`
+    println!("x: {}", x)
+}
diff --git a/src/test/ui/parser/issue-101477-let.stderr b/src/test/ui/parser/issue-101477-let.stderr
new file mode 100644
index 00000000000..1b30d4b1786
--- /dev/null
+++ b/src/test/ui/parser/issue-101477-let.stderr
@@ -0,0 +1,8 @@
+error: unexpected `==`
+  --> $DIR/issue-101477-let.rs:4:11
+   |
+LL |     let x == 2;
+   |           ^^ help: try using `=` instead
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/recover-field-semi.rs b/src/test/ui/parser/recover-field-semi.rs
new file mode 100644
index 00000000000..b703578860e
--- /dev/null
+++ b/src/test/ui/parser/recover-field-semi.rs
@@ -0,0 +1,16 @@
+struct Foo {
+    foo: i32;
+    //~^ ERROR struct fields are separated by `,`
+}
+
+union Bar { //~ ERROR
+    foo: i32;
+    //~^ ERROR union fields are separated by `,`
+}
+
+enum Baz {
+    Qux { foo: i32; }
+    //~^ ERROR struct fields are separated by `,`
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/recover-field-semi.stderr b/src/test/ui/parser/recover-field-semi.stderr
new file mode 100644
index 00000000000..657366db9b4
--- /dev/null
+++ b/src/test/ui/parser/recover-field-semi.stderr
@@ -0,0 +1,29 @@
+error: struct fields are separated by `,`
+  --> $DIR/recover-field-semi.rs:2:13
+   |
+LL |     foo: i32;
+   |             ^ help: replace `;` with `,`
+
+error: union fields are separated by `,`
+  --> $DIR/recover-field-semi.rs:7:13
+   |
+LL |     foo: i32;
+   |             ^ help: replace `;` with `,`
+
+error: struct fields are separated by `,`
+  --> $DIR/recover-field-semi.rs:12:19
+   |
+LL |     Qux { foo: i32; }
+   |                   ^ help: replace `;` with `,`
+
+error: unions cannot have zero fields
+  --> $DIR/recover-field-semi.rs:6:1
+   |
+LL | / union Bar {
+LL | |     foo: i32;
+LL | |
+LL | | }
+   | |_^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/parser/removed-syntax-field-semicolon.rs b/src/test/ui/parser/removed-syntax-field-semicolon.rs
index ac28e21ae03..808f2a5cc38 100644
--- a/src/test/ui/parser/removed-syntax-field-semicolon.rs
+++ b/src/test/ui/parser/removed-syntax-field-semicolon.rs
@@ -1,6 +1,6 @@
 struct S {
     bar: ();
-    //~^ ERROR expected `,`, or `}`, found `;`
+    //~^ ERROR struct fields are separated by `,`
 }
 
 fn main() {}
diff --git a/src/test/ui/parser/removed-syntax-field-semicolon.stderr b/src/test/ui/parser/removed-syntax-field-semicolon.stderr
index fbefeb26a50..e4f75f67206 100644
--- a/src/test/ui/parser/removed-syntax-field-semicolon.stderr
+++ b/src/test/ui/parser/removed-syntax-field-semicolon.stderr
@@ -1,8 +1,8 @@
-error: expected `,`, or `}`, found `;`
+error: struct fields are separated by `,`
   --> $DIR/removed-syntax-field-semicolon.rs:2:12
    |
 LL |     bar: ();
-   |            ^
+   |            ^ help: replace `;` with `,`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/suggest-suggest-semicolon-before-array.fixed b/src/test/ui/parser/suggest-semicolon-before-array.fixed
index a06b58b2740..a06b58b2740 100644
--- a/src/test/ui/parser/suggest-suggest-semicolon-before-array.fixed
+++ b/src/test/ui/parser/suggest-semicolon-before-array.fixed
diff --git a/src/test/ui/parser/suggest-suggest-semicolon-before-array.rs b/src/test/ui/parser/suggest-semicolon-before-array.rs
index f601ca2aef5..f601ca2aef5 100644
--- a/src/test/ui/parser/suggest-suggest-semicolon-before-array.rs
+++ b/src/test/ui/parser/suggest-semicolon-before-array.rs
diff --git a/src/test/ui/parser/suggest-suggest-semicolon-before-array.stderr b/src/test/ui/parser/suggest-semicolon-before-array.stderr
index bf86b43554d..8a33321fbd5 100644
--- a/src/test/ui/parser/suggest-suggest-semicolon-before-array.stderr
+++ b/src/test/ui/parser/suggest-semicolon-before-array.stderr
@@ -1,5 +1,5 @@
 error: expected `;`, found `[`
-  --> $DIR/suggest-suggest-semicolon-before-array.rs:8:5
+  --> $DIR/suggest-semicolon-before-array.rs:8:5
    |
 LL |     [1, 3]
    |     ^
diff --git a/src/test/ui/parser/unnecessary-let.rs b/src/test/ui/parser/unnecessary-let.rs
new file mode 100644
index 00000000000..6279109621d
--- /dev/null
+++ b/src/test/ui/parser/unnecessary-let.rs
@@ -0,0 +1,11 @@
+fn main() {
+    for let x of [1, 2, 3] {}
+    //~^ ERROR expected pattern, found `let`
+    //~| ERROR missing `in` in `for` loop
+
+    match 1 {
+        let 1 => {}
+        //~^ ERROR expected pattern, found `let`
+        _ => {}
+    }
+}
diff --git a/src/test/ui/parser/unnecessary-let.stderr b/src/test/ui/parser/unnecessary-let.stderr
new file mode 100644
index 00000000000..952119cae3e
--- /dev/null
+++ b/src/test/ui/parser/unnecessary-let.stderr
@@ -0,0 +1,20 @@
+error: expected pattern, found `let`
+  --> $DIR/unnecessary-let.rs:2:9
+   |
+LL |     for let x of [1, 2, 3] {}
+   |         ^^^ help: remove the unnecessary `let` keyword
+
+error: missing `in` in `for` loop
+  --> $DIR/unnecessary-let.rs:2:15
+   |
+LL |     for let x of [1, 2, 3] {}
+   |               ^^ help: try using `in` here instead
+
+error: expected pattern, found `let`
+  --> $DIR/unnecessary-let.rs:7:9
+   |
+LL |         let 1 => {}
+   |         ^^^ help: remove the unnecessary `let` keyword
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
index 4249a74b3ed..fad84dda0e1 100644
--- a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
+++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
@@ -40,9 +40,8 @@ error[E0382]: borrow of moved value
   --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:12:14
    |
 LL |         Some(ref _y @ _z) => {}
-   |              ^^^^^^^^^--
-   |              |        |
-   |              |        value moved here
+   |              ^^^^^^   -- value moved here
+   |              |
    |              value borrowed here after move
    |
    = note: move occurs because value has type `X`, which does not implement the `Copy` trait
@@ -55,9 +54,8 @@ error[E0382]: borrow of moved value
   --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:26:14
    |
 LL |         Some(ref mut _y @ _z) => {}
-   |              ^^^^^^^^^^^^^--
-   |              |            |
-   |              |            value moved here
+   |              ^^^^^^^^^^   -- value moved here
+   |              |
    |              value borrowed here after move
    |
    = note: move occurs because value has type `X`, which does not implement the `Copy` trait
diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr
index ee0885a014a..a481ca46833 100644
--- a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr
+++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr
@@ -2,9 +2,8 @@ error[E0382]: use of partially moved value
   --> $DIR/bind-by-move-no-subbindings-fun-param.rs:7:6
    |
 LL | fn f(a @ A(u): A) -> Box<u8> {
-   |      ^^^^^^-^
-   |      |     |
-   |      |     value partially moved here
+   |      ^     - value partially moved here
+   |      |
    |      value used here after partial move
    |
    = note: partial move occurs because value has type `Box<u8>`, which does not implement the `Copy` trait
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr
index 8e00bf5c328..83751843b1b 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr
@@ -2,7 +2,7 @@ error[E0382]: use of moved value
   --> $DIR/borrowck-move-and-move.rs:11:9
    |
 LL |     let a @ b = U;
-   |         ^^^^-   - move occurs because value has type `U`, which does not implement the `Copy` trait
+   |         ^   -   - move occurs because value has type `U`, which does not implement the `Copy` trait
    |         |   |
    |         |   value moved here
    |         value used here after move
@@ -11,9 +11,8 @@ error[E0382]: use of partially moved value
   --> $DIR/borrowck-move-and-move.rs:13:9
    |
 LL |     let a @ (b, c) = (U, U);
-   |         ^^^^^^^^-^
-   |         |       |
-   |         |       value partially moved here
+   |         ^       - value partially moved here
+   |         |
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -22,9 +21,8 @@ error[E0382]: use of partially moved value
   --> $DIR/borrowck-move-and-move.rs:15:9
    |
 LL |     let a @ (b, c) = (u(), u());
-   |         ^^^^^^^^-^
-   |         |       |
-   |         |       value partially moved here
+   |         ^       - value partially moved here
+   |         |
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -35,9 +33,8 @@ error[E0382]: use of moved value
 LL |     match Ok(U) {
    |           ----- move occurs because value has type `Result<U, U>`, which does not implement the `Copy` trait
 LL |         a @ Ok(b) | a @ Err(b) => {}
-   |         -------^-
-   |         |      |
-   |         |      value used here after move
+   |         -      ^ value used here after move
+   |         |
    |         value moved here
 
 error[E0382]: use of moved value
@@ -46,18 +43,16 @@ error[E0382]: use of moved value
 LL |     match Ok(U) {
    |           ----- move occurs because value has type `Result<U, U>`, which does not implement the `Copy` trait
 LL |         a @ Ok(b) | a @ Err(b) => {}
-   |                     --------^-
-   |                     |       |
-   |                     |       value used here after move
+   |                     -       ^ value used here after move
+   |                     |
    |                     value moved here
 
 error[E0382]: use of partially moved value
   --> $DIR/borrowck-move-and-move.rs:25:9
    |
 LL |         xs @ [a, .., b] => {}
-   |         ^^^^^^^^^^^^^-^
-   |         |            |
-   |         |            value partially moved here
+   |         ^^           - value partially moved here
+   |         |
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -66,9 +61,8 @@ error[E0382]: use of partially moved value
   --> $DIR/borrowck-move-and-move.rs:29:9
    |
 LL |         xs @ [_, ys @ .., _] => {}
-   |         ^^^^^^^^^-------^^^^
-   |         |        |
-   |         |        value partially moved here
+   |         ^^       -- value partially moved here
+   |         |
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -77,7 +71,7 @@ error[E0382]: use of moved value
   --> $DIR/borrowck-move-and-move.rs:22:12
    |
 LL |     fn fun(a @ b: U) {}
-   |            ^^^^-
+   |            ^----
    |            |   |
    |            |   value moved here
    |            value used here after move
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr
index 4b2048855eb..002c7609f61 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr
@@ -74,9 +74,8 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-at-and-box.rs:31:9
    |
 LL |     let ref a @ box b = Box::new(NC);
-   |         ^^^^^^^^^^^^-
-   |         |           |
-   |         |           value moved here
+   |         ^^^^^       - value moved here
+   |         |
    |         value borrowed here after move
    |
    = note: move occurs because value has type `NC`, which does not implement the `Copy` trait
@@ -85,9 +84,8 @@ error[E0502]: cannot borrow value as immutable because it is also borrowed as mu
   --> $DIR/borrowck-pat-at-and-box.rs:38:9
    |
 LL |     let ref a @ box ref mut b = Box::new(NC);
-   |         ^^^^^^^^^^^^---------
-   |         |           |
-   |         |           mutable borrow occurs here
+   |         ^^^^^       --------- mutable borrow occurs here
+   |         |
    |         immutable borrow occurs here
 ...
 LL |     *b = NC;
@@ -97,9 +95,8 @@ error[E0502]: cannot borrow value as immutable because it is also borrowed as mu
   --> $DIR/borrowck-pat-at-and-box.rs:42:9
    |
 LL |     let ref a @ box ref mut b = Box::new(NC);
-   |         ^^^^^^^^^^^^---------
-   |         |           |
-   |         |           mutable borrow occurs here
+   |         ^^^^^       --------- mutable borrow occurs here
+   |         |
    |         immutable borrow occurs here
 ...
 LL |     *b = NC;
@@ -109,9 +106,8 @@ error[E0502]: cannot borrow value as mutable because it is also borrowed as immu
   --> $DIR/borrowck-pat-at-and-box.rs:48:9
    |
 LL |     let ref mut a @ box ref b = Box::new(NC);
-   |         ^^^^^^^^^^^^^^^^-----
-   |         |               |
-   |         |               immutable borrow occurs here
+   |         ^^^^^^^^^       ----- immutable borrow occurs here
+   |         |
    |         mutable borrow occurs here
 ...
 LL |     drop(b);
@@ -121,9 +117,8 @@ error[E0502]: cannot borrow value as mutable because it is also borrowed as immu
   --> $DIR/borrowck-pat-at-and-box.rs:62:9
    |
 LL |         ref mut a @ box ref b => {
-   |         ^^^^^^^^^^^^^^^^-----
-   |         |               |
-   |         |               immutable borrow occurs here
+   |         ^^^^^^^^^       ----- immutable borrow occurs here
+   |         |
    |         mutable borrow occurs here
 ...
 LL |             drop(b);
@@ -133,9 +128,8 @@ error[E0502]: cannot borrow value as mutable because it is also borrowed as immu
   --> $DIR/borrowck-pat-at-and-box.rs:54:11
    |
 LL |     fn f5(ref mut a @ box ref b: Box<NC>) {
-   |           ^^^^^^^^^^^^^^^^-----
-   |           |               |
-   |           |               immutable borrow occurs here
+   |           ^^^^^^^^^       ----- immutable borrow occurs here
+   |           |
    |           mutable borrow occurs here
 ...
 LL |         drop(b);
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
index bc2c1625fd0..a9e66de0842 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
@@ -262,9 +262,8 @@ error[E0382]: use of partially moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:9
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^---------^
-   |         |                       |
-   |         |                       value partially moved here
+   |         ^                       - value partially moved here
+   |         |
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -273,9 +272,8 @@ error[E0382]: use of partially moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:9
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^---------^
-   |         |                       |
-   |         |                       value partially moved here
+   |         ^                       - value partially moved here
+   |         |
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -286,10 +284,7 @@ error[E0382]: use of moved value
 LL |     match Some((U, U)) {
    |           ------------ move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
-   |         -----------------------------^^^^^^^^^--
-   |         |                            |
-   |         |                            value used here after move
-   |         value moved here
+   |         - value moved here           ^ value used here after move
 
 error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:55:30
@@ -297,9 +292,8 @@ error[E0382]: borrow of moved value
 LL |     match Some([U, U]) {
    |           ------------ move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait
 LL |         mut a @ Some([ref b, ref mut c]) => {}
-   |         ---------------------^^^^^^^^^--
-   |         |                    |
-   |         |                    value borrowed here after move
+   |         -----                ^^^^^^^^^ value borrowed here after move
+   |         |
    |         value moved here
 
 error[E0382]: borrow of moved value
@@ -308,9 +302,8 @@ error[E0382]: borrow of moved value
 LL |     match Some(u()) {
    |           --------- move occurs because value has type `Option<U>`, which does not implement the `Copy` trait
 LL |         a @ Some(ref b) => {}
-   |         ---------^^^^^-
-   |         |        |
-   |         |        value borrowed here after move
+   |         -        ^^^^^ value borrowed here after move
+   |         |
    |         value moved here
 
 error[E0382]: use of moved value
@@ -319,10 +312,7 @@ error[E0382]: use of moved value
 LL |     match Some((u(), u())) {
    |           ---------------- move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
-   |         -----------------------------^^^^^^^^^--
-   |         |                            |
-   |         |                            value used here after move
-   |         value moved here
+   |         - value moved here           ^ value used here after move
 
 error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:75:30
@@ -330,18 +320,16 @@ error[E0382]: borrow of moved value
 LL |     match Some([u(), u()]) {
    |           ---------------- move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait
 LL |         mut a @ Some([ref b, ref mut c]) => {}
-   |         ---------------------^^^^^^^^^--
-   |         |                    |
-   |         |                    value borrowed here after move
+   |         -----                ^^^^^^^^^ value borrowed here after move
+   |         |
    |         value moved here
 
 error[E0382]: use of partially moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:11
    |
 LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
-   |           ^^^^^^^^^^^^^^^^^^^^-------------^
-   |           |                   |
-   |           |                   value partially moved here
+   |           ^^^^^               ----- value partially moved here
+   |           |
    |           value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr
index c019aae3dfc..e03a9298214 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr
@@ -237,9 +237,8 @@ error[E0382]: borrow of partially moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:30:9
    |
 LL |     let ref mut a @ [b, mut c] = [U, U];
-   |         ^^^^^^^^^^^^^^^^-----^
-   |         |               |
-   |         |               value partially moved here
+   |         ^^^^^^^^^       ----- value partially moved here
+   |         |
    |         value borrowed here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -248,7 +247,7 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:33:9
    |
 LL |     let ref a @ b = u();
-   |         ^^^^^^^^-   --- move occurs because value has type `U`, which does not implement the `Copy` trait
+   |         ^^^^^   -   --- move occurs because value has type `U`, which does not implement the `Copy` trait
    |         |       |
    |         |       value moved here
    |         value borrowed here after move
@@ -257,9 +256,8 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:36:18
    |
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
-   |                  ^^^^^^^^-----
-   |                  |       |
-   |                  |       value moved here
+   |                  ^^^^^   ----- value moved here
+   |                  |
    |                  value borrowed here after move
    |
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -268,9 +266,8 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:36:33
    |
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
-   |                                 ^^^^^^^^-
-   |                                 |       |
-   |                                 |       value moved here
+   |                                 ^^^^^   - value moved here
+   |                                 |
    |                                 value borrowed here after move
    |
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -279,9 +276,8 @@ error[E0382]: borrow of partially moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:42:9
    |
 LL |     let ref mut a @ [b, mut c] = [u(), u()];
-   |         ^^^^^^^^^^^^^^^^-----^
-   |         |               |
-   |         |               value partially moved here
+   |         ^^^^^^^^^       ----- value partially moved here
+   |         |
    |         value borrowed here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -290,9 +286,8 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:69:23
    |
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
-   |                       ^^^^^^^^-----
-   |                       |       |
-   |                       |       value moved here
+   |                       ^^^^^   ----- value moved here
+   |                       |
    |                       value borrowed here after move
    |
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -305,9 +300,8 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:69:38
    |
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
-   |                                      ^^^^^^^^-
-   |                                      |       |
-   |                                      |       value moved here
+   |                                      ^^^^^   - value moved here
+   |                                      |
    |                                      value borrowed here after move
    |
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -320,7 +314,7 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:11:11
    |
 LL |     fn f1(ref a @ b: U) {}
-   |           ^^^^^^^^-
+   |           ^^^^^----
    |           |       |
    |           |       value moved here
    |           value borrowed here after move
@@ -330,9 +324,8 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:14:20
    |
 LL |     fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
-   |                    ^^^^^^^^-----
-   |                    |       |
-   |                    |       value moved here
+   |                    ^^^^^   ----- value moved here
+   |                    |
    |                    value borrowed here after move
    |
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -341,9 +334,8 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:14:35
    |
 LL |     fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
-   |                                   ^^^^^^^^-
-   |                                   |       |
-   |                                   |       value moved here
+   |                                   ^^^^^   - value moved here
+   |                                   |
    |                                   value borrowed here after move
    |
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -352,9 +344,8 @@ error[E0382]: borrow of partially moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:20:11
    |
 LL |     fn f3(ref mut a @ [b, mut c]: [U; 2]) {}
-   |           ^^^^^^^^^^^^^^^^-----^
-   |           |               |
-   |           |               value partially moved here
+   |           ^^^^^^^^^       ----- value partially moved here
+   |           |
    |           value borrowed here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
index 2ae78d1084e..9fd5e229afd 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
@@ -298,9 +298,8 @@ error[E0502]: cannot borrow value as immutable because it is also borrowed as mu
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:8:31
    |
 LL |         ref mut z @ &mut Some(ref a) => {
-   |         ----------------------^^^^^-
-   |         |                     |
-   |         |                     immutable borrow occurs here
+   |         ---------             ^^^^^ immutable borrow occurs here
+   |         |
    |         mutable borrow occurs here
 ...
 LL |             **z = None;
@@ -310,9 +309,8 @@ error[E0502]: cannot borrow value as mutable because it is also borrowed as immu
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:46:9
    |
 LL |     let ref mut a @ ref b = u();
-   |         ^^^^^^^^^^^^-----
-   |         |           |
-   |         |           immutable borrow occurs here
+   |         ^^^^^^^^^   ----- immutable borrow occurs here
+   |         |
    |         mutable borrow occurs here
 ...
 LL |     drop(b);
@@ -322,9 +320,8 @@ error[E0502]: cannot borrow value as immutable because it is also borrowed as mu
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:51:9
    |
 LL |     let ref a @ ref mut b = u();
-   |         ^^^^^^^^---------
-   |         |       |
-   |         |       mutable borrow occurs here
+   |         ^^^^^   --------- mutable borrow occurs here
+   |         |
    |         immutable borrow occurs here
 ...
 LL |     *b = u();
@@ -334,9 +331,8 @@ error[E0502]: cannot borrow value as mutable because it is also borrowed as immu
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:20
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
-   |         -----------^^^^^^^^^-
-   |         |          |
-   |         |          mutable borrow occurs here
+   |         -----      ^^^^^^^^^ mutable borrow occurs here
+   |         |
    |         immutable borrow occurs here
 ...
 LL |             drop(a);
@@ -346,9 +342,8 @@ error[E0502]: cannot borrow value as mutable because it is also borrowed as immu
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:45
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
-   |                                 ------------^^^^^^^^^-
-   |                                 |           |
-   |                                 |           mutable borrow occurs here
+   |                                 -----       ^^^^^^^^^ mutable borrow occurs here
+   |                                 |
    |                                 immutable borrow occurs here
 ...
 LL |             drop(a);
@@ -406,9 +401,8 @@ error[E0502]: cannot borrow value as immutable because it is also borrowed as mu
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:117:9
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
-   |         ^^^^^^^^^---------^^^^^^^^^^^^
-   |         |        |
-   |         |        mutable borrow occurs here
+   |         ^^^^^    --------- mutable borrow occurs here
+   |         |
    |         immutable borrow occurs here
 ...
 LL |     *b = U;
@@ -418,9 +412,8 @@ error[E0502]: cannot borrow value as immutable because it is also borrowed as mu
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:9
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
-   |         ^^^^^^^^^---------^^^^^^^^^^^^
-   |         |        |
-   |         |        mutable borrow occurs here
+   |         ^^^^^    --------- mutable borrow occurs here
+   |         |
    |         immutable borrow occurs here
 ...
 LL |     *b = U;
@@ -430,9 +423,8 @@ error[E0502]: cannot borrow value as immutable because it is also borrowed as mu
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:129:9
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
-   |         ^^^^^^^^^---------^^^^^^^^^^^^
-   |         |        |
-   |         |        mutable borrow occurs here
+   |         ^^^^^    --------- mutable borrow occurs here
+   |         |
    |         immutable borrow occurs here
 LL |
 LL |     *b = U;
@@ -442,7 +434,7 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:30
    |
 LL |     fn f4_also_moved(ref a @ ref mut b @ c: U) {}
-   |                      --------^^^^^^^^^^^^-
+   |                      --------^^^^^^^^^----
    |                      |       |           |
    |                      |       |           value moved here
    |                      |       value borrowed here after move
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
index aa02230419b..e47aea9c77e 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
@@ -262,9 +262,8 @@ error[E0499]: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:29:9
    |
 LL |     let ref mut a @ ref mut b = U;
-   |         ^^^^^^^^^^^^---------
-   |         |           |
-   |         |           first mutable borrow occurs here
+   |         ^^^^^^^^^   --------- first mutable borrow occurs here
+   |         |
    |         second mutable borrow occurs here
 ...
 LL |     drop(b);
@@ -274,9 +273,8 @@ error[E0499]: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:39:9
    |
 LL |     let ref mut a @ ref mut b = U;
-   |         ^^^^^^^^^^^^---------
-   |         |           |
-   |         |           first mutable borrow occurs here
+   |         ^^^^^^^^^   --------- first mutable borrow occurs here
+   |         |
    |         second mutable borrow occurs here
 ...
 LL |     *b = U;
@@ -286,9 +284,8 @@ error[E0499]: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:89:24
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
-   |         ---------------^^^^^^^^^-
-   |         |              |
-   |         |              second mutable borrow occurs here
+   |         ---------      ^^^^^^^^^ second mutable borrow occurs here
+   |         |
    |         first mutable borrow occurs here
 ...
 LL |             *a = Err(U);
@@ -298,9 +295,8 @@ error[E0499]: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:89:53
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
-   |                                     ----------------^^^^^^^^^-
-   |                                     |               |
-   |                                     |               second mutable borrow occurs here
+   |                                     ---------       ^^^^^^^^^ second mutable borrow occurs here
+   |                                     |
    |                                     first mutable borrow occurs here
 ...
 LL |             *a = Err(U);
@@ -310,9 +306,8 @@ error[E0499]: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:101:24
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
-   |         ---------------^^^^^^^^^-
-   |         |              |
-   |         |              second mutable borrow occurs here
+   |         ---------      ^^^^^^^^^ second mutable borrow occurs here
+   |         |
    |         first mutable borrow occurs here
 ...
 LL |             drop(a);
@@ -322,9 +317,8 @@ error[E0499]: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:101:53
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
-   |                                     ----------------^^^^^^^^^-
-   |                                     |               |
-   |                                     |               second mutable borrow occurs here
+   |                                     ---------       ^^^^^^^^^ second mutable borrow occurs here
+   |                                     |
    |                                     first mutable borrow occurs here
 ...
 LL |             drop(a);
@@ -334,7 +328,7 @@ error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-ref-mut-twice.rs:21:34
    |
 LL |     fn f4_also_moved(ref mut a @ ref mut b @ c: U) {}
-   |                      ------------^^^^^^^^^^^^-
+   |                      ------------^^^^^^^^^----
    |                      |           |           |
    |                      |           |           value moved here
    |                      |           value borrowed here after move
diff --git a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr
index d290144b615..cd3234952fa 100644
--- a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr
+++ b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr
@@ -2,9 +2,8 @@ error[E0382]: use of partially moved value
   --> $DIR/copy-and-move-mixed.rs:12:9
    |
 LL |     let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C));
-   |         ^^^^^^^^^^------------^
-   |         |         |
-   |         |         value partially moved here
+   |         ^         - value partially moved here
+   |         |
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `NC<C, C>`, which does not implement the `Copy` trait
diff --git a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
index d78faa682b5..840a513d6c6 100644
--- a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
+++ b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
@@ -48,7 +48,7 @@ error[E0382]: borrow of moved value
   --> $DIR/default-binding-modes-both-sides-independent.rs:29:9
    |
 LL |     let ref mut a @ b = NotCopy;
-   |         ^^^^^^^^^^^^-   ------- move occurs because value has type `NotCopy`, which does not implement the `Copy` trait
+   |         ^^^^^^^^^   -   ------- move occurs because value has type `NotCopy`, which does not implement the `Copy` trait
    |         |           |
    |         |           value moved here
    |         value borrowed here after move
diff --git a/src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr b/src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr
index 3180bd0afc1..70beb5d4232 100644
--- a/src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr
+++ b/src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr
@@ -11,7 +11,7 @@ error[E0596]: cannot borrow `not_mut` as mutable, as it is not declared as mutab
   --> $DIR/nested-binding-modes-mut.rs:9:5
    |
 LL |     let not_mut @ mut is_mut = 42;
-   |         -------------------- help: consider changing this to be mutable: `mut not_mut`
+   |         ------- help: consider changing this to be mutable: `mut not_mut`
 LL |     &mut is_mut;
 LL |     &mut not_mut;
    |     ^^^^^^^^^^^^ cannot borrow as mutable
diff --git a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
index 5beca04d285..bac2db6ce82 100644
--- a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
+++ b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
@@ -35,7 +35,7 @@ error[E0502]: cannot borrow `arr[..]` as mutable because it is also borrowed as
   --> $DIR/borrowck-move-ref-pattern.rs:13:16
    |
 LL |     let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
-   |                             ---------------- immutable borrow occurs here
+   |                             ----------- immutable borrow occurs here
 ...
 LL |     let [_, _, ref mut _x2, _x3, mut _x4] = arr;
    |                ^^^^^^^^^^^ mutable borrow occurs here
@@ -47,7 +47,7 @@ error[E0505]: cannot move out of `arr[..]` because it is borrowed
   --> $DIR/borrowck-move-ref-pattern.rs:13:29
    |
 LL |     let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
-   |                             ---------------- borrow of `arr[..]` occurs here
+   |                             ----------- borrow of `arr[..]` occurs here
 ...
 LL |     let [_, _, ref mut _x2, _x3, mut _x4] = arr;
    |                             ^^^ move out of `arr[..]` occurs here
@@ -59,7 +59,7 @@ error[E0505]: cannot move out of `arr[..]` because it is borrowed
   --> $DIR/borrowck-move-ref-pattern.rs:13:34
    |
 LL |     let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
-   |                             ---------------- borrow of `arr[..]` occurs here
+   |                             ----------- borrow of `arr[..]` occurs here
 ...
 LL |     let [_, _, ref mut _x2, _x3, mut _x4] = arr;
    |                                  ^^^^^^^ move out of `arr[..]` occurs here
diff --git a/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs b/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs
index d968c48fb1a..5d4181a30f0 100644
--- a/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs
+++ b/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs
@@ -22,22 +22,22 @@ fn main() {
         HiddenEnum::A => {}
         HiddenEnum::C => {}
     }
-    //~^^^^ non-exhaustive patterns: `B` not covered
+    //~^^^^ non-exhaustive patterns: `HiddenEnum::B` not covered
 
     match HiddenEnum::A {
         HiddenEnum::A => {}
     }
-    //~^^^ non-exhaustive patterns: `B` and `_` not covered
+    //~^^^ non-exhaustive patterns: `HiddenEnum::B` and `_` not covered
 
     match None {
         None => {}
         Some(HiddenEnum::A) => {}
     }
-    //~^^^^ non-exhaustive patterns: `Some(B)` and `Some(_)` not covered
+    //~^^^^ non-exhaustive patterns: `Some(HiddenEnum::B)` and `Some(_)` not covered
 
     match InCrate::A {
         InCrate::A => {}
         InCrate::B => {}
     }
-    //~^^^^ non-exhaustive patterns: `C` not covered
+    //~^^^^ non-exhaustive patterns: `InCrate::C` not covered
 }
diff --git a/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr b/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr
index 643e734f9d4..b450a9aeddf 100644
--- a/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr
+++ b/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr
@@ -16,11 +16,11 @@ LL ~         HiddenEnum::B => {}
 LL +         _ => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `B` not covered
+error[E0004]: non-exhaustive patterns: `HiddenEnum::B` not covered
   --> $DIR/doc-hidden-non-exhaustive.rs:21:11
    |
 LL |     match HiddenEnum::A {
-   |           ^^^^^^^^^^^^^ pattern `B` not covered
+   |           ^^^^^^^^^^^^^ pattern `HiddenEnum::B` not covered
    |
 note: `HiddenEnum` defined here
   --> $DIR/auxiliary/hidden.rs:3:5
@@ -34,14 +34,14 @@ LL |     B,
 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 ~         HiddenEnum::C => {}
-LL +         B => todo!()
+LL +         HiddenEnum::B => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `B` and `_` not covered
+error[E0004]: non-exhaustive patterns: `HiddenEnum::B` and `_` not covered
   --> $DIR/doc-hidden-non-exhaustive.rs:27:11
    |
 LL |     match HiddenEnum::A {
-   |           ^^^^^^^^^^^^^ patterns `B` and `_` not covered
+   |           ^^^^^^^^^^^^^ patterns `HiddenEnum::B` and `_` not covered
    |
 note: `HiddenEnum` defined here
   --> $DIR/auxiliary/hidden.rs:3:5
@@ -55,14 +55,14 @@ LL |     B,
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~         HiddenEnum::A => {}
-LL +         B | _ => todo!()
+LL +         HiddenEnum::B | _ => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `Some(B)` and `Some(_)` not covered
+error[E0004]: non-exhaustive patterns: `Some(HiddenEnum::B)` and `Some(_)` not covered
   --> $DIR/doc-hidden-non-exhaustive.rs:32:11
    |
 LL |     match None {
-   |           ^^^^ patterns `Some(B)` and `Some(_)` not covered
+   |           ^^^^ patterns `Some(HiddenEnum::B)` and `Some(_)` not covered
    |
 note: `Option<HiddenEnum>` defined here
   --> $SRC_DIR/core/src/option.rs:LL:COL
@@ -76,14 +76,14 @@ LL |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~         Some(HiddenEnum::A) => {}
-LL +         Some(B) | Some(_) => todo!()
+LL +         Some(HiddenEnum::B) | Some(_) => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `C` not covered
+error[E0004]: non-exhaustive patterns: `InCrate::C` not covered
   --> $DIR/doc-hidden-non-exhaustive.rs:38:11
    |
 LL |     match InCrate::A {
-   |           ^^^^^^^^^^ pattern `C` not covered
+   |           ^^^^^^^^^^ pattern `InCrate::C` not covered
    |
 note: `InCrate` defined here
   --> $DIR/doc-hidden-non-exhaustive.rs:11:5
@@ -97,7 +97,7 @@ LL |     C,
 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 ~         InCrate::B => {}
-LL +         C => todo!()
+LL +         InCrate::C => todo!()
    |
 
 error: aborting due to 5 previous errors
diff --git a/src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr b/src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr
index d31ee0dbd14..5e12bc1d22f 100644
--- a/src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr
+++ b/src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr
@@ -105,11 +105,11 @@ LL | union NonEmptyUnion2 {
    = note: the matched value is of type `NonEmptyUnion2`
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
-error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
+error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered
   --> $DIR/empty-match.rs:83:20
    |
 LL |     match_no_arms!(NonEmptyEnum1::Foo(true));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered
    |
 note: `NonEmptyEnum1` defined here
   --> $DIR/empty-match.rs:24:5
@@ -121,11 +121,11 @@ LL |     Foo(bool),
    = note: the matched value is of type `NonEmptyEnum1`
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern
 
-error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
+error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
   --> $DIR/empty-match.rs:84:20
    |
 LL |     match_no_arms!(NonEmptyEnum2::Foo(true));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
    |
 note: `NonEmptyEnum2` defined here
   --> $DIR/empty-match.rs:27:5
@@ -139,11 +139,11 @@ LL |     Bar,
    = note: the matched value is of type `NonEmptyEnum2`
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
 
-error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
+error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
   --> $DIR/empty-match.rs:85:20
    |
 LL |     match_no_arms!(NonEmptyEnum5::V1);
-   |                    ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+   |                    ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
    |
 note: `NonEmptyEnum5` defined here
   --> $DIR/empty-match.rs:30:6
@@ -238,11 +238,11 @@ LL ~             _ if false => {}
 LL +             NonEmptyUnion2 { .. } => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
+error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered
   --> $DIR/empty-match.rs:92:24
    |
 LL |     match_guarded_arm!(NonEmptyEnum1::Foo(true));
-   |                        ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered
    |
 note: `NonEmptyEnum1` defined here
   --> $DIR/empty-match.rs:24:5
@@ -255,14 +255,14 @@ LL |     Foo(bool),
 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 ~             _ if false => {}
-LL +             Foo(_) => todo!()
+LL +             NonEmptyEnum1::Foo(_) => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
+error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
   --> $DIR/empty-match.rs:93:24
    |
 LL |     match_guarded_arm!(NonEmptyEnum2::Foo(true));
-   |                        ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
    |
 note: `NonEmptyEnum2` defined here
   --> $DIR/empty-match.rs:27:5
@@ -277,14 +277,14 @@ LL |     Bar,
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~             _ if false => {}
-LL +             Foo(_) | Bar => todo!()
+LL +             NonEmptyEnum2::Foo(_) | NonEmptyEnum2::Bar => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
+error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
   --> $DIR/empty-match.rs:94:24
    |
 LL |     match_guarded_arm!(NonEmptyEnum5::V1);
-   |                        ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+   |                        ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
    |
 note: `NonEmptyEnum5` defined here
   --> $DIR/empty-match.rs:30:6
diff --git a/src/test/ui/pattern/usefulness/empty-match.normal.stderr b/src/test/ui/pattern/usefulness/empty-match.normal.stderr
index d31ee0dbd14..5e12bc1d22f 100644
--- a/src/test/ui/pattern/usefulness/empty-match.normal.stderr
+++ b/src/test/ui/pattern/usefulness/empty-match.normal.stderr
@@ -105,11 +105,11 @@ LL | union NonEmptyUnion2 {
    = note: the matched value is of type `NonEmptyUnion2`
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
-error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
+error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered
   --> $DIR/empty-match.rs:83:20
    |
 LL |     match_no_arms!(NonEmptyEnum1::Foo(true));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered
    |
 note: `NonEmptyEnum1` defined here
   --> $DIR/empty-match.rs:24:5
@@ -121,11 +121,11 @@ LL |     Foo(bool),
    = note: the matched value is of type `NonEmptyEnum1`
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern
 
-error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
+error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
   --> $DIR/empty-match.rs:84:20
    |
 LL |     match_no_arms!(NonEmptyEnum2::Foo(true));
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
    |
 note: `NonEmptyEnum2` defined here
   --> $DIR/empty-match.rs:27:5
@@ -139,11 +139,11 @@ LL |     Bar,
    = note: the matched value is of type `NonEmptyEnum2`
    = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms
 
-error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
+error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
   --> $DIR/empty-match.rs:85:20
    |
 LL |     match_no_arms!(NonEmptyEnum5::V1);
-   |                    ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+   |                    ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
    |
 note: `NonEmptyEnum5` defined here
   --> $DIR/empty-match.rs:30:6
@@ -238,11 +238,11 @@ LL ~             _ if false => {}
 LL +             NonEmptyUnion2 { .. } => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
+error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered
   --> $DIR/empty-match.rs:92:24
    |
 LL |     match_guarded_arm!(NonEmptyEnum1::Foo(true));
-   |                        ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered
    |
 note: `NonEmptyEnum1` defined here
   --> $DIR/empty-match.rs:24:5
@@ -255,14 +255,14 @@ LL |     Foo(bool),
 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 ~             _ if false => {}
-LL +             Foo(_) => todo!()
+LL +             NonEmptyEnum1::Foo(_) => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
+error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
   --> $DIR/empty-match.rs:93:24
    |
 LL |     match_guarded_arm!(NonEmptyEnum2::Foo(true));
-   |                        ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
    |
 note: `NonEmptyEnum2` defined here
   --> $DIR/empty-match.rs:27:5
@@ -277,14 +277,14 @@ LL |     Bar,
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~             _ if false => {}
-LL +             Foo(_) | Bar => todo!()
+LL +             NonEmptyEnum2::Foo(_) | NonEmptyEnum2::Bar => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
+error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
   --> $DIR/empty-match.rs:94:24
    |
 LL |     match_guarded_arm!(NonEmptyEnum5::V1);
-   |                        ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
+   |                        ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
    |
 note: `NonEmptyEnum5` defined here
   --> $DIR/empty-match.rs:30:6
diff --git a/src/test/ui/pattern/usefulness/empty-match.rs b/src/test/ui/pattern/usefulness/empty-match.rs
index 8110ec013d7..9cdc0413ba1 100644
--- a/src/test/ui/pattern/usefulness/empty-match.rs
+++ b/src/test/ui/pattern/usefulness/empty-match.rs
@@ -80,16 +80,16 @@ fn main() {
     match_no_arms!(NonEmptyStruct2(true)); //~ ERROR type `NonEmptyStruct2` is non-empty
     match_no_arms!((NonEmptyUnion1 { foo: () })); //~ ERROR type `NonEmptyUnion1` is non-empty
     match_no_arms!((NonEmptyUnion2 { foo: () })); //~ ERROR type `NonEmptyUnion2` is non-empty
-    match_no_arms!(NonEmptyEnum1::Foo(true)); //~ ERROR `Foo(_)` not covered
-    match_no_arms!(NonEmptyEnum2::Foo(true)); //~ ERROR `Foo(_)` and `Bar` not covered
-    match_no_arms!(NonEmptyEnum5::V1); //~ ERROR `V1`, `V2`, `V3` and 2 more not covered
+    match_no_arms!(NonEmptyEnum1::Foo(true)); //~ ERROR `NonEmptyEnum1::Foo(_)` not covered
+    match_no_arms!(NonEmptyEnum2::Foo(true)); //~ ERROR `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
+    match_no_arms!(NonEmptyEnum5::V1); //~ ERROR `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
 
     match_guarded_arm!(0u8); //~ ERROR `_` not covered
     match_guarded_arm!(NonEmptyStruct1); //~ ERROR `NonEmptyStruct1` not covered
     match_guarded_arm!(NonEmptyStruct2(true)); //~ ERROR `NonEmptyStruct2(_)` not covered
     match_guarded_arm!((NonEmptyUnion1 { foo: () })); //~ ERROR `NonEmptyUnion1 { .. }` not covered
     match_guarded_arm!((NonEmptyUnion2 { foo: () })); //~ ERROR `NonEmptyUnion2 { .. }` not covered
-    match_guarded_arm!(NonEmptyEnum1::Foo(true)); //~ ERROR `Foo(_)` not covered
-    match_guarded_arm!(NonEmptyEnum2::Foo(true)); //~ ERROR `Foo(_)` and `Bar` not covered
-    match_guarded_arm!(NonEmptyEnum5::V1); //~ ERROR `V1`, `V2`, `V3` and 2 more not covered
+    match_guarded_arm!(NonEmptyEnum1::Foo(true)); //~ ERROR `NonEmptyEnum1::Foo(_)` not covered
+    match_guarded_arm!(NonEmptyEnum2::Foo(true)); //~ ERROR `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered
+    match_guarded_arm!(NonEmptyEnum5::V1); //~ ERROR `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered
 }
diff --git a/src/test/ui/pattern/usefulness/issue-15129.rs b/src/test/ui/pattern/usefulness/issue-15129.rs
index d2b72a86b74..f02e5c0c6f8 100644
--- a/src/test/ui/pattern/usefulness/issue-15129.rs
+++ b/src/test/ui/pattern/usefulness/issue-15129.rs
@@ -10,7 +10,7 @@ pub enum V {
 
 fn main() {
     match (T::T1(()), V::V2(true)) {
-        //~^ ERROR non-exhaustive patterns: `(T1(()), V2(_))` and `(T2(()), V1(_))` not covered
+        //~^ ERROR non-exhaustive patterns: `(T::T1(()), V::V2(_))` and `(T::T2(()), V::V1(_))` not covered
         (T::T1(()), V::V1(i)) => (),
         (T::T2(()), V::V2(b)) => (),
     }
diff --git a/src/test/ui/pattern/usefulness/issue-15129.stderr b/src/test/ui/pattern/usefulness/issue-15129.stderr
index af60f3ff50b..ee8410b7650 100644
--- a/src/test/ui/pattern/usefulness/issue-15129.stderr
+++ b/src/test/ui/pattern/usefulness/issue-15129.stderr
@@ -1,14 +1,14 @@
-error[E0004]: non-exhaustive patterns: `(T1(()), V2(_))` and `(T2(()), V1(_))` not covered
+error[E0004]: non-exhaustive patterns: `(T::T1(()), V::V2(_))` and `(T::T2(()), V::V1(_))` not covered
   --> $DIR/issue-15129.rs:12:11
    |
 LL |     match (T::T1(()), V::V2(true)) {
-   |           ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `(T1(()), V2(_))` and `(T2(()), V1(_))` not covered
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `(T::T1(()), V::V2(_))` and `(T::T2(()), V::V1(_))` not covered
    |
    = note: the matched value is of type `(T, V)`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~         (T::T2(()), V::V2(b)) => (),
-LL ~         (T1(()), V2(_)) | (T2(()), V1(_)) => todo!(),
+LL ~         (T::T1(()), V::V2(_)) | (T::T2(()), V::V1(_)) => todo!(),
    |
 
 error: aborting due to previous error
diff --git a/src/test/ui/pattern/usefulness/issue-31561.rs b/src/test/ui/pattern/usefulness/issue-31561.rs
index 813b2409cc8..5b878851a31 100644
--- a/src/test/ui/pattern/usefulness/issue-31561.rs
+++ b/src/test/ui/pattern/usefulness/issue-31561.rs
@@ -6,5 +6,5 @@ enum Thing {
 
 fn main() {
     let Thing::Foo(y) = Thing::Foo(1);
-    //~^ ERROR refutable pattern in local binding: `Bar` and `Baz` not covered
+    //~^ ERROR refutable pattern in local binding: `Thing::Bar` and `Thing::Baz` not covered
 }
diff --git a/src/test/ui/pattern/usefulness/issue-31561.stderr b/src/test/ui/pattern/usefulness/issue-31561.stderr
index 9da6b5eeead..46aebccc5ff 100644
--- a/src/test/ui/pattern/usefulness/issue-31561.stderr
+++ b/src/test/ui/pattern/usefulness/issue-31561.stderr
@@ -1,8 +1,8 @@
-error[E0005]: refutable pattern in local binding: `Bar` and `Baz` not covered
+error[E0005]: refutable pattern in local binding: `Thing::Bar` and `Thing::Baz` not covered
   --> $DIR/issue-31561.rs:8:9
    |
 LL |     let Thing::Foo(y) = Thing::Foo(1);
-   |         ^^^^^^^^^^^^^ patterns `Bar` and `Baz` not covered
+   |         ^^^^^^^^^^^^^ patterns `Thing::Bar` and `Thing::Baz` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
diff --git a/src/test/ui/pattern/usefulness/issue-35609.stderr b/src/test/ui/pattern/usefulness/issue-35609.stderr
index 2247b818d43..c9781d52e6d 100644
--- a/src/test/ui/pattern/usefulness/issue-35609.stderr
+++ b/src/test/ui/pattern/usefulness/issue-35609.stderr
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: `(B, _)`, `(C, _)`, `(D, _)` and 2 more not covered
+error[E0004]: non-exhaustive patterns: `(Enum::B, _)`, `(Enum::C, _)`, `(Enum::D, _)` and 2 more not covered
   --> $DIR/issue-35609.rs:10:11
    |
 LL |     match (A, ()) {
-   |           ^^^^^^^ patterns `(B, _)`, `(C, _)`, `(D, _)` and 2 more not covered
+   |           ^^^^^^^ patterns `(Enum::B, _)`, `(Enum::C, _)`, `(Enum::D, _)` and 2 more not covered
    |
    = note: the matched value is of type `(Enum, ())`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
@@ -11,11 +11,11 @@ LL ~         (A, _) => {}
 LL +         _ => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `(_, B)`, `(_, C)`, `(_, D)` and 2 more not covered
+error[E0004]: non-exhaustive patterns: `(_, Enum::B)`, `(_, Enum::C)`, `(_, Enum::D)` and 2 more not covered
   --> $DIR/issue-35609.rs:14:11
    |
 LL |     match (A, A) {
-   |           ^^^^^^ patterns `(_, B)`, `(_, C)`, `(_, D)` and 2 more not covered
+   |           ^^^^^^ patterns `(_, Enum::B)`, `(_, Enum::C)`, `(_, Enum::D)` and 2 more not covered
    |
    = note: the matched value is of type `(Enum, Enum)`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
@@ -24,11 +24,11 @@ LL ~         (_, A) => {}
 LL +         _ => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
+error[E0004]: non-exhaustive patterns: `((Enum::B, _), _)`, `((Enum::C, _), _)`, `((Enum::D, _), _)` and 2 more not covered
   --> $DIR/issue-35609.rs:18:11
    |
 LL |     match ((A, ()), ()) {
-   |           ^^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
+   |           ^^^^^^^^^^^^^ patterns `((Enum::B, _), _)`, `((Enum::C, _), _)`, `((Enum::D, _), _)` and 2 more not covered
    |
    = note: the matched value is of type `((Enum, ()), ())`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
@@ -37,11 +37,11 @@ LL ~         ((A, ()), _) => {}
 LL +         _ => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
+error[E0004]: non-exhaustive patterns: `((Enum::B, _), _)`, `((Enum::C, _), _)`, `((Enum::D, _), _)` and 2 more not covered
   --> $DIR/issue-35609.rs:22:11
    |
 LL |     match ((A, ()), A) {
-   |           ^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
+   |           ^^^^^^^^^^^^ patterns `((Enum::B, _), _)`, `((Enum::C, _), _)`, `((Enum::D, _), _)` and 2 more not covered
    |
    = note: the matched value is of type `((Enum, ()), Enum)`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
@@ -50,11 +50,11 @@ LL ~         ((A, ()), _) => {}
 LL +         _ => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
+error[E0004]: non-exhaustive patterns: `((Enum::B, _), _)`, `((Enum::C, _), _)`, `((Enum::D, _), _)` and 2 more not covered
   --> $DIR/issue-35609.rs:26:11
    |
 LL |     match ((A, ()), ()) {
-   |           ^^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
+   |           ^^^^^^^^^^^^^ patterns `((Enum::B, _), _)`, `((Enum::C, _), _)`, `((Enum::D, _), _)` and 2 more not covered
    |
    = note: the matched value is of type `((Enum, ()), ())`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
@@ -63,11 +63,11 @@ LL ~         ((A, _), _) => {}
 LL +         _ => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `S(B, _)`, `S(C, _)`, `S(D, _)` and 2 more not covered
+error[E0004]: non-exhaustive patterns: `S(Enum::B, _)`, `S(Enum::C, _)`, `S(Enum::D, _)` and 2 more not covered
   --> $DIR/issue-35609.rs:31:11
    |
 LL |     match S(A, ()) {
-   |           ^^^^^^^^ patterns `S(B, _)`, `S(C, _)`, `S(D, _)` and 2 more not covered
+   |           ^^^^^^^^ patterns `S(Enum::B, _)`, `S(Enum::C, _)`, `S(Enum::D, _)` and 2 more not covered
    |
 note: `S` defined here
   --> $DIR/issue-35609.rs:6:8
@@ -81,11 +81,11 @@ LL ~         S(A, _) => {}
 LL +         _ => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `Sd { x: B, .. }`, `Sd { x: C, .. }`, `Sd { x: D, .. }` and 2 more not covered
+error[E0004]: non-exhaustive patterns: `Sd { x: Enum::B, .. }`, `Sd { x: Enum::C, .. }`, `Sd { x: Enum::D, .. }` and 2 more not covered
   --> $DIR/issue-35609.rs:35:11
    |
 LL |     match (Sd { x: A, y: () }) {
-   |           ^^^^^^^^^^^^^^^^^^^^ patterns `Sd { x: B, .. }`, `Sd { x: C, .. }`, `Sd { x: D, .. }` and 2 more not covered
+   |           ^^^^^^^^^^^^^^^^^^^^ patterns `Sd { x: Enum::B, .. }`, `Sd { x: Enum::C, .. }`, `Sd { x: Enum::D, .. }` and 2 more not covered
    |
 note: `Sd` defined here
   --> $DIR/issue-35609.rs:7:8
@@ -99,11 +99,11 @@ LL ~         Sd { x: A, y: _ } => {}
 LL +         _ => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `Some(B)`, `Some(C)`, `Some(D)` and 2 more not covered
+error[E0004]: non-exhaustive patterns: `Some(Enum::B)`, `Some(Enum::C)`, `Some(Enum::D)` and 2 more not covered
   --> $DIR/issue-35609.rs:39:11
    |
 LL |     match Some(A) {
-   |           ^^^^^^^ patterns `Some(B)`, `Some(C)`, `Some(D)` and 2 more not covered
+   |           ^^^^^^^ patterns `Some(Enum::B)`, `Some(Enum::C)`, `Some(Enum::D)` and 2 more not covered
    |
 note: `Option<Enum>` defined here
   --> $SRC_DIR/core/src/option.rs:LL:COL
diff --git a/src/test/ui/pattern/usefulness/issue-39362.stderr b/src/test/ui/pattern/usefulness/issue-39362.stderr
index ca37af6fb80..b8b17918aef 100644
--- a/src/test/ui/pattern/usefulness/issue-39362.stderr
+++ b/src/test/ui/pattern/usefulness/issue-39362.stderr
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered
+error[E0004]: non-exhaustive patterns: `Foo::Bar { bar: Bar::C, .. }`, `Foo::Bar { bar: Bar::D, .. }`, `Foo::Bar { bar: Bar::E, .. }` and 1 more not covered
   --> $DIR/issue-39362.rs:10:11
    |
 LL |     match f {
-   |           ^ patterns `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered
+   |           ^ patterns `Foo::Bar { bar: Bar::C, .. }`, `Foo::Bar { bar: Bar::D, .. }`, `Foo::Bar { bar: Bar::E, .. }` and 1 more not covered
    |
 note: `Foo` defined here
   --> $DIR/issue-39362.rs:2:5
diff --git a/src/test/ui/pattern/usefulness/issue-40221.stderr b/src/test/ui/pattern/usefulness/issue-40221.stderr
index c477e435335..4973e42b054 100644
--- a/src/test/ui/pattern/usefulness/issue-40221.stderr
+++ b/src/test/ui/pattern/usefulness/issue-40221.stderr
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: `C(QA)` not covered
+error[E0004]: non-exhaustive patterns: `P::C(PC::QA)` not covered
   --> $DIR/issue-40221.rs:11:11
    |
 LL |     match proto {
-   |           ^^^^^ pattern `C(QA)` not covered
+   |           ^^^^^ pattern `P::C(PC::QA)` not covered
    |
 note: `P` defined here
   --> $DIR/issue-40221.rs:2:5
@@ -15,7 +15,7 @@ LL |     C(PC),
 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 ~         P::C(PC::Q) => (),
-LL ~         C(QA) => todo!(),
+LL ~         P::C(PC::QA) => todo!(),
    |
 
 error: aborting due to previous error
diff --git a/src/test/ui/pattern/usefulness/issue-50900.rs b/src/test/ui/pattern/usefulness/issue-50900.rs
index 27135af9575..9cc760e9a10 100644
--- a/src/test/ui/pattern/usefulness/issue-50900.rs
+++ b/src/test/ui/pattern/usefulness/issue-50900.rs
@@ -13,7 +13,7 @@ impl Tag {
 
 fn main() {
     match Tag::ExifIFDPointer {
-    //~^ ERROR: non-exhaustive patterns: `Tag(Exif, _)` not covered
+    //~^ ERROR: non-exhaustive patterns: `Tag(Context::Exif, _)` not covered
         Tag::ExifIFDPointer => {}
     }
 }
diff --git a/src/test/ui/pattern/usefulness/issue-50900.stderr b/src/test/ui/pattern/usefulness/issue-50900.stderr
index 2bdbecabbbe..348246d28aa 100644
--- a/src/test/ui/pattern/usefulness/issue-50900.stderr
+++ b/src/test/ui/pattern/usefulness/issue-50900.stderr
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: `Tag(Exif, _)` not covered
+error[E0004]: non-exhaustive patterns: `Tag(Context::Exif, _)` not covered
   --> $DIR/issue-50900.rs:15:11
    |
 LL |     match Tag::ExifIFDPointer {
-   |           ^^^^^^^^^^^^^^^^^^^ pattern `Tag(Exif, _)` not covered
+   |           ^^^^^^^^^^^^^^^^^^^ pattern `Tag(Context::Exif, _)` not covered
    |
 note: `Tag` defined here
   --> $DIR/issue-50900.rs:2:12
@@ -13,7 +13,7 @@ LL | pub struct Tag(pub Context, pub u16);
 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 ~         Tag::ExifIFDPointer => {}
-LL +         Tag(Exif, _) => todo!()
+LL +         Tag(Context::Exif, _) => todo!()
    |
 
 error: aborting due to previous error
diff --git a/src/test/ui/pattern/usefulness/issue-56379.rs b/src/test/ui/pattern/usefulness/issue-56379.rs
index 9bccccca9c2..097cf98d012 100644
--- a/src/test/ui/pattern/usefulness/issue-56379.rs
+++ b/src/test/ui/pattern/usefulness/issue-56379.rs
@@ -6,7 +6,7 @@ enum Foo {
 
 fn main() {
     match Foo::A(true) {
-        //~^ ERROR non-exhaustive patterns: `A(false)`, `B(false)` and `C(false)` not covered
+        //~^ ERROR non-exhaustive patterns: `Foo::A(false)`, `Foo::B(false)` and `Foo::C(false)` not covered
         Foo::A(true) => {}
         Foo::B(true) => {}
         Foo::C(true) => {}
diff --git a/src/test/ui/pattern/usefulness/issue-56379.stderr b/src/test/ui/pattern/usefulness/issue-56379.stderr
index f6261001c5e..6eed6bfae4c 100644
--- a/src/test/ui/pattern/usefulness/issue-56379.stderr
+++ b/src/test/ui/pattern/usefulness/issue-56379.stderr
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: `A(false)`, `B(false)` and `C(false)` not covered
+error[E0004]: non-exhaustive patterns: `Foo::A(false)`, `Foo::B(false)` and `Foo::C(false)` not covered
   --> $DIR/issue-56379.rs:8:11
    |
 LL |     match Foo::A(true) {
-   |           ^^^^^^^^^^^^ patterns `A(false)`, `B(false)` and `C(false)` not covered
+   |           ^^^^^^^^^^^^ patterns `Foo::A(false)`, `Foo::B(false)` and `Foo::C(false)` not covered
    |
 note: `Foo` defined here
   --> $DIR/issue-56379.rs:2:5
@@ -19,7 +19,7 @@ LL |     C(bool),
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~         Foo::C(true) => {}
-LL +         A(false) | B(false) | C(false) => todo!()
+LL +         Foo::A(false) | Foo::B(false) | Foo::C(false) => todo!()
    |
 
 error: aborting due to previous error
diff --git a/src/test/ui/pattern/usefulness/issue-72377.rs b/src/test/ui/pattern/usefulness/issue-72377.rs
index b0d8a53ed93..b5ad3075ca7 100644
--- a/src/test/ui/pattern/usefulness/issue-72377.rs
+++ b/src/test/ui/pattern/usefulness/issue-72377.rs
@@ -6,7 +6,7 @@ fn main() {
     let y = Some(X::A);
 
     match (x, y) {
-        //~^ ERROR non-exhaustive patterns: `(A, Some(A))`, `(A, Some(B))`, `(B, Some(B))` and 2
+        //~^ ERROR non-exhaustive patterns: `(X::A, Some(X::A))`, `(X::A, Some(X::B))`, `(X::B, Some(X::B))` and 2
         //~| more not covered
         (_, None) => false,
         (v, Some(w)) if v == w => true,
diff --git a/src/test/ui/pattern/usefulness/issue-72377.stderr b/src/test/ui/pattern/usefulness/issue-72377.stderr
index 20f002dd3db..123dd051d24 100644
--- a/src/test/ui/pattern/usefulness/issue-72377.stderr
+++ b/src/test/ui/pattern/usefulness/issue-72377.stderr
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: `(A, Some(A))`, `(A, Some(B))`, `(B, Some(B))` and 2 more not covered
+error[E0004]: non-exhaustive patterns: `(X::A, Some(X::A))`, `(X::A, Some(X::B))`, `(X::B, Some(X::B))` and 2 more not covered
   --> $DIR/issue-72377.rs:8:11
    |
 LL |     match (x, y) {
-   |           ^^^^^^ patterns `(A, Some(A))`, `(A, Some(B))`, `(B, Some(B))` and 2 more not covered
+   |           ^^^^^^ patterns `(X::A, Some(X::A))`, `(X::A, Some(X::B))`, `(X::B, Some(X::B))` and 2 more not covered
    |
    = note: the matched value is of type `(X, Option<X>)`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
diff --git a/src/test/ui/pattern/usefulness/match-arm-statics-2.rs b/src/test/ui/pattern/usefulness/match-arm-statics-2.rs
index 4c5f2d35649..3c9c16561c0 100644
--- a/src/test/ui/pattern/usefulness/match-arm-statics-2.rs
+++ b/src/test/ui/pattern/usefulness/match-arm-statics-2.rs
@@ -27,7 +27,7 @@ const EAST: Direction = East;
 
 fn nonexhaustive_2() {
     match Some(Some(North)) {
-    //~^ ERROR non-exhaustive patterns: `Some(Some(West))` not covered
+    //~^ ERROR non-exhaustive patterns: `Some(Some(Direction::West))` not covered
         Some(NONE) => (),
         Some(Some(North)) => (),
         Some(Some(EAST)) => (),
@@ -46,7 +46,7 @@ const STATIC_FOO: Foo = Foo { bar: None, baz: NEW_FALSE };
 
 fn nonexhaustive_3() {
     match (Foo { bar: Some(North), baz: NewBool(true) }) {
-    //~^ ERROR non-exhaustive patterns: `Foo { bar: Some(North), baz: NewBool(true) }`
+    //~^ ERROR non-exhaustive patterns: `Foo { bar: Some(Direction::North), baz: NewBool(true) }`
         Foo { bar: None, baz: NewBool(true) } => (),
         Foo { bar: _, baz: NEW_FALSE } => (),
         Foo { bar: Some(West), baz: NewBool(true) } => (),
diff --git a/src/test/ui/pattern/usefulness/match-arm-statics-2.stderr b/src/test/ui/pattern/usefulness/match-arm-statics-2.stderr
index a2b66f5ed67..b0d7fe5eb68 100644
--- a/src/test/ui/pattern/usefulness/match-arm-statics-2.stderr
+++ b/src/test/ui/pattern/usefulness/match-arm-statics-2.stderr
@@ -11,11 +11,11 @@ LL ~         (false, true) => (),
 LL +         (true, false) => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `Some(Some(West))` not covered
+error[E0004]: non-exhaustive patterns: `Some(Some(Direction::West))` not covered
   --> $DIR/match-arm-statics-2.rs:29:11
    |
 LL |     match Some(Some(North)) {
-   |           ^^^^^^^^^^^^^^^^^ pattern `Some(Some(West))` not covered
+   |           ^^^^^^^^^^^^^^^^^ pattern `Some(Some(Direction::West))` not covered
    |
 note: `Option<Option<Direction>>` defined here
   --> $SRC_DIR/core/src/option.rs:LL:COL
@@ -32,14 +32,14 @@ LL |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
 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(Some(West)) => todo!()
+LL +         Some(Some(Direction::West)) => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `Foo { bar: Some(North), baz: NewBool(true) }` not covered
+error[E0004]: non-exhaustive patterns: `Foo { bar: Some(Direction::North), baz: NewBool(true) }` not covered
   --> $DIR/match-arm-statics-2.rs:48:11
    |
 LL |     match (Foo { bar: Some(North), baz: NewBool(true) }) {
-   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { bar: Some(North), baz: NewBool(true) }` not covered
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { bar: Some(Direction::North), baz: NewBool(true) }` not covered
    |
 note: `Foo` defined here
   --> $DIR/match-arm-statics-2.rs:40:8
@@ -50,7 +50,7 @@ LL | struct Foo {
 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 ~         Foo { bar: Some(EAST), .. } => (),
-LL +         Foo { bar: Some(North), baz: NewBool(true) } => todo!()
+LL +         Foo { bar: Some(Direction::North), baz: NewBool(true) } => todo!()
    |
 
 error: aborting due to 3 previous errors
diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs b/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs
index 2e15bc2d2a5..af42fc1aeb4 100644
--- a/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs
+++ b/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs
@@ -35,43 +35,43 @@ enum E {
 
 fn by_val(e: E) {
     let e1 = e.clone();
-    match e1 { //~ ERROR non-exhaustive patterns: `B` and `C` not covered
-        //~^ NOTE patterns `B` and `C` not covered
+    match e1 { //~ ERROR non-exhaustive patterns: `E::B` and `E::C` not covered
+        //~^ NOTE patterns `E::B` and `E::C` not covered
         //~| NOTE the matched value is of type `E`
         E::A => {}
     }
 
-    let E::A = e; //~ ERROR refutable pattern in local binding: `B` and `C` not covered
-    //~^ NOTE patterns `B` and `C` not covered
+    let E::A = e; //~ ERROR refutable pattern in local binding: `E::B` and `E::C` not covered
+    //~^ NOTE patterns `E::B` and `E::C` not covered
     //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with
     //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
     //~| NOTE the matched value is of type `E`
 }
 
 fn by_ref_once(e: &E) {
-    match e { //~ ERROR non-exhaustive patterns: `&B` and `&C` not covered
-    //~^ NOTE patterns `&B` and `&C` not covered
+    match e { //~ ERROR non-exhaustive patterns: `&E::B` and `&E::C` not covered
+    //~^ NOTE patterns `&E::B` and `&E::C` not covered
     //~| NOTE the matched value is of type `&E`
         E::A => {}
     }
 
-    let E::A = e; //~ ERROR refutable pattern in local binding: `&B` and `&C` not covered
-    //~^ NOTE patterns `&B` and `&C` not covered
+    let E::A = e; //~ ERROR refutable pattern in local binding: `&E::B` and `&E::C` not covered
+    //~^ NOTE patterns `&E::B` and `&E::C` not covered
     //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with
     //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
     //~| NOTE the matched value is of type `&E`
 }
 
 fn by_ref_thrice(e: & &mut &E) {
-    match e { //~ ERROR non-exhaustive patterns: `&&mut &B` and `&&mut &C` not covered
-    //~^ NOTE patterns `&&mut &B` and `&&mut &C` not covered
+    match e { //~ ERROR non-exhaustive patterns: `&&mut &E::B` and `&&mut &E::C` not covered
+    //~^ NOTE patterns `&&mut &E::B` and `&&mut &E::C` not covered
     //~| NOTE the matched value is of type `&&mut &E`
         E::A => {}
     }
 
     let E::A = e;
-    //~^ ERROR refutable pattern in local binding: `&&mut &B` and `&&mut &C` not covered
-    //~| NOTE patterns `&&mut &B` and `&&mut &C` not covered
+    //~^ ERROR refutable pattern in local binding: `&&mut &E::B` and `&&mut &E::C` not covered
+    //~| NOTE patterns `&&mut &E::B` and `&&mut &E::C` not covered
     //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with
     //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
     //~| NOTE the matched value is of type `&&mut &E`
@@ -89,15 +89,15 @@ enum Opt {
 }
 
 fn ref_pat(e: Opt) {
-    match e {//~ ERROR non-exhaustive patterns: `None` not covered
-        //~^ NOTE pattern `None` not covered
+    match e {//~ ERROR non-exhaustive patterns: `Opt::None` not covered
+        //~^ NOTE pattern `Opt::None` not covered
         //~| NOTE the matched value is of type `Opt`
         Opt::Some(ref _x) => {}
     }
 
-    let Opt::Some(ref _x) = e; //~ ERROR refutable pattern in local binding: `None` not covered
+    let Opt::Some(ref _x) = e; //~ ERROR refutable pattern in local binding: `Opt::None` not covered
     //~^ NOTE the matched value is of type `Opt`
-    //~| NOTE pattern `None` not covered
+    //~| NOTE pattern `Opt::None` not covered
     //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with
     //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
 }
diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.stderr
index 0f06c31c468..ac2a9713e7d 100644
--- a/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.stderr
+++ b/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.stderr
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: `B` and `C` not covered
+error[E0004]: non-exhaustive patterns: `E::B` and `E::C` not covered
   --> $DIR/non-exhaustive-defined-here.rs:38:11
    |
 LL |     match e1 {
-   |           ^^ patterns `B` and `C` not covered
+   |           ^^ patterns `E::B` and `E::C` not covered
    |
 note: `E` defined here
   --> $DIR/non-exhaustive-defined-here.rs:14:5
@@ -19,14 +19,14 @@ LL |     C
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~         E::A => {}
-LL +         B | C => todo!()
+LL +         E::B | E::C => todo!()
    |
 
-error[E0005]: refutable pattern in local binding: `B` and `C` not covered
+error[E0005]: refutable pattern in local binding: `E::B` and `E::C` not covered
   --> $DIR/non-exhaustive-defined-here.rs:44:9
    |
 LL |     let E::A = e;
-   |         ^^^^ patterns `B` and `C` not covered
+   |         ^^^^ patterns `E::B` and `E::C` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
@@ -47,11 +47,11 @@ help: you might want to use `if let` to ignore the variants that aren't matched
 LL |     if let E::A = e { todo!() }
    |     ++              ~~~~~~~~~~~
 
-error[E0004]: non-exhaustive patterns: `&B` and `&C` not covered
+error[E0004]: non-exhaustive patterns: `&E::B` and `&E::C` not covered
   --> $DIR/non-exhaustive-defined-here.rs:52:11
    |
 LL |     match e {
-   |           ^ patterns `&B` and `&C` not covered
+   |           ^ patterns `&E::B` and `&E::C` not covered
    |
 note: `E` defined here
   --> $DIR/non-exhaustive-defined-here.rs:14:5
@@ -68,14 +68,14 @@ LL |     C
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~         E::A => {}
-LL +         &B | &C => todo!()
+LL +         &E::B | &E::C => todo!()
    |
 
-error[E0005]: refutable pattern in local binding: `&B` and `&C` not covered
+error[E0005]: refutable pattern in local binding: `&E::B` and `&E::C` not covered
   --> $DIR/non-exhaustive-defined-here.rs:58:9
    |
 LL |     let E::A = e;
-   |         ^^^^ patterns `&B` and `&C` not covered
+   |         ^^^^ patterns `&E::B` and `&E::C` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
@@ -96,11 +96,11 @@ help: you might want to use `if let` to ignore the variants that aren't matched
 LL |     if let E::A = e { todo!() }
    |     ++              ~~~~~~~~~~~
 
-error[E0004]: non-exhaustive patterns: `&&mut &B` and `&&mut &C` not covered
+error[E0004]: non-exhaustive patterns: `&&mut &E::B` and `&&mut &E::C` not covered
   --> $DIR/non-exhaustive-defined-here.rs:66:11
    |
 LL |     match e {
-   |           ^ patterns `&&mut &B` and `&&mut &C` not covered
+   |           ^ patterns `&&mut &E::B` and `&&mut &E::C` not covered
    |
 note: `E` defined here
   --> $DIR/non-exhaustive-defined-here.rs:14:5
@@ -117,14 +117,14 @@ LL |     C
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~         E::A => {}
-LL +         &&mut &B | &&mut &C => todo!()
+LL +         &&mut &E::B | &&mut &E::C => todo!()
    |
 
-error[E0005]: refutable pattern in local binding: `&&mut &B` and `&&mut &C` not covered
+error[E0005]: refutable pattern in local binding: `&&mut &E::B` and `&&mut &E::C` not covered
   --> $DIR/non-exhaustive-defined-here.rs:72:9
    |
 LL |     let E::A = e;
-   |         ^^^^ patterns `&&mut &B` and `&&mut &C` not covered
+   |         ^^^^ patterns `&&mut &E::B` and `&&mut &E::C` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
@@ -145,11 +145,11 @@ help: you might want to use `if let` to ignore the variants that aren't matched
 LL |     if let E::A = e { todo!() }
    |     ++              ~~~~~~~~~~~
 
-error[E0004]: non-exhaustive patterns: `None` not covered
+error[E0004]: non-exhaustive patterns: `Opt::None` not covered
   --> $DIR/non-exhaustive-defined-here.rs:92:11
    |
 LL |     match e {
-   |           ^ pattern `None` not covered
+   |           ^ pattern `Opt::None` not covered
    |
 note: `Opt` defined here
   --> $DIR/non-exhaustive-defined-here.rs:84:5
@@ -163,14 +163,14 @@ LL |     None,
 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 ~         Opt::Some(ref _x) => {}
-LL +         None => todo!()
+LL +         Opt::None => todo!()
    |
 
-error[E0005]: refutable pattern in local binding: `None` not covered
+error[E0005]: refutable pattern in local binding: `Opt::None` not covered
   --> $DIR/non-exhaustive-defined-here.rs:98:9
    |
 LL |     let Opt::Some(ref _x) = e;
-   |         ^^^^^^^^^^^^^^^^^ pattern `None` not covered
+   |         ^^^^^^^^^^^^^^^^^ pattern `Opt::None` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.rs b/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.rs
index d198144790b..69c3c76580a 100644
--- a/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.rs
+++ b/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.rs
@@ -12,7 +12,7 @@ fn match_nested_vecs<'a, T>(l1: Option<&'a [T]>, l2: Result<&'a [T], ()>) -> &'s
 
 fn main() {
     let x = T::A(U::C);
-    match x { //~ ERROR non-exhaustive patterns: `A(C)` not covered
+    match x { //~ ERROR non-exhaustive patterns: `T::A(U::C)` not covered
         T::A(U::D) => { panic!("hello"); }
         T::B => { panic!("goodbye"); }
     }
diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.stderr
index cbbd544f943..44f32742110 100644
--- a/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.stderr
+++ b/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.stderr
@@ -11,11 +11,11 @@ LL ~         (None, Ok(&[_, _, ..])) => "None, Ok(at least two elements)",
 LL +         (Some(&[]), Err(_)) => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `A(C)` not covered
+error[E0004]: non-exhaustive patterns: `T::A(U::C)` not covered
   --> $DIR/non-exhaustive-match-nested.rs:15:11
    |
 LL |     match x {
-   |           ^ pattern `A(C)` not covered
+   |           ^ pattern `T::A(U::C)` not covered
    |
 note: `T` defined here
   --> $DIR/non-exhaustive-match-nested.rs:1:10
@@ -26,7 +26,7 @@ LL | enum T { A(U), B }
 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 ~         T::B => { panic!("goodbye"); }
-LL +         A(C) => todo!()
+LL +         T::A(U::C) => todo!()
    |
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match.rs b/src/test/ui/pattern/usefulness/non-exhaustive-match.rs
index 4ff12aa2ff5..1cb58b8cebe 100644
--- a/src/test/ui/pattern/usefulness/non-exhaustive-match.rs
+++ b/src/test/ui/pattern/usefulness/non-exhaustive-match.rs
@@ -4,7 +4,7 @@ enum T { A, B }
 
 fn main() {
     let x = T::A;
-    match x { T::B => { } } //~ ERROR non-exhaustive patterns: `A` not covered
+    match x { T::B => { } } //~ ERROR non-exhaustive patterns: `T::A` not covered
     match true { //~ ERROR non-exhaustive patterns: `false` not covered
       true => {}
     }
@@ -15,11 +15,11 @@ fn main() {
                       //  and `(_, _, 5_i32..=i32::MAX)` not covered
       (_, _, 4) => {}
     }
-    match (T::A, T::A) { //~ ERROR non-exhaustive patterns: `(A, A)` and `(B, B)` not covered
+    match (T::A, T::A) { //~ ERROR non-exhaustive patterns: `(T::A, T::A)` and `(T::B, T::B)` not covered
       (T::A, T::B) => {}
       (T::B, T::A) => {}
     }
-    match T::A { //~ ERROR non-exhaustive patterns: `B` not covered
+    match T::A { //~ ERROR non-exhaustive patterns: `T::B` not covered
       T::A => {}
     }
     // This is exhaustive, though the algorithm got it wrong at one point
diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr
index f2362c316df..4234600d0d0 100644
--- a/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr
+++ b/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: `A` not covered
+error[E0004]: non-exhaustive patterns: `T::A` not covered
   --> $DIR/non-exhaustive-match.rs:7:11
    |
 LL |     match x { T::B => { } }
-   |           ^ pattern `A` not covered
+   |           ^ pattern `T::A` not covered
    |
 note: `T` defined here
   --> $DIR/non-exhaustive-match.rs:3:10
@@ -12,8 +12,8 @@ LL | enum T { A, B }
    = note: the matched value is of type `T`
 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 |     match x { T::B => { }, A => todo!() }
-   |                          ++++++++++++++
+LL |     match x { T::B => { }, T::A => todo!() }
+   |                          +++++++++++++++++
 
 error[E0004]: non-exhaustive patterns: `false` not covered
   --> $DIR/non-exhaustive-match.rs:8:11
@@ -62,24 +62,24 @@ LL ~       (_, _, 4) => {}
 LL +       (_, _, i32::MIN..=3_i32) | (_, _, 5_i32..=i32::MAX) => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `(A, A)` and `(B, B)` not covered
+error[E0004]: non-exhaustive patterns: `(T::A, T::A)` and `(T::B, T::B)` not covered
   --> $DIR/non-exhaustive-match.rs:18:11
    |
 LL |     match (T::A, T::A) {
-   |           ^^^^^^^^^^^^ patterns `(A, A)` and `(B, B)` not covered
+   |           ^^^^^^^^^^^^ patterns `(T::A, T::A)` and `(T::B, T::B)` not covered
    |
    = note: the matched value is of type `(T, T)`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~       (T::B, T::A) => {}
-LL +       (A, A) | (B, B) => todo!()
+LL +       (T::A, T::A) | (T::B, T::B) => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `B` not covered
+error[E0004]: non-exhaustive patterns: `T::B` not covered
   --> $DIR/non-exhaustive-match.rs:22:11
    |
 LL |     match T::A {
-   |           ^^^^ pattern `B` not covered
+   |           ^^^^ pattern `T::B` not covered
    |
 note: `T` defined here
   --> $DIR/non-exhaustive-match.rs:3:13
@@ -90,7 +90,7 @@ LL | enum T { A, B }
 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 ~       T::A => {}
-LL +       B => todo!()
+LL +       T::B => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `[]` not covered
diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.rs b/src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.rs
index abb4ea8daf5..4bd34421922 100644
--- a/src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.rs
+++ b/src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.rs
@@ -21,7 +21,7 @@ enum Color {
 
 fn enum_with_single_missing_variant() {
     match Color::Red {
-    //~^ ERROR non-exhaustive patterns: `Red` not covered
+    //~^ ERROR non-exhaustive patterns: `Color::Red` not covered
         Color::CustomRGBA { .. } => (),
         Color::Green => ()
     }
@@ -33,7 +33,7 @@ enum Direction {
 
 fn enum_with_multiple_missing_variants() {
     match Direction::North {
-    //~^ ERROR non-exhaustive patterns: `East`, `South` and `West` not covered
+    //~^ ERROR non-exhaustive patterns: `Direction::East`, `Direction::South` and `Direction::West` not covered
         Direction::North => ()
     }
 }
@@ -44,7 +44,7 @@ enum ExcessiveEnum {
 
 fn enum_with_excessive_missing_variants() {
     match ExcessiveEnum::First {
-    //~^ ERROR `Second`, `Third`, `Fourth` and 8 more not covered
+    //~^ ERROR `ExcessiveEnum::Second`, `ExcessiveEnum::Third`, `ExcessiveEnum::Fourth` and 8 more not covered
 
         ExcessiveEnum::First => ()
     }
@@ -52,7 +52,7 @@ fn enum_with_excessive_missing_variants() {
 
 fn enum_struct_variant() {
     match Color::Red {
-    //~^ ERROR non-exhaustive patterns: `CustomRGBA { a: true, .. }` not covered
+    //~^ ERROR non-exhaustive patterns: `Color::CustomRGBA { a: true, .. }` not covered
         Color::Red => (),
         Color::Green => (),
         Color::CustomRGBA { a: false, r: _, g: _, b: 0 } => (),
@@ -68,7 +68,7 @@ enum Enum {
 fn vectors_with_nested_enums() {
     let x: &'static [Enum] = &[Enum::First, Enum::Second(false)];
     match *x {
-    //~^ ERROR non-exhaustive patterns: `[Second(true), Second(false)]` not covered
+    //~^ ERROR non-exhaustive patterns: `[Enum::Second(true), Enum::Second(false)]` not covered
         [] => (),
         [_] => (),
         [Enum::First, _] => (),
diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr
index b0cfd631fb0..b8af566de7c 100644
--- a/src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr
+++ b/src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr
@@ -16,11 +16,11 @@ LL ~         Foo { first: false, second: Some([1, 2, 3, 4]) } => (),
 LL +         Foo { first: false, second: Some([_, _, _, _]) } => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `Red` not covered
+error[E0004]: non-exhaustive patterns: `Color::Red` not covered
   --> $DIR/non-exhaustive-pattern-witness.rs:23:11
    |
 LL |     match Color::Red {
-   |           ^^^^^^^^^^ pattern `Red` not covered
+   |           ^^^^^^^^^^ pattern `Color::Red` not covered
    |
 note: `Color` defined here
   --> $DIR/non-exhaustive-pattern-witness.rs:17:5
@@ -33,14 +33,14 @@ LL |     Red,
 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 ~         Color::Green => (),
-LL +         Red => todo!()
+LL +         Color::Red => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `East`, `South` and `West` not covered
+error[E0004]: non-exhaustive patterns: `Direction::East`, `Direction::South` and `Direction::West` not covered
   --> $DIR/non-exhaustive-pattern-witness.rs:35:11
    |
 LL |     match Direction::North {
-   |           ^^^^^^^^^^^^^^^^ patterns `East`, `South` and `West` not covered
+   |           ^^^^^^^^^^^^^^^^ patterns `Direction::East`, `Direction::South` and `Direction::West` not covered
    |
 note: `Direction` defined here
   --> $DIR/non-exhaustive-pattern-witness.rs:31:12
@@ -56,14 +56,14 @@ LL |     North, East, South, West
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~         Direction::North => (),
-LL +         East | South | West => todo!()
+LL +         Direction::East | Direction::South | Direction::West => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `Second`, `Third`, `Fourth` and 8 more not covered
+error[E0004]: non-exhaustive patterns: `ExcessiveEnum::Second`, `ExcessiveEnum::Third`, `ExcessiveEnum::Fourth` and 8 more not covered
   --> $DIR/non-exhaustive-pattern-witness.rs:46:11
    |
 LL |     match ExcessiveEnum::First {
-   |           ^^^^^^^^^^^^^^^^^^^^ patterns `Second`, `Third`, `Fourth` and 8 more not covered
+   |           ^^^^^^^^^^^^^^^^^^^^ patterns `ExcessiveEnum::Second`, `ExcessiveEnum::Third`, `ExcessiveEnum::Fourth` and 8 more not covered
    |
 note: `ExcessiveEnum` defined here
   --> $DIR/non-exhaustive-pattern-witness.rs:41:6
@@ -77,11 +77,11 @@ LL ~         ExcessiveEnum::First => (),
 LL +         _ => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `CustomRGBA { a: true, .. }` not covered
+error[E0004]: non-exhaustive patterns: `Color::CustomRGBA { a: true, .. }` not covered
   --> $DIR/non-exhaustive-pattern-witness.rs:54:11
    |
 LL |     match Color::Red {
-   |           ^^^^^^^^^^ pattern `CustomRGBA { a: true, .. }` not covered
+   |           ^^^^^^^^^^ pattern `Color::CustomRGBA { a: true, .. }` not covered
    |
 note: `Color` defined here
   --> $DIR/non-exhaustive-pattern-witness.rs:19:5
@@ -95,20 +95,20 @@ LL |     CustomRGBA { a: bool, r: u8, g: u8, b: u8 }
 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 ~         Color::CustomRGBA { a: false, r: _, g: _, b: _ } => (),
-LL +         CustomRGBA { a: true, .. } => todo!()
+LL +         Color::CustomRGBA { a: true, .. } => todo!()
    |
 
-error[E0004]: non-exhaustive patterns: `[Second(true), Second(false)]` not covered
+error[E0004]: non-exhaustive patterns: `[Enum::Second(true), Enum::Second(false)]` not covered
   --> $DIR/non-exhaustive-pattern-witness.rs:70:11
    |
 LL |     match *x {
-   |           ^^ pattern `[Second(true), Second(false)]` not covered
+   |           ^^ pattern `[Enum::Second(true), Enum::Second(false)]` not covered
    |
    = note: the matched value is of type `[Enum]`
 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 ~         [_, _, ref tail @ .., _] => (),
-LL +         [Second(true), Second(false)] => todo!()
+LL +         [Enum::Second(true), Enum::Second(false)] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `((), false)` not covered
diff --git a/src/test/ui/pattern/usefulness/stable-gated-patterns.rs b/src/test/ui/pattern/usefulness/stable-gated-patterns.rs
index ff1c472e24f..03db01160dd 100644
--- a/src/test/ui/pattern/usefulness/stable-gated-patterns.rs
+++ b/src/test/ui/pattern/usefulness/stable-gated-patterns.rs
@@ -8,7 +8,7 @@ fn main() {
     match UnstableEnum::Stable {
         UnstableEnum::Stable => {}
     }
-    //~^^^ non-exhaustive patterns: `Stable2` and `_` not covered
+    //~^^^ non-exhaustive patterns: `UnstableEnum::Stable2` and `_` not covered
 
     match UnstableEnum::Stable {
         UnstableEnum::Stable => {}
diff --git a/src/test/ui/pattern/usefulness/stable-gated-patterns.stderr b/src/test/ui/pattern/usefulness/stable-gated-patterns.stderr
index 98c75953add..7b8588a3c73 100644
--- a/src/test/ui/pattern/usefulness/stable-gated-patterns.stderr
+++ b/src/test/ui/pattern/usefulness/stable-gated-patterns.stderr
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: `Stable2` and `_` not covered
+error[E0004]: non-exhaustive patterns: `UnstableEnum::Stable2` and `_` not covered
   --> $DIR/stable-gated-patterns.rs:8:11
    |
 LL |     match UnstableEnum::Stable {
-   |           ^^^^^^^^^^^^^^^^^^^^ patterns `Stable2` and `_` not covered
+   |           ^^^^^^^^^^^^^^^^^^^^ patterns `UnstableEnum::Stable2` and `_` not covered
    |
 note: `UnstableEnum` defined here
   --> $DIR/auxiliary/unstable.rs:9:5
@@ -16,7 +16,7 @@ LL |     Stable2,
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~         UnstableEnum::Stable => {}
-LL +         Stable2 | _ => todo!()
+LL +         UnstableEnum::Stable2 | _ => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `_` not covered
diff --git a/src/test/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr b/src/test/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr
index 6127fad3f7d..85c97be29d6 100644
--- a/src/test/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr
+++ b/src/test/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: `B { x: Some(_) }` not covered
+error[E0004]: non-exhaustive patterns: `A::B { x: Some(_) }` not covered
   --> $DIR/struct-like-enum-nonexhaustive.rs:8:11
    |
 LL |     match x {
-   |           ^ pattern `B { x: Some(_) }` not covered
+   |           ^ pattern `A::B { x: Some(_) }` not covered
    |
 note: `A` defined here
   --> $DIR/struct-like-enum-nonexhaustive.rs:2:5
@@ -15,7 +15,7 @@ LL |     B { x: Option<isize> },
 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 ~         A::B { x: None } => {}
-LL +         B { x: Some(_) } => todo!()
+LL +         A::B { x: Some(_) } => todo!()
    |
 
 error: aborting due to previous error
diff --git a/src/test/ui/pattern/usefulness/unstable-gated-patterns.rs b/src/test/ui/pattern/usefulness/unstable-gated-patterns.rs
index bdab327fd57..7046555e0d2 100644
--- a/src/test/ui/pattern/usefulness/unstable-gated-patterns.rs
+++ b/src/test/ui/pattern/usefulness/unstable-gated-patterns.rs
@@ -11,7 +11,7 @@ fn main() {
         UnstableEnum::Stable => {}
         UnstableEnum::Stable2 => {}
     }
-    //~^^^^ non-exhaustive patterns: `Unstable` not covered
+    //~^^^^ non-exhaustive patterns: `UnstableEnum::Unstable` not covered
 
     // Ok: all variants are explicitly matched
     match UnstableEnum::Stable {
diff --git a/src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr b/src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr
index f07a25ca89b..6dc9a405839 100644
--- a/src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr
+++ b/src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr
@@ -1,8 +1,8 @@
-error[E0004]: non-exhaustive patterns: `Unstable` not covered
+error[E0004]: non-exhaustive patterns: `UnstableEnum::Unstable` not covered
   --> $DIR/unstable-gated-patterns.rs:10:11
    |
 LL |     match UnstableEnum::Stable {
-   |           ^^^^^^^^^^^^^^^^^^^^ pattern `Unstable` not covered
+   |           ^^^^^^^^^^^^^^^^^^^^ pattern `UnstableEnum::Unstable` not covered
    |
 note: `UnstableEnum` defined here
   --> $DIR/auxiliary/unstable.rs:11:5
@@ -16,7 +16,7 @@ LL |     Unstable,
 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 ~         UnstableEnum::Stable2 => {}
-LL +         Unstable => todo!()
+LL +         UnstableEnum::Unstable => todo!()
    |
 
 error: aborting due to previous error
diff --git a/src/test/ui/repr/invalid_repr_list_help.rs b/src/test/ui/repr/invalid_repr_list_help.rs
new file mode 100644
index 00000000000..c320984536c
--- /dev/null
+++ b/src/test/ui/repr/invalid_repr_list_help.rs
@@ -0,0 +1,17 @@
+#![crate_type = "lib"]
+
+#[repr(uwu)] //~ERROR: unrecognized representation hint
+pub struct OwO;
+
+#[repr(uwu = "a")] //~ERROR: unrecognized representation hint
+pub struct OwO2(i32);
+
+#[repr(uwu(4))] //~ERROR: unrecognized representation hint
+pub struct OwO3 {
+    x: i32,
+}
+
+#[repr(uwu, u8)] //~ERROR: unrecognized representation hint
+pub enum OwO4 {
+    UwU = 1,
+}
diff --git a/src/test/ui/repr/invalid_repr_list_help.stderr b/src/test/ui/repr/invalid_repr_list_help.stderr
new file mode 100644
index 00000000000..2acd56d9a32
--- /dev/null
+++ b/src/test/ui/repr/invalid_repr_list_help.stderr
@@ -0,0 +1,35 @@
+error[E0552]: unrecognized representation hint
+  --> $DIR/invalid_repr_list_help.rs:3:8
+   |
+LL | #[repr(uwu)]
+   |        ^^^
+   |
+   = help: valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
+
+error[E0552]: unrecognized representation hint
+  --> $DIR/invalid_repr_list_help.rs:6:8
+   |
+LL | #[repr(uwu = "a")]
+   |        ^^^^^^^^^
+   |
+   = help: valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
+
+error[E0552]: unrecognized representation hint
+  --> $DIR/invalid_repr_list_help.rs:9:8
+   |
+LL | #[repr(uwu(4))]
+   |        ^^^^^^
+   |
+   = help: valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
+
+error[E0552]: unrecognized representation hint
+  --> $DIR/invalid_repr_list_help.rs:14:8
+   |
+LL | #[repr(uwu, u8)]
+   |        ^^^
+   |
+   = help: valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0552`.
diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.rs b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.rs
index 70253a4fc90..69a283c3163 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.rs
@@ -31,7 +31,7 @@ fn empty_non_exhaustive(x: EmptyNonExhaustiveEnum) {
 
 fn main() {
     match NonExhaustiveEnum::Unit {}
-    //~^ ERROR `Unit`, `Tuple(_)` and `Struct { .. }` not covered [E0004]
+    //~^ ERROR `NonExhaustiveEnum::Unit`, `NonExhaustiveEnum::Tuple(_)` and `NonExhaustiveEnum::Struct { .. }` not covered [E0004]
     match NormalEnum::Unit {}
-    //~^ ERROR `Unit`, `Tuple(_)` and `Struct { .. }` not covered [E0004]
+    //~^ ERROR `NormalEnum::Unit`, `NormalEnum::Tuple(_)` and `NormalEnum::Struct { .. }` not covered [E0004]
 }
diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr
index 1f20904483f..de1bf8be885 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr
@@ -10,11 +10,11 @@ note: the lint level is defined here
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error[E0004]: non-exhaustive patterns: `Unit`, `Tuple(_)` and `Struct { .. }` not covered
+error[E0004]: non-exhaustive patterns: `NonExhaustiveEnum::Unit`, `NonExhaustiveEnum::Tuple(_)` and `NonExhaustiveEnum::Struct { .. }` not covered
   --> $DIR/enum_same_crate_empty_match.rs:33:11
    |
 LL |     match NonExhaustiveEnum::Unit {}
-   |           ^^^^^^^^^^^^^^^^^^^^^^^ patterns `Unit`, `Tuple(_)` and `Struct { .. }` not covered
+   |           ^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonExhaustiveEnum::Unit`, `NonExhaustiveEnum::Tuple(_)` and `NonExhaustiveEnum::Struct { .. }` not covered
    |
 note: `NonExhaustiveEnum` defined here
   --> $DIR/enum_same_crate_empty_match.rs:5:5
@@ -33,15 +33,15 @@ LL |     Struct { field: u32 }
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~     match NonExhaustiveEnum::Unit {
-LL +         Unit | Tuple(_) | Struct { .. } => todo!(),
+LL +         NonExhaustiveEnum::Unit | NonExhaustiveEnum::Tuple(_) | NonExhaustiveEnum::Struct { .. } => todo!(),
 LL +     }
    |
 
-error[E0004]: non-exhaustive patterns: `Unit`, `Tuple(_)` and `Struct { .. }` not covered
+error[E0004]: non-exhaustive patterns: `NormalEnum::Unit`, `NormalEnum::Tuple(_)` and `NormalEnum::Struct { .. }` not covered
   --> $DIR/enum_same_crate_empty_match.rs:35:11
    |
 LL |     match NormalEnum::Unit {}
-   |           ^^^^^^^^^^^^^^^^ patterns `Unit`, `Tuple(_)` and `Struct { .. }` not covered
+   |           ^^^^^^^^^^^^^^^^ patterns `NormalEnum::Unit`, `NormalEnum::Tuple(_)` and `NormalEnum::Struct { .. }` not covered
    |
 note: `NormalEnum` defined here
   --> $DIR/enum_same_crate_empty_match.rs:14:5
@@ -60,7 +60,7 @@ LL |     Struct { field: u32 }
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~     match NormalEnum::Unit {
-LL +         Unit | Tuple(_) | Struct { .. } => todo!(),
+LL +         NormalEnum::Unit | NormalEnum::Tuple(_) | NormalEnum::Struct { .. } => todo!(),
 LL +     }
    |
 
diff --git a/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr
index a9885449f3f..4b9f8564d23 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr
@@ -81,7 +81,7 @@ error: some variants are not matched explicitly
   --> $DIR/omitted-patterns.rs:58:9
    |
 LL |         _ => {}
-   |         ^ pattern `Struct { .. }` not covered
+   |         ^ pattern `NonExhaustiveEnum::Struct { .. }` not covered
    |
 note: the lint level is defined here
   --> $DIR/omitted-patterns.rs:57:16
@@ -95,7 +95,7 @@ error: some variants are not matched explicitly
   --> $DIR/omitted-patterns.rs:65:9
    |
 LL |         _ => {}
-   |         ^ pattern `Tuple(_)` not covered
+   |         ^ pattern `NonExhaustiveEnum::Tuple(_)` not covered
    |
 note: the lint level is defined here
   --> $DIR/omitted-patterns.rs:64:16
@@ -109,7 +109,7 @@ error: some variants are not matched explicitly
   --> $DIR/omitted-patterns.rs:75:9
    |
 LL |         _ => {}
-   |         ^ pattern `Unit` not covered
+   |         ^ pattern `NonExhaustiveEnum::Unit` not covered
    |
 note: the lint level is defined here
   --> $DIR/omitted-patterns.rs:74:16
@@ -123,7 +123,7 @@ error: some variants are not matched explicitly
   --> $DIR/omitted-patterns.rs:92:32
    |
 LL |         NestedNonExhaustive::A(_) => {}
-   |                                ^ patterns `Tuple(_)` and `Struct { .. }` not covered
+   |                                ^ patterns `NonExhaustiveEnum::Tuple(_)` and `NonExhaustiveEnum::Struct { .. }` not covered
    |
 note: the lint level is defined here
   --> $DIR/omitted-patterns.rs:89:12
@@ -137,7 +137,7 @@ error: some variants are not matched explicitly
   --> $DIR/omitted-patterns.rs:94:9
    |
 LL |         _ => {}
-   |         ^ pattern `C` not covered
+   |         ^ pattern `NestedNonExhaustive::C` not covered
    |
    = help: ensure that all variants are matched explicitly by adding the suggested match arms
    = note: the matched value is of type `NestedNonExhaustive` and the `non_exhaustive_omitted_patterns` attribute was found
@@ -146,7 +146,7 @@ error: some variants are not matched explicitly
   --> $DIR/omitted-patterns.rs:132:9
    |
 LL |         _ => {}
-   |         ^ pattern `A(_)` not covered
+   |         ^ pattern `NonExhaustiveSingleVariant::A(_)` not covered
    |
 note: the lint level is defined here
   --> $DIR/omitted-patterns.rs:130:12
@@ -160,7 +160,7 @@ error: some variants are not matched explicitly
   --> $DIR/omitted-patterns.rs:144:9
    |
 LL |         _ => {}
-   |         ^ pattern `Unstable` not covered
+   |         ^ pattern `UnstableEnum::Unstable` not covered
    |
 note: the lint level is defined here
   --> $DIR/omitted-patterns.rs:143:16
@@ -174,7 +174,7 @@ error: some variants are not matched explicitly
   --> $DIR/omitted-patterns.rs:168:9
    |
 LL |         _ => {}
-   |         ^ pattern `Unstable2` not covered
+   |         ^ pattern `OnlyUnstableEnum::Unstable2` not covered
    |
 note: the lint level is defined here
   --> $DIR/omitted-patterns.rs:165:12
diff --git a/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr
index 7cce178988a..533e8abf2d6 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr
@@ -16,7 +16,7 @@ error: some variants are not matched explicitly
   --> $DIR/stable-omitted-patterns.rs:23:9
    |
 LL |         _ => {}
-   |         ^ pattern `Stable2` not covered
+   |         ^ pattern `UnstableEnum::Stable2` not covered
    |
 note: the lint level is defined here
   --> $DIR/stable-omitted-patterns.rs:22:16
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr
index 32a5c07f196..a9c54af0418 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr
@@ -55,11 +55,11 @@ LL +         _ => todo!(),
 LL ~     }
    |
 
-error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered
+error[E0004]: non-exhaustive patterns: `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered
   --> $DIR/match.rs:31:11
    |
 LL |     match x {}
-   |           ^ patterns `Tuple(_)` and `Struct { .. }` not covered
+   |           ^ patterns `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered
    |
 note: `UninhabitedVariants` defined here
   --> $DIR/auxiliary/uninhabited.rs:17:23
@@ -74,7 +74,7 @@ LL |     #[non_exhaustive] Struct { x: ! }
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~     match x {
-LL +         Tuple(_) | Struct { .. } => todo!(),
+LL +         UninhabitedVariants::Tuple(_) | UninhabitedVariants::Struct { .. } => todo!(),
 LL ~     }
    |
 
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr
index c89c70ae6cc..ec2a2f6f055 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr
@@ -36,11 +36,11 @@ LL +         _ => todo!(),
 LL ~     }
    |
 
-error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered
+error[E0004]: non-exhaustive patterns: `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered
   --> $DIR/match_same_crate.rs:38:11
    |
 LL |     match x {}
-   |           ^ patterns `Tuple(_)` and `Struct { .. }` not covered
+   |           ^ patterns `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered
    |
 note: `UninhabitedVariants` defined here
   --> $DIR/match_same_crate.rs:16:23
@@ -55,7 +55,7 @@ LL |     #[non_exhaustive] Struct { x: ! }
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~     match x {
-LL +         Tuple(_) | Struct { .. } => todo!(),
+LL +         UninhabitedVariants::Tuple(_) | UninhabitedVariants::Struct { .. } => todo!(),
 LL ~     }
    |
 
diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr
index d854ea28ff6..b6b777ec56c 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr
@@ -55,11 +55,11 @@ LL +         _ => todo!(),
 LL ~     }
    |
 
-error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered
+error[E0004]: non-exhaustive patterns: `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered
   --> $DIR/match_with_exhaustive_patterns.rs:34:11
    |
 LL |     match x {}
-   |           ^ patterns `Tuple(_)` and `Struct { .. }` not covered
+   |           ^ patterns `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered
    |
 note: `UninhabitedVariants` defined here
   --> $DIR/auxiliary/uninhabited.rs:17:23
@@ -74,7 +74,7 @@ LL |     #[non_exhaustive] Struct { x: ! }
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~     match x {
-LL +         Tuple(_) | Struct { .. } => todo!(),
+LL +         UninhabitedVariants::Tuple(_) | UninhabitedVariants::Struct { .. } => todo!(),
 LL ~     }
    |
 
diff --git a/src/test/ui/sanitize/memory-eager.rs b/src/test/ui/sanitize/memory-eager.rs
new file mode 100644
index 00000000000..8a0590bf16c
--- /dev/null
+++ b/src/test/ui/sanitize/memory-eager.rs
@@ -0,0 +1,38 @@
+// needs-sanitizer-support
+// needs-sanitizer-memory
+// min-llvm-version: 14.0.0
+//
+// revisions: unoptimized optimized
+//
+// [optimized]compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins -O
+// [unoptimized]compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins
+//
+// run-fail
+// error-pattern: MemorySanitizer: use-of-uninitialized-value
+// error-pattern: Uninitialized value was created by an allocation
+// error-pattern: in the stack frame of function 'random'
+//
+// This test case intentionally limits the usage of the std,
+// since it will be linked with an uninstrumented version of it.
+
+#![feature(core_intrinsics)]
+#![feature(start)]
+#![feature(bench_black_box)]
+
+use std::hint::black_box;
+use std::mem::MaybeUninit;
+
+#[inline(never)]
+#[no_mangle]
+#[allow(invalid_value)]
+fn random() -> char {
+    let r = unsafe { MaybeUninit::uninit().assume_init() };
+    // Avoid optimizing everything out.
+    black_box(r)
+}
+
+#[start]
+fn main(_: isize, _: *const *const u8) -> isize {
+    random();
+    0
+}
diff --git a/src/test/ui/sanitize/memory.rs b/src/test/ui/sanitize/memory.rs
index adda51f6be0..14d4de65dd3 100644
--- a/src/test/ui/sanitize/memory.rs
+++ b/src/test/ui/sanitize/memory.rs
@@ -1,7 +1,10 @@
 // needs-sanitizer-support
 // needs-sanitizer-memory
 //
-// compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins -O
+// revisions: unoptimized optimized
+//
+// [optimized]compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins -O
+// [unoptimized]compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins
 //
 // run-fail
 // error-pattern: MemorySanitizer: use-of-uninitialized-value
@@ -22,9 +25,9 @@ use std::mem::MaybeUninit;
 #[inline(never)]
 #[no_mangle]
 fn random() -> [isize; 32] {
-    let r = unsafe { MaybeUninit::uninit().assume_init() };
+    let r = MaybeUninit::uninit();
     // Avoid optimizing everything out.
-    black_box(r)
+    unsafe { std::intrinsics::volatile_load(r.as_ptr()) }
 }
 
 #[inline(never)]
@@ -39,6 +42,6 @@ fn xor(a: &[isize]) -> isize {
 
 #[start]
 fn main(_: isize, _: *const *const u8) -> isize {
-    let r = random();
+    let r = black_box(random as fn() -> [isize; 32])();
     xor(&r)
 }
diff --git a/src/test/ui/stats/hir-stats.rs b/src/test/ui/stats/hir-stats.rs
index a24b3ada57e..5102574d4be 100644
--- a/src/test/ui/stats/hir-stats.rs
+++ b/src/test/ui/stats/hir-stats.rs
@@ -1,6 +1,7 @@
 // check-pass
 // compile-flags: -Zhir-stats
 // only-x86_64
+// ignore-stage1
 
 // The aim here is to include at least one of every different type of top-level
 // AST/HIR node reported by `-Zhir-stats`.
diff --git a/src/test/ui/stats/hir-stats.stderr b/src/test/ui/stats/hir-stats.stderr
index 78f70997555..8d977606530 100644
--- a/src/test/ui/stats/hir-stats.stderr
+++ b/src/test/ui/stats/hir-stats.stderr
@@ -21,39 +21,39 @@ ast-stats-1 - MacCall                   32 ( 0.4%)             1
 ast-stats-1 - Expr                      96 ( 1.1%)             3
 ast-stats-1 Param                    160 ( 1.9%)             4            40
 ast-stats-1 FnDecl                   200 ( 2.4%)             5            40
-ast-stats-1 Variant                  240 ( 2.8%)             2           120
+ast-stats-1 Variant                  240 ( 2.9%)             2           120
 ast-stats-1 Block                    288 ( 3.4%)             6            48
 ast-stats-1 GenericBound             352 ( 4.2%)             4            88
 ast-stats-1 - Trait                    352 ( 4.2%)             4
 ast-stats-1 AssocItem                416 ( 4.9%)             4           104
 ast-stats-1 - TyAlias                  208 ( 2.5%)             2
 ast-stats-1 - Fn                       208 ( 2.5%)             2
-ast-stats-1 GenericParam             520 ( 6.1%)             5           104
-ast-stats-1 PathSegment              720 ( 8.5%)            30            24
-ast-stats-1 Expr                     832 ( 9.8%)             8           104
+ast-stats-1 GenericParam             480 ( 5.7%)             5            96
+ast-stats-1 PathSegment              720 ( 8.6%)            30            24
+ast-stats-1 Expr                     832 ( 9.9%)             8           104
 ast-stats-1 - Path                     104 ( 1.2%)             1
 ast-stats-1 - Match                    104 ( 1.2%)             1
 ast-stats-1 - Struct                   104 ( 1.2%)             1
 ast-stats-1 - Lit                      208 ( 2.5%)             2
 ast-stats-1 - Block                    312 ( 3.7%)             3
-ast-stats-1 Pat                      840 ( 9.9%)             7           120
+ast-stats-1 Pat                      840 (10.0%)             7           120
 ast-stats-1 - Struct                   120 ( 1.4%)             1
 ast-stats-1 - Wild                     120 ( 1.4%)             1
 ast-stats-1 - Ident                    600 ( 7.1%)             5
-ast-stats-1 Ty                     1_344 (15.9%)            14            96
+ast-stats-1 Ty                     1_344 (16.0%)            14            96
 ast-stats-1 - Rptr                      96 ( 1.1%)             1
 ast-stats-1 - Ptr                       96 ( 1.1%)             1
 ast-stats-1 - ImplicitSelf             192 ( 2.3%)             2
 ast-stats-1 - Path                     960 (11.4%)            10
-ast-stats-1 Item                   1_656 (19.6%)             9           184
+ast-stats-1 Item                   1_656 (19.7%)             9           184
 ast-stats-1 - Trait                    184 ( 2.2%)             1
 ast-stats-1 - Enum                     184 ( 2.2%)             1
 ast-stats-1 - ForeignMod               184 ( 2.2%)             1
 ast-stats-1 - Impl                     184 ( 2.2%)             1
 ast-stats-1 - Fn                       368 ( 4.4%)             2
-ast-stats-1 - Use                      552 ( 6.5%)             3
+ast-stats-1 - Use                      552 ( 6.6%)             3
 ast-stats-1 ----------------------------------------------------------------
-ast-stats-1 Total                  8_456
+ast-stats-1 Total                  8_416
 ast-stats-1
 ast-stats-2 POST EXPANSION AST STATS
 ast-stats-2 Name                Accumulated Size         Count     Item Size
@@ -86,12 +86,12 @@ ast-stats-2 - Trait                    352 ( 3.8%)             4
 ast-stats-2 AssocItem                416 ( 4.5%)             4           104
 ast-stats-2 - TyAlias                  208 ( 2.3%)             2
 ast-stats-2 - Fn                       208 ( 2.3%)             2
-ast-stats-2 GenericParam             520 ( 5.7%)             5           104
-ast-stats-2 PathSegment              792 ( 8.6%)            33            24
-ast-stats-2 Pat                      840 ( 9.1%)             7           120
+ast-stats-2 GenericParam             480 ( 5.2%)             5            96
+ast-stats-2 PathSegment              792 ( 8.7%)            33            24
+ast-stats-2 Pat                      840 ( 9.2%)             7           120
 ast-stats-2 - Struct                   120 ( 1.3%)             1
 ast-stats-2 - Wild                     120 ( 1.3%)             1
-ast-stats-2 - Ident                    600 ( 6.5%)             5
+ast-stats-2 - Ident                    600 ( 6.6%)             5
 ast-stats-2 Expr                     936 (10.2%)             9           104
 ast-stats-2 - Path                     104 ( 1.1%)             1
 ast-stats-2 - Match                    104 ( 1.1%)             1
@@ -99,12 +99,12 @@ ast-stats-2 - Struct                   104 ( 1.1%)             1
 ast-stats-2 - InlineAsm                104 ( 1.1%)             1
 ast-stats-2 - Lit                      208 ( 2.3%)             2
 ast-stats-2 - Block                    312 ( 3.4%)             3
-ast-stats-2 Ty                     1_344 (14.6%)            14            96
+ast-stats-2 Ty                     1_344 (14.7%)            14            96
 ast-stats-2 - Rptr                      96 ( 1.0%)             1
 ast-stats-2 - Ptr                       96 ( 1.0%)             1
 ast-stats-2 - ImplicitSelf             192 ( 2.1%)             2
 ast-stats-2 - Path                     960 (10.5%)            10
-ast-stats-2 Item                   2_024 (22.0%)            11           184
+ast-stats-2 Item                   2_024 (22.1%)            11           184
 ast-stats-2 - Trait                    184 ( 2.0%)             1
 ast-stats-2 - Enum                     184 ( 2.0%)             1
 ast-stats-2 - ExternCrate              184 ( 2.0%)             1
@@ -113,65 +113,66 @@ ast-stats-2 - Impl                     184 ( 2.0%)             1
 ast-stats-2 - Fn                       368 ( 4.0%)             2
 ast-stats-2 - Use                      736 ( 8.0%)             4
 ast-stats-2 ----------------------------------------------------------------
-ast-stats-2 Total                  9_184
+ast-stats-2 Total                  9_144
 ast-stats-2
 hir-stats HIR STATS
 hir-stats Name                Accumulated Size         Count     Item Size
 hir-stats ----------------------------------------------------------------
 hir-stats ForeignItemRef            24 ( 0.2%)             1            24
+hir-stats Lifetime                  32 ( 0.3%)             1            32
 hir-stats Mod                       32 ( 0.3%)             1            32
 hir-stats ExprField                 40 ( 0.4%)             1            40
 hir-stats TraitItemRef              56 ( 0.6%)             2            28
-hir-stats Param                     64 ( 0.6%)             2            32
-hir-stats Local                     64 ( 0.6%)             1            64
+hir-stats Local                     64 ( 0.7%)             1            64
+hir-stats Param                     64 ( 0.7%)             2            32
 hir-stats InlineAsm                 72 ( 0.7%)             1            72
 hir-stats ImplItemRef               72 ( 0.7%)             2            36
+hir-stats Body                      96 ( 1.0%)             3            32
+hir-stats GenericArg                96 ( 1.0%)             4            24
+hir-stats - Type                      24 ( 0.2%)             1
+hir-stats - Lifetime                  72 ( 0.7%)             3
 hir-stats FieldDef                  96 ( 1.0%)             2            48
 hir-stats Arm                       96 ( 1.0%)             2            48
-hir-stats Body                      96 ( 1.0%)             3            32
 hir-stats Stmt                      96 ( 1.0%)             3            32
 hir-stats - Local                     32 ( 0.3%)             1
 hir-stats - Semi                      32 ( 0.3%)             1
 hir-stats - Expr                      32 ( 0.3%)             1
 hir-stats FnDecl                   120 ( 1.2%)             3            40
 hir-stats Attribute                128 ( 1.3%)             4            32
-hir-stats GenericArgs              144 ( 1.4%)             3            48
-hir-stats Variant                  160 ( 1.6%)             2            80
-hir-stats GenericArg               160 ( 1.6%)             4            40
-hir-stats - Type                      40 ( 0.4%)             1
-hir-stats - Lifetime                 120 ( 1.2%)             3
-hir-stats GenericBound             192 ( 1.9%)             4            48
-hir-stats - Trait                    192 ( 1.9%)             4
-hir-stats WherePredicate           216 ( 2.1%)             3            72
-hir-stats - BoundPredicate           216 ( 2.1%)             3
-hir-stats Block                    288 ( 2.9%)             6            48
-hir-stats GenericParam             400 ( 4.0%)             5            80
-hir-stats Pat                      440 ( 4.4%)             5            88
-hir-stats - Wild                      88 ( 0.9%)             1
-hir-stats - Struct                    88 ( 0.9%)             1
-hir-stats - Binding                  264 ( 2.6%)             3
-hir-stats Generics                 560 ( 5.5%)            10            56
-hir-stats Expr                     672 ( 6.7%)            12            56
-hir-stats - Path                      56 ( 0.6%)             1
-hir-stats - Struct                    56 ( 0.6%)             1
-hir-stats - Match                     56 ( 0.6%)             1
-hir-stats - InlineAsm                 56 ( 0.6%)             1
-hir-stats - Lit                      112 ( 1.1%)             2
-hir-stats - Block                    336 ( 3.3%)             6
-hir-stats Item                     960 ( 9.5%)            12            80
+hir-stats GenericArgs              144 ( 1.5%)             3            48
+hir-stats Variant                  160 ( 1.7%)             2            80
+hir-stats WherePredicate           168 ( 1.7%)             3            56
+hir-stats - BoundPredicate           168 ( 1.7%)             3
+hir-stats GenericBound             192 ( 2.0%)             4            48
+hir-stats - Trait                    192 ( 2.0%)             4
+hir-stats Block                    288 ( 3.0%)             6            48
+hir-stats Pat                      360 ( 3.7%)             5            72
+hir-stats - Wild                      72 ( 0.7%)             1
+hir-stats - Struct                    72 ( 0.7%)             1
+hir-stats - Binding                  216 ( 2.2%)             3
+hir-stats GenericParam             400 ( 4.1%)             5            80
+hir-stats Generics                 560 ( 5.8%)            10            56
+hir-stats Ty                       720 ( 7.4%)            15            48
+hir-stats - Ptr                       48 ( 0.5%)             1
+hir-stats - Rptr                      48 ( 0.5%)             1
+hir-stats - Path                     624 ( 6.4%)            13
+hir-stats Expr                     768 ( 7.9%)            12            64
+hir-stats - Path                      64 ( 0.7%)             1
+hir-stats - Struct                    64 ( 0.7%)             1
+hir-stats - Match                     64 ( 0.7%)             1
+hir-stats - InlineAsm                 64 ( 0.7%)             1
+hir-stats - Lit                      128 ( 1.3%)             2
+hir-stats - Block                    384 ( 4.0%)             6
+hir-stats Item                     960 ( 9.9%)            12            80
 hir-stats - Trait                     80 ( 0.8%)             1
 hir-stats - Enum                      80 ( 0.8%)             1
 hir-stats - ExternCrate               80 ( 0.8%)             1
 hir-stats - ForeignMod                80 ( 0.8%)             1
 hir-stats - Impl                      80 ( 0.8%)             1
-hir-stats - Fn                       160 ( 1.6%)             2
-hir-stats - Use                      400 ( 4.0%)             5
-hir-stats Ty                     1_080 (10.7%)            15            72
-hir-stats - Ptr                       72 ( 0.7%)             1
-hir-stats - Rptr                      72 ( 0.7%)             1
-hir-stats - Path                     936 ( 9.3%)            13
-hir-stats Path                   1_536 (15.2%)            32            48
-hir-stats PathSegment            2_240 (22.2%)            40            56
+hir-stats - Fn                       160 ( 1.7%)             2
+hir-stats - Use                      400 ( 4.1%)             5
+hir-stats Path                   1_536 (15.9%)            32            48
+hir-stats PathSegment            2_240 (23.1%)            40            56
 hir-stats ----------------------------------------------------------------
-hir-stats Total                 10_104
+hir-stats Total                  9_680
 hir-stats
diff --git a/src/test/ui/structs-enums/type-sizes.rs b/src/test/ui/structs-enums/type-sizes.rs
index 73a11a5e743..7a23f13630a 100644
--- a/src/test/ui/structs-enums/type-sizes.rs
+++ b/src/test/ui/structs-enums/type-sizes.rs
@@ -120,6 +120,54 @@ pub enum AlwaysTaggedBecauseItHasNoNiche {
     B
 }
 
+pub enum NicheFilledMultipleFields {
+    A(bool, u8),
+    B(u8),
+    C(u8),
+    D(bool),
+    E,
+    F,
+    G,
+}
+
+struct BoolInTheMiddle(std::num::NonZeroU16, bool, u8);
+
+enum NicheWithData {
+    A,
+    B([u16; 5]),
+    Largest { a1: u32, a2: BoolInTheMiddle, a3: u32 },
+    C,
+    D(u32, u32),
+}
+
+// A type with almost 2^16 invalid values.
+#[repr(u16)]
+pub enum NicheU16 {
+    _0,
+}
+
+pub enum EnumManyVariant<X> {
+    Dataful(u8, X),
+
+    // 0x100 niche variants.
+    _00, _01, _02, _03, _04, _05, _06, _07, _08, _09, _0A, _0B, _0C, _0D, _0E, _0F,
+    _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _1A, _1B, _1C, _1D, _1E, _1F,
+    _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _2A, _2B, _2C, _2D, _2E, _2F,
+    _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _3A, _3B, _3C, _3D, _3E, _3F,
+    _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _4A, _4B, _4C, _4D, _4E, _4F,
+    _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _5A, _5B, _5C, _5D, _5E, _5F,
+    _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _6A, _6B, _6C, _6D, _6E, _6F,
+    _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _7A, _7B, _7C, _7D, _7E, _7F,
+    _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _8A, _8B, _8C, _8D, _8E, _8F,
+    _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _9A, _9B, _9C, _9D, _9E, _9F,
+    _A0, _A1, _A2, _A3, _A4, _A5, _A6, _A7, _A8, _A9, _AA, _AB, _AC, _AD, _AE, _AF,
+    _B0, _B1, _B2, _B3, _B4, _B5, _B6, _B7, _B8, _B9, _BA, _BB, _BC, _BD, _BE, _BF,
+    _C0, _C1, _C2, _C3, _C4, _C5, _C6, _C7, _C8, _C9, _CA, _CB, _CC, _CD, _CE, _CF,
+    _D0, _D1, _D2, _D3, _D4, _D5, _D6, _D7, _D8, _D9, _DA, _DB, _DC, _DD, _DE, _DF,
+    _E0, _E1, _E2, _E3, _E4, _E5, _E6, _E7, _E8, _E9, _EA, _EB, _EC, _ED, _EE, _EF,
+    _F0, _F1, _F2, _F3, _F4, _F5, _F6, _F7, _F8, _F9, _FA, _FB, _FC, _FD, _FE, _FF,
+}
+
 pub fn main() {
     assert_eq!(size_of::<u8>(), 1 as usize);
     assert_eq!(size_of::<u32>(), 4 as usize);
@@ -170,4 +218,35 @@ pub fn main() {
     assert_eq!(size_of::<AlwaysTaggedBecauseItHasNoNiche>(), 8);
     assert_eq!(size_of::<Option<AlwaysTaggedBecauseItHasNoNiche>>(), 8);
     assert_eq!(size_of::<Option<Option<AlwaysTaggedBecauseItHasNoNiche>>>(), 8);
+
+    assert_eq!(size_of::<NicheFilledMultipleFields>(), 2);
+    assert_eq!(size_of::<Option<NicheFilledMultipleFields>>(), 2);
+    assert_eq!(size_of::<Option<Option<NicheFilledMultipleFields>>>(), 2);
+
+    struct S1{ a: u16, b: std::num::NonZeroU16, c: u16, d: u8, e: u32, f: u64, g:[u8;2] }
+    assert_eq!(size_of::<S1>(), 24);
+    assert_eq!(size_of::<Option<S1>>(), 24);
+
+    assert_eq!(size_of::<NicheWithData>(), 12);
+    assert_eq!(size_of::<Option<NicheWithData>>(), 12);
+    assert_eq!(size_of::<Option<Option<NicheWithData>>>(), 12);
+    assert_eq!(
+        size_of::<Option<Option2<&(), Option<NicheWithData>>>>(),
+        size_of::<(&(), NicheWithData)>()
+    );
+
+    pub enum FillPadding { A(std::num::NonZeroU8, u32), B }
+    assert_eq!(size_of::<FillPadding>(), 8);
+    assert_eq!(size_of::<Option<FillPadding>>(), 8);
+    assert_eq!(size_of::<Option<Option<FillPadding>>>(), 8);
+
+    assert_eq!(size_of::<Result<(std::num::NonZeroU8, u8, u8), u16>>(), 4);
+    assert_eq!(size_of::<Option<Result<(std::num::NonZeroU8, u8, u8), u16>>>(), 4);
+    assert_eq!(size_of::<Result<(std::num::NonZeroU8, u8, u8, u8), u16>>(), 4);
+
+    assert_eq!(size_of::<EnumManyVariant<u16>>(), 6);
+    assert_eq!(size_of::<EnumManyVariant<NicheU16>>(), 4);
+    assert_eq!(size_of::<EnumManyVariant<Option<NicheU16>>>(), 4);
+    assert_eq!(size_of::<EnumManyVariant<Option2<NicheU16,u8>>>(), 6);
+    assert_eq!(size_of::<EnumManyVariant<Option<(NicheU16,u8)>>>(), 6);
 }
diff --git a/src/test/ui/suggestions/issue-101421.rs b/src/test/ui/suggestions/issue-101421.rs
new file mode 100644
index 00000000000..b615997d1a9
--- /dev/null
+++ b/src/test/ui/suggestions/issue-101421.rs
@@ -0,0 +1,12 @@
+pub trait Ice {
+    fn f(&self, _: ());
+}
+
+impl Ice for () {
+    fn f(&self, _: ()) {}
+}
+
+fn main() {
+    ().f::<()>(());
+    //~^ ERROR this associated function takes 0 generic arguments but 1 generic argument was supplied
+}
diff --git a/src/test/ui/suggestions/issue-101421.stderr b/src/test/ui/suggestions/issue-101421.stderr
new file mode 100644
index 00000000000..f8e1efb8820
--- /dev/null
+++ b/src/test/ui/suggestions/issue-101421.stderr
@@ -0,0 +1,17 @@
+error[E0107]: this associated function takes 0 generic arguments but 1 generic argument was supplied
+  --> $DIR/issue-101421.rs:10:8
+   |
+LL |     ().f::<()>(());
+   |        ^------ help: remove these generics
+   |        |
+   |        expected 0 generic arguments
+   |
+note: associated function defined here, with 0 generic parameters
+  --> $DIR/issue-101421.rs:2:8
+   |
+LL |     fn f(&self, _: ());
+   |        ^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0107`.
diff --git a/src/test/ui/suggestions/issue-97677.fixed b/src/test/ui/suggestions/issue-97677.fixed
index 73ca9f97b43..1e7569fa451 100644
--- a/src/test/ui/suggestions/issue-97677.fixed
+++ b/src/test/ui/suggestions/issue-97677.fixed
@@ -1,6 +1,6 @@
 // run-rustfix
 
-fn add_ten<N: std::ops::Add<i32, Output=N>>(n: N) -> N {
+fn add_ten<N: std::ops::Add<i32, Output = N>>(n: N) -> N {
     n + 10
     //~^ ERROR cannot add `{integer}` to `N`
 }
diff --git a/src/test/ui/suggestions/issue-97677.stderr b/src/test/ui/suggestions/issue-97677.stderr
index 069b184ac63..575d79267f2 100644
--- a/src/test/ui/suggestions/issue-97677.stderr
+++ b/src/test/ui/suggestions/issue-97677.stderr
@@ -8,8 +8,8 @@ LL |     n + 10
    |
 help: consider restricting type parameter `N`
    |
-LL | fn add_ten<N: std::ops::Add<i32, Output=N>>(n: N) -> N {
-   |             ++++++++++++++++++++++++++++++
+LL | fn add_ten<N: std::ops::Add<i32, Output = N>>(n: N) -> N {
+   |             ++++++++++++++++++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr
index 0212c2d712c..e5d2ead6ad6 100644
--- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr
+++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr
@@ -22,8 +22,8 @@ LL | |     });
    | |______^
 help: consider adding an explicit lifetime bound...
    |
-LL | fn func<T: Test + 'a>(foo: &Foo, t: T) {
-   |                 ++++
+LL | fn func<'a, T: Test + 'a>(foo: &Foo, t: T) {
+   |         +++         ++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
index 0d749f04bea..ed1b91676a2 100644
--- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
+++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
@@ -47,8 +47,10 @@ LL | |     }
    | |_____^
 help: consider adding an explicit lifetime bound...
    |
-LL |     G: Get<T> + 'a,
-   |               ++++
+LL ~ fn bar<'a, G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+LL | where
+LL ~     G: Get<T> + 'a,
+   |
 
 error[E0311]: the parameter type `G` may not live long enough
   --> $DIR/missing-lifetimes-in-signature.rs:52:5
@@ -74,8 +76,8 @@ LL | |     }
    | |_____^
 help: consider adding an explicit lifetime bound...
    |
-LL | fn qux<'a, G: 'a + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
-   |                  ++++
+LL | fn qux<'b, 'a, G: 'a + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
+   |        +++           ++++
 
 error[E0311]: the parameter type `G` may not live long enough
   --> $DIR/missing-lifetimes-in-signature.rs:61:9
@@ -101,8 +103,8 @@ LL | |         }
    | |_________^
 help: consider adding an explicit lifetime bound...
    |
-LL |     fn qux<'b, G: Get<T> + 'b + 'c, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
-   |                               ++++
+LL |     fn qux<'c, 'b, G: Get<T> + 'b + 'c, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ {
+   |            +++                    ++++
 
 error[E0311]: the parameter type `G` may not live long enough
   --> $DIR/missing-lifetimes-in-signature.rs:73:5
@@ -130,8 +132,8 @@ LL | |     }
    | |_____^
 help: consider adding an explicit lifetime bound...
    |
-LL | fn bat<'a, G: 'a + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
-   |                  ++++
+LL | fn bat<'b, 'a, G: 'a + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
+   |        +++           ++++
 
 error[E0621]: explicit lifetime required in the type of `dest`
   --> $DIR/missing-lifetimes-in-signature.rs:73:5
diff --git a/src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.rs b/src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.rs
new file mode 100644
index 00000000000..2f540060a34
--- /dev/null
+++ b/src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.rs
@@ -0,0 +1,18 @@
+// Generalizes the suggestion introduced in #100838
+
+trait Foo<T> {
+    fn bar(&self, _: T);
+}
+
+impl Foo<i32> for i32 {
+    fn bar(&self, x: i32) {
+        println!("{}", self + x);
+    }
+}
+
+fn main() {
+    1.bar::<i32>(0);
+    //~^ ERROR this associated function takes 0 generic arguments but 1 generic argument was supplied
+    //~| HELP consider moving this generic argument to the `Foo` trait, which takes up to 1 argument
+    //~| HELP remove these generics
+}
diff --git a/src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr b/src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr
new file mode 100644
index 00000000000..9557220f6bb
--- /dev/null
+++ b/src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr
@@ -0,0 +1,24 @@
+error[E0107]: this associated function takes 0 generic arguments but 1 generic argument was supplied
+  --> $DIR/move-generic-to-trait-in-method-with-params.rs:14:7
+   |
+LL |     1.bar::<i32>(0);
+   |       ^^^ expected 0 generic arguments
+   |
+note: associated function defined here, with 0 generic parameters
+  --> $DIR/move-generic-to-trait-in-method-with-params.rs:4:8
+   |
+LL |     fn bar(&self, _: T);
+   |        ^^^
+help: consider moving this generic argument to the `Foo` trait, which takes up to 1 argument
+   |
+LL |     Foo::<i32>::bar(1, 0);
+   |     ~~~~~~~~~~~~~~~~~~~~~
+help: remove these generics
+   |
+LL -     1.bar::<i32>(0);
+LL +     1.bar(0);
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0107`.
diff --git a/src/test/ui/suggestions/restrict-type-not-param.rs b/src/test/ui/suggestions/restrict-type-not-param.rs
new file mode 100644
index 00000000000..60f5ba45c26
--- /dev/null
+++ b/src/test/ui/suggestions/restrict-type-not-param.rs
@@ -0,0 +1,12 @@
+use std::ops::Add;
+
+struct Wrapper<T>(T);
+
+trait Foo {}
+
+fn qux<T>(a: Wrapper<T>, b: T) -> T {
+    a + b
+    //~^ ERROR cannot add `T` to `Wrapper<T>`
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/restrict-type-not-param.stderr b/src/test/ui/suggestions/restrict-type-not-param.stderr
new file mode 100644
index 00000000000..e7d9c5ecbe4
--- /dev/null
+++ b/src/test/ui/suggestions/restrict-type-not-param.stderr
@@ -0,0 +1,26 @@
+error[E0369]: cannot add `T` to `Wrapper<T>`
+  --> $DIR/restrict-type-not-param.rs:8:7
+   |
+LL |     a + b
+   |     - ^ - T
+   |     |
+   |     Wrapper<T>
+   |
+note: an implementation of `Add<_>` might be missing for `Wrapper<T>`
+  --> $DIR/restrict-type-not-param.rs:3:1
+   |
+LL | struct Wrapper<T>(T);
+   | ^^^^^^^^^^^^^^^^^ must implement `Add<_>`
+note: the following trait must be implemented
+  --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
+   |
+LL | pub trait Add<Rhs = Self> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL | fn qux<T>(a: Wrapper<T>, b: T) -> T where Wrapper<T>: Add<T, Output = T> {
+   |                                     ++++++++++++++++++++++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0369`.
diff --git a/src/test/ui/traits/resolution-in-overloaded-op.stderr b/src/test/ui/traits/resolution-in-overloaded-op.stderr
index 34fae64e4d2..fe5e1d6d285 100644
--- a/src/test/ui/traits/resolution-in-overloaded-op.stderr
+++ b/src/test/ui/traits/resolution-in-overloaded-op.stderr
@@ -8,8 +8,8 @@ LL |     a * b
    |
 help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
    |
-LL | fn foo<T: MyMul<f64, f64>>(a: &T, b: f64) -> f64 where &T: Mul<f64> {
-   |                                                  ++++++++++++++++++
+LL | fn foo<T: MyMul<f64, f64>>(a: &T, b: f64) -> f64 where &T: Mul<f64, Output = f64> {
+   |                                                  ++++++++++++++++++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/constrain_inputs.rs b/src/test/ui/type-alias-impl-trait/constrain_inputs.rs
index c32174288ee..03fb64b7b94 100644
--- a/src/test/ui/type-alias-impl-trait/constrain_inputs.rs
+++ b/src/test/ui/type-alias-impl-trait/constrain_inputs.rs
@@ -1,17 +1,33 @@
-// check-pass
-
 #![feature(type_alias_impl_trait)]
 
-mod foo {
+mod lifetime_params {
     type Ty<'a> = impl Sized;
     fn defining(s: &str) -> Ty<'_> { s }
     fn execute(ty: Ty<'_>) -> &str { todo!() }
+    //~^ ERROR return type references an anonymous lifetime, which is not constrained by the fn input types
+
+    type BadFnSig = fn(Ty<'_>) -> &str;
+    //~^ ERROR return type references an anonymous lifetime, which is not constrained by the fn input types
+    type BadTraitRef = dyn Fn(Ty<'_>) -> &str;
+    //~^ ERROR binding for associated type `Output` references an anonymous lifetime
 }
 
-mod bar {
+mod lifetime_params_2 {
     type Ty<'a> = impl FnOnce() -> &'a str;
     fn defining(s: &str) -> Ty<'_> { move || s }
     fn execute(ty: Ty<'_>) -> &str { ty() }
+    //~^ ERROR return type references an anonymous lifetime, which is not constrained by the fn input types
+}
+
+// regression test for https://github.com/rust-lang/rust/issues/97104
+mod type_params {
+    type Ty<T> = impl Sized;
+    fn define<T>(s: T) -> Ty<T> { s }
+
+    type BadFnSig = fn(Ty<&str>) -> &str;
+    //~^ ERROR return type references an anonymous lifetime, which is not constrained by the fn input types
+    type BadTraitRef = dyn Fn(Ty<&str>) -> &str;
+    //~^ ERROR binding for associated type `Output` references an anonymous lifetime
 }
 
 fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/constrain_inputs.stderr b/src/test/ui/type-alias-impl-trait/constrain_inputs.stderr
new file mode 100644
index 00000000000..93953fd06d1
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/constrain_inputs.stderr
@@ -0,0 +1,58 @@
+error[E0581]: return type references an anonymous lifetime, which is not constrained by the fn input types
+  --> $DIR/constrain_inputs.rs:6:31
+   |
+LL |     fn execute(ty: Ty<'_>) -> &str { todo!() }
+   |                               ^^^^
+   |
+   = note: lifetimes appearing in an associated or opaque type are not considered constrained
+   = note: consider introducing a named lifetime parameter
+
+error[E0581]: return type references an anonymous lifetime, which is not constrained by the fn input types
+  --> $DIR/constrain_inputs.rs:9:35
+   |
+LL |     type BadFnSig = fn(Ty<'_>) -> &str;
+   |                                   ^^^^
+   |
+   = note: lifetimes appearing in an associated or opaque type are not considered constrained
+   = note: consider introducing a named lifetime parameter
+
+error[E0582]: binding for associated type `Output` references an anonymous lifetime, which does not appear in the trait input types
+  --> $DIR/constrain_inputs.rs:11:42
+   |
+LL |     type BadTraitRef = dyn Fn(Ty<'_>) -> &str;
+   |                                          ^^^^
+   |
+   = note: lifetimes appearing in an associated or opaque type are not considered constrained
+   = note: consider introducing a named lifetime parameter
+
+error[E0581]: return type references an anonymous lifetime, which is not constrained by the fn input types
+  --> $DIR/constrain_inputs.rs:18:31
+   |
+LL |     fn execute(ty: Ty<'_>) -> &str { ty() }
+   |                               ^^^^
+   |
+   = note: lifetimes appearing in an associated or opaque type are not considered constrained
+   = note: consider introducing a named lifetime parameter
+
+error[E0581]: return type references an anonymous lifetime, which is not constrained by the fn input types
+  --> $DIR/constrain_inputs.rs:27:37
+   |
+LL |     type BadFnSig = fn(Ty<&str>) -> &str;
+   |                                     ^^^^
+   |
+   = note: lifetimes appearing in an associated or opaque type are not considered constrained
+   = note: consider introducing a named lifetime parameter
+
+error[E0582]: binding for associated type `Output` references an anonymous lifetime, which does not appear in the trait input types
+  --> $DIR/constrain_inputs.rs:29:44
+   |
+LL |     type BadTraitRef = dyn Fn(Ty<&str>) -> &str;
+   |                                            ^^^^
+   |
+   = note: lifetimes appearing in an associated or opaque type are not considered constrained
+   = note: consider introducing a named lifetime parameter
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0581, E0582.
+For more information about an error, try `rustc --explain E0581`.
diff --git a/src/test/ui/type-alias-impl-trait/constrain_inputs_unsound.rs b/src/test/ui/type-alias-impl-trait/constrain_inputs_unsound.rs
new file mode 100644
index 00000000000..3bae0f17309
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/constrain_inputs_unsound.rs
@@ -0,0 +1,31 @@
+#![feature(type_alias_impl_trait)]
+
+trait Static: 'static {}
+impl Static for () {}
+
+type Gal<T> = impl Static;
+fn _defining<T>() -> Gal<T> {}
+
+trait Callable<Arg> { type Output; }
+
+/// We can infer `<C as Callable<Arg>>::Output: 'static`,
+/// because we know `C: 'static` and `Arg: 'static`,
+fn box_str<C, Arg>(s: C::Output) -> Box<dyn AsRef<str> + 'static>
+where
+    Arg: Static,
+    C: ?Sized + Callable<Arg> + 'static,
+    C::Output: AsRef<str>,
+{
+    Box::new(s)
+}
+
+fn extend_lifetime(s: &str) -> Box<dyn AsRef<str> + 'static> {
+    type MalformedTy = dyn for<'a> Callable<Gal<&'a ()>, Output = &'a str>;
+    //~^ ERROR binding for associated type `Output` references lifetime `'a`
+    box_str::<MalformedTy, _>(s)
+}
+
+fn main() {
+    let extended = extend_lifetime(&String::from("hello"));
+    println!("{}", extended.as_ref().as_ref());
+}
diff --git a/src/test/ui/type-alias-impl-trait/constrain_inputs_unsound.stderr b/src/test/ui/type-alias-impl-trait/constrain_inputs_unsound.stderr
new file mode 100644
index 00000000000..d5fc46cb1f5
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/constrain_inputs_unsound.stderr
@@ -0,0 +1,9 @@
+error[E0582]: binding for associated type `Output` references lifetime `'a`, which does not appear in the trait input types
+  --> $DIR/constrain_inputs_unsound.rs:23:58
+   |
+LL |     type MalformedTy = dyn for<'a> Callable<Gal<&'a ()>, Output = &'a str>;
+   |                                                          ^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0582`.
diff --git a/src/test/ui/typeck/assign-non-lval-derefmut.stderr b/src/test/ui/typeck/assign-non-lval-derefmut.stderr
index a6fcdfe21f4..e394cf8206e 100644
--- a/src/test/ui/typeck/assign-non-lval-derefmut.stderr
+++ b/src/test/ui/typeck/assign-non-lval-derefmut.stderr
@@ -19,7 +19,7 @@ LL |     x.lock().unwrap() += 1;
    |     |
    |     cannot use `+=` on type `MutexGuard<'_, usize>`
    |
-help: `+=` can be used on `usize`, you can dereference `x.lock().unwrap()`
+help: `+=` can be used on `usize` if you dereference the left-hand side
    |
 LL |     *x.lock().unwrap() += 1;
    |     +
@@ -47,7 +47,7 @@ LL |     y += 1;
    |     |
    |     cannot use `+=` on type `MutexGuard<'_, usize>`
    |
-help: `+=` can be used on `usize`, you can dereference `y`
+help: `+=` can be used on `usize` if you dereference the left-hand side
    |
 LL |     *y += 1;
    |     +
diff --git a/src/test/ui/typeck/assign-non-lval-mut-ref.stderr b/src/test/ui/typeck/assign-non-lval-mut-ref.stderr
index be2e9fe95e8..cbdc960baab 100644
--- a/src/test/ui/typeck/assign-non-lval-mut-ref.stderr
+++ b/src/test/ui/typeck/assign-non-lval-mut-ref.stderr
@@ -19,7 +19,7 @@ LL |     x.last_mut().unwrap() += 1;
    |     |
    |     cannot use `+=` on type `&mut usize`
    |
-help: `+=` can be used on `usize`, you can dereference `x.last_mut().unwrap()`
+help: `+=` can be used on `usize` if you dereference the left-hand side
    |
 LL |     *x.last_mut().unwrap() += 1;
    |     +
@@ -45,7 +45,7 @@ LL |     y += 1;
    |     |
    |     cannot use `+=` on type `&mut usize`
    |
-help: `+=` can be used on `usize`, you can dereference `y`
+help: `+=` can be used on `usize` if you dereference the left-hand side
    |
 LL |     *y += 1;
    |     +
diff --git a/src/test/ui/typeck/point-at-type-param-in-path-expr.rs b/src/test/ui/typeck/point-at-type-param-in-path-expr.rs
new file mode 100644
index 00000000000..9a21536f9b1
--- /dev/null
+++ b/src/test/ui/typeck/point-at-type-param-in-path-expr.rs
@@ -0,0 +1,6 @@
+fn foo<T: std::fmt::Display>() {}
+
+fn main() {
+    let x = foo::<()>;
+    //~^ ERROR `()` doesn't implement `std::fmt::Display`
+}
diff --git a/src/test/ui/typeck/point-at-type-param-in-path-expr.stderr b/src/test/ui/typeck/point-at-type-param-in-path-expr.stderr
new file mode 100644
index 00000000000..1feaa0508bf
--- /dev/null
+++ b/src/test/ui/typeck/point-at-type-param-in-path-expr.stderr
@@ -0,0 +1,17 @@
+error[E0277]: `()` doesn't implement `std::fmt::Display`
+  --> $DIR/point-at-type-param-in-path-expr.rs:4:19
+   |
+LL |     let x = foo::<()>;
+   |                   ^^ `()` cannot be formatted with the default formatter
+   |
+   = help: the trait `std::fmt::Display` is not implemented for `()`
+   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+note: required by a bound in `foo`
+  --> $DIR/point-at-type-param-in-path-expr.rs:1:11
+   |
+LL | fn foo<T: std::fmt::Display>() {}
+   |           ^^^^^^^^^^^^^^^^^ required by this bound in `foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/uninhabited/uninhabited-irrefutable.rs b/src/test/ui/uninhabited/uninhabited-irrefutable.rs
index 661b5486adc..1a0f3c5e550 100644
--- a/src/test/ui/uninhabited/uninhabited-irrefutable.rs
+++ b/src/test/ui/uninhabited/uninhabited-irrefutable.rs
@@ -24,5 +24,5 @@ enum Foo {
 
 fn main() {
     let x: Foo = Foo::D(123, 456);
-    let Foo::D(_y, _z) = x; //~ ERROR refutable pattern in local binding: `A(_)` not covered
+    let Foo::D(_y, _z) = x; //~ ERROR refutable pattern in local binding: `Foo::A(_)` not covered
 }
diff --git a/src/test/ui/uninhabited/uninhabited-irrefutable.stderr b/src/test/ui/uninhabited/uninhabited-irrefutable.stderr
index c571e17a7b3..feeaa89e76f 100644
--- a/src/test/ui/uninhabited/uninhabited-irrefutable.stderr
+++ b/src/test/ui/uninhabited/uninhabited-irrefutable.stderr
@@ -1,8 +1,8 @@
-error[E0005]: refutable pattern in local binding: `A(_)` not covered
+error[E0005]: refutable pattern in local binding: `Foo::A(_)` not covered
   --> $DIR/uninhabited-irrefutable.rs:27:9
    |
 LL |     let Foo::D(_y, _z) = x;
-   |         ^^^^^^^^^^^^^^ pattern `A(_)` not covered
+   |         ^^^^^^^^^^^^^^ pattern `Foo::A(_)` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 4ed54cecce3ce9ab6ff058781f4c8a500ee6b8b
+Subproject 646e9a0b9ea8354cc409d05f10e8dc752c5de78
diff --git a/src/tools/clippy/book/src/development/common_tools_writing_lints.md b/src/tools/clippy/book/src/development/common_tools_writing_lints.md
index 15e00c7d7ce..2bc275ceff0 100644
--- a/src/tools/clippy/book/src/development/common_tools_writing_lints.md
+++ b/src/tools/clippy/book/src/development/common_tools_writing_lints.md
@@ -66,7 +66,7 @@ Starting with an `expr`, you can check whether it is calling a specific method
 impl<'tcx> LateLintPass<'tcx> for MyStructLint {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         // Check our expr is calling a method
-        if let hir::ExprKind::MethodCall(path, _, [_self_arg, ..]) = &expr.kind
+        if let hir::ExprKind::MethodCall(path, _, _self_arg, ..) = &expr.kind
             // Check the name of this method is `some_method`
             && path.ident.name == sym!(some_method)
             // Optionally, check the type of the self argument.
diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs
index be05e67d724..331b76484b8 100644
--- a/src/tools/clippy/clippy_dev/src/new_lint.rs
+++ b/src/tools/clippy/clippy_dev/src/new_lint.rs
@@ -120,15 +120,17 @@ fn add_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> {
 
     let new_lint = if enable_msrv {
         format!(
-            "store.register_{lint_pass}_pass(move || Box::new({module_name}::{camel_name}::new(msrv)));\n    ",
+            "store.register_{lint_pass}_pass(move |{ctor_arg}| Box::new({module_name}::{camel_name}::new(msrv)));\n    ",
             lint_pass = lint.pass,
+            ctor_arg = if lint.pass == "late" { "_" } else { "" },
             module_name = lint.name,
             camel_name = to_camel_case(lint.name),
         )
     } else {
         format!(
-            "store.register_{lint_pass}_pass(|| Box::new({module_name}::{camel_name}));\n    ",
+            "store.register_{lint_pass}_pass(|{ctor_arg}| Box::new({module_name}::{camel_name}));\n    ",
             lint_pass = lint.pass,
+            ctor_arg = if lint.pass == "late" { "_" } else { "" },
             module_name = lint.name,
             camel_name = to_camel_case(lint.name),
         )
diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
index 6a6554f968b..7cd198ace86 100644
--- a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
+++ b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
@@ -43,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
             && matches!(cx.tcx.get_diagnostic_name(macro_call.def_id), Some(sym::assert_macro))
             && let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn)
             && matches!(panic_expn, PanicExpn::Empty)
-            && let ExprKind::MethodCall(method_segment, [recv], _) = condition.kind
+            && let ExprKind::MethodCall(method_segment, recv, [], _) = condition.kind
             && let result_type_with_refs = cx.typeck_results().expr_ty(recv)
             && let result_type = result_type_with_refs.peel_refs()
             && is_type_diagnostic_item(cx, result_type, sym::Result)
diff --git a/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs b/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs
index ad206b5fb30..d9e2c9c8578 100644
--- a/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs
+++ b/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs
@@ -55,7 +55,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ExVisitor<'a, 'tcx> {
             // do not lint if the closure is called using an iterator (see #1141)
             if_chain! {
                 if let Some(parent) = get_parent_expr(self.cx, expr);
-                if let ExprKind::MethodCall(_, [self_arg, ..], _) = &parent.kind;
+                if let ExprKind::MethodCall(_, self_arg, ..) = &parent.kind;
                 let caller = self.cx.typeck_results().expr_ty(self_arg);
                 if let Some(iter_id) = self.cx.tcx.get_diagnostic_item(sym::Iterator);
                 if implements_trait(self.cx, caller, iter_id, &[]);
@@ -117,7 +117,8 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInIfConditions {
                             );
                         }
                     } else {
-                        let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
+                        let span =
+                            block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
                         if span.from_expansion() || expr.span.from_expansion() {
                             return;
                         }
diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs
index 6eb78d21e82..656d639f0ef 100644
--- a/src/tools/clippy/clippy_lints/src/booleans.rs
+++ b/src/tools/clippy/clippy_lints/src/booleans.rs
@@ -270,8 +270,8 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
                 ))
             })
         },
-        ExprKind::MethodCall(path, args, _) if args.len() == 1 => {
-            let type_of_receiver = cx.typeck_results().expr_ty(&args[0]);
+        ExprKind::MethodCall(path, receiver, [], _) => {
+            let type_of_receiver = cx.typeck_results().expr_ty(receiver);
             if !is_type_diagnostic_item(cx, type_of_receiver, sym::Option)
                 && !is_type_diagnostic_item(cx, type_of_receiver, sym::Result)
             {
@@ -285,7 +285,7 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
                     let path: &str = path.ident.name.as_str();
                     a == path
                 })
-                .and_then(|(_, neg_method)| Some(format!("{}.{}()", snippet_opt(cx, args[0].span)?, neg_method)))
+                .and_then(|(_, neg_method)| Some(format!("{}.{}()", snippet_opt(cx, receiver.span)?, neg_method)))
         },
         _ => None,
     }
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
index 6426e8c25ac..3f1edabe6c5 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
@@ -20,7 +20,7 @@ pub(super) fn check(
     if meets_msrv(msrv, msrvs::UNSIGNED_ABS)
         && let ty::Int(from) = cast_from.kind()
         && let ty::Uint(to) = cast_to.kind()
-        && let ExprKind::MethodCall(method_path, args, _) = cast_expr.kind
+        && let ExprKind::MethodCall(method_path, receiver, ..) = cast_expr.kind
         && method_path.ident.name.as_str() == "abs"
     {
         let span = if from.bit_width() == to.bit_width() {
@@ -37,7 +37,7 @@ pub(super) fn check(
             span,
             &format!("casting the result of `{cast_from}::abs()` to {cast_to}"),
             "replace with",
-            format!("{}.unsigned_abs()", Sugg::hir(cx, &args[0], "..").maybe_par()),
+            format!("{}.unsigned_abs()", Sugg::hir(cx, receiver, "..").maybe_par()),
             Applicability::MachineApplicable,
         );
     }
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
index 64f87c80f8d..406547a4454 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
@@ -44,7 +44,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
                 .saturating_sub(constant_int(cx, right).map_or(0, |s| u64::try_from(s).expect("shift too high"))),
             _ => nbits,
         },
-        ExprKind::MethodCall(method, [left, right], _) => {
+        ExprKind::MethodCall(method, left, [right], _) => {
             if signed {
                 return nbits;
             }
@@ -55,7 +55,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
             };
             apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::max_value()))
         },
-        ExprKind::MethodCall(method, [_, lo, hi], _) => {
+        ExprKind::MethodCall(method, _, [lo, hi], _) => {
             if method.ident.as_str() == "clamp" {
                 //FIXME: make this a diagnostic item
                 if let (Some(lo_bits), Some(hi_bits)) = (get_constant_bits(cx, lo), get_constant_bits(cx, hi)) {
@@ -64,7 +64,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
             }
             nbits
         },
-        ExprKind::MethodCall(method, [_value], _) => {
+        ExprKind::MethodCall(method, _value, [], _) => {
             if method.ident.name.as_str() == "signum" {
                 0 // do not lint if cast comes from a `signum` function
             } else {
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 d476a1a7646..da7b12f6726 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
@@ -18,7 +18,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
             cx.typeck_results().expr_ty(expr),
         );
         lint_cast_ptr_alignment(cx, expr, cast_from, cast_to);
-    } else if let ExprKind::MethodCall(method_path, [self_arg, ..], _) = &expr.kind {
+    } else if let ExprKind::MethodCall(method_path, self_arg, ..) = &expr.kind {
         if method_path.ident.name == sym!(cast)
             && let Some(generic_args) = method_path.args
             && let [GenericArg::Type(cast_to)] = generic_args.args
@@ -64,7 +64,7 @@ fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
         return false;
     };
     match parent.kind {
-        ExprKind::MethodCall(name, [self_arg, ..], _) if self_arg.hir_id == e.hir_id => {
+        ExprKind::MethodCall(name, self_arg, ..) if self_arg.hir_id == e.hir_id => {
             if matches!(name.ident.as_str(), "read_unaligned" | "write_unaligned")
                 && let Some(def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id)
                 && let Some(def_id) = cx.tcx.impl_of_method(def_id)
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
index 75f70b77ed4..5b59350be04 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
@@ -41,14 +41,14 @@ fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast
             }
 
             // Don't lint for the result of methods that always return non-negative values.
-            if let ExprKind::MethodCall(path, _, _) = cast_op.kind {
+            if let ExprKind::MethodCall(path, ..) = cast_op.kind {
                 let mut method_name = path.ident.name.as_str();
                 let allowed_methods = ["abs", "checked_abs", "rem_euclid", "checked_rem_euclid"];
 
                 if_chain! {
                     if method_name == "unwrap";
                     if let Some(arglist) = method_chain_args(cast_op, &["unwrap"]);
-                    if let ExprKind::MethodCall(inner_path, _, _) = &arglist[0][0].kind;
+                    if let ExprKind::MethodCall(inner_path, ..) = &arglist[0].0.kind;
                     then {
                         method_name = inner_path.ident.name.as_str();
                     }
diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs
index 74f7df61177..4e68d6810e2 100644
--- a/src/tools/clippy/clippy_lints/src/default.rs
+++ b/src/tools/clippy/clippy_lints/src/default.rs
@@ -142,7 +142,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
                 if adt.is_struct();
                 let variant = adt.non_enum_variant();
                 if adt.did().is_local() || !variant.is_field_list_non_exhaustive();
-                let module_did = cx.tcx.parent_module(stmt.hir_id).to_def_id();
+                let module_did = cx.tcx.parent_module(stmt.hir_id);
                 if variant
                     .fields
                     .iter()
diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
index fb418a3251f..64c5de51042 100644
--- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
+++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
@@ -69,10 +69,7 @@ struct NumericFallbackVisitor<'a, 'tcx> {
 
 impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
     fn new(cx: &'a LateContext<'tcx>) -> Self {
-        Self {
-            ty_bounds: vec![TyBound::Nothing],
-            cx,
-        }
+        Self { ty_bounds: vec![TyBound::Nothing], cx }
     }
 
     /// Check whether a passed literal has potential to cause fallback or not.
@@ -129,19 +126,21 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
                     }
                     return;
                 }
-            },
+            }
 
-            ExprKind::MethodCall(_, args, _) => {
+            ExprKind::MethodCall(_, receiver, args, _) => {
                 if let Some(def_id) = self.cx.typeck_results().type_dependent_def_id(expr.hir_id) {
                     let fn_sig = self.cx.tcx.fn_sig(def_id).skip_binder();
-                    for (expr, bound) in iter::zip(*args, fn_sig.inputs()) {
+                    for (expr, bound) in
+                        iter::zip(std::iter::once(*receiver).chain(args.iter()), fn_sig.inputs())
+                    {
                         self.ty_bounds.push(TyBound::Ty(*bound));
                         self.visit_expr(expr);
                         self.ty_bounds.pop();
                     }
                     return;
                 }
-            },
+            }
 
             ExprKind::Struct(_, fields, base) => {
                 let ty = self.cx.typeck_results().expr_ty(expr);
@@ -176,15 +175,15 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
                         return;
                     }
                 }
-            },
+            }
 
             ExprKind::Lit(lit) => {
                 let ty = self.cx.typeck_results().expr_ty(expr);
                 self.check_lit(lit, ty, expr.hir_id);
                 return;
-            },
+            }
 
-            _ => {},
+            _ => {}
         }
 
         walk_expr(self, expr);
@@ -198,7 +197,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
                 } else {
                     self.ty_bounds.push(TyBound::Nothing);
                 }
-            },
+            }
 
             _ => self.ty_bounds.push(TyBound::Nothing),
         }
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 1506ea604f0..d1ab7fb6796 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -503,7 +503,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
     }
 
     fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
-        if let PatKind::Binding(BindingAnnotation::Ref, id, name, _) = pat.kind {
+        if let PatKind::Binding(BindingAnnotation::REF, id, name, _) = pat.kind {
             if let Some(opt_prev_pat) = self.ref_locals.get_mut(&id) {
                 // This binding id has been seen before. Add this pattern to the list of changes.
                 if let Some(prev_pat) = opt_prev_pat {
@@ -581,7 +581,7 @@ fn try_parse_ref_op<'tcx>(
     expr: &'tcx Expr<'_>,
 ) -> Option<(RefOp, &'tcx Expr<'tcx>)> {
     let (def_id, arg) = match expr.kind {
-        ExprKind::MethodCall(_, [arg], _) => (typeck.type_dependent_def_id(expr.hir_id)?, arg),
+        ExprKind::MethodCall(_, arg, [], _) => (typeck.type_dependent_def_id(expr.hir_id)?, arg),
         ExprKind::Call(
             Expr {
                 kind: ExprKind::Path(path),
@@ -796,58 +796,59 @@ fn walk_parents<'tcx>(
                             },
                         })
                     }),
-                ExprKind::MethodCall(_, args, _) => {
+                ExprKind::MethodCall(_, receiver, args, _) => {
                     let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
-                    args.iter().position(|arg| arg.hir_id == child_id).map(|i| {
-                        if i == 0 {
-                            // Check for calls to trait methods where the trait is implemented on a reference.
-                            // Two cases need to be handled:
-                            // * `self` methods on `&T` will never have auto-borrow
-                            // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take
-                            //   priority.
-                            if e.hir_id != child_id {
-                                Position::ReborrowStable(precedence)
-                            } else if let Some(trait_id) = cx.tcx.trait_of_item(id)
-                                && let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e))
-                                && let ty::Ref(_, sub_ty, _) = *arg_ty.kind()
-                                && let subs = match cx
-                                    .typeck_results()
-                                    .node_substs_opt(parent.hir_id)
-                                    .and_then(|subs| subs.get(1..))
-                                {
-                                    Some(subs) => cx.tcx.mk_substs(subs.iter().copied()),
-                                    None => cx.tcx.mk_substs(std::iter::empty::<ty::subst::GenericArg<'_>>()),
-                                } && let impl_ty = if cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref() {
-                                    // Trait methods taking `&self`
-                                    sub_ty
-                                } else {
-                                    // Trait methods taking `self`
-                                    arg_ty
-                                } && impl_ty.is_ref()
-                                && cx.tcx.infer_ctxt().enter(|infcx|
-                                    infcx
-                                        .type_implements_trait(trait_id, impl_ty, subs, cx.param_env)
-                                        .must_apply_modulo_regions()
-                                )
+                    if receiver.hir_id == child_id {
+                        // Check for calls to trait methods where the trait is implemented on a reference.
+                        // Two cases need to be handled:
+                        // * `self` methods on `&T` will never have auto-borrow
+                        // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take
+                        //   priority.
+                        if e.hir_id != child_id {
+                            return Some(Position::ReborrowStable(precedence))
+                        } else if let Some(trait_id) = cx.tcx.trait_of_item(id)
+                            && let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e))
+                            && let ty::Ref(_, sub_ty, _) = *arg_ty.kind()
+                            && let subs = match cx
+                                .typeck_results()
+                                .node_substs_opt(parent.hir_id)
+                                .and_then(|subs| subs.get(1..))
                             {
-                                Position::MethodReceiverRefImpl
+                                Some(subs) => cx.tcx.mk_substs(subs.iter().copied()),
+                                None => cx.tcx.mk_substs(std::iter::empty::<ty::subst::GenericArg<'_>>()),
+                            } && let impl_ty = if cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref() {
+                                // Trait methods taking `&self`
+                                sub_ty
                             } else {
-                                Position::MethodReceiver
-                            }
+                                // Trait methods taking `self`
+                                arg_ty
+                            } && impl_ty.is_ref()
+                            && cx.tcx.infer_ctxt().enter(|infcx|
+                                infcx
+                                    .type_implements_trait(trait_id, impl_ty, subs, cx.param_env)
+                                    .must_apply_modulo_regions()
+                            )
+                        {
+                            return Some(Position::MethodReceiverRefImpl)
                         } else {
-                            let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i];
+                            return Some(Position::MethodReceiver)
+                        }
+                    }
+                    args.iter()
+                        .position(|arg| arg.hir_id == child_id)
+                        .map(|i| {
+                            let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i + 1];
                             if let ty::Param(param_ty) = ty.kind() {
-                                needless_borrow_impl_arg_position(cx, parent, i, *param_ty, e, precedence, msrv)
+                                needless_borrow_impl_arg_position(cx, parent, i + 1, *param_ty, e, precedence, msrv)
                             } else {
                                 ty_auto_deref_stability(
                                     cx,
-                                    cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)),
+                                    cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i + 1)),
                                     precedence,
                                 )
                                 .position_for_arg()
                             }
-                        }
-                    })
+                        })
                 },
                 ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess(name.name)),
                 ExprKind::Unary(UnOp::Deref, child) if child.hir_id == e.hir_id => Some(Position::Deref),
@@ -1174,7 +1175,7 @@ fn replace_types<'tcx>(
         if replaced.insert(param_ty.index) {
             for projection_predicate in projection_predicates {
                 if projection_predicate.projection_ty.self_ty() == param_ty.to_ty(cx.tcx)
-                    && let ty::Term::Ty(term_ty) = projection_predicate.term
+                    && let Some(term_ty) = projection_predicate.term.ty()
                     && let ty::Param(term_param_ty) = term_ty.kind()
                 {
                     let item_def_id = projection_predicate.projection_ty.item_def_id;
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 9ca443b7dff..23c86482b46 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -15,7 +15,7 @@ use rustc_middle::hir::nested_filter;
 use rustc_middle::traits::Reveal;
 use rustc_middle::ty::{
     self, Binder, BoundConstness, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind, TraitPredicate, TraitRef,
-    Ty, TyCtxt, Visibility,
+    Ty, TyCtxt,
 };
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
@@ -464,7 +464,7 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
 fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) {
     if_chain! {
         if let ty::Adt(adt, substs) = ty.kind();
-        if cx.tcx.visibility(adt.did()) == Visibility::Public;
+        if cx.tcx.visibility(adt.did()).is_public();
         if let Some(eq_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Eq);
         if let Some(def_id) = trait_ref.trait_def_id();
         if cx.tcx.is_diagnostic_item(sym::PartialEq, def_id);
diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs
index da111e7378e..512872cedc1 100644
--- a/src/tools/clippy/clippy_lints/src/doc.rs
+++ b/src/tools/clippy/clippy_lints/src/doc.rs
@@ -828,7 +828,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
 
         // check for `unwrap`
         if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
-            let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
+            let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs();
             if is_type_diagnostic_item(self.cx, receiver_ty, sym::Option)
                 || is_type_diagnostic_item(self.cx, receiver_ty, sym::Result)
             {
diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs
index 4e3ae4c9614..e70df3f53c7 100644
--- a/src/tools/clippy/clippy_lints/src/entry.rs
+++ b/src/tools/clippy/clippy_lints/src/entry.rs
@@ -245,8 +245,8 @@ fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Optio
     match expr.kind {
         ExprKind::MethodCall(
             _,
+            map,
             [
-                map,
                 Expr {
                     kind: ExprKind::AddrOf(_, _, key),
                     span: key_span,
@@ -280,7 +280,7 @@ struct InsertExpr<'tcx> {
     value: &'tcx Expr<'tcx>,
 }
 fn try_parse_insert<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<InsertExpr<'tcx>> {
-    if let ExprKind::MethodCall(_, [map, key, value], _) = expr.kind {
+    if let ExprKind::MethodCall(_, map, [key, value], _) = expr.kind {
         let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
         if match_def_path(cx, id, &paths::BTREEMAP_INSERT) || match_def_path(cx, id, &paths::HASHMAP_INSERT) {
             Some(InsertExpr { map, key, value })
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 fdfb821ac78..bce49165e5b 100644
--- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
+++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
@@ -51,7 +51,9 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
             false
         },
         PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)),
-        PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => !etc.is_some() && array_rec(a),
+        PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => {
+            !etc.as_opt_usize().is_some() && array_rec(a)
+        }
         PatKind::Ref(x, _) | PatKind::Box(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 4f9ff97f1fd..1342a4697b9 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -106,7 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
             if !is_adjusted(cx, &body.value);
             if let ExprKind::Call(callee, args) = body.value.kind;
             if let ExprKind::Path(_) = callee.kind;
-            if check_inputs(cx, body.params, args);
+            if check_inputs(cx, body.params, None, args);
             let callee_ty = cx.typeck_results().expr_ty_adjusted(callee);
             let call_ty = cx.typeck_results().type_dependent_def_id(body.value.hir_id)
                 .map_or(callee_ty, |id| cx.tcx.type_of(id));
@@ -146,8 +146,8 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
 
         if_chain!(
             if !is_adjusted(cx, &body.value);
-            if let ExprKind::MethodCall(path, args, _) = body.value.kind;
-            if check_inputs(cx, body.params, args);
+            if let ExprKind::MethodCall(path, receiver, args, _) = body.value.kind;
+            if check_inputs(cx, body.params, Some(receiver), args);
             let method_def_id = cx.typeck_results().type_dependent_def_id(body.value.hir_id).unwrap();
             let substs = cx.typeck_results().node_substs(body.value.hir_id);
             let call_ty = cx.tcx.bound_type_of(method_def_id).subst(cx.tcx, substs);
@@ -167,12 +167,17 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
     }
 }
 
-fn check_inputs(cx: &LateContext<'_>, params: &[Param<'_>], call_args: &[Expr<'_>]) -> bool {
-    if params.len() != call_args.len() {
+fn check_inputs(
+    cx: &LateContext<'_>,
+    params: &[Param<'_>],
+    receiver: Option<&Expr<'_>>,
+    call_args: &[Expr<'_>],
+) -> bool {
+    if receiver.map_or(params.len() != call_args.len(), |_| params.len() != call_args.len() + 1) {
         return false;
     }
     let binding_modes = cx.typeck_results().pat_binding_modes();
-    std::iter::zip(params, call_args).all(|(param, arg)| {
+    let check_inputs = |param: &Param<'_>, arg| {
         match param.pat.kind {
             PatKind::Binding(_, id, ..) if path_to_local_id(arg, id) => {},
             _ => return false,
@@ -200,7 +205,9 @@ fn check_inputs(cx: &LateContext<'_>, params: &[Param<'_>], call_args: &[Expr<'_
             },
             _ => false,
         }
-    })
+    };
+    std::iter::zip(params, receiver.into_iter().chain(call_args.iter()))
+        .all(|(param, arg)| check_inputs(param, arg))
 }
 
 fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tcx>) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs
index 5bf4313b41a..b9ed4af0219 100644
--- a/src/tools/clippy/clippy_lints/src/explicit_write.rs
+++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs
@@ -45,10 +45,10 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
             // match call to unwrap
-            if let ExprKind::MethodCall(unwrap_fun, [write_call], _) = expr.kind;
+            if let ExprKind::MethodCall(unwrap_fun, write_call, [], _) = expr.kind;
             if unwrap_fun.ident.name == sym::unwrap;
             // match call to write_fmt
-            if let ExprKind::MethodCall(write_fun, [write_recv, write_arg], _) = look_in_block(cx, &write_call.kind);
+            if let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = look_in_block(cx, &write_call.kind);
             if write_fun.ident.name == sym!(write_fmt);
             // match calls to std::io::stdout() / std::io::stderr ()
             if let Some(dest_name) = if match_function_call(cx, write_recv, &paths::STDOUT).is_some() {
@@ -128,7 +128,7 @@ fn look_in_block<'tcx, 'hir>(cx: &LateContext<'tcx>, kind: &'tcx ExprKind<'hir>)
         if let Some(Node::Pat(res_pat)) = cx.tcx.hir().find(expr_res);
 
         // Find id of the local we found in the block
-        if let PatKind::Binding(BindingAnnotation::Unannotated, local_hir_id, _ident, None) = local.pat.kind;
+        if let PatKind::Binding(BindingAnnotation::NONE, local_hir_id, _ident, None) = local.pat.kind;
 
         // If those two are the same hir id
         if res_pat.hir_id == local_hir_id;
diff --git a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
index b88e53aeca6..790eea63f58 100644
--- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
+++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
@@ -84,7 +84,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h
 
             // check for `unwrap`
             if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
-                let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
+                let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs();
                 if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option)
                     || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result)
                 {
diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
index bb50e8fcabb..728db41d600 100644
--- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
@@ -164,15 +164,15 @@ fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>) -> Su
     suggestion.maybe_par()
 }
 
-fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
-    if let Some(method) = get_specialized_log_method(cx, &args[1]) {
+fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
+    if let Some(method) = get_specialized_log_method(cx, &args[0]) {
         span_lint_and_sugg(
             cx,
             SUBOPTIMAL_FLOPS,
             expr.span,
             "logarithm for bases 2, 10 and e can be computed more accurately",
             "consider using",
-            format!("{}.{}()", Sugg::hir(cx, &args[0], "..").maybe_par(), method),
+            format!("{}.{}()", Sugg::hir(cx, receiver, "..").maybe_par(), method),
             Applicability::MachineApplicable,
         );
     }
@@ -180,14 +180,14 @@ fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
 
 // TODO: Lint expressions of the form `(x + y).ln()` where y > 1 and
 // suggest usage of `(x + (y - 1)).ln_1p()` instead
-fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
+fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) {
     if let ExprKind::Binary(
         Spanned {
             node: BinOpKind::Add, ..
         },
         lhs,
         rhs,
-    ) = &args[0].kind
+    ) = receiver.kind
     {
         let recv = match (
             constant(cx, cx.typeck_results(), lhs),
@@ -235,9 +235,9 @@ fn get_integer_from_float_constant(value: &Constant) -> Option<i32> {
     }
 }
 
-fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
+fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
     // Check receiver
-    if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) {
+    if let Some((value, _)) = constant(cx, cx.typeck_results(), receiver) {
         let method = if F32(f32_consts::E) == value || F64(f64_consts::E) == value {
             "exp"
         } else if F32(2.0) == value || F64(2.0) == value {
@@ -252,24 +252,24 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
             expr.span,
             "exponent for bases 2 and e can be computed more accurately",
             "consider using",
-            format!("{}.{}()", prepare_receiver_sugg(cx, &args[1]), method),
+            format!("{}.{}()", prepare_receiver_sugg(cx, &args[0]), method),
             Applicability::MachineApplicable,
         );
     }
 
     // Check argument
-    if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[1]) {
+    if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) {
         let (lint, help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value {
             (
                 SUBOPTIMAL_FLOPS,
                 "square-root of a number can be computed more efficiently and accurately",
-                format!("{}.sqrt()", Sugg::hir(cx, &args[0], "..").maybe_par()),
+                format!("{}.sqrt()", Sugg::hir(cx, receiver, "..").maybe_par()),
             )
         } else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value {
             (
                 IMPRECISE_FLOPS,
                 "cube-root of a number can be computed more accurately",
-                format!("{}.cbrt()", Sugg::hir(cx, &args[0], "..").maybe_par()),
+                format!("{}.cbrt()", Sugg::hir(cx, receiver, "..").maybe_par()),
             )
         } else if let Some(exponent) = get_integer_from_float_constant(&value) {
             (
@@ -277,7 +277,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
                 "exponentiation with integer powers can be computed more efficiently",
                 format!(
                     "{}.powi({})",
-                    Sugg::hir(cx, &args[0], "..").maybe_par(),
+                    Sugg::hir(cx, receiver, "..").maybe_par(),
                     numeric_literal::format(&exponent.to_string(), None, false)
                 ),
             )
@@ -297,13 +297,14 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
     }
 }
 
-fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
-    if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[1]) {
+fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
+    if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) {
         if value == Int(2) {
             if let Some(parent) = get_parent_expr(cx, expr) {
                 if let Some(grandparent) = get_parent_expr(cx, parent) {
-                    if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, args, _) = grandparent.kind {
-                        if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() {
+                    if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = grandparent.kind
+                    {
+                        if method_name.as_str() == "sqrt" && detect_hypot(cx, receiver).is_some() {
                             return;
                         }
                     }
@@ -327,8 +328,8 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
                         "consider using",
                         format!(
                             "{}.mul_add({}, {})",
-                            Sugg::hir(cx, &args[0], "..").maybe_par(),
-                            Sugg::hir(cx, &args[0], ".."),
+                            Sugg::hir(cx, receiver, "..").maybe_par(),
+                            Sugg::hir(cx, receiver, ".."),
                             Sugg::hir(cx, other_addend, ".."),
                         ),
                         Applicability::MachineApplicable,
@@ -339,14 +340,14 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
     }
 }
 
-fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<String> {
+fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option<String> {
     if let ExprKind::Binary(
         Spanned {
             node: BinOpKind::Add, ..
         },
         add_lhs,
         add_rhs,
-    ) = args[0].kind
+    ) = receiver.kind
     {
         // check if expression of the form x * x + y * y
         if_chain! {
@@ -363,12 +364,12 @@ fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<String> {
         if_chain! {
             if let ExprKind::MethodCall(
                 PathSegment { ident: lmethod_name, .. },
-                [largs_0, largs_1, ..],
+                largs_0, [largs_1, ..],
                 _
             ) = &add_lhs.kind;
             if let ExprKind::MethodCall(
                 PathSegment { ident: rmethod_name, .. },
-                [rargs_0, rargs_1, ..],
+                rargs_0, [rargs_1, ..],
                 _
             ) = &add_rhs.kind;
             if lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi";
@@ -384,8 +385,8 @@ fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<String> {
     None
 }
 
-fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
-    if let Some(message) = detect_hypot(cx, args) {
+fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) {
+    if let Some(message) = detect_hypot(cx, receiver) {
         span_lint_and_sugg(
             cx,
             IMPRECISE_FLOPS,
@@ -406,7 +407,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) {
         if cx.typeck_results().expr_ty(lhs).is_floating_point();
         if let Some((value, _)) = constant(cx, cx.typeck_results(), rhs);
         if F32(1.0) == value || F64(1.0) == value;
-        if let ExprKind::MethodCall(path, [self_arg, ..], _) = &lhs.kind;
+        if let ExprKind::MethodCall(path, self_arg, ..) = &lhs.kind;
         if cx.typeck_results().expr_ty(self_arg).is_floating_point();
         if path.ident.name.as_str() == "exp";
         then {
@@ -450,8 +451,8 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) {
     ) = &expr.kind
     {
         if let Some(parent) = get_parent_expr(cx, expr) {
-            if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, args, _) = parent.kind {
-                if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() {
+            if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = parent.kind {
+                if method_name.as_str() == "sqrt" && detect_hypot(cx, receiver).is_some() {
                     return;
                 }
             }
@@ -586,14 +587,14 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) {
 
 fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool {
     if_chain! {
-        if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, args_a, _) = expr_a.kind;
-        if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, args_b, _) = expr_b.kind;
+        if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, _, args_a, _) = expr_a.kind;
+        if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, _, args_b, _) = expr_b.kind;
         then {
             return method_name_a.as_str() == method_name_b.as_str() &&
                 args_a.len() == args_b.len() &&
                 (
                     ["ln", "log2", "log10"].contains(&method_name_a.as_str()) ||
-                    method_name_a.as_str() == "log" && args_a.len() == 2 && eq_expr_value(cx, &args_a[1], &args_b[1])
+                    method_name_a.as_str() == "log" && args_a.len() == 1 && eq_expr_value(cx, &args_a[0], &args_b[0])
                 );
         }
     }
@@ -612,8 +613,8 @@ fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) {
             rhs,
         ) = &expr.kind;
         if are_same_base_logs(cx, lhs, rhs);
-        if let ExprKind::MethodCall(_, [largs_self, ..], _) = &lhs.kind;
-        if let ExprKind::MethodCall(_, [rargs_self, ..], _) = &rhs.kind;
+        if let ExprKind::MethodCall(_, largs_self, ..) = &lhs.kind;
+        if let ExprKind::MethodCall(_, rargs_self, ..) = &rhs.kind;
         then {
             span_lint_and_sugg(
                 cx,
@@ -711,16 +712,16 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
             return;
         }
 
-        if let ExprKind::MethodCall(path, args, _) = &expr.kind {
-            let recv_ty = cx.typeck_results().expr_ty(&args[0]);
+        if let ExprKind::MethodCall(path, receiver, args, _) = &expr.kind {
+            let recv_ty = cx.typeck_results().expr_ty(receiver);
 
             if recv_ty.is_floating_point() {
                 match path.ident.name.as_str() {
-                    "ln" => check_ln1p(cx, expr, args),
-                    "log" => check_log_base(cx, expr, args),
-                    "powf" => check_powf(cx, expr, args),
-                    "powi" => check_powi(cx, expr, args),
-                    "sqrt" => check_hypot(cx, expr, args),
+                    "ln" => check_ln1p(cx, expr, receiver),
+                    "log" => check_log_base(cx, expr, receiver, args),
+                    "powf" => check_powf(cx, expr, receiver, args),
+                    "powi" => check_powi(cx, expr, receiver, args),
+                    "sqrt" => check_hypot(cx, expr, receiver),
                     _ => {},
                 }
             }
diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs
index 9fb9fd99748..2a55c48cf77 100644
--- a/src/tools/clippy/clippy_lints/src/format_args.rs
+++ b/src/tools/clippy/clippy_lints/src/format_args.rs
@@ -99,7 +99,12 @@ fn outermost_expn_data(expn_data: ExpnData) -> ExpnData {
     }
 }
 
-fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symbol, arg: &Expr<'_>) {
+fn check_format_in_format_args(
+    cx: &LateContext<'_>,
+    call_site: Span,
+    name: Symbol,
+    arg: &Expr<'_>,
+) {
     let expn_data = arg.span.ctxt().outer_expn_data();
     if expn_data.call_site.from_expansion() {
         return;
@@ -126,7 +131,7 @@ fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symb
 fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Expr<'_>) {
     if_chain! {
         if !value.span.from_expansion();
-        if let ExprKind::MethodCall(_, [receiver], _) = value.kind;
+        if let ExprKind::MethodCall(_, receiver, [], _) = value.kind;
         if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id);
         if is_diag_trait_item(cx, method_def_id, sym::ToString);
         let receiver_ty = cx.typeck_results().expr_ty(receiver);
@@ -177,10 +182,7 @@ fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Ex
 
 // Returns true if `hir_id` is referred to by multiple format params
 fn is_aliased(args: &FormatArgsExpn<'_>, hir_id: HirId) -> bool {
-    args.params()
-        .filter(|param| param.value.hir_id == hir_id)
-        .at_most_one()
-        .is_err()
+    args.params().filter(|param| param.value.hir_id == hir_id).at_most_one().is_err()
 }
 
 fn count_needed_derefs<'tcx, I>(mut ty: Ty<'tcx>, mut iter: I) -> (usize, Ty<'tcx>)
@@ -190,11 +192,7 @@ where
     let mut n_total = 0;
     let mut n_needed = 0;
     loop {
-        if let Some(Adjustment {
-            kind: Adjust::Deref(overloaded_deref),
-            target,
-        }) = iter.next()
-        {
+        if let Some(Adjustment { kind: Adjust::Deref(overloaded_deref), target }) = iter.next() {
             n_total += 1;
             if overloaded_deref.is_some() {
                 n_needed = n_total;
diff --git a/src/tools/clippy/clippy_lints/src/format_impl.rs b/src/tools/clippy/clippy_lints/src/format_impl.rs
index d8bc0bf08f2..b628fd9f758 100644
--- a/src/tools/clippy/clippy_lints/src/format_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/format_impl.rs
@@ -139,7 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatImpl {
 fn check_to_string_in_display(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if_chain! {
         // Get the hir_id of the object we are calling the method on
-        if let ExprKind::MethodCall(path, [ref self_arg, ..], _) = expr.kind;
+        if let ExprKind::MethodCall(path, self_arg, ..) = expr.kind;
         // Is the method to_string() ?
         if path.ident.name == sym::to_string;
         // Is the method a part of the ToString trait? (i.e. not to_string() implemented
diff --git a/src/tools/clippy/clippy_lints/src/format_push_string.rs b/src/tools/clippy/clippy_lints/src/format_push_string.rs
index ebf5ab086dc..9b9f1872bfc 100644
--- a/src/tools/clippy/clippy_lints/src/format_push_string.rs
+++ b/src/tools/clippy/clippy_lints/src/format_push_string.rs
@@ -54,7 +54,7 @@ fn is_format(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 impl<'tcx> LateLintPass<'tcx> for FormatPushString {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         let arg = match expr.kind {
-            ExprKind::MethodCall(_, [_, arg], _) => {
+            ExprKind::MethodCall(_, _, [arg], _) => {
                 if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) &&
                 match_def_path(cx, fn_def_id, &paths::PUSH_STR) {
                     arg
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 6672a6cb0b5..a17b23f5edc 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -212,7 +212,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> {
             return;
         }
         match expr.kind {
-            Call(_, args) | MethodCall(_, args, _) => {
+            Call(_, args) => {
                 let mut tys = DefIdSet::default();
                 for arg in args {
                     if self.cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id())
@@ -230,6 +230,24 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> {
                     tys.clear();
                 }
             },
+            MethodCall(_, receiver, args, _) => {
+                let mut tys = DefIdSet::default();
+                for arg in std::iter::once(receiver).chain(args.iter()) {
+                    if self.cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id())
+                        && is_mutable_ty(
+                            self.cx,
+                            self.cx.tcx.typeck(arg.hir_id.owner).expr_ty(arg),
+                            arg.span,
+                            &mut tys,
+                        )
+                        && is_mutated_static(arg)
+                    {
+                        self.mutates_static = true;
+                        return;
+                    }
+                    tys.clear();
+                }
+            },
             Assign(target, ..) | AssignOp(_, target, _) | AddrOf(_, hir::Mutability::Mut, target) => {
                 self.mutates_static |= is_mutated_static(target);
             },
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 565a1c871d7..3bbfa52e810 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
@@ -88,11 +88,12 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> {
                     }
                 }
             },
-            hir::ExprKind::MethodCall(_, args, _) => {
+            hir::ExprKind::MethodCall(_, receiver, args, _) => {
                 let def_id = self.typeck_results.type_dependent_def_id(expr.hir_id).unwrap();
                 let base_type = self.cx.tcx.type_of(def_id);
 
                 if type_is_unsafe_function(self.cx, base_type) {
+                    self.check_arg(receiver);
                     for arg in args {
                         self.check_arg(arg);
                     }
diff --git a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
index 4d703d691ac..9ea8c494cfc 100644
--- a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
+++ b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
@@ -129,7 +129,7 @@ impl<'tcx, 'l> ArmVisitor<'tcx, 'l> {
 
 fn is_mutex_lock_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
     if_chain! {
-        if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind;
+        if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind;
         if path.ident.as_str() == "lock";
         let ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
         if is_type_diagnostic_item(cx, ty, sym::Mutex);
diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
index d0c6495e35a..0dd7f5bf000 100644
--- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
@@ -95,12 +95,14 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap<hir
     let mut removed_pat: FxHashSet<hir::HirId> = FxHashSet::default();
     let mut slices: FxIndexMap<hir::HirId, SliceLintInformation> = FxIndexMap::default();
     pat.walk_always(|pat| {
-        if let hir::PatKind::Binding(binding, value_hir_id, ident, sub_pat) = pat.kind {
-            // We'll just ignore mut and ref mut for simplicity sake right now
-            if let hir::BindingAnnotation::Mutable | hir::BindingAnnotation::RefMut = binding {
-                return;
-            }
-
+        // We'll just ignore mut and ref mut for simplicity sake right now
+        if let hir::PatKind::Binding(
+            hir::BindingAnnotation(by_ref, hir::Mutability::Not),
+            value_hir_id,
+            ident,
+            sub_pat,
+        ) = pat.kind
+        {
             // This block catches bindings with sub patterns. It would be hard to build a correct suggestion
             // for them and it's likely that the user knows what they are doing in such a case.
             if removed_pat.contains(&value_hir_id) {
@@ -116,7 +118,7 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap<hir
             if let ty::Slice(inner_ty) | ty::Array(inner_ty, _) = bound_ty.peel_refs().kind() {
                 // The values need to use the `ref` keyword if they can't be copied.
                 // This will need to be adjusted if the lint want to support mutable access in the future
-                let src_is_ref = bound_ty.is_ref() && binding != hir::BindingAnnotation::Ref;
+                let src_is_ref = bound_ty.is_ref() && by_ref != hir::ByRef::Yes;
                 let needs_ref = !(src_is_ref || is_copy(cx, *inner_ty));
 
                 let slice_info = slices
diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
index 01c7eef4e04..d55a8e1ead1 100644
--- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
@@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for InfiniteIter {
             MaybeInfinite => (MAYBE_INFINITE_ITER, "possible infinite iteration detected"),
             Finite => {
                 return;
-            },
+            }
         };
         span_lint(cx, lint, expr.span, msg);
     }
@@ -123,43 +123,43 @@ use self::Heuristic::{All, Always, Any, First};
 /// is an upper bound, e.g., some methods can return a possibly
 /// infinite iterator at worst, e.g., `take_while`.
 const HEURISTICS: [(&str, usize, Heuristic, Finiteness); 19] = [
-    ("zip", 2, All, Infinite),
-    ("chain", 2, Any, Infinite),
-    ("cycle", 1, Always, Infinite),
-    ("map", 2, First, Infinite),
-    ("by_ref", 1, First, Infinite),
-    ("cloned", 1, First, Infinite),
-    ("rev", 1, First, Infinite),
-    ("inspect", 1, First, Infinite),
-    ("enumerate", 1, First, Infinite),
-    ("peekable", 2, First, Infinite),
-    ("fuse", 1, First, Infinite),
-    ("skip", 2, First, Infinite),
-    ("skip_while", 1, First, Infinite),
-    ("filter", 2, First, Infinite),
-    ("filter_map", 2, First, Infinite),
-    ("flat_map", 2, First, Infinite),
-    ("unzip", 1, First, Infinite),
-    ("take_while", 2, First, MaybeInfinite),
-    ("scan", 3, First, MaybeInfinite),
+    ("zip", 1, All, Infinite),
+    ("chain", 1, Any, Infinite),
+    ("cycle", 0, Always, Infinite),
+    ("map", 1, First, Infinite),
+    ("by_ref", 0, First, Infinite),
+    ("cloned", 0, First, Infinite),
+    ("rev", 0, First, Infinite),
+    ("inspect", 0, First, Infinite),
+    ("enumerate", 0, First, Infinite),
+    ("peekable", 1, First, Infinite),
+    ("fuse", 0, First, Infinite),
+    ("skip", 1, First, Infinite),
+    ("skip_while", 0, First, Infinite),
+    ("filter", 1, First, Infinite),
+    ("filter_map", 1, First, Infinite),
+    ("flat_map", 1, First, Infinite),
+    ("unzip", 0, First, Infinite),
+    ("take_while", 1, First, MaybeInfinite),
+    ("scan", 2, First, MaybeInfinite),
 ];
 
 fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
     match expr.kind {
-        ExprKind::MethodCall(method, args, _) => {
+        ExprKind::MethodCall(method, receiver, args, _) => {
             for &(name, len, heuristic, cap) in &HEURISTICS {
                 if method.ident.name.as_str() == name && args.len() == len {
                     return (match heuristic {
                         Always => Infinite,
-                        First => is_infinite(cx, &args[0]),
-                        Any => is_infinite(cx, &args[0]).or(is_infinite(cx, &args[1])),
-                        All => is_infinite(cx, &args[0]).and(is_infinite(cx, &args[1])),
+                        First => is_infinite(cx, receiver),
+                        Any => is_infinite(cx, receiver).or(is_infinite(cx, &args[0])),
+                        All => is_infinite(cx, receiver).and(is_infinite(cx, &args[0])),
                     })
                     .and(cap);
                 }
             }
-            if method.ident.name == sym!(flat_map) && args.len() == 2 {
-                if let ExprKind::Closure(&Closure { body, .. }) = args[1].kind {
+            if method.ident.name == sym!(flat_map) && args.len() == 1 {
+                if let ExprKind::Closure(&Closure { body, .. }) = args[0].kind {
                     let body = cx.tcx.hir().body(body);
                     return is_infinite(cx, &body.value);
                 }
@@ -179,29 +179,29 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
 /// the names and argument lengths of methods that *may* exhaust their
 /// iterators
 const POSSIBLY_COMPLETING_METHODS: [(&str, usize); 6] = [
-    ("find", 2),
-    ("rfind", 2),
-    ("position", 2),
-    ("rposition", 2),
-    ("any", 2),
-    ("all", 2),
+    ("find", 1),
+    ("rfind", 1),
+    ("position", 1),
+    ("rposition", 1),
+    ("any", 1),
+    ("all", 1),
 ];
 
 /// the names and argument lengths of methods that *always* exhaust
 /// their iterators
 const COMPLETING_METHODS: [(&str, usize); 12] = [
-    ("count", 1),
-    ("fold", 3),
-    ("for_each", 2),
-    ("partition", 2),
-    ("max", 1),
-    ("max_by", 2),
-    ("max_by_key", 2),
-    ("min", 1),
-    ("min_by", 2),
-    ("min_by_key", 2),
-    ("sum", 1),
-    ("product", 1),
+    ("count", 0),
+    ("fold", 2),
+    ("for_each", 1),
+    ("partition", 1),
+    ("max", 0),
+    ("max_by", 1),
+    ("max_by_key", 1),
+    ("min", 0),
+    ("min_by", 1),
+    ("min_by_key", 1),
+    ("sum", 0),
+    ("product", 0),
 ];
 
 /// the paths of types that are known to be infinitely allocating
@@ -218,26 +218,24 @@ const INFINITE_COLLECTORS: &[Symbol] = &[
 
 fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
     match expr.kind {
-        ExprKind::MethodCall(method, args, _) => {
+        ExprKind::MethodCall(method, receiver, args, _) => {
             for &(name, len) in &COMPLETING_METHODS {
                 if method.ident.name.as_str() == name && args.len() == len {
-                    return is_infinite(cx, &args[0]);
+                    return is_infinite(cx, receiver);
                 }
             }
             for &(name, len) in &POSSIBLY_COMPLETING_METHODS {
                 if method.ident.name.as_str() == name && args.len() == len {
-                    return MaybeInfinite.and(is_infinite(cx, &args[0]));
+                    return MaybeInfinite.and(is_infinite(cx, receiver));
                 }
             }
-            if method.ident.name == sym!(last) && args.len() == 1 {
-                let not_double_ended = cx
-                    .tcx
-                    .get_diagnostic_item(sym::DoubleEndedIterator)
-                    .map_or(false, |id| {
-                        !implements_trait(cx, cx.typeck_results().expr_ty(&args[0]), id, &[])
+            if method.ident.name == sym!(last) && args.is_empty() {
+                let not_double_ended =
+                    cx.tcx.get_diagnostic_item(sym::DoubleEndedIterator).map_or(false, |id| {
+                        !implements_trait(cx, cx.typeck_results().expr_ty(receiver), id, &[])
                     });
                 if not_double_ended {
-                    return is_infinite(cx, &args[0]);
+                    return is_infinite(cx, receiver);
                 }
             } else if method.ident.name == sym!(collect) {
                 let ty = cx.typeck_results().expr_ty(expr);
@@ -245,7 +243,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
                     .iter()
                     .any(|diag_item| is_type_diagnostic_item(cx, ty, *diag_item))
                 {
-                    return is_infinite(cx, &args[0]);
+                    return is_infinite(cx, receiver);
                 }
             }
         },
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 246f5aad8fb..3cbdaff407b 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -370,7 +370,7 @@ fn check_for_is_empty<'tcx>(
 }
 
 fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) {
-    if let (&ExprKind::MethodCall(method_path, args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) {
+    if let (&ExprKind::MethodCall(method_path, receiver, args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) {
         // check if we are in an is_empty() method
         if let Some(name) = get_item_name(cx, method) {
             if name.as_str() == "is_empty" {
@@ -378,7 +378,7 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>
             }
         }
 
-        check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to);
+        check_len(cx, span, method_path.ident.name, receiver, args, &lit.node, op, compare_to);
     } else {
         check_empty_expr(cx, span, method, lit, op);
     }
@@ -388,6 +388,7 @@ fn check_len(
     cx: &LateContext<'_>,
     span: Span,
     method_name: Symbol,
+    receiver: &Expr<'_>,
     args: &[Expr<'_>],
     lit: &LitKind,
     op: &str,
@@ -399,7 +400,7 @@ fn check_len(
             return;
         }
 
-        if method_name == sym::len && args.len() == 1 && has_is_empty(cx, &args[0]) {
+        if method_name == sym::len && args.is_empty() && has_is_empty(cx, receiver) {
             let mut applicability = Applicability::MachineApplicable;
             span_lint_and_sugg(
                 cx,
@@ -410,7 +411,7 @@ fn check_len(
                 format!(
                     "{}{}.is_empty()",
                     op,
-                    snippet_with_applicability(cx, args[0].span, "_", &mut applicability)
+                    snippet_with_applicability(cx, receiver.span, "_", &mut applicability)
                 ),
                 applicability,
             );
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 56bbbbbc819..10fc0f4018e 100644
--- a/src/tools/clippy/clippy_lints/src/let_if_seq.rs
+++ b/src/tools/clippy/clippy_lints/src/let_if_seq.rs
@@ -4,7 +4,7 @@ use clippy_utils::{path_to_local_id, visitors::is_local_used};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
-use rustc_hir::BindingAnnotation;
+use rustc_hir::{BindingAnnotation, Mutability};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
@@ -98,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq {
                     };
 
                     let mutability = match mode {
-                        BindingAnnotation::RefMut | BindingAnnotation::Mutable => "<mut> ",
+                        BindingAnnotation(_, Mutability::Mut) => "<mut> ",
                         _ => "",
                     };
 
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index dfdaf90f09f..c70aa79ac8d 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -523,7 +523,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     #[cfg(feature = "internal")]
     {
         if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) {
-            store.register_late_pass(|| Box::new(utils::internal_lints::metadata_collector::MetadataCollector::new()));
+            store.register_late_pass(|_| Box::new(utils::internal_lints::metadata_collector::MetadataCollector::new()));
             return;
         }
     }
@@ -533,69 +533,69 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     {
         store.register_early_pass(|| Box::new(utils::internal_lints::ClippyLintsInternal));
         store.register_early_pass(|| Box::new(utils::internal_lints::ProduceIce));
-        store.register_late_pass(|| Box::new(utils::internal_lints::CollapsibleCalls));
-        store.register_late_pass(|| Box::new(utils::internal_lints::CompilerLintFunctions::new()));
-        store.register_late_pass(|| Box::new(utils::internal_lints::IfChainStyle));
-        store.register_late_pass(|| Box::new(utils::internal_lints::InvalidPaths));
-        store.register_late_pass(|| Box::new(utils::internal_lints::InterningDefinedSymbol::default()));
-        store.register_late_pass(|| Box::new(utils::internal_lints::LintWithoutLintPass::default()));
-        store.register_late_pass(|| Box::new(utils::internal_lints::MatchTypeOnDiagItem));
-        store.register_late_pass(|| Box::new(utils::internal_lints::OuterExpnDataPass));
-        store.register_late_pass(|| Box::new(utils::internal_lints::MsrvAttrImpl));
+        store.register_late_pass(|_| Box::new(utils::internal_lints::CollapsibleCalls));
+        store.register_late_pass(|_| Box::new(utils::internal_lints::CompilerLintFunctions::new()));
+        store.register_late_pass(|_| Box::new(utils::internal_lints::IfChainStyle));
+        store.register_late_pass(|_| Box::new(utils::internal_lints::InvalidPaths));
+        store.register_late_pass(|_| Box::new(utils::internal_lints::InterningDefinedSymbol::default()));
+        store.register_late_pass(|_| Box::new(utils::internal_lints::LintWithoutLintPass::default()));
+        store.register_late_pass(|_| Box::new(utils::internal_lints::MatchTypeOnDiagItem));
+        store.register_late_pass(|_| Box::new(utils::internal_lints::OuterExpnDataPass));
+        store.register_late_pass(|_| Box::new(utils::internal_lints::MsrvAttrImpl));
     }
 
     let arithmetic_allowed = conf.arithmetic_allowed.clone();
-    store.register_late_pass(move || Box::new(operators::arithmetic::Arithmetic::new(arithmetic_allowed.clone())));
-    store.register_late_pass(|| Box::new(utils::dump_hir::DumpHir));
-    store.register_late_pass(|| Box::new(utils::author::Author));
+    store.register_late_pass(move |_| Box::new(operators::arithmetic::Arithmetic::new(arithmetic_allowed.clone())));
+    store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir));
+    store.register_late_pass(|_| Box::new(utils::author::Author));
     let await_holding_invalid_types = conf.await_holding_invalid_types.clone();
-    store.register_late_pass(move || {
+    store.register_late_pass(move |_| {
         Box::new(await_holding_invalid::AwaitHolding::new(
             await_holding_invalid_types.clone(),
         ))
     });
-    store.register_late_pass(|| Box::new(serde_api::SerdeApi));
+    store.register_late_pass(|_| Box::new(serde_api::SerdeApi));
     let vec_box_size_threshold = conf.vec_box_size_threshold;
     let type_complexity_threshold = conf.type_complexity_threshold;
     let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
-    store.register_late_pass(move || {
+    store.register_late_pass(move |_| {
         Box::new(types::Types::new(
             vec_box_size_threshold,
             type_complexity_threshold,
             avoid_breaking_exported_api,
         ))
     });
-    store.register_late_pass(|| Box::new(booleans::NonminimalBool));
-    store.register_late_pass(|| Box::new(enum_clike::UnportableVariant));
-    store.register_late_pass(|| Box::new(float_literal::FloatLiteral));
-    store.register_late_pass(|| Box::new(ptr::Ptr));
-    store.register_late_pass(|| Box::new(needless_bool::NeedlessBool));
-    store.register_late_pass(|| Box::new(needless_bool::BoolComparison));
-    store.register_late_pass(|| Box::new(needless_for_each::NeedlessForEach));
-    store.register_late_pass(|| Box::new(misc::MiscLints));
-    store.register_late_pass(|| Box::new(eta_reduction::EtaReduction));
-    store.register_late_pass(|| Box::new(mut_mut::MutMut));
-    store.register_late_pass(|| Box::new(mut_reference::UnnecessaryMutPassed));
-    store.register_late_pass(|| Box::new(len_zero::LenZero));
-    store.register_late_pass(|| Box::new(attrs::Attributes));
-    store.register_late_pass(|| Box::new(blocks_in_if_conditions::BlocksInIfConditions));
-    store.register_late_pass(|| Box::new(unicode::Unicode));
-    store.register_late_pass(|| Box::new(uninit_vec::UninitVec));
-    store.register_late_pass(|| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd));
-    store.register_late_pass(|| Box::new(strings::StringAdd));
-    store.register_late_pass(|| Box::new(implicit_return::ImplicitReturn));
-    store.register_late_pass(|| Box::new(implicit_saturating_sub::ImplicitSaturatingSub));
-    store.register_late_pass(|| Box::new(default_numeric_fallback::DefaultNumericFallback));
-    store.register_late_pass(|| Box::new(inconsistent_struct_constructor::InconsistentStructConstructor));
-    store.register_late_pass(|| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions));
+    store.register_late_pass(|_| Box::new(booleans::NonminimalBool));
+    store.register_late_pass(|_| Box::new(enum_clike::UnportableVariant));
+    store.register_late_pass(|_| Box::new(float_literal::FloatLiteral));
+    store.register_late_pass(|_| Box::new(ptr::Ptr));
+    store.register_late_pass(|_| Box::new(needless_bool::NeedlessBool));
+    store.register_late_pass(|_| Box::new(needless_bool::BoolComparison));
+    store.register_late_pass(|_| Box::new(needless_for_each::NeedlessForEach));
+    store.register_late_pass(|_| Box::new(misc::MiscLints));
+    store.register_late_pass(|_| Box::new(eta_reduction::EtaReduction));
+    store.register_late_pass(|_| Box::new(mut_mut::MutMut));
+    store.register_late_pass(|_| Box::new(mut_reference::UnnecessaryMutPassed));
+    store.register_late_pass(|_| Box::new(len_zero::LenZero));
+    store.register_late_pass(|_| Box::new(attrs::Attributes));
+    store.register_late_pass(|_| Box::new(blocks_in_if_conditions::BlocksInIfConditions));
+    store.register_late_pass(|_| Box::new(unicode::Unicode));
+    store.register_late_pass(|_| Box::new(uninit_vec::UninitVec));
+    store.register_late_pass(|_| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd));
+    store.register_late_pass(|_| Box::new(strings::StringAdd));
+    store.register_late_pass(|_| Box::new(implicit_return::ImplicitReturn));
+    store.register_late_pass(|_| Box::new(implicit_saturating_sub::ImplicitSaturatingSub));
+    store.register_late_pass(|_| Box::new(default_numeric_fallback::DefaultNumericFallback));
+    store.register_late_pass(|_| Box::new(inconsistent_struct_constructor::InconsistentStructConstructor));
+    store.register_late_pass(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions));
     store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports));
 
     let msrv = read_msrv(conf, sess);
     let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
     let allow_expect_in_tests = conf.allow_expect_in_tests;
     let allow_unwrap_in_tests = conf.allow_unwrap_in_tests;
-    store.register_late_pass(move || Box::new(approx_const::ApproxConstant::new(msrv)));
-    store.register_late_pass(move || {
+    store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(msrv)));
+    store.register_late_pass(move |_| {
         Box::new(methods::Methods::new(
             avoid_breaking_exported_api,
             msrv,
@@ -603,74 +603,74 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
             allow_unwrap_in_tests,
         ))
     });
-    store.register_late_pass(move || Box::new(matches::Matches::new(msrv)));
+    store.register_late_pass(move |_| Box::new(matches::Matches::new(msrv)));
     store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(msrv)));
-    store.register_late_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv)));
-    store.register_late_pass(move || Box::new(manual_strip::ManualStrip::new(msrv)));
+    store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv)));
+    store.register_late_pass(move |_| Box::new(manual_strip::ManualStrip::new(msrv)));
     store.register_early_pass(move || Box::new(redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv)));
     store.register_early_pass(move || Box::new(redundant_field_names::RedundantFieldNames::new(msrv)));
-    store.register_late_pass(move || Box::new(checked_conversions::CheckedConversions::new(msrv)));
-    store.register_late_pass(move || Box::new(mem_replace::MemReplace::new(msrv)));
-    store.register_late_pass(move || Box::new(ranges::Ranges::new(msrv)));
-    store.register_late_pass(move || Box::new(from_over_into::FromOverInto::new(msrv)));
-    store.register_late_pass(move || Box::new(use_self::UseSelf::new(msrv)));
-    store.register_late_pass(move || Box::new(missing_const_for_fn::MissingConstForFn::new(msrv)));
-    store.register_late_pass(move || Box::new(needless_question_mark::NeedlessQuestionMark));
-    store.register_late_pass(move || Box::new(casts::Casts::new(msrv)));
+    store.register_late_pass(move |_| Box::new(checked_conversions::CheckedConversions::new(msrv)));
+    store.register_late_pass(move |_| Box::new(mem_replace::MemReplace::new(msrv)));
+    store.register_late_pass(move |_| Box::new(ranges::Ranges::new(msrv)));
+    store.register_late_pass(move |_| Box::new(from_over_into::FromOverInto::new(msrv)));
+    store.register_late_pass(move |_| Box::new(use_self::UseSelf::new(msrv)));
+    store.register_late_pass(move |_| Box::new(missing_const_for_fn::MissingConstForFn::new(msrv)));
+    store.register_late_pass(move |_| Box::new(needless_question_mark::NeedlessQuestionMark));
+    store.register_late_pass(move |_| Box::new(casts::Casts::new(msrv)));
     store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv)));
-    store.register_late_pass(|| Box::new(size_of_in_element_count::SizeOfInElementCount));
-    store.register_late_pass(|| Box::new(same_name_method::SameNameMethod));
+    store.register_late_pass(|_| Box::new(size_of_in_element_count::SizeOfInElementCount));
+    store.register_late_pass(|_| Box::new(same_name_method::SameNameMethod));
     let max_suggested_slice_pattern_length = conf.max_suggested_slice_pattern_length;
-    store.register_late_pass(move || {
+    store.register_late_pass(move |_| {
         Box::new(index_refutable_slice::IndexRefutableSlice::new(
             max_suggested_slice_pattern_length,
             msrv,
         ))
     });
-    store.register_late_pass(|| Box::new(shadow::Shadow::default()));
-    store.register_late_pass(|| Box::new(unit_types::UnitTypes));
-    store.register_late_pass(|| Box::new(loops::Loops));
-    store.register_late_pass(|| Box::new(main_recursion::MainRecursion::default()));
-    store.register_late_pass(|| Box::new(lifetimes::Lifetimes));
-    store.register_late_pass(|| Box::new(entry::HashMapPass));
-    store.register_late_pass(|| Box::new(minmax::MinMaxPass));
-    store.register_late_pass(|| Box::new(zero_div_zero::ZeroDiv));
-    store.register_late_pass(|| Box::new(mutex_atomic::Mutex));
-    store.register_late_pass(|| Box::new(needless_update::NeedlessUpdate));
-    store.register_late_pass(|| Box::new(needless_borrowed_ref::NeedlessBorrowedRef));
-    store.register_late_pass(|| Box::new(borrow_deref_ref::BorrowDerefRef));
-    store.register_late_pass(|| Box::new(no_effect::NoEffect));
-    store.register_late_pass(|| Box::new(temporary_assignment::TemporaryAssignment));
-    store.register_late_pass(move || Box::new(transmute::Transmute::new(msrv)));
+    store.register_late_pass(|_| Box::new(shadow::Shadow::default()));
+    store.register_late_pass(|_| Box::new(unit_types::UnitTypes));
+    store.register_late_pass(|_| Box::new(loops::Loops));
+    store.register_late_pass(|_| Box::new(main_recursion::MainRecursion::default()));
+    store.register_late_pass(|_| Box::new(lifetimes::Lifetimes));
+    store.register_late_pass(|_| Box::new(entry::HashMapPass));
+    store.register_late_pass(|_| Box::new(minmax::MinMaxPass));
+    store.register_late_pass(|_| Box::new(zero_div_zero::ZeroDiv));
+    store.register_late_pass(|_| Box::new(mutex_atomic::Mutex));
+    store.register_late_pass(|_| Box::new(needless_update::NeedlessUpdate));
+    store.register_late_pass(|_| Box::new(needless_borrowed_ref::NeedlessBorrowedRef));
+    store.register_late_pass(|_| Box::new(borrow_deref_ref::BorrowDerefRef));
+    store.register_late_pass(|_| Box::new(no_effect::NoEffect));
+    store.register_late_pass(|_| Box::new(temporary_assignment::TemporaryAssignment));
+    store.register_late_pass(move |_| Box::new(transmute::Transmute::new(msrv)));
     let cognitive_complexity_threshold = conf.cognitive_complexity_threshold;
-    store.register_late_pass(move || {
+    store.register_late_pass(move |_| {
         Box::new(cognitive_complexity::CognitiveComplexity::new(
             cognitive_complexity_threshold,
         ))
     });
     let too_large_for_stack = conf.too_large_for_stack;
-    store.register_late_pass(move || Box::new(escape::BoxedLocal { too_large_for_stack }));
-    store.register_late_pass(move || Box::new(vec::UselessVec { too_large_for_stack }));
-    store.register_late_pass(|| Box::new(panic_unimplemented::PanicUnimplemented));
-    store.register_late_pass(|| Box::new(strings::StringLitAsBytes));
-    store.register_late_pass(|| Box::new(derive::Derive));
-    store.register_late_pass(|| Box::new(derivable_impls::DerivableImpls));
-    store.register_late_pass(|| Box::new(drop_forget_ref::DropForgetRef));
-    store.register_late_pass(|| Box::new(empty_enum::EmptyEnum));
-    store.register_late_pass(|| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons));
-    store.register_late_pass(|| Box::new(regex::Regex));
-    store.register_late_pass(|| Box::new(copies::CopyAndPaste));
-    store.register_late_pass(|| Box::new(copy_iterator::CopyIterator));
-    store.register_late_pass(|| Box::new(format::UselessFormat));
-    store.register_late_pass(|| Box::new(swap::Swap));
-    store.register_late_pass(|| Box::new(overflow_check_conditional::OverflowCheckConditional));
-    store.register_late_pass(|| Box::new(new_without_default::NewWithoutDefault::default()));
+    store.register_late_pass(move |_| Box::new(escape::BoxedLocal { too_large_for_stack }));
+    store.register_late_pass(move |_| Box::new(vec::UselessVec { too_large_for_stack }));
+    store.register_late_pass(|_| Box::new(panic_unimplemented::PanicUnimplemented));
+    store.register_late_pass(|_| Box::new(strings::StringLitAsBytes));
+    store.register_late_pass(|_| Box::new(derive::Derive));
+    store.register_late_pass(|_| Box::new(derivable_impls::DerivableImpls));
+    store.register_late_pass(|_| Box::new(drop_forget_ref::DropForgetRef));
+    store.register_late_pass(|_| Box::new(empty_enum::EmptyEnum));
+    store.register_late_pass(|_| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons));
+    store.register_late_pass(|_| Box::new(regex::Regex));
+    store.register_late_pass(|_| Box::new(copies::CopyAndPaste));
+    store.register_late_pass(|_| Box::new(copy_iterator::CopyIterator));
+    store.register_late_pass(|_| Box::new(format::UselessFormat));
+    store.register_late_pass(|_| Box::new(swap::Swap));
+    store.register_late_pass(|_| Box::new(overflow_check_conditional::OverflowCheckConditional));
+    store.register_late_pass(|_| Box::new(new_without_default::NewWithoutDefault::default()));
     let disallowed_names = conf.disallowed_names.iter().cloned().collect::<FxHashSet<_>>();
-    store.register_late_pass(move || Box::new(disallowed_names::DisallowedNames::new(disallowed_names.clone())));
+    store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(disallowed_names.clone())));
     let too_many_arguments_threshold = conf.too_many_arguments_threshold;
     let too_many_lines_threshold = conf.too_many_lines_threshold;
     let large_error_threshold = conf.large_error_threshold;
-    store.register_late_pass(move || {
+    store.register_late_pass(move |_| {
         Box::new(functions::Functions::new(
             too_many_arguments_threshold,
             too_many_lines_threshold,
@@ -678,73 +678,73 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         ))
     });
     let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
-    store.register_late_pass(move || Box::new(doc::DocMarkdown::new(doc_valid_idents.clone())));
-    store.register_late_pass(|| Box::new(neg_multiply::NegMultiply));
-    store.register_late_pass(|| Box::new(mem_forget::MemForget));
-    store.register_late_pass(|| Box::new(let_if_seq::LetIfSeq));
-    store.register_late_pass(|| Box::new(mixed_read_write_in_expression::EvalOrderDependence));
-    store.register_late_pass(|| Box::new(missing_doc::MissingDoc::new()));
-    store.register_late_pass(|| Box::new(missing_inline::MissingInline));
-    store.register_late_pass(move || Box::new(exhaustive_items::ExhaustiveItems));
-    store.register_late_pass(|| Box::new(match_result_ok::MatchResultOk));
-    store.register_late_pass(|| Box::new(partialeq_ne_impl::PartialEqNeImpl));
-    store.register_late_pass(|| Box::new(unused_io_amount::UnusedIoAmount));
+    store.register_late_pass(move |_| Box::new(doc::DocMarkdown::new(doc_valid_idents.clone())));
+    store.register_late_pass(|_| Box::new(neg_multiply::NegMultiply));
+    store.register_late_pass(|_| Box::new(mem_forget::MemForget));
+    store.register_late_pass(|_| Box::new(let_if_seq::LetIfSeq));
+    store.register_late_pass(|_| Box::new(mixed_read_write_in_expression::EvalOrderDependence));
+    store.register_late_pass(|_| Box::new(missing_doc::MissingDoc::new()));
+    store.register_late_pass(|_| Box::new(missing_inline::MissingInline));
+    store.register_late_pass(move |_| Box::new(exhaustive_items::ExhaustiveItems));
+    store.register_late_pass(|_| Box::new(match_result_ok::MatchResultOk));
+    store.register_late_pass(|_| Box::new(partialeq_ne_impl::PartialEqNeImpl));
+    store.register_late_pass(|_| Box::new(unused_io_amount::UnusedIoAmount));
     let enum_variant_size_threshold = conf.enum_variant_size_threshold;
-    store.register_late_pass(move || Box::new(large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold)));
-    store.register_late_pass(|| Box::new(explicit_write::ExplicitWrite));
-    store.register_late_pass(|| Box::new(needless_pass_by_value::NeedlessPassByValue));
+    store.register_late_pass(move |_| Box::new(large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold)));
+    store.register_late_pass(|_| Box::new(explicit_write::ExplicitWrite));
+    store.register_late_pass(|_| Box::new(needless_pass_by_value::NeedlessPassByValue));
     let pass_by_ref_or_value = pass_by_ref_or_value::PassByRefOrValue::new(
         conf.trivial_copy_size_limit,
         conf.pass_by_value_size_limit,
         conf.avoid_breaking_exported_api,
         &sess.target,
     );
-    store.register_late_pass(move || Box::new(pass_by_ref_or_value));
-    store.register_late_pass(|| Box::new(ref_option_ref::RefOptionRef));
-    store.register_late_pass(|| Box::new(infinite_iter::InfiniteIter));
-    store.register_late_pass(|| Box::new(inline_fn_without_body::InlineFnWithoutBody));
-    store.register_late_pass(|| Box::new(useless_conversion::UselessConversion::default()));
-    store.register_late_pass(|| Box::new(implicit_hasher::ImplicitHasher));
-    store.register_late_pass(|| Box::new(fallible_impl_from::FallibleImplFrom));
-    store.register_late_pass(|| Box::new(question_mark::QuestionMark));
+    store.register_late_pass(move |_| Box::new(pass_by_ref_or_value));
+    store.register_late_pass(|_| Box::new(ref_option_ref::RefOptionRef));
+    store.register_late_pass(|_| Box::new(infinite_iter::InfiniteIter));
+    store.register_late_pass(|_| Box::new(inline_fn_without_body::InlineFnWithoutBody));
+    store.register_late_pass(|_| Box::new(useless_conversion::UselessConversion::default()));
+    store.register_late_pass(|_| Box::new(implicit_hasher::ImplicitHasher));
+    store.register_late_pass(|_| Box::new(fallible_impl_from::FallibleImplFrom));
+    store.register_late_pass(|_| Box::new(question_mark::QuestionMark));
     store.register_early_pass(|| Box::new(suspicious_operation_groupings::SuspiciousOperationGroupings));
-    store.register_late_pass(|| Box::new(suspicious_trait_impl::SuspiciousImpl));
-    store.register_late_pass(|| Box::new(map_unit_fn::MapUnit));
-    store.register_late_pass(|| Box::new(inherent_impl::MultipleInherentImpl));
-    store.register_late_pass(|| Box::new(neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd));
-    store.register_late_pass(|| Box::new(unwrap::Unwrap));
-    store.register_late_pass(|| Box::new(indexing_slicing::IndexingSlicing));
-    store.register_late_pass(|| Box::new(non_copy_const::NonCopyConst));
-    store.register_late_pass(|| Box::new(ptr_offset_with_cast::PtrOffsetWithCast));
-    store.register_late_pass(|| Box::new(redundant_clone::RedundantClone));
-    store.register_late_pass(|| Box::new(slow_vector_initialization::SlowVectorInit));
-    store.register_late_pass(move || Box::new(unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api)));
-    store.register_late_pass(|| Box::new(assertions_on_constants::AssertionsOnConstants));
-    store.register_late_pass(|| Box::new(assertions_on_result_states::AssertionsOnResultStates));
-    store.register_late_pass(|| Box::new(inherent_to_string::InherentToString));
+    store.register_late_pass(|_| Box::new(suspicious_trait_impl::SuspiciousImpl));
+    store.register_late_pass(|_| Box::new(map_unit_fn::MapUnit));
+    store.register_late_pass(|_| Box::new(inherent_impl::MultipleInherentImpl));
+    store.register_late_pass(|_| Box::new(neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd));
+    store.register_late_pass(|_| Box::new(unwrap::Unwrap));
+    store.register_late_pass(|_| Box::new(indexing_slicing::IndexingSlicing));
+    store.register_late_pass(|_| Box::new(non_copy_const::NonCopyConst));
+    store.register_late_pass(|_| Box::new(ptr_offset_with_cast::PtrOffsetWithCast));
+    store.register_late_pass(|_| Box::new(redundant_clone::RedundantClone));
+    store.register_late_pass(|_| Box::new(slow_vector_initialization::SlowVectorInit));
+    store.register_late_pass(move |_| Box::new(unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api)));
+    store.register_late_pass(|_| Box::new(assertions_on_constants::AssertionsOnConstants));
+    store.register_late_pass(|_| Box::new(assertions_on_result_states::AssertionsOnResultStates));
+    store.register_late_pass(|_| Box::new(inherent_to_string::InherentToString));
     let max_trait_bounds = conf.max_trait_bounds;
-    store.register_late_pass(move || Box::new(trait_bounds::TraitBounds::new(max_trait_bounds)));
-    store.register_late_pass(|| Box::new(comparison_chain::ComparisonChain));
-    store.register_late_pass(|| Box::new(mut_key::MutableKeyType));
+    store.register_late_pass(move |_| Box::new(trait_bounds::TraitBounds::new(max_trait_bounds)));
+    store.register_late_pass(|_| Box::new(comparison_chain::ComparisonChain));
+    store.register_late_pass(|_| Box::new(mut_key::MutableKeyType));
     store.register_early_pass(|| Box::new(reference::DerefAddrOf));
     store.register_early_pass(|| Box::new(double_parens::DoubleParens));
-    store.register_late_pass(|| Box::new(format_impl::FormatImpl::new()));
+    store.register_late_pass(|_| Box::new(format_impl::FormatImpl::new()));
     store.register_early_pass(|| Box::new(unsafe_removed_from_name::UnsafeNameRemoval));
     store.register_early_pass(|| Box::new(else_if_without_else::ElseIfWithoutElse));
     store.register_early_pass(|| Box::new(int_plus_one::IntPlusOne));
     store.register_early_pass(|| Box::new(formatting::Formatting));
     store.register_early_pass(|| Box::new(misc_early::MiscEarlyLints));
     store.register_early_pass(|| Box::new(redundant_closure_call::RedundantClosureCall));
-    store.register_late_pass(|| Box::new(redundant_closure_call::RedundantClosureCall));
+    store.register_late_pass(|_| Box::new(redundant_closure_call::RedundantClosureCall));
     store.register_early_pass(|| Box::new(unused_unit::UnusedUnit));
-    store.register_late_pass(|| Box::new(returns::Return));
+    store.register_late_pass(|_| Box::new(returns::Return));
     store.register_early_pass(|| Box::new(collapsible_if::CollapsibleIf));
     store.register_early_pass(|| Box::new(items_after_statements::ItemsAfterStatements));
     store.register_early_pass(|| Box::new(precedence::Precedence));
-    store.register_late_pass(|| Box::new(needless_parens_on_range_literals::NeedlessParensOnRangeLiterals));
+    store.register_late_pass(|_| Box::new(needless_parens_on_range_literals::NeedlessParensOnRangeLiterals));
     store.register_early_pass(|| Box::new(needless_continue::NeedlessContinue));
     store.register_early_pass(|| Box::new(redundant_else::RedundantElse));
-    store.register_late_pass(|| Box::new(create_dir::CreateDir));
+    store.register_late_pass(|_| Box::new(create_dir::CreateDir));
     store.register_early_pass(|| Box::new(needless_arbitrary_self_type::NeedlessArbitrarySelfType));
     let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions;
     store.register_early_pass(move || {
@@ -759,7 +759,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         ))
     });
     let enum_variant_name_threshold = conf.enum_variant_name_threshold;
-    store.register_late_pass(move || {
+    store.register_late_pass(move |_| {
         Box::new(enum_variants::EnumVariantNames::new(
             enum_variant_name_threshold,
             avoid_breaking_exported_api,
@@ -767,23 +767,23 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     });
     store.register_early_pass(|| Box::new(tabs_in_doc_comments::TabsInDocComments));
     let upper_case_acronyms_aggressive = conf.upper_case_acronyms_aggressive;
-    store.register_late_pass(move || {
+    store.register_late_pass(move |_| {
         Box::new(upper_case_acronyms::UpperCaseAcronyms::new(
             avoid_breaking_exported_api,
             upper_case_acronyms_aggressive,
         ))
     });
-    store.register_late_pass(|| Box::new(default::Default::default()));
-    store.register_late_pass(move || Box::new(unused_self::UnusedSelf::new(avoid_breaking_exported_api)));
-    store.register_late_pass(|| Box::new(mutable_debug_assertion::DebugAssertWithMutCall));
-    store.register_late_pass(|| Box::new(exit::Exit));
-    store.register_late_pass(|| Box::new(to_digit_is_some::ToDigitIsSome));
+    store.register_late_pass(|_| Box::new(default::Default::default()));
+    store.register_late_pass(move |_| Box::new(unused_self::UnusedSelf::new(avoid_breaking_exported_api)));
+    store.register_late_pass(|_| Box::new(mutable_debug_assertion::DebugAssertWithMutCall));
+    store.register_late_pass(|_| Box::new(exit::Exit));
+    store.register_late_pass(|_| Box::new(to_digit_is_some::ToDigitIsSome));
     let array_size_threshold = conf.array_size_threshold;
-    store.register_late_pass(move || Box::new(large_stack_arrays::LargeStackArrays::new(array_size_threshold)));
-    store.register_late_pass(move || Box::new(large_const_arrays::LargeConstArrays::new(array_size_threshold)));
-    store.register_late_pass(|| Box::new(floating_point_arithmetic::FloatingPointArithmetic));
+    store.register_late_pass(move |_| Box::new(large_stack_arrays::LargeStackArrays::new(array_size_threshold)));
+    store.register_late_pass(move |_| Box::new(large_const_arrays::LargeConstArrays::new(array_size_threshold)));
+    store.register_late_pass(|_| Box::new(floating_point_arithmetic::FloatingPointArithmetic));
     store.register_early_pass(|| Box::new(as_conversions::AsConversions));
-    store.register_late_pass(|| Box::new(let_underscore::LetUnderscore));
+    store.register_late_pass(|_| Box::new(let_underscore::LetUnderscore));
     store.register_early_pass(|| Box::new(single_component_path_imports::SingleComponentPathImports));
     let max_fn_params_bools = conf.max_fn_params_bools;
     let max_struct_bools = conf.max_struct_bools;
@@ -795,17 +795,17 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     });
     store.register_early_pass(|| Box::new(option_env_unwrap::OptionEnvUnwrap));
     let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports;
-    store.register_late_pass(move || Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports)));
-    store.register_late_pass(|| Box::new(redundant_pub_crate::RedundantPubCrate::default()));
-    store.register_late_pass(|| Box::new(unnamed_address::UnnamedAddress));
-    store.register_late_pass(move || Box::new(dereference::Dereferencing::new(msrv)));
-    store.register_late_pass(|| Box::new(option_if_let_else::OptionIfLetElse));
-    store.register_late_pass(|| Box::new(future_not_send::FutureNotSend));
-    store.register_late_pass(|| Box::new(if_let_mutex::IfLetMutex));
-    store.register_late_pass(|| Box::new(if_not_else::IfNotElse));
-    store.register_late_pass(|| Box::new(equatable_if_let::PatternEquality));
-    store.register_late_pass(|| Box::new(manual_async_fn::ManualAsyncFn));
-    store.register_late_pass(|| Box::new(panic_in_result_fn::PanicInResultFn));
+    store.register_late_pass(move |_| Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports)));
+    store.register_late_pass(|_| Box::new(redundant_pub_crate::RedundantPubCrate::default()));
+    store.register_late_pass(|_| Box::new(unnamed_address::UnnamedAddress));
+    store.register_late_pass(move |_| Box::new(dereference::Dereferencing::new(msrv)));
+    store.register_late_pass(|_| Box::new(option_if_let_else::OptionIfLetElse));
+    store.register_late_pass(|_| Box::new(future_not_send::FutureNotSend));
+    store.register_late_pass(|_| Box::new(if_let_mutex::IfLetMutex));
+    store.register_late_pass(|_| Box::new(if_not_else::IfNotElse));
+    store.register_late_pass(|_| Box::new(equatable_if_let::PatternEquality));
+    store.register_late_pass(|_| Box::new(manual_async_fn::ManualAsyncFn));
+    store.register_late_pass(|_| Box::new(panic_in_result_fn::PanicInResultFn));
     let single_char_binding_names_threshold = conf.single_char_binding_names_threshold;
     store.register_early_pass(move || {
         Box::new(non_expressive_names::NonExpressiveNames {
@@ -814,92 +814,92 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     });
     let macro_matcher = conf.standard_macro_braces.iter().cloned().collect::<FxHashSet<_>>();
     store.register_early_pass(move || Box::new(nonstandard_macro_braces::MacroBraces::new(&macro_matcher)));
-    store.register_late_pass(|| Box::new(macro_use::MacroUseImports::default()));
-    store.register_late_pass(|| Box::new(pattern_type_mismatch::PatternTypeMismatch));
-    store.register_late_pass(|| Box::new(unwrap_in_result::UnwrapInResult));
-    store.register_late_pass(|| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned));
-    store.register_late_pass(|| Box::new(async_yields_async::AsyncYieldsAsync));
+    store.register_late_pass(|_| Box::new(macro_use::MacroUseImports::default()));
+    store.register_late_pass(|_| Box::new(pattern_type_mismatch::PatternTypeMismatch));
+    store.register_late_pass(|_| Box::new(unwrap_in_result::UnwrapInResult));
+    store.register_late_pass(|_| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned));
+    store.register_late_pass(|_| Box::new(async_yields_async::AsyncYieldsAsync));
     let disallowed_methods = conf.disallowed_methods.clone();
-    store.register_late_pass(move || Box::new(disallowed_methods::DisallowedMethods::new(disallowed_methods.clone())));
+    store.register_late_pass(move |_| Box::new(disallowed_methods::DisallowedMethods::new(disallowed_methods.clone())));
     store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86AttSyntax));
     store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86IntelSyntax));
-    store.register_late_pass(|| Box::new(empty_drop::EmptyDrop));
-    store.register_late_pass(|| Box::new(strings::StrToString));
-    store.register_late_pass(|| Box::new(strings::StringToString));
-    store.register_late_pass(|| Box::new(zero_sized_map_values::ZeroSizedMapValues));
-    store.register_late_pass(|| Box::new(vec_init_then_push::VecInitThenPush::default()));
-    store.register_late_pass(|| Box::new(redundant_slicing::RedundantSlicing));
-    store.register_late_pass(|| Box::new(from_str_radix_10::FromStrRadix10));
-    store.register_late_pass(move || Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv)));
-    store.register_late_pass(|| Box::new(bool_assert_comparison::BoolAssertComparison));
+    store.register_late_pass(|_| Box::new(empty_drop::EmptyDrop));
+    store.register_late_pass(|_| Box::new(strings::StrToString));
+    store.register_late_pass(|_| Box::new(strings::StringToString));
+    store.register_late_pass(|_| Box::new(zero_sized_map_values::ZeroSizedMapValues));
+    store.register_late_pass(|_| Box::new(vec_init_then_push::VecInitThenPush::default()));
+    store.register_late_pass(|_| Box::new(redundant_slicing::RedundantSlicing));
+    store.register_late_pass(|_| Box::new(from_str_radix_10::FromStrRadix10));
+    store.register_late_pass(move |_| Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv)));
+    store.register_late_pass(|_| Box::new(bool_assert_comparison::BoolAssertComparison));
     store.register_early_pass(move || Box::new(module_style::ModStyle));
-    store.register_late_pass(|| Box::new(unused_async::UnusedAsync));
+    store.register_late_pass(|_| Box::new(unused_async::UnusedAsync));
     let disallowed_types = conf.disallowed_types.clone();
-    store.register_late_pass(move || Box::new(disallowed_types::DisallowedTypes::new(disallowed_types.clone())));
+    store.register_late_pass(move |_| Box::new(disallowed_types::DisallowedTypes::new(disallowed_types.clone())));
     let import_renames = conf.enforced_import_renames.clone();
-    store.register_late_pass(move || {
+    store.register_late_pass(move |_| {
         Box::new(missing_enforced_import_rename::ImportRename::new(
             import_renames.clone(),
         ))
     });
     let scripts = conf.allowed_scripts.clone();
     store.register_early_pass(move || Box::new(disallowed_script_idents::DisallowedScriptIdents::new(&scripts)));
-    store.register_late_pass(|| Box::new(strlen_on_c_strings::StrlenOnCStrings));
-    store.register_late_pass(move || Box::new(self_named_constructors::SelfNamedConstructors));
-    store.register_late_pass(move || Box::new(iter_not_returning_iterator::IterNotReturningIterator));
-    store.register_late_pass(move || Box::new(manual_assert::ManualAssert));
+    store.register_late_pass(|_| Box::new(strlen_on_c_strings::StrlenOnCStrings));
+    store.register_late_pass(move |_| Box::new(self_named_constructors::SelfNamedConstructors));
+    store.register_late_pass(move |_| Box::new(iter_not_returning_iterator::IterNotReturningIterator));
+    store.register_late_pass(move |_| Box::new(manual_assert::ManualAssert));
     let enable_raw_pointer_heuristic_for_send = conf.enable_raw_pointer_heuristic_for_send;
-    store.register_late_pass(move || {
+    store.register_late_pass(move |_| {
         Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new(
             enable_raw_pointer_heuristic_for_send,
         ))
     });
-    store.register_late_pass(move || Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks));
-    store.register_late_pass(move || Box::new(format_args::FormatArgs));
-    store.register_late_pass(|| Box::new(trailing_empty_array::TrailingEmptyArray));
+    store.register_late_pass(move |_| Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks));
+    store.register_late_pass(move |_| Box::new(format_args::FormatArgs));
+    store.register_late_pass(|_| Box::new(trailing_empty_array::TrailingEmptyArray));
     store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes));
-    store.register_late_pass(|| Box::new(needless_late_init::NeedlessLateInit));
-    store.register_late_pass(|| Box::new(return_self_not_must_use::ReturnSelfNotMustUse));
-    store.register_late_pass(|| Box::new(init_numbered_fields::NumberedFields));
+    store.register_late_pass(|_| Box::new(needless_late_init::NeedlessLateInit));
+    store.register_late_pass(|_| Box::new(return_self_not_must_use::ReturnSelfNotMustUse));
+    store.register_late_pass(|_| Box::new(init_numbered_fields::NumberedFields));
     store.register_early_pass(|| Box::new(single_char_lifetime_names::SingleCharLifetimeNames));
-    store.register_late_pass(move || Box::new(manual_bits::ManualBits::new(msrv)));
-    store.register_late_pass(|| Box::new(default_union_representation::DefaultUnionRepresentation));
+    store.register_late_pass(move |_| Box::new(manual_bits::ManualBits::new(msrv)));
+    store.register_late_pass(|_| Box::new(default_union_representation::DefaultUnionRepresentation));
     store.register_early_pass(|| Box::new(doc_link_with_quotes::DocLinkWithQuotes));
-    store.register_late_pass(|| Box::new(only_used_in_recursion::OnlyUsedInRecursion::default()));
+    store.register_late_pass(|_| Box::new(only_used_in_recursion::OnlyUsedInRecursion::default()));
     let allow_dbg_in_tests = conf.allow_dbg_in_tests;
-    store.register_late_pass(move || Box::new(dbg_macro::DbgMacro::new(allow_dbg_in_tests)));
+    store.register_late_pass(move |_| Box::new(dbg_macro::DbgMacro::new(allow_dbg_in_tests)));
     let cargo_ignore_publish = conf.cargo_ignore_publish;
-    store.register_late_pass(move || {
+    store.register_late_pass(move |_| {
         Box::new(cargo::Cargo {
             ignore_publish: cargo_ignore_publish,
         })
     });
     store.register_early_pass(|| Box::new(crate_in_macro_def::CrateInMacroDef));
     store.register_early_pass(|| Box::new(empty_structs_with_brackets::EmptyStructsWithBrackets));
-    store.register_late_pass(|| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings));
+    store.register_late_pass(|_| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings));
     store.register_early_pass(|| Box::new(pub_use::PubUse));
-    store.register_late_pass(|| Box::new(format_push_string::FormatPushString));
+    store.register_late_pass(|_| Box::new(format_push_string::FormatPushString));
     let max_include_file_size = conf.max_include_file_size;
-    store.register_late_pass(move || Box::new(large_include_file::LargeIncludeFile::new(max_include_file_size)));
-    store.register_late_pass(|| Box::new(strings::TrimSplitWhitespace));
-    store.register_late_pass(|| Box::new(rc_clone_in_vec_init::RcCloneInVecInit));
+    store.register_late_pass(move |_| Box::new(large_include_file::LargeIncludeFile::new(max_include_file_size)));
+    store.register_late_pass(|_| Box::new(strings::TrimSplitWhitespace));
+    store.register_late_pass(|_| Box::new(rc_clone_in_vec_init::RcCloneInVecInit));
     store.register_early_pass(|| Box::new(duplicate_mod::DuplicateMod::default()));
     store.register_early_pass(|| Box::new(unused_rounding::UnusedRounding));
     store.register_early_pass(move || Box::new(almost_complete_letter_range::AlmostCompleteLetterRange::new(msrv)));
-    store.register_late_pass(|| Box::new(swap_ptr_to_ref::SwapPtrToRef));
-    store.register_late_pass(|| Box::new(mismatching_type_param_order::TypeParamMismatch));
-    store.register_late_pass(|| Box::new(read_zero_byte_vec::ReadZeroByteVec));
-    store.register_late_pass(|| Box::new(default_instead_of_iter_empty::DefaultIterEmpty));
-    store.register_late_pass(move || Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv)));
-    store.register_late_pass(move || Box::new(manual_retain::ManualRetain::new(msrv)));
+    store.register_late_pass(|_| Box::new(swap_ptr_to_ref::SwapPtrToRef));
+    store.register_late_pass(|_| Box::new(mismatching_type_param_order::TypeParamMismatch));
+    store.register_late_pass(|_| Box::new(read_zero_byte_vec::ReadZeroByteVec));
+    store.register_late_pass(|_| Box::new(default_instead_of_iter_empty::DefaultIterEmpty));
+    store.register_late_pass(move |_| Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv)));
+    store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(msrv)));
     let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold;
-    store.register_late_pass(move || Box::new(operators::Operators::new(verbose_bit_mask_threshold)));
-    store.register_late_pass(|| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked));
-    store.register_late_pass(|| Box::new(std_instead_of_core::StdReexports::default()));
-    store.register_late_pass(|| Box::new(manual_instant_elapsed::ManualInstantElapsed));
-    store.register_late_pass(|| Box::new(partialeq_to_none::PartialeqToNone));
-    store.register_late_pass(|| Box::new(manual_string_new::ManualStringNew));
-    store.register_late_pass(|| Box::new(unused_peekable::UnusedPeekable));
+    store.register_late_pass(move |_| Box::new(operators::Operators::new(verbose_bit_mask_threshold)));
+    store.register_late_pass(|_| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked));
+    store.register_late_pass(|_| Box::new(std_instead_of_core::StdReexports::default()));
+    store.register_late_pass(|_| Box::new(manual_instant_elapsed::ManualInstantElapsed));
+    store.register_late_pass(|_| Box::new(partialeq_to_none::PartialeqToNone));
+    store.register_late_pass(|_| Box::new(manual_string_new::ManualStringNew));
+    store.register_late_pass(|_| Box::new(unused_peekable::UnusedPeekable));
     store.register_early_pass(|| Box::new(multi_assignments::MultiAssignments));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs
index 215c83a7edf..09b2376d5c0 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs
@@ -106,7 +106,7 @@ fn get_binding(pat: &Pat<'_>) -> Option<HirId> {
             hir_id = None;
             return;
         }
-        if let BindingAnnotation::Unannotated = annotation {
+        if let BindingAnnotation::NONE = annotation {
             hir_id = Some(id);
         }
     });
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
index a65df48e413..3fc569af89e 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
@@ -119,7 +119,7 @@ fn build_manual_memcpy_suggestion<'tcx>(
 
     let print_limit = |end: &Expr<'_>, end_str: &str, base: &Expr<'_>, sugg: MinifyingSugg<'static>| {
         if_chain! {
-            if let ExprKind::MethodCall(method, [recv], _) = end.kind;
+            if let ExprKind::MethodCall(method, recv, [], _) = end.kind;
             if method.ident.name == sym::len;
             if path_to_local(recv) == path_to_local(base);
             then {
@@ -341,7 +341,7 @@ fn get_slice_like_element_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Opti
 
 fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
     if_chain! {
-        if let ExprKind::MethodCall(method, [arg], _) = expr.kind;
+        if let ExprKind::MethodCall(method, arg, [], _) = expr.kind;
         if method.ident.name == sym::clone;
         then { arg } else { expr }
     }
diff --git a/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs b/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs
index 0696afa3922..8412875b11b 100644
--- a/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs
@@ -33,7 +33,7 @@ fn unpack_cond<'tcx>(cond: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &'tcx Expr<'_>) {
     if_chain! {
         if let ExprKind::Block(Block { stmts: [], expr: None, ..}, _) = body.kind;
-        if let ExprKind::MethodCall(method, [callee, ..], _) = unpack_cond(cond).kind;
+        if let ExprKind::MethodCall(method, callee, ..) = unpack_cond(cond).kind;
         if [sym::load, sym::compare_exchange, sym::compare_exchange_weak].contains(&method.ident.name);
         if let ty::Adt(def, _substs) = cx.typeck_results().expr_ty(callee).kind();
         if cx.tcx.is_diagnostic_item(sym::AtomicBool, def.did());
diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs
index ed270bd490d..74f3bda9f43 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs
@@ -742,7 +742,7 @@ fn check_for_loop<'tcx>(
 fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) {
     let mut next_loop_linted = false; // whether or not ITER_NEXT_LOOP lint was used
 
-    if let ExprKind::MethodCall(method, [self_arg], _) = arg.kind {
+    if let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind {
         let method_name = method.ident.as_str();
         // check for looping over x.iter() or x.iter_mut(), could use &x or &mut x
         match method_name {
diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
index aedf3810b23..fce2d54639c 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
@@ -44,7 +44,7 @@ fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option<HirId>
     if_chain! {
         if let Some(hir_id) = path_to_local(bound);
         if let Node::Pat(pat) = cx.tcx.hir().get(hir_id);
-        if let PatKind::Binding(BindingAnnotation::Mutable, ..) = pat.kind;
+        if let PatKind::Binding(BindingAnnotation::MUT, ..) = pat.kind;
         then {
             return Some(hir_id);
         }
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
index 6d987f393fa..6e6faa79adc 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
@@ -25,11 +25,11 @@ pub(super) fn check<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
 }
 fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
     if_chain! {
-        if let ExprKind::MethodCall(method, args, _) = expr.kind;
-        if let ExprKind::MethodCall(chain_method, _, _) = args[0].kind;
-        if chain_method.ident.name == sym!(collect) && is_trait_method(cx, &args[0], sym::Iterator);
+        if let ExprKind::MethodCall(method, receiver, args, _) = expr.kind;
+        if let ExprKind::MethodCall(chain_method, ..) = receiver.kind;
+        if chain_method.ident.name == sym!(collect) && is_trait_method(cx, receiver, sym::Iterator);
         then {
-            let ty = cx.typeck_results().expr_ty(&args[0]);
+            let ty = cx.typeck_results().expr_ty(receiver);
             let mut applicability = Applicability::MaybeIncorrect;
             let is_empty_sugg = "next().is_none()".to_string();
             let method_name = method.ident.name.as_str();
@@ -41,7 +41,7 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont
                     "len" => "count()".to_string(),
                     "is_empty" => is_empty_sugg,
                     "contains" => {
-                        let contains_arg = snippet_with_applicability(cx, args[1].span, "??", &mut applicability);
+                        let contains_arg = snippet_with_applicability(cx, args[0].span, "??", &mut applicability);
                         let (arg, pred) = contains_arg
                             .strip_prefix('&')
                             .map_or(("&x", &*contains_arg), |s| ("x", s));
@@ -80,7 +80,7 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
                 if let StmtKind::Local(local) = stmt.kind;
                 if let PatKind::Binding(_, id, ..) = local.pat.kind;
                 if let Some(init_expr) = local.init;
-                if let ExprKind::MethodCall(method_name, &[ref iter_source], ..) = init_expr.kind;
+                if let ExprKind::MethodCall(method_name, iter_source, [], ..) = init_expr.kind;
                 if method_name.ident.name == sym!(collect) && is_trait_method(cx, init_expr, sym::Iterator);
                 let ty = cx.typeck_results().expr_ty(init_expr);
                 if is_type_diagnostic_item(cx, ty, sym::Vec) ||
@@ -203,7 +203,7 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> {
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
         // Check function calls on our collection
-        if let ExprKind::MethodCall(method_name, [recv, args @ ..], _) = &expr.kind {
+        if let ExprKind::MethodCall(method_name, recv, [args @ ..], _) = &expr.kind {
             if method_name.ident.name == sym!(collect) && is_trait_method(self.cx, expr, sym::Iterator) {
                 self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(recv));
                 self.visit_expr(recv);
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 7ca4a7c4ebf..ffcf83e4605 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
@@ -188,7 +188,7 @@ pub(super) fn check<'tcx>(
 
 fn is_len_call(expr: &Expr<'_>, var: Symbol) -> bool {
     if_chain! {
-        if let ExprKind::MethodCall(method, [recv], _) = expr.kind;
+        if let ExprKind::MethodCall(method, recv, [], _) = expr.kind;
         if method.ident.name == sym::len;
         if let ExprKind::Path(QPath::Resolved(_, path)) = recv.kind;
         if path.segments.len() == 1;
@@ -301,7 +301,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         if_chain! {
             // a range index op
-            if let ExprKind::MethodCall(meth, [args_0, args_1, ..], _) = &expr.kind;
+            if let ExprKind::MethodCall(meth, args_0, [args_1, ..], _) = &expr.kind;
             if (meth.ident.name == sym::index && match_trait_method(self.cx, expr, &paths::INDEX))
                 || (meth.ident.name == sym::index_mut && match_trait_method(self.cx, expr, &paths::INDEX_MUT));
             if !self.check(args_1, args_0, expr);
@@ -356,9 +356,12 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
                     self.visit_expr(expr);
                 }
             },
-            ExprKind::MethodCall(_, args, _) => {
+            ExprKind::MethodCall(_, receiver, args, _) => {
                 let def_id = self.cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
-                for (ty, expr) in iter::zip(self.cx.tcx.fn_sig(def_id).inputs().skip_binder(), args) {
+                for (ty, expr) in iter::zip(
+                    self.cx.tcx.fn_sig(def_id).inputs().skip_binder(),
+                    std::iter::once(receiver).chain(args.iter()),
+                ) {
                     self.prefer_mutable = false;
                     if let ty::Ref(_, _, mutbl) = *ty.kind() {
                         if mutbl == Mutability::Mut {
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 5448360049d..116e589cad6 100644
--- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
@@ -120,8 +120,9 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
         | ExprKind::Repeat(e, _)
         | ExprKind::DropTemps(e) => never_loop_expr(e, main_loop_id),
         ExprKind::Let(let_expr) => never_loop_expr(let_expr.init, main_loop_id),
-        ExprKind::Array(es) | ExprKind::MethodCall(_, es, _) | ExprKind::Tup(es) => {
-            never_loop_expr_all(&mut es.iter(), main_loop_id)
+        ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(&mut es.iter(), main_loop_id),
+        ExprKind::MethodCall(_, receiver, es, _) => {
+            never_loop_expr_all(&mut std::iter::once(receiver).chain(es.iter()), main_loop_id)
         },
         ExprKind::Struct(_, fields, base) => {
             let fields = never_loop_expr_all(&mut fields.iter().map(|f| f.expr), main_loop_id);
diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
index 1439f1f4c75..aeefe6e33fb 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
@@ -7,7 +7,7 @@ use if_chain::if_chain;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Node, Pat, PatKind, Stmt, StmtKind};
+use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Mutability, Node, Pat, PatKind, Stmt, StmtKind};
 use rustc_lint::LateContext;
 use rustc_span::symbol::sym;
 use std::iter::Iterator;
@@ -65,7 +65,7 @@ pub(super) fn check<'tcx>(
                             if_chain! {
                                 if let Node::Pat(pat) = node;
                                 if let PatKind::Binding(bind_ann, ..) = pat.kind;
-                                if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable);
+                                if !matches!(bind_ann, BindingAnnotation(_, Mutability::Mut));
                                 let parent_node = cx.tcx.hir().get_parent_node(hir_id);
                                 if let Some(Node::Local(parent_let_expr)) = cx.tcx.hir().find(parent_node);
                                 if let Some(init) = parent_let_expr.init;
@@ -180,10 +180,9 @@ fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(&
     if_chain! {
             // Extract method being called
             if let StmtKind::Semi(semi_stmt) = &stmt.kind;
-            if let ExprKind::MethodCall(path, args, _) = &semi_stmt.kind;
+            if let ExprKind::MethodCall(path, self_expr, args, _) = &semi_stmt.kind;
             // Figure out the parameters for the method call
-            if let Some(self_expr) = args.get(0);
-            if let Some(pushed_item) = args.get(1);
+            if let Some(pushed_item) = args.get(0);
             // Check that the method being called is push() on a Vec
             if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec);
             if path.ident.name.as_str() == "push";
diff --git a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
index a0bd7ad0ac6..f4b47808dfa 100644
--- a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
@@ -35,32 +35,29 @@ pub(super) fn check<'tcx>(
         ) => (arg, "&mut "),
         ExprKind::MethodCall(
             method,
-            [
-                Expr {
-                    kind: ExprKind::Array([arg]),
-                    ..
-                },
-            ],
+            Expr {
+                kind: ExprKind::Array([arg]),
+                ..
+            },
+            [],
             _,
         ) if method.ident.name == rustc_span::sym::iter => (arg, "&"),
         ExprKind::MethodCall(
             method,
-            [
-                Expr {
-                    kind: ExprKind::Array([arg]),
-                    ..
-                },
-            ],
+            Expr {
+                kind: ExprKind::Array([arg]),
+                ..
+            },
+            [],
             _,
         ) if method.ident.name.as_str() == "iter_mut" => (arg, "&mut "),
         ExprKind::MethodCall(
             method,
-            [
-                Expr {
-                    kind: ExprKind::Array([arg]),
-                    ..
-                },
-            ],
+            Expr {
+                kind: ExprKind::Array([arg]),
+                ..
+            },
+            [],
             _,
         ) if method.ident.name == rustc_span::sym::into_iter => (arg, ""),
         // Only check for arrays edition 2021 or later, as this case will trigger a compiler error otherwise.
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 ca617859db4..735d704a43c 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
@@ -11,7 +11,14 @@ 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::Local(&Local { init: Some(e), els: None, .. }) | StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind {
+            if let StmtKind::Local(&Local {
+                init: Some(e),
+                els: None,
+                ..
+            })
+            | StmtKind::Semi(e)
+            | StmtKind::Expr(e) = stmt.kind
+            {
                 (e, !stmts.is_empty() || expr.is_some())
             } else {
                 return;
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 e9e215e662f..2c54033f859 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
@@ -23,7 +23,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let Res::Def(_, pat_did) = pat_path.res;
         if match_def_path(cx, pat_did, &paths::OPTION_SOME);
         // check for call to `Iterator::next`
-        if let ExprKind::MethodCall(method_name, [iter_expr], _) = let_expr.kind;
+        if let ExprKind::MethodCall(method_name, iter_expr, [], _) = let_expr.kind;
         if method_name.ident.name == sym::next;
         if is_trait_method(cx, let_expr, sym::Iterator);
         if let Some(iter_expr_struct) = try_parse_iter_expr(cx, iter_expr);
diff --git a/src/tools/clippy/clippy_lints/src/manual_bits.rs b/src/tools/clippy/clippy_lints/src/manual_bits.rs
index 940601a44fb..6655c92b1da 100644
--- a/src/tools/clippy/clippy_lints/src/manual_bits.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_bits.rs
@@ -134,7 +134,7 @@ fn create_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, base_sugg: String) -> Stri
 fn is_ty_conversion(expr: &Expr<'_>) -> bool {
     if let ExprKind::Cast(..) = expr.kind {
         true
-    } else if let ExprKind::MethodCall(path, [_], _) = expr.kind
+    } else if let ExprKind::MethodCall(path, _, [], _) = expr.kind
         && path.ident.name == rustc_span::sym::try_into
     {
         // This is only called for `usize` which implements `TryInto`. Therefore,
diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs
index 42d2577cc31..f28c37d3dca 100644
--- a/src/tools/clippy/clippy_lints/src/manual_retain.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs
@@ -66,9 +66,9 @@ 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
-            && let hir::ExprKind::MethodCall(seg, _, _) = &collect_expr.kind
+            && let hir::ExprKind::MethodCall(seg, ..) = &collect_expr.kind
             && seg.args.is_none()
-            && let hir::ExprKind::MethodCall(_, [target_expr], _) = &collect_expr.kind
+            && 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)
             && match_def_path(cx, collect_def_id, &paths::CORE_ITER_COLLECT) {
             check_into_iter(cx, parent_expr, left_expr, target_expr, self.msrv);
@@ -87,10 +87,10 @@ fn check_into_iter(
     target_expr: &hir::Expr<'_>,
     msrv: Option<RustcVersion>,
 ) {
-    if let hir::ExprKind::MethodCall(_, [into_iter_expr, _], _) = &target_expr.kind
+    if let hir::ExprKind::MethodCall(_, into_iter_expr, [_], _) = &target_expr.kind
         && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
         && match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
-        && let hir::ExprKind::MethodCall(_, [struct_expr], _) = &into_iter_expr.kind
+        && let hir::ExprKind::MethodCall(_, struct_expr, [], _) = &into_iter_expr.kind
         && let Some(into_iter_def_id) = cx.typeck_results().type_dependent_def_id(into_iter_expr.hir_id)
         && match_def_path(cx, into_iter_def_id, &paths::CORE_ITER_INTO_ITER)
         && match_acceptable_type(cx, left_expr, msrv)
@@ -106,14 +106,14 @@ fn check_iter(
     target_expr: &hir::Expr<'_>,
     msrv: Option<RustcVersion>,
 ) {
-    if let hir::ExprKind::MethodCall(_, [filter_expr], _) = &target_expr.kind
+    if let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind
         && let Some(copied_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
         && (match_def_path(cx, copied_def_id, &paths::CORE_ITER_COPIED)
             || match_def_path(cx, copied_def_id, &paths::CORE_ITER_CLONED))
-        && let hir::ExprKind::MethodCall(_, [iter_expr, _], _) = &filter_expr.kind
+        && let hir::ExprKind::MethodCall(_, iter_expr, [_], _) = &filter_expr.kind
         && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id)
         && match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
-        && let hir::ExprKind::MethodCall(_, [struct_expr], _) = &iter_expr.kind
+        && let hir::ExprKind::MethodCall(_, struct_expr, [], _) = &iter_expr.kind
         && let Some(iter_expr_def_id) = cx.typeck_results().type_dependent_def_id(iter_expr.hir_id)
         && match_acceptable_def_path(cx, iter_expr_def_id)
         && match_acceptable_type(cx, left_expr, msrv)
@@ -130,13 +130,13 @@ fn check_to_owned(
     msrv: Option<RustcVersion>,
 ) {
     if meets_msrv(msrv,  msrvs::STRING_RETAIN)
-        && let hir::ExprKind::MethodCall(_, [filter_expr], _) = &target_expr.kind
+        && let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind
         && let Some(to_owned_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
         && match_def_path(cx, to_owned_def_id, &paths::TO_OWNED_METHOD)
-        && let hir::ExprKind::MethodCall(_, [chars_expr, _], _) = &filter_expr.kind
+        && let hir::ExprKind::MethodCall(_, chars_expr, [_], _) = &filter_expr.kind
         && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id)
         && match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
-        && let hir::ExprKind::MethodCall(_, [str_expr], _) = &chars_expr.kind
+        && let hir::ExprKind::MethodCall(_, str_expr, [], _) = &chars_expr.kind
         && let Some(chars_expr_def_id) = cx.typeck_results().type_dependent_def_id(chars_expr.hir_id)
         && match_def_path(cx, chars_expr_def_id, &paths::STR_CHARS)
         && let ty = cx.typeck_results().expr_ty(str_expr).peel_refs()
@@ -147,7 +147,7 @@ fn check_to_owned(
 }
 
 fn suggest(cx: &LateContext<'_>, parent_expr: &hir::Expr<'_>, left_expr: &hir::Expr<'_>, filter_expr: &hir::Expr<'_>) {
-    if let hir::ExprKind::MethodCall(_, [_, closure], _) = filter_expr.kind
+    if let hir::ExprKind::MethodCall(_, _, [closure], _) = filter_expr.kind
         && let hir::ExprKind::Closure(&hir::Closure { body, ..}) = closure.kind
         && let filter_body = cx.tcx.hir().body(body)
         && let [filter_params] = filter_body.params
diff --git a/src/tools/clippy/clippy_lints/src/manual_string_new.rs b/src/tools/clippy/clippy_lints/src/manual_string_new.rs
index a90eaa8fdcb..6acfb2ae347 100644
--- a/src/tools/clippy/clippy_lints/src/manual_string_new.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_string_new.rs
@@ -55,8 +55,8 @@ impl LateLintPass<'_> for ManualStringNew {
             ExprKind::Call(func, args) => {
                 parse_call(cx, expr.span, func, args);
             },
-            ExprKind::MethodCall(path_segment, args, _) => {
-                parse_method_call(cx, expr.span, path_segment, args);
+            ExprKind::MethodCall(path_segment, receiver, ..) => {
+                parse_method_call(cx, expr.span, path_segment, receiver);
             },
             _ => (),
         }
@@ -88,14 +88,9 @@ fn warn_then_suggest(cx: &LateContext<'_>, span: Span) {
 }
 
 /// Tries to parse an expression as a method call, emitting the warning if necessary.
-fn parse_method_call(cx: &LateContext<'_>, span: Span, path_segment: &PathSegment<'_>, args: &[Expr<'_>]) {
-    if args.is_empty() {
-        // When parsing TryFrom::try_from(...).expect(...), we will have more than 1 arg.
-        return;
-    }
-
+fn parse_method_call(cx: &LateContext<'_>, span: Span, path_segment: &PathSegment<'_>, receiver: &Expr<'_>) {
     let ident = path_segment.ident.as_str();
-    let method_arg_kind = &args[0].kind;
+    let method_arg_kind = &receiver.kind;
     if ["to_string", "to_owned", "into"].contains(&ident) && is_expr_kind_empty_str(method_arg_kind) {
         warn_then_suggest(cx, span);
     } else if let ExprKind::Call(func, args) = method_arg_kind {
diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs
index dfb3efc4e28..7941c8c9c7e 100644
--- a/src/tools/clippy/clippy_lints/src/manual_strip.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs
@@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
 
         if_chain! {
             if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr);
-            if let ExprKind::MethodCall(_, [target_arg, pattern], _) = cond.kind;
+            if let ExprKind::MethodCall(_, target_arg, [pattern], _) = cond.kind;
             if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id);
             if let ExprKind::Path(target_path) = &target_arg.kind;
             then {
@@ -132,7 +132,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
 // Returns `Some(arg)` if `expr` matches `arg.len()` and `None` otherwise.
 fn len_arg<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
     if_chain! {
-        if let ExprKind::MethodCall(_, [arg], _) = expr.kind;
+        if let ExprKind::MethodCall(_, arg, [], _) = expr.kind;
         if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         if match_def_path(cx, method_def_id, &paths::STR_LEN);
         then {
diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
index 6db852c3ffe..33d74481529 100644
--- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
@@ -200,8 +200,13 @@ fn suggestion_msg(function_type: &str, map_type: &str) -> String {
     )
 }
 
-fn lint_map_unit_fn(cx: &LateContext<'_>, stmt: &hir::Stmt<'_>, expr: &hir::Expr<'_>, map_args: &[hir::Expr<'_>]) {
-    let var_arg = &map_args[0];
+fn lint_map_unit_fn(
+    cx: &LateContext<'_>,
+    stmt: &hir::Stmt<'_>,
+    expr: &hir::Expr<'_>,
+    map_args: (&hir::Expr<'_>, &[hir::Expr<'_>]),
+) {
+    let var_arg = &map_args.0;
 
     let (map_type, variant, lint) = if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::Option) {
         ("Option", "Some", OPTION_MAP_UNIT_FN)
@@ -210,7 +215,7 @@ fn lint_map_unit_fn(cx: &LateContext<'_>, stmt: &hir::Stmt<'_>, expr: &hir::Expr
     } else {
         return;
     };
-    let fn_arg = &map_args[1];
+    let fn_arg = &map_args.1[0];
 
     if is_unit_function(cx, fn_arg) {
         let mut applicability = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/match_result_ok.rs b/src/tools/clippy/clippy_lints/src/match_result_ok.rs
index 3349b85f134..8588ab1ed8d 100644
--- a/src/tools/clippy/clippy_lints/src/match_result_ok.rs
+++ b/src/tools/clippy/clippy_lints/src/match_result_ok.rs
@@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchResultOk {
             };
 
         if_chain! {
-            if let ExprKind::MethodCall(ok_path, [ref result_types_0, ..], _) = let_expr.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
+            if let ExprKind::MethodCall(ok_path, result_types_0, ..) = let_expr.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
             if let PatKind::TupleStruct(QPath::Resolved(_, x), y, _)  = let_pat.kind; //get operation
             if method_chain_args(let_expr, &["ok"]).is_some(); //test to see if using ok() method use std::marker::Sized;
             if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(result_types_0), sym::Result);
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_map.rs b/src/tools/clippy/clippy_lints/src/matches/manual_map.rs
index 8f98b43b9e5..b0198e856d5 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_map.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_map.rs
@@ -165,7 +165,7 @@ fn check<'tcx>(
                 }
 
                 // `ref` and `ref mut` annotations were handled earlier.
-                let annotation = if matches!(annotation, BindingAnnotation::Mutable) {
+                let annotation = if matches!(annotation, BindingAnnotation::MUT) {
                     "mut "
                 } else {
                     ""
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
index a0efdecec67..91d17f481e2 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::{is_lang_ctor, peel_blocks};
 use rustc_errors::Applicability;
-use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, LangItem, PatKind, QPath};
+use rustc_hir::{Arm, BindingAnnotation, ByRef, Expr, ExprKind, LangItem, Mutability, PatKind, QPath};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
 
@@ -10,18 +10,17 @@ use super::MATCH_AS_REF;
 
 pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
     if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() {
-        let arm_ref: Option<BindingAnnotation> = if is_none_arm(cx, &arms[0]) {
+        let arm_ref_mut = if is_none_arm(cx, &arms[0]) {
             is_ref_some_arm(cx, &arms[1])
         } else if is_none_arm(cx, &arms[1]) {
             is_ref_some_arm(cx, &arms[0])
         } else {
             None
         };
-        if let Some(rb) = arm_ref {
-            let suggestion = if rb == BindingAnnotation::Ref {
-                "as_ref"
-            } else {
-                "as_mut"
+        if let Some(rb) = arm_ref_mut {
+            let suggestion = match rb {
+                Mutability::Not => "as_ref",
+                Mutability::Mut => "as_mut",
             };
 
             let output_ty = cx.typeck_results().expr_ty(expr);
@@ -66,19 +65,18 @@ fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
 }
 
 // Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`)
-fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<BindingAnnotation> {
+fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<Mutability> {
     if_chain! {
         if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind;
         if is_lang_ctor(cx, qpath, LangItem::OptionSome);
-        if let PatKind::Binding(rb, .., ident, _) = first_pat.kind;
-        if rb == BindingAnnotation::Ref || rb == BindingAnnotation::RefMut;
+        if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., ident, _) = first_pat.kind;
         if let ExprKind::Call(e, [arg]) = peel_blocks(arm.body).kind;
         if let ExprKind::Path(ref some_path) = e.kind;
         if is_lang_ctor(cx, some_path, LangItem::OptionSome);
         if let ExprKind::Path(QPath::Resolved(_, path2)) = arg.kind;
         if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name;
         then {
-            return Some(rb)
+            return Some(mutabl)
         }
     }
     None
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 e32ef9933af..93874b103b4 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
@@ -248,7 +248,7 @@ impl<'a> NormalizedPat<'a> {
                 } else {
                     (None, adt.non_enum_variant())
                 };
-                let (front, back) = match wild_idx {
+                let (front, back) = match wild_idx.as_opt_usize() {
                     Some(i) => pats.split_at(i),
                     None => (pats, [].as_slice()),
                 };
@@ -268,7 +268,7 @@ impl<'a> NormalizedPat<'a> {
                     ty::Tuple(subs) => subs.len(),
                     _ => return Self::Wild,
                 };
-                let (front, back) = match wild_idx {
+                let (front, back) = match wild_idx.as_opt_usize() {
                     Some(i) => pats.split_at(i),
                     None => (pats, [].as_slice()),
                 };
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
index fa3b8d1fcea..1e80b6cf2d8 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
@@ -48,7 +48,7 @@ struct MatchExprVisitor<'a, 'tcx> {
 impl<'a, 'tcx> Visitor<'tcx> for MatchExprVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
         match ex.kind {
-            ExprKind::MethodCall(segment, [receiver], _) if self.case_altered(segment.ident.as_str(), receiver) => {},
+            ExprKind::MethodCall(segment, receiver, [], _) if self.case_altered(segment.ident.as_str(), receiver) => {},
             _ => walk_expr(self, ex),
         }
     }
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 6f037339ec7..634eef82e53 100644
--- a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
@@ -8,7 +8,7 @@ use clippy_utils::{
 };
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::OptionNone;
-use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, FnRetTy, Guard, Node, Pat, PatKind, Path, QPath};
+use rustc_hir::{Arm, BindingAnnotation, ByRef, Expr, ExprKind, FnRetTy, Guard, Node, Pat, PatKind, Path, QPath};
 use rustc_lint::LateContext;
 use rustc_span::sym;
 use rustc_typeck::hir_ty_to_ty;
@@ -189,8 +189,7 @@ fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
                 },
             )),
         ) => {
-            return !matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut)
-                && pat_ident.name == first_seg.ident.name;
+            return !matches!(annot, BindingAnnotation(ByRef::Yes, _)) && pat_ident.name == first_seg.ident.name;
         },
         // Example: `Custom::TypeA => Custom::TypeB`, or `None => None`
         (PatKind::Path(QPath::Resolved(_, p_path)), ExprKind::Path(QPath::Resolved(_, e_path))) => {
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
index 8499e050af2..f7443471e31 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -120,7 +120,7 @@ fn find_sugg_for_if_let<'tcx>(
     // check that `while_let_on_iterator` lint does not trigger
     if_chain! {
         if keyword == "while";
-        if let ExprKind::MethodCall(method_path, _, _) = let_expr.kind;
+        if let ExprKind::MethodCall(method_path, ..) = let_expr.kind;
         if method_path.ident.name == sym::next;
         if is_trait_method(cx, let_expr, sym::Iterator);
         then {
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 b0b15b3f54c..86a9df03497 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
@@ -291,7 +291,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
         self.is_chain_end = false;
 
         match ex.kind {
-            ExprKind::MethodCall(_, [ref expr, ..], _) => {
+            ExprKind::MethodCall(_, expr, ..) => {
                 self.visit_expr(expr);
             }
             ExprKind::Binary(_, left, right) => {
@@ -331,8 +331,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
             ExprKind::Index(..) |
             ExprKind::Ret(..) |
             ExprKind::Repeat(..) |
-            ExprKind::Yield(..) |
-            ExprKind::MethodCall(..) => walk_expr(self, ex),
+            ExprKind::Yield(..) => walk_expr(self, ex),
             ExprKind::AddrOf(_, _, _) |
             ExprKind::Block(_, _) |
             ExprKind::Break(_, _) |
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 92091a0c339..1bf1c4d1078 100644
--- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
@@ -175,7 +175,7 @@ fn collect_pat_paths<'a>(acc: &mut Vec<Ty<'a>>, cx: &LateContext<'a>, pat: &Pat<
             let p_ty = cx.typeck_results().pat_ty(p);
             collect_pat_paths(acc, cx, p, p_ty);
         }),
-        PatKind::TupleStruct(..) | PatKind::Binding(BindingAnnotation::Unannotated, .., None) | PatKind::Path(_) => {
+        PatKind::TupleStruct(..) | PatKind::Binding(BindingAnnotation::NONE, .., None) | PatKind::Path(_) => {
             acc.push(ty);
         },
         _ => {},
@@ -200,6 +200,8 @@ fn form_exhaustive_matches<'a>(cx: &LateContext<'a>, ty: Ty<'a>, left: &Pat<'_>,
             // We don't actually know the position and the presence of the `..` (dotdot) operator
             // in the arms, so we need to evaluate the correct offsets here in order to iterate in
             // both arms at the same time.
+            let left_pos = left_pos.as_opt_usize();
+            let right_pos = right_pos.as_opt_usize();
             let len = max(
                 left_in.len() + {
                     if left_pos.is_some() { 1 } else { 0 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/bytecount.rs b/src/tools/clippy/clippy_lints/src/methods/bytecount.rs
index 6a7c63d76f7..fef90f6eba4 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bytecount.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bytecount.rs
@@ -42,11 +42,11 @@ pub(super) fn check<'tcx>(
         if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(needle).peel_refs().kind();
         if !is_local_used(cx, needle, arg_id);
         then {
-            let haystack = if let ExprKind::MethodCall(path, args, _) =
+            let haystack = if let ExprKind::MethodCall(path, receiver, [], _) =
                     filter_recv.kind {
                 let p = path.ident.name;
-                if (p == sym::iter || p == sym!(iter_mut)) && args.len() == 1 {
-                    &args[0]
+                if p == sym::iter || p == sym!(iter_mut) {
+                    receiver
                 } else {
                     filter_recv
                 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs b/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
index f7b79f0839b..51aec21527a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
@@ -23,7 +23,7 @@ pub(super) fn check(
         if Some(id) == cx.tcx.lang_items().option_some_variant();
         then {
             let mut applicability = Applicability::MachineApplicable;
-            let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0][0]).peel_refs();
+            let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0].0).peel_refs();
 
             if *self_ty.kind() != ty::Str {
                 return false;
@@ -37,7 +37,7 @@ pub(super) fn check(
                 "like this",
                 format!("{}{}.{}({})",
                         if info.eq { "" } else { "!" },
-                        snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability),
+                        snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability),
                         suggest,
                         snippet_with_applicability(cx, arg_char.span, "..", &mut applicability)),
                 applicability,
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
index a7c0e43923e..b85bfec2b12 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
@@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(
                 "like this",
                 format!("{}{}.{}('{}')",
                         if info.eq { "" } else { "!" },
-                        snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability),
+                        snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability),
                         suggest,
                         c.escape_default()),
                 applicability,
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 60e1355f9b9..f5bead387d7 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
@@ -4,7 +4,7 @@ use clippy_utils::source::snippet_with_context;
 use clippy_utils::sugg;
 use clippy_utils::ty::is_copy;
 use rustc_errors::Applicability;
-use rustc_hir::{BindingAnnotation, Expr, ExprKind, MatchSource, Node, PatKind, QPath};
+use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, MatchSource, Node, PatKind, QPath};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, adjustment::Adjust};
 use rustc_span::symbol::{sym, Symbol};
@@ -14,11 +14,14 @@ use super::CLONE_ON_COPY;
 
 /// Checks for the `CLONE_ON_COPY` lint.
 #[allow(clippy::too_many_lines)]
-pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, args: &[Expr<'_>]) {
-    let arg = match args {
-        [arg] if method_name == sym::clone => arg,
-        _ => return,
-    };
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    expr: &Expr<'_>,
+    method_name: Symbol,
+    receiver: &Expr<'_>,
+    args: &[Expr<'_>],
+) {
+    let arg = if method_name == sym::clone && args.is_empty() { receiver } else { return };
     if cx
         .typeck_results()
         .type_dependent_def_id(expr.hir_id)
@@ -81,7 +84,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol,
                 // &*x is a nop, &x.clone() is not
                 ExprKind::AddrOf(..) => return,
                 // (*x).func() is useless, x.clone().func() can work in case func borrows self
-                ExprKind::MethodCall(_, [self_arg, ..], _)
+                ExprKind::MethodCall(_, self_arg, ..)
                     if expr.hir_id == self_arg.hir_id && ty != cx.typeck_results().expr_ty_adjusted(expr) =>
                 {
                     return;
@@ -91,19 +94,14 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol,
                     hir_callee.kind,
                     ExprKind::Path(QPath::LangItem(rustc_hir::LangItem::TryTraitBranch, _, _))
                 ),
-                ExprKind::MethodCall(_, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true,
+                ExprKind::MethodCall(_, self_arg, ..) if expr.hir_id == self_arg.hir_id => true,
                 ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar)
                 | ExprKind::Field(..)
                 | ExprKind::Index(..) => true,
                 _ => false,
             },
             // local binding capturing a reference
-            Some(Node::Local(l))
-                if matches!(
-                    l.pat.kind,
-                    PatKind::Binding(BindingAnnotation::Ref | BindingAnnotation::RefMut, ..)
-                ) =>
-            {
+            Some(Node::Local(l)) if matches!(l.pat.kind, PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..)) => {
                 return;
             },
             _ => false,
diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs
index 6417bc81304..f82ca891200 100644
--- a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs
@@ -10,12 +10,17 @@ use rustc_span::symbol::{sym, Symbol};
 
 use super::CLONE_ON_REF_PTR;
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) {
-    if !(args.len() == 1 && method_name == sym::clone) {
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    expr: &hir::Expr<'_>,
+    method_name: Symbol,
+    receiver: &hir::Expr<'_>,
+    args: &[hir::Expr<'_>],
+) {
+    if !(args.is_empty() && method_name == sym::clone) {
         return;
     }
-    let arg = &args[0];
-    let obj_ty = cx.typeck_results().expr_ty(arg).peel_refs();
+    let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs();
 
     if let ty::Adt(_, subst) = obj_ty.kind() {
         let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) {
@@ -28,7 +33,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Sym
             return;
         };
 
-        let snippet = snippet_with_macro_callsite(cx, arg.span, "..");
+        let snippet = snippet_with_macro_callsite(cx, receiver.span, "..");
 
         span_lint_and_sugg(
             cx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs b/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs
index 561033be5b6..501646863fe 100644
--- a/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs
@@ -23,7 +23,7 @@ pub(super) fn check<'tcx>(
         // If the parent node's `to` argument is the same as the `to` argument
         // of the last replace call in the current chain, don't lint as it was already linted
         if let Some(parent) = get_parent_expr(cx, expr)
-            && let Some(("replace", [_, current_from, current_to], _)) = method_call(parent)
+            && let Some(("replace", _, [current_from, current_to], _)) = method_call(parent)
             && eq_expr_value(cx, to, current_to)
             && from_kind == cx.typeck_results().expr_ty(current_from).peel_refs().kind()
         {
@@ -48,7 +48,7 @@ fn collect_replace_calls<'tcx>(
     let mut from_args = VecDeque::new();
 
     let _: Option<()> = for_each_expr(expr, |e| {
-        if let Some(("replace", [_, from, to], _)) = method_call(e) {
+        if let Some(("replace", _, [from, to], _)) = method_call(e) {
             if eq_expr_value(cx, to_arg, to) && cx.typeck_results().expr_ty(from).peel_refs().is_char() {
                 methods.push_front(e);
                 from_args.push_front(from);
@@ -78,7 +78,7 @@ fn check_consecutive_replace_calls<'tcx>(
         .collect();
     let app = Applicability::MachineApplicable;
     let earliest_replace_call = replace_methods.methods.front().unwrap();
-    if let Some((_, [..], span_lo)) = method_call(earliest_replace_call) {
+    if let Some((_, _, [..], span_lo)) = method_call(earliest_replace_call) {
         span_lint_and_sugg(
             cx,
             COLLAPSIBLE_STR_REPLACE,
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 6f2307d8f18..bd846d71d46 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
@@ -19,6 +19,7 @@ pub(super) fn check<'tcx>(
     expr: &hir::Expr<'_>,
     method_span: Span,
     name: &str,
+    receiver: &'tcx hir::Expr<'tcx>,
     args: &'tcx [hir::Expr<'tcx>],
 ) {
     // Strip `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or
@@ -28,16 +29,13 @@ pub(super) fn check<'tcx>(
         loop {
             arg_root = match &arg_root.kind {
                 hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => expr,
-                hir::ExprKind::MethodCall(method_name, call_args, _) => {
-                    if call_args.len() == 1
-                        && (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref)
-                        && {
-                            let arg_type = cx.typeck_results().expr_ty(&call_args[0]);
-                            let base_type = arg_type.peel_refs();
-                            *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym::String)
-                        }
-                    {
-                        &call_args[0]
+                hir::ExprKind::MethodCall(method_name, receiver, [], ..) => {
+                    if (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref) && {
+                        let arg_type = cx.typeck_results().expr_ty(receiver);
+                        let base_type = arg_type.peel_refs();
+                        *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym::String)
+                    } {
+                        receiver
                     } else {
                         break;
                     }
@@ -114,11 +112,11 @@ pub(super) fn check<'tcx>(
         }
     }
 
-    if args.len() != 2 || name != "expect" || !is_call(&args[1].kind) {
+    if args.len() != 1 || name != "expect" || !is_call(&args[0].kind) {
         return;
     }
 
-    let receiver_type = cx.typeck_results().expr_ty_adjusted(&args[0]);
+    let receiver_type = cx.typeck_results().expr_ty_adjusted(receiver);
     let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym::Option) {
         "||"
     } else if is_type_diagnostic_item(cx, receiver_type, sym::Result) {
@@ -127,7 +125,7 @@ pub(super) fn check<'tcx>(
         return;
     };
 
-    let arg_root = get_arg_root(cx, &args[1]);
+    let arg_root = get_arg_root(cx, &args[0]);
 
     let span_replace_word = method_span.with_hi(expr.span.hi());
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs b/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs
index a15fe609402..37b28463527 100644
--- a/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs
@@ -14,7 +14,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg:
     if_chain! {
         if is_type_diagnostic_item(cx, ty, sym::Vec);
         //check source object
-        if let ExprKind::MethodCall(src_method, [drain_vec, drain_arg], _) = &arg.kind;
+        if let ExprKind::MethodCall(src_method, drain_vec, [drain_arg], _) = &arg.kind;
         if src_method.ident.as_str() == "drain";
         let src_ty = cx.typeck_results().expr_ty(drain_vec);
         //check if actual src type is mutable for code suggestion
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
index 692e22a7c5c..9dc839afc62 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
@@ -28,11 +28,11 @@ fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy
             let closure_expr = peel_blocks(&body.value);
             let arg_id = body.params[0].pat.hir_id;
             match closure_expr.kind {
-                hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, args, _) => {
+                hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => {
                     if_chain! {
                     if ident.name == method_name;
-                    if let hir::ExprKind::Path(path) = &args[0].kind;
-                    if let Res::Local(ref local) = cx.qpath_res(path, args[0].hir_id);
+                    if let hir::ExprKind::Path(path) = &receiver.kind;
+                    if let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id);
                     then {
                         return arg_id == *local
                     }
@@ -106,7 +106,7 @@ pub(super) fn check<'tcx>(
             };
             // closure ends with is_some() or is_ok()
             if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind;
-            if let ExprKind::MethodCall(path, [filter_arg], _) = filter_body.value.kind;
+            if let ExprKind::MethodCall(path, filter_arg, [], _) = filter_body.value.kind;
             if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).peel_refs().ty_adt_def();
             if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did()) {
                 Some(false)
@@ -123,13 +123,13 @@ pub(super) fn check<'tcx>(
             if let [map_param] = map_body.params;
             if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind;
             // closure ends with expect() or unwrap()
-            if let ExprKind::MethodCall(seg, [map_arg, ..], _) = map_body.value.kind;
+            if let ExprKind::MethodCall(seg, map_arg, ..) = map_body.value.kind;
             if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or);
 
             // .filter(..).map(|y| f(y).copied().unwrap())
             //                     ~~~~
             let map_arg_peeled = match map_arg.kind {
-                ExprKind::MethodCall(method, [original_arg], _) if acceptable_methods(method) => {
+                ExprKind::MethodCall(method, original_arg, [], _) if acceptable_methods(method) => {
                     original_arg
                 },
                 _ => map_arg,
diff --git a/src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs b/src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs
index 23368238ef5..02aada87202 100644
--- a/src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs
@@ -22,7 +22,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg:
     ) = arg.kind
 
         // LHS of subtraction is "x.len()"
-        && let ExprKind::MethodCall(lhs_path, [lhs_recv], _) = &lhs.kind
+        && let ExprKind::MethodCall(lhs_path, lhs_recv, [], _) = &lhs.kind
         && lhs_path.ident.name == sym::len
 
         // RHS of subtraction is 1
diff --git a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
index f52170df662..e1c9b5248a8 100644
--- a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
@@ -12,13 +12,19 @@ use rustc_span::symbol::{sym, Symbol};
 use super::INEFFICIENT_TO_STRING;
 
 /// Checks for the `INEFFICIENT_TO_STRING` lint
-pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) {
+pub fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &hir::Expr<'_>,
+    method_name: Symbol,
+    receiver: &hir::Expr<'_>,
+    args: &[hir::Expr<'_>],
+) {
     if_chain! {
-        if args.len() == 1 && method_name == sym::to_string;
+        if args.is_empty() && method_name == sym::to_string;
         if let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         if match_def_path(cx, to_string_meth_did, &paths::TO_STRING_METHOD);
         if let Some(substs) = cx.typeck_results().node_substs_opt(expr.hir_id);
-        let arg_ty = cx.typeck_results().expr_ty_adjusted(&args[0]);
+        let arg_ty = cx.typeck_results().expr_ty_adjusted(receiver);
         let self_ty = substs.type_at(0);
         let (deref_self_ty, deref_count) = walk_ptrs_ty_depth(self_ty);
         if deref_count >= 1;
@@ -35,7 +41,7 @@ pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy
                         self_ty, deref_self_ty
                     ));
                     let mut applicability = Applicability::MachineApplicable;
-                    let arg_snippet = snippet_with_applicability(cx, args[0].span, "..", &mut applicability);
+                    let arg_snippet = snippet_with_applicability(cx, receiver.span, "..", &mut applicability);
                     diag.span_suggestion(
                         expr.span,
                         "try dereferencing the receiver",
diff --git a/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs b/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs
index da13b4ba37a..11e76841e9f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs
@@ -16,9 +16,9 @@ pub(super) fn check(
     expr: &hir::Expr<'_>,
     method_span: Span,
     method_name: Symbol,
-    args: &[hir::Expr<'_>],
+    receiver: &hir::Expr<'_>,
 ) {
-    let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0]);
+    let self_ty = cx.typeck_results().expr_ty_adjusted(receiver);
     if_chain! {
         if let ty::Ref(..) = self_ty.kind();
         if method_name == sym::into_iter;
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs b/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs
index 43e9451f7d3..beb772100af 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs
@@ -24,7 +24,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
                     if let Some(id) = path_to_local(recv);
                     if let Node::Pat(pat) = cx.tcx.hir().get(id);
                     if let PatKind::Binding(ann, _, _, _)  = pat.kind;
-                    if ann != BindingAnnotation::Mutable;
+                    if ann != BindingAnnotation::MUT;
                     then {
                         application = Applicability::Unspecified;
                         diag.span_help(
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs b/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs
index 152072e09c7..a669cbbbcc6 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs
@@ -35,7 +35,7 @@ fn is_full_range(cx: &LateContext<'_>, container: &Expr<'_>, range: Range<'_>) -
         && range.end.map_or(true, |e| {
             if range.limits == RangeLimits::HalfOpen
                 && let ExprKind::Path(QPath::Resolved(None, container_path)) = container.kind
-                && let ExprKind::MethodCall(name, [self_arg], _) = e.kind
+                && let ExprKind::MethodCall(name, self_arg, [], _) = e.kind
                 && name.ident.name == sym::len
                 && let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind
             {
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 ffedda95ff8..e8442091fd3 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
@@ -33,13 +33,13 @@ pub(super) fn check<'tcx>(
             let closure_expr = peel_blocks(&closure_body.value);
             match closure_body.params[0].pat.kind {
                 hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding(
-                    hir::BindingAnnotation::Unannotated, .., name, None
+                    hir::BindingAnnotation::NONE, .., name, None
                 ) = inner.kind {
                     if ident_eq(name, closure_expr) {
                         lint_explicit_closure(cx, e.span, recv.span, true, msrv);
                     }
                 },
-                hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, .., name, None) => {
+                hir::PatKind::Binding(hir::BindingAnnotation::NONE, .., name, None) => {
                     match closure_expr.kind {
                         hir::ExprKind::Unary(hir::UnOp::Deref, inner) => {
                             if ident_eq(name, inner) {
@@ -48,7 +48,7 @@ pub(super) fn check<'tcx>(
                                 }
                             }
                         },
-                        hir::ExprKind::MethodCall(method, [obj], _) => if_chain! {
+                        hir::ExprKind::MethodCall(method, obj, [], _) => if_chain! {
                             if ident_eq(name, obj) && method.ident.name == sym::clone;
                             if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id);
                             if let Some(trait_id) = cx.tcx.trait_of_item(fn_id);
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index a0d190a58af..48a9d6e7c32 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -3161,11 +3161,13 @@ impl_lint_pass!(Methods => [
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
-fn method_call<'tcx>(recv: &'tcx hir::Expr<'tcx>) -> Option<(&'tcx str, &'tcx [hir::Expr<'tcx>], Span)> {
-    if let ExprKind::MethodCall(path, args, _) = recv.kind {
-        if !args.iter().any(|e| e.span.from_expansion()) {
+fn method_call<'tcx>(
+    recv: &'tcx hir::Expr<'tcx>,
+) -> Option<(&'tcx str, &'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], Span)> {
+    if let ExprKind::MethodCall(path, receiver, args, _) = recv.kind {
+        if !args.iter().any(|e| e.span.from_expansion()) && !receiver.span.from_expansion() {
             let name = path.ident.name.as_str();
-            return Some((name, args, path.ident.span));
+            return Some((name, receiver, args, path.ident.span));
         }
     }
     None
@@ -3183,17 +3185,17 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             hir::ExprKind::Call(func, args) => {
                 from_iter_instead_of_collect::check(cx, expr, args, func);
             },
-            hir::ExprKind::MethodCall(method_call, args, _) => {
+            hir::ExprKind::MethodCall(method_call, receiver, args, _) => {
                 let method_span = method_call.ident.span;
-                or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), args);
-                expect_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), args);
-                clone_on_copy::check(cx, expr, method_call.ident.name, args);
-                clone_on_ref_ptr::check(cx, expr, method_call.ident.name, args);
-                inefficient_to_string::check(cx, expr, method_call.ident.name, args);
-                single_char_add_str::check(cx, expr, args);
-                into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, args);
-                single_char_pattern::check(cx, expr, method_call.ident.name, args);
-                unnecessary_to_owned::check(cx, expr, method_call.ident.name, args, self.msrv);
+                or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args);
+                expect_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args);
+                clone_on_copy::check(cx, expr, method_call.ident.name, receiver, args);
+                clone_on_ref_ptr::check(cx, expr, method_call.ident.name, receiver, args);
+                inefficient_to_string::check(cx, expr, method_call.ident.name, receiver, args);
+                single_char_add_str::check(cx, expr, receiver, args);
+                into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, receiver);
+                single_char_pattern::check(cx, expr, method_call.ident.name, receiver, args);
+                unnecessary_to_owned::check(cx, expr, method_call.ident.name, receiver, args, self.msrv);
             },
             hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => {
                 let mut info = BinaryExprInfo {
@@ -3302,9 +3304,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
                 // one of the associated types must be Self
                 for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
                     if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
-                        let assoc_ty = match projection_predicate.term {
-                            ty::Term::Ty(ty) => ty,
-                            ty::Term::Const(_c) => continue,
+                        let assoc_ty = match projection_predicate.term.unpack() {
+                            ty::TermKind::Ty(ty) => ty,
+                            ty::TermKind::Const(_c) => continue,
                         };
                         // walk the associated type and check for Self
                         if let Some(self_adt) = self_ty.ty_adt_def() {
@@ -3379,7 +3381,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
 impl Methods {
     #[allow(clippy::too_many_lines)]
     fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if let Some((name, [recv, args @ ..], span)) = method_call(expr) {
+        if let Some((name, recv, args, span)) = method_call(expr) {
             match (name, args) {
                 ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => {
                     zst_offset::check(cx, expr, recv);
@@ -3399,13 +3401,13 @@ impl Methods {
                 ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
                 ("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, self.msrv),
                 ("collect", []) => match method_call(recv) {
-                    Some((name @ ("cloned" | "copied"), [recv2], _)) => {
+                    Some((name @ ("cloned" | "copied"), recv2, [], _)) => {
                         iter_cloned_collect::check(cx, name, expr, recv2);
                     },
-                    Some(("map", [m_recv, m_arg], _)) => {
+                    Some(("map", m_recv, [m_arg], _)) => {
                         map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
                     },
-                    Some(("take", [take_self_arg, take_arg], _)) => {
+                    Some(("take", take_self_arg, [take_arg], _)) => {
                         if meets_msrv(self.msrv, msrvs::STR_REPEAT) {
                             manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
                         }
@@ -3413,26 +3415,26 @@ impl Methods {
                     _ => {},
                 },
                 ("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) {
-                    Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false),
-                    Some((name2 @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => {
+                    Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false),
+                    Some((name2 @ ("into_iter" | "iter" | "iter_mut"), recv2, [], _)) => {
                         iter_count::check(cx, expr, recv2, name2);
                     },
-                    Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg),
-                    Some(("filter", [recv2, arg], _)) => bytecount::check(cx, expr, recv2, arg),
-                    Some(("bytes", [recv2], _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
+                    Some(("map", _, [arg], _)) => suspicious_map::check(cx, expr, recv, arg),
+                    Some(("filter", recv2, [arg], _)) => bytecount::check(cx, expr, recv2, arg),
+                    Some(("bytes", recv2, [], _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
                     _ => {},
                 },
                 ("drain", [arg]) => {
                     iter_with_drain::check(cx, expr, recv, span, arg);
                 },
                 ("ends_with", [arg]) => {
-                    if let ExprKind::MethodCall(_, _, span) = expr.kind {
+                    if let ExprKind::MethodCall(.., span) = expr.kind {
                         case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg);
                     }
                 },
                 ("expect", [_]) => match method_call(recv) {
-                    Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv),
-                    Some(("err", [recv], err_span)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span),
+                    Some(("ok", recv, [], _)) => ok_expect::check(cx, expr, recv),
+                    Some(("err", recv, [], err_span)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span),
                     _ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests),
                 },
                 ("expect_err", [_]) => expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests),
@@ -3452,13 +3454,13 @@ impl Methods {
                     flat_map_option::check(cx, expr, arg, span);
                 },
                 ("flatten", []) => match method_call(recv) {
-                    Some(("map", [recv, map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
-                    Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true),
+                    Some(("map", recv, [map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
+                    Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true),
                     _ => {},
                 },
                 ("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span),
                 ("for_each", [_]) => {
-                    if let Some(("inspect", [_, _], span2)) = method_call(recv) {
+                    if let Some(("inspect", _, [_], span2)) = method_call(recv) {
                         inspect_for_each::check(cx, expr, span2);
                     }
                 },
@@ -3478,12 +3480,12 @@ impl Methods {
                     iter_on_single_or_empty_collections::check(cx, expr, name, recv);
                 },
                 ("join", [join_arg]) => {
-                    if let Some(("collect", _, span)) = method_call(recv) {
+                    if let Some(("collect", _, _, span)) = method_call(recv) {
                         unnecessary_join::check(cx, expr, recv, join_arg, span);
                     }
                 },
                 ("last", []) | ("skip", [_]) => {
-                    if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
+                    if let Some((name2, recv2, args2, _span2)) = method_call(recv) {
                         if let ("cloned", []) = (name2, args2) {
                             iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
                         }
@@ -3498,7 +3500,7 @@ impl Methods {
                     } else {
                         map_err_ignore::check(cx, expr, m_arg);
                     }
-                    if let Some((name, [recv2, args @ ..], span2)) = method_call(recv) {
+                    if let Some((name, recv2, args, span2)) = method_call(recv) {
                         match (name, args) {
                             ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv),
                             ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv),
@@ -3518,7 +3520,7 @@ impl Methods {
                     manual_ok_or::check(cx, expr, recv, def, map);
                 },
                 ("next", []) => {
-                    if let Some((name2, [recv2, args2 @ ..], _)) = method_call(recv) {
+                    if let Some((name2, recv2, args2, _)) = method_call(recv) {
                         match (name2, args2) {
                             ("cloned", []) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
                             ("filter", [arg]) => filter_next::check(cx, expr, recv2, arg),
@@ -3531,10 +3533,10 @@ impl Methods {
                     }
                 },
                 ("nth", [n_arg]) => match method_call(recv) {
-                    Some(("bytes", [recv2], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
-                    Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, 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(("bytes", recv2, [], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
+                    Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, 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),
                     _ => iter_nth_zero::check(cx, expr, recv, n_arg),
                 },
                 ("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
@@ -3591,7 +3593,7 @@ impl Methods {
                 },
                 ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
                 ("take", [_arg]) => {
-                    if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
+                    if let Some((name2, recv2, args2, _span2)) = method_call(recv) {
                         if let ("cloned", []) = (name2, args2) {
                             iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
                         }
@@ -3614,13 +3616,13 @@ impl Methods {
                 },
                 ("unwrap", []) => {
                     match method_call(recv) {
-                        Some(("get", [recv, get_arg], _)) => {
+                        Some(("get", recv, [get_arg], _)) => {
                             get_unwrap::check(cx, expr, recv, get_arg, false);
                         },
-                        Some(("get_mut", [recv, get_arg], _)) => {
+                        Some(("get_mut", recv, [get_arg], _)) => {
                             get_unwrap::check(cx, expr, recv, get_arg, true);
                         },
-                        Some(("or", [recv, or_arg], or_span)) => {
+                        Some(("or", recv, [or_arg], or_span)) => {
                             or_then_unwrap::check(cx, expr, recv, or_arg, or_span);
                         },
                         _ => {},
@@ -3629,19 +3631,19 @@ impl Methods {
                 },
                 ("unwrap_err", []) => unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests),
                 ("unwrap_or", [u_arg]) => match method_call(recv) {
-                    Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => {
+                    Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), lhs, [rhs], _)) => {
                         manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
                     },
-                    Some(("map", [m_recv, m_arg], span)) => {
+                    Some(("map", m_recv, [m_arg], span)) => {
                         option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span);
                     },
-                    Some(("then_some", [t_recv, t_arg], _)) => {
+                    Some(("then_some", t_recv, [t_arg], _)) => {
                         obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg);
                     },
                     _ => {},
                 },
                 ("unwrap_or_else", [u_arg]) => match method_call(recv) {
-                    Some(("map", [recv, map_arg], _))
+                    Some(("map", recv, [map_arg], _))
                         if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, self.msrv) => {},
                     _ => {
                         unwrap_or_else_default::check(cx, expr, recv, u_arg);
@@ -3649,7 +3651,7 @@ impl Methods {
                     },
                 },
                 ("zip", [arg]) => {
-                    if let ExprKind::MethodCall(name, [iter_recv], _) = recv.kind
+                    if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind
                         && name.ident.name == sym::iter
                     {
                         range_zip_with_len::check(cx, expr, iter_recv, arg);
@@ -3662,7 +3664,7 @@ impl Methods {
 }
 
 fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, is_some: bool) {
-    if let Some((name @ ("find" | "position" | "rposition"), [f_recv, arg], span)) = method_call(recv) {
+    if let Some((name @ ("find" | "position" | "rposition"), f_recv, [arg], span)) = method_call(recv) {
         search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span);
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/open_options.rs b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
index c3112823e34..903fa306f93 100644
--- a/src/tools/clippy/clippy_lints/src/methods/open_options.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
@@ -36,12 +36,12 @@ enum OpenOption {
 }
 
 fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec<(OpenOption, Argument)>) {
-    if let ExprKind::MethodCall(path, arguments, _) = argument.kind {
-        let obj_ty = cx.typeck_results().expr_ty(&arguments[0]).peel_refs();
+    if let ExprKind::MethodCall(path, receiver, arguments, _) = argument.kind {
+        let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs();
 
         // Only proceed if this is a call on some object of type std::fs::OpenOptions
-        if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 2 {
-            let argument_option = match arguments[1].kind {
+        if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 1 {
+            let argument_option = match arguments[0].kind {
                 ExprKind::Lit(ref span) => {
                     if let Spanned {
                         node: LitKind::Bool(lit),
@@ -77,7 +77,7 @@ fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec
                 _ => (),
             }
 
-            get_open_options(cx, &arguments[0], options);
+            get_open_options(cx, receiver, options);
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
index 20cad0f181e..81c67b4ca6a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
@@ -56,13 +56,12 @@ pub(super) fn check<'tcx>(
             let closure_expr = peel_blocks(&closure_body.value);
 
             match &closure_expr.kind {
-                hir::ExprKind::MethodCall(_, args, _) => {
+                hir::ExprKind::MethodCall(_, receiver, [], _) => {
                     if_chain! {
-                        if args.len() == 1;
-                        if path_to_local_id(&args[0], closure_body.params[0].pat.hir_id);
+                        if path_to_local_id(receiver, closure_body.params[0].pat.hir_id);
                         let adj = cx
                             .typeck_results()
-                            .expr_adjustments(&args[0])
+                            .expr_adjustments(receiver)
                             .iter()
                             .map(|x| &x.kind)
                             .collect::<Box<[_]>>();
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
index 6af134019a4..76876d86629 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
@@ -20,6 +20,7 @@ pub(super) fn check<'tcx>(
     expr: &hir::Expr<'_>,
     method_span: Span,
     name: &str,
+    receiver: &'tcx hir::Expr<'_>,
     args: &'tcx [hir::Expr<'_>],
 ) {
     /// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`.
@@ -144,7 +145,7 @@ pub(super) fn check<'tcx>(
         }
     }
 
-    if let [self_arg, arg] = args {
+    if let [arg] = args {
         let inner_arg = if let hir::ExprKind::Block(
             hir::Block {
                 stmts: [],
@@ -163,11 +164,11 @@ pub(super) fn check<'tcx>(
                 let or_has_args = !or_args.is_empty();
                 if !check_unwrap_or_default(cx, name, fun, arg, or_has_args, expr.span, method_span) {
                     let fun_span = if or_has_args { None } else { Some(fun.span) };
-                    check_general_case(cx, name, method_span, self_arg, arg, expr.span, fun_span);
+                    check_general_case(cx, name, method_span, receiver, arg, expr.span, fun_span);
                 }
             },
             hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => {
-                check_general_case(cx, name, method_span, self_arg, arg, expr.span, None);
+                check_general_case(cx, name, method_span, receiver, arg, expr.span, None);
             },
             _ => (),
         }
diff --git a/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs b/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs
index 00a2a0d14d1..867a3b40237 100644
--- a/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs
@@ -16,7 +16,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'
         if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg);
         if is_integer_const(cx, start, 0);
         // `.len()` call
-        if let ExprKind::MethodCall(len_path, [len_recv], _) = end.kind;
+        if let ExprKind::MethodCall(len_path, len_recv, [], _) = end.kind;
         if len_path.ident.name == sym::len;
         // `.iter()` and `.len()` called on same `Path`
         if let ExprKind::Path(QPath::Resolved(_, iter_path)) = recv.kind;
diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_add_str.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_add_str.rs
index 9a5fabcf7cd..81450fd8c6c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/single_char_add_str.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/single_char_add_str.rs
@@ -3,12 +3,12 @@ use clippy_utils::{match_def_path, paths};
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
     if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
         if match_def_path(cx, fn_def_id, &paths::PUSH_STR) {
-            single_char_push_string::check(cx, expr, args);
+            single_char_push_string::check(cx, expr, receiver, args);
         } else if match_def_path(cx, fn_def_id, &paths::INSERT_STR) {
-            single_char_insert_string::check(cx, expr, args);
+            single_char_insert_string::check(cx, expr, receiver, args);
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs
index 6cdc954c03b..18b6b5be175 100644
--- a/src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs
@@ -8,12 +8,12 @@ use rustc_lint::LateContext;
 use super::SINGLE_CHAR_ADD_STR;
 
 /// lint for length-1 `str`s as argument for `insert_str`
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
     let mut applicability = Applicability::MachineApplicable;
-    if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[2], &mut applicability) {
+    if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) {
         let base_string_snippet =
-            snippet_with_applicability(cx, args[0].span.source_callsite(), "_", &mut applicability);
-        let pos_arg = snippet_with_applicability(cx, args[1].span, "..", &mut applicability);
+            snippet_with_applicability(cx, receiver.span.source_callsite(), "_", &mut applicability);
+        let pos_arg = snippet_with_applicability(cx, args[0].span, "..", &mut applicability);
         let sugg = format!("{}.insert({}, {})", base_string_snippet, pos_arg, extension_string);
         span_lint_and_sugg(
             cx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs
index bf9006c6906..4221c52d5cd 100644
--- a/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs
@@ -10,37 +10,43 @@ use rustc_span::symbol::Symbol;
 use super::SINGLE_CHAR_PATTERN;
 
 const PATTERN_METHODS: [(&str, usize); 24] = [
-    ("contains", 1),
-    ("starts_with", 1),
-    ("ends_with", 1),
-    ("find", 1),
-    ("rfind", 1),
-    ("split", 1),
-    ("split_inclusive", 1),
-    ("rsplit", 1),
-    ("split_terminator", 1),
-    ("rsplit_terminator", 1),
-    ("splitn", 2),
-    ("rsplitn", 2),
-    ("split_once", 1),
-    ("rsplit_once", 1),
-    ("matches", 1),
-    ("rmatches", 1),
-    ("match_indices", 1),
-    ("rmatch_indices", 1),
-    ("strip_prefix", 1),
-    ("strip_suffix", 1),
-    ("trim_start_matches", 1),
-    ("trim_end_matches", 1),
-    ("replace", 1),
-    ("replacen", 1),
+    ("contains", 0),
+    ("starts_with", 0),
+    ("ends_with", 0),
+    ("find", 0),
+    ("rfind", 0),
+    ("split", 0),
+    ("split_inclusive", 0),
+    ("rsplit", 0),
+    ("split_terminator", 0),
+    ("rsplit_terminator", 0),
+    ("splitn", 1),
+    ("rsplitn", 1),
+    ("split_once", 0),
+    ("rsplit_once", 0),
+    ("matches", 0),
+    ("rmatches", 0),
+    ("match_indices", 0),
+    ("rmatch_indices", 0),
+    ("strip_prefix", 0),
+    ("strip_suffix", 0),
+    ("trim_start_matches", 0),
+    ("trim_end_matches", 0),
+    ("replace", 0),
+    ("replacen", 0),
 ];
 
 /// lint for length-1 `str`s for methods in `PATTERN_METHODS`
-pub(super) fn check(cx: &LateContext<'_>, _expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) {
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    _expr: &hir::Expr<'_>,
+    method_name: Symbol,
+    receiver: &hir::Expr<'_>,
+    args: &[hir::Expr<'_>],
+) {
     for &(method, pos) in &PATTERN_METHODS {
         if_chain! {
-            if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(&args[0]).kind();
+            if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind();
             if *ty.kind() == ty::Str;
             if method_name.as_str() == method && args.len() > pos;
             let arg = &args[pos];
diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs
index 0237d39cbdb..9ea6751956a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs
@@ -8,11 +8,11 @@ use rustc_lint::LateContext;
 use super::SINGLE_CHAR_ADD_STR;
 
 /// lint for length-1 `str`s as argument for `push_str`
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
     let mut applicability = Applicability::MachineApplicable;
-    if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) {
+    if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[0], &mut applicability) {
         let base_string_snippet =
-            snippet_with_applicability(cx, args[0].span.source_callsite(), "..", &mut applicability);
+            snippet_with_applicability(cx, receiver.span.source_callsite(), "..", &mut applicability);
         let sugg = format!("{}.push({})", base_string_snippet, extension_string);
         span_lint_and_sugg(
             cx,
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 4ac738272d0..9ca4d65550d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
@@ -130,7 +130,7 @@ fn check_manual_split_once_indirect(
     let ctxt = expr.span.ctxt();
     let mut parents = cx.tcx.hir().parent_iter(expr.hir_id);
     if let (_, Node::Local(local)) = parents.next()?
-        && let PatKind::Binding(BindingAnnotation::Mutable, iter_binding_id, iter_ident, None) = local.pat.kind
+        && 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()?
 
@@ -212,11 +212,10 @@ fn indirect_usage<'tcx>(
     ctxt: SyntaxContext,
 ) -> Option<IndirectUsage<'tcx>> {
     if let StmtKind::Local(Local {
-        pat:
-            Pat {
-                kind: PatKind::Binding(BindingAnnotation::Unannotated, _, ident, None),
-                ..
-            },
+        pat: Pat {
+            kind: PatKind::Binding(BindingAnnotation::NONE, _, ident, None),
+            ..
+        },
         init: Some(init_expr),
         hir_id: local_hir_id,
         ..
@@ -292,7 +291,7 @@ fn parse_iter_usage<'tcx>(
 ) -> Option<IterUsage> {
     let (kind, span) = match iter.next() {
         Some((_, Node::Expr(e))) if e.span.ctxt() == ctxt => {
-            let (name, args) = if let ExprKind::MethodCall(name, [_, args @ ..], _) = e.kind {
+            let (name, args) = if let ExprKind::MethodCall(name, _, [args @ ..], _) = e.kind {
                 (name, args)
             } else {
                 return None;
@@ -327,7 +326,7 @@ fn parse_iter_usage<'tcx>(
                         } else {
                             if_chain! {
                                 if let Some((_, Node::Expr(next_expr))) = iter.next();
-                                if let ExprKind::MethodCall(next_name, [_], _) = next_expr.kind;
+                                if let ExprKind::MethodCall(next_name, _, [], _) = next_expr.kind;
                                 if next_name.ident.name == sym::next;
                                 if next_expr.span.ctxt() == ctxt;
                                 if let Some(next_id) = cx.typeck_results().type_dependent_def_id(next_expr.hir_id);
@@ -367,7 +366,7 @@ fn parse_iter_usage<'tcx>(
                 }
             },
             _ if e.span.ctxt() != ctxt => (None, span),
-            ExprKind::MethodCall(name, [_], _)
+            ExprKind::MethodCall(name, _, [], _)
                 if name.ident.name == sym::unwrap
                     && cx
                         .typeck_results()
diff --git a/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs b/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs
index d06658f2a5e..143dcee3505 100644
--- a/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs
@@ -16,7 +16,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
         return;
     }
     if let Some(arglists) = method_chain_args(arg, &["chars"]) {
-        let target = &arglists[0][0];
+        let target = &arglists[0].0;
         let self_ty = cx.typeck_results().expr_ty(target).peel_refs();
         let ref_str = if *self_ty.kind() == ty::Str {
             ""
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
index 19037093e20..95138c0e25b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
@@ -43,7 +43,7 @@ pub fn check_for_loop_iter(
         if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
         then {
             let snippet = if_chain! {
-                if let ExprKind::MethodCall(maybe_iter_method_name, [collection], _) = receiver.kind;
+                if let ExprKind::MethodCall(maybe_iter_method_name, collection, [], _) = receiver.kind;
                 if maybe_iter_method_name.ident.name == sym::iter;
 
                 if let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
index 1876c7fb9d0..a187a8d6016 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
@@ -54,7 +54,7 @@ pub(super) fn check<'tcx>(
                 // This is a duplicate of what's happening in clippy_lints::methods::method_call,
                 // which isn't ideal, We want to get the method call span,
                 // but prefer to avoid changing the signature of the function itself.
-                if let hir::ExprKind::MethodCall(_, _, span) = expr.kind {
+                if let hir::ExprKind::MethodCall(.., span) = expr.kind {
                     span_lint_and_then(cx, UNNECESSARY_LAZY_EVALUATIONS, expr.span, msg, |diag| {
                         diag.span_suggestion(
                             span,
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
index 1966990bd77..6f25acca1de 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
@@ -50,9 +50,13 @@ fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident
         // The two exprs are method calls.
         // Check to see that the function is the same and the arguments are mirrored
         // This is enough because the receiver of the method is listed in the arguments
-        (ExprKind::MethodCall(left_segment, left_args, _), ExprKind::MethodCall(right_segment, right_args, _)) => {
+        (
+            ExprKind::MethodCall(left_segment, left_receiver, left_args, _),
+            ExprKind::MethodCall(right_segment, right_receiver, right_args, _),
+        ) => {
             left_segment.ident == right_segment.ident
                 && iter::zip(*left_args, *right_args).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident))
+                && mirrored_exprs(left_receiver, a_ident, right_receiver, b_ident)
         },
         // Two tuples with mirrored contents
         (ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) => {
@@ -125,7 +129,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Exp
             Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..},
             Param { pat: Pat { kind: PatKind::Binding(_, _, right_ident, _), .. }, .. }
         ] = &closure_body.params;
-        if let ExprKind::MethodCall(method_path, [left_expr, right_expr], _) = closure_body.value.kind;
+        if let ExprKind::MethodCall(method_path, left_expr, [right_expr], _) = closure_body.value.kind;
         if method_path.ident.name == sym::cmp;
         if is_trait_method(cx, &closure_body.value, sym::Ord);
         then {
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 44bf8435294..85da97a39f9 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
@@ -24,12 +24,13 @@ pub fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'tcx>,
     method_name: Symbol,
-    args: &'tcx [Expr<'tcx>],
+    receiver: &'tcx Expr<'_>,
+    args: &'tcx [Expr<'_>],
     msrv: Option<RustcVersion>,
 ) {
     if_chain! {
         if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
-        if let [receiver] = args;
+        if args.is_empty();
         then {
             if is_cloned_or_copied(cx, method_name, method_def_id) {
                 unnecessary_iter_cloned::check(cx, expr, method_name, receiver);
@@ -245,9 +246,14 @@ fn check_other_call_arg<'tcx>(
 ) -> bool {
     if_chain! {
         if let Some((maybe_call, maybe_arg)) = skip_addr_of_ancestors(cx, expr);
-        if let Some((callee_def_id, call_substs, call_args)) = get_callee_substs_and_args(cx, maybe_call);
+        if let Some((callee_def_id, call_substs, call_receiver, call_args)) = get_callee_substs_and_args(cx, maybe_call);
         let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
-        if let Some(i) = call_args.iter().position(|arg| arg.hir_id == maybe_arg.hir_id);
+        let index = if let Some(call_receiver) = call_receiver {
+            std::iter::once(call_receiver).chain(call_args.iter()).position(|arg| arg.hir_id == maybe_arg.hir_id)
+        } else {
+            call_args.iter().position(|arg| arg.hir_id == maybe_arg.hir_id)
+        };
+        if let Some(i) = index;
         if let Some(input) = fn_sig.inputs().get(i);
         let (input, n_refs) = peel_mid_ty_refs(*input);
         if let (trait_predicates, projection_predicates) = get_input_traits_and_projections(cx, callee_def_id, input);
@@ -268,7 +274,7 @@ fn check_other_call_arg<'tcx>(
                         .subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.term);
                 implements_trait(cx, receiver_ty, deref_trait_id, &[])
                     && get_associated_type(cx, receiver_ty, deref_trait_id, "Target")
-                        .map_or(false, |ty| ty::Term::Ty(ty) == normalized_ty)
+                        .map_or(false, |ty| ty::TermKind::Ty(ty) == normalized_ty.unpack())
             } else {
                 false
             }
@@ -342,22 +348,22 @@ fn skip_addr_of_ancestors<'tcx>(
 fn get_callee_substs_and_args<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'tcx>,
-) -> Option<(DefId, SubstsRef<'tcx>, &'tcx [Expr<'tcx>])> {
+) -> Option<(DefId, SubstsRef<'tcx>, Option<&'tcx Expr<'tcx>>, &'tcx [Expr<'tcx>])> {
     if_chain! {
         if let ExprKind::Call(callee, args) = expr.kind;
         let callee_ty = cx.typeck_results().expr_ty(callee);
         if let ty::FnDef(callee_def_id, _) = callee_ty.kind();
         then {
             let substs = cx.typeck_results().node_substs(callee.hir_id);
-            return Some((*callee_def_id, substs, args));
+            return Some((*callee_def_id, substs, None, args));
         }
     }
     if_chain! {
-        if let ExprKind::MethodCall(_, args, _) = expr.kind;
+        if let ExprKind::MethodCall(_, receiver, args, _) = expr.kind;
         if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         then {
             let substs = cx.typeck_results().node_substs(expr.hir_id);
-            return Some((method_def_id, substs, args));
+            return Some((method_def_id, substs, Some(receiver), args));
         }
     }
     None
diff --git a/src/tools/clippy/clippy_lints/src/methods/utils.rs b/src/tools/clippy/clippy_lints/src/methods/utils.rs
index 3015531e843..ae6b165fdc3 100644
--- a/src/tools/clippy/clippy_lints/src/methods/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/utils.rs
@@ -28,7 +28,7 @@ pub(super) fn derefs_to_slice<'tcx>(
         }
     }
 
-    if let hir::ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind {
+    if let hir::ExprKind::MethodCall(path, self_arg, ..) = &expr.kind {
         if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(self_arg)) {
             Some(self_arg)
         } else {
@@ -139,9 +139,9 @@ impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> {
                         self.addr_of_exprs.push(parent);
                         return;
                     },
-                    ExprKind::MethodCall(_, args, _) => {
+                    ExprKind::MethodCall(.., args, _) => {
                         if_chain! {
-                            if args.iter().skip(1).all(|arg| !self.is_binding(arg));
+                            if args.iter().all(|arg| !self.is_binding(arg));
                             if let Some(method_def_id) = self.cx.typeck_results().type_dependent_def_id(parent.hir_id);
                             let method_ty = self.cx.tcx.type_of(method_def_id);
                             let self_ty = method_ty.fn_sig(self.cx.tcx).input(0).skip_binder();
diff --git a/src/tools/clippy/clippy_lints/src/minmax.rs b/src/tools/clippy/clippy_lints/src/minmax.rs
index a081cde8572..44b21e7b080 100644
--- a/src/tools/clippy/clippy_lints/src/minmax.rs
+++ b/src/tools/clippy/clippy_lints/src/minmax.rs
@@ -75,23 +75,22 @@ fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Cons
                     .qpath_res(qpath, path.hir_id)
                     .opt_def_id()
                     .and_then(|def_id| match cx.tcx.get_diagnostic_name(def_id) {
-                        Some(sym::cmp_min) => fetch_const(cx, args, MinMax::Min),
-                        Some(sym::cmp_max) => fetch_const(cx, args, MinMax::Max),
+                        Some(sym::cmp_min) => fetch_const(cx, None, args, MinMax::Min),
+                        Some(sym::cmp_max) => fetch_const(cx, None, args, MinMax::Max),
                         _ => None,
                     })
             } else {
                 None
             }
         },
-        ExprKind::MethodCall(path, args, _) => {
+        ExprKind::MethodCall(path, receiver, args @ [_], _) => {
             if_chain! {
-                if let [obj, _] = args;
-                if cx.typeck_results().expr_ty(obj).is_floating_point() || match_trait_method(cx, expr, &paths::ORD);
+                if cx.typeck_results().expr_ty(receiver).is_floating_point() || match_trait_method(cx, expr, &paths::ORD);
                 then {
                     if path.ident.name == sym!(max) {
-                        fetch_const(cx, args, MinMax::Max)
+                        fetch_const(cx, Some(receiver), args, MinMax::Max)
                     } else if path.ident.name == sym!(min) {
-                        fetch_const(cx, args, MinMax::Min)
+                        fetch_const(cx, Some(receiver), args, MinMax::Min)
                     } else {
                         None
                     }
@@ -104,16 +103,24 @@ fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Cons
     }
 }
 
-fn fetch_const<'a>(cx: &LateContext<'_>, args: &'a [Expr<'a>], m: MinMax) -> Option<(MinMax, Constant, &'a Expr<'a>)> {
-    if args.len() != 2 {
+fn fetch_const<'a>(
+    cx: &LateContext<'_>,
+    receiver: Option<&'a Expr<'a>>,
+    args: &'a [Expr<'a>],
+    m: MinMax,
+) -> Option<(MinMax, Constant, &'a Expr<'a>)> {
+    let mut args = receiver.into_iter().chain(args.into_iter());
+    let arg0 = args.next()?;
+    let arg1 = args.next()?;
+    if args.next().is_some() {
         return None;
     }
-    constant_simple(cx, cx.typeck_results(), &args[0]).map_or_else(
-        || constant_simple(cx, cx.typeck_results(), &args[1]).map(|c| (m, c, &args[0])),
+    constant_simple(cx, cx.typeck_results(), arg0).map_or_else(
+        || constant_simple(cx, cx.typeck_results(), arg1).map(|c| (m, c, arg0)),
         |c| {
-            if constant_simple(cx, cx.typeck_results(), &args[1]).is_none() {
+            if constant_simple(cx, cx.typeck_results(), arg1).is_none() {
                 // otherwise ignore
-                Some((m, c, &args[1]))
+                Some((m, c, arg1))
             } else {
                 None
             }
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index 8224e80c9cc..ea245edd770 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -5,8 +5,8 @@ use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
-    self as hir, def, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind, Stmt,
-    StmtKind, TyKind,
+    self as hir, def, BinOpKind, BindingAnnotation, Body, ByRef, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind,
+    Stmt, StmtKind, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
@@ -146,7 +146,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
             return;
         }
         for arg in iter_input_pats(decl, body) {
-            if let PatKind::Binding(BindingAnnotation::Ref | BindingAnnotation::RefMut, ..) = arg.pat.kind {
+            if let PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..) = arg.pat.kind {
                 span_lint(
                     cx,
                     TOPLEVEL_REF_ARG,
@@ -162,9 +162,8 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
         if_chain! {
             if !in_external_macro(cx.tcx.sess, stmt.span);
             if let StmtKind::Local(local) = stmt.kind;
-            if let PatKind::Binding(an, .., name, None) = local.pat.kind;
+            if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., name, None) = local.pat.kind;
             if let Some(init) = local.init;
-            if an == BindingAnnotation::Ref || an == BindingAnnotation::RefMut;
             then {
                 // use the macro callsite when the init span (but not the whole local span)
                 // comes from an expansion like `vec![1, 2, 3]` in `let ref _ = vec![1, 2, 3];`
@@ -173,7 +172,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
                 } else {
                     Sugg::hir(cx, init, "..")
                 };
-                let (mutopt, initref) = if an == BindingAnnotation::RefMut {
+                let (mutopt, initref) = if mutabl == Mutability::Mut {
                     ("mut ", sugg_init.mut_addr())
                 } else {
                     ("", sugg_init.addr())
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/redundant_pattern.rs b/src/tools/clippy/clippy_lints/src/misc_early/redundant_pattern.rs
index 525dbf7757c..d7bb0616acb 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/redundant_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/redundant_pattern.rs
@@ -1,18 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use rustc_ast::ast::{BindingMode, Mutability, Pat, PatKind};
+use rustc_ast::ast::{Pat, PatKind};
 use rustc_errors::Applicability;
 use rustc_lint::EarlyContext;
 
 use super::REDUNDANT_PATTERN;
 
 pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
-    if let PatKind::Ident(left, ident, Some(ref right)) = pat.kind {
-        let left_binding = match left {
-            BindingMode::ByRef(Mutability::Mut) => "ref mut ",
-            BindingMode::ByRef(Mutability::Not) => "ref ",
-            BindingMode::ByValue(..) => "",
-        };
-
+    if let PatKind::Ident(ann, ident, Some(ref right)) = pat.kind {
         if let PatKind::Wild = right.kind {
             span_lint_and_sugg(
                 cx,
@@ -23,7 +17,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
                     ident.name, ident.name,
                 ),
                 "try",
-                format!("{}{}", left_binding, ident.name),
+                format!("{}{}", ann.prefix_str(), ident.name),
                 Applicability::MachineApplicable,
             );
         }
diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs
index f434a655f8a..82dc03ef5c5 100644
--- a/src/tools/clippy/clippy_lints/src/mut_reference.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs
@@ -43,18 +43,24 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed {
                 if let ExprKind::Path(ref path) = fn_expr.kind {
                     check_arguments(
                         cx,
-                        arguments,
+                        arguments.iter().collect(),
                         cx.typeck_results().expr_ty(fn_expr),
                         &rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)),
                         "function",
                     );
                 }
             },
-            ExprKind::MethodCall(path, arguments, _) => {
+            ExprKind::MethodCall(path, receiver, arguments, _) => {
                 let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap();
                 let substs = cx.typeck_results().node_substs(e.hir_id);
                 let method_type = cx.tcx.bound_type_of(def_id).subst(cx.tcx, substs);
-                check_arguments(cx, arguments, method_type, path.ident.as_str(), "method");
+                check_arguments(
+                    cx,
+                    std::iter::once(receiver).chain(arguments.iter()).collect(),
+                    method_type,
+                    path.ident.as_str(),
+                    "method",
+                );
             },
             _ => (),
         }
@@ -63,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed {
 
 fn check_arguments<'tcx>(
     cx: &LateContext<'tcx>,
-    arguments: &[Expr<'_>],
+    arguments: Vec<&Expr<'_>>,
     type_definition: Ty<'tcx>,
     name: &str,
     fn_kind: &str,
diff --git a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
index 9838d3cad9f..f2ffac85bf4 100644
--- a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use if_chain::if_chain;
-use rustc_ast::ast::{BindingMode, Lifetime, Mutability, Param, PatKind, Path, TyKind};
+use rustc_ast::ast::{BindingAnnotation, ByRef, Lifetime, Mutability, Param, PatKind, Path, TyKind};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -120,14 +120,14 @@ impl EarlyLintPass for NeedlessArbitrarySelfType {
 
         match &p.ty.kind {
             TyKind::Path(None, path) => {
-                if let PatKind::Ident(BindingMode::ByValue(mutbl), _, _) = p.pat.kind {
+                if let PatKind::Ident(BindingAnnotation(ByRef::No, mutbl), _, _) = p.pat.kind {
                     check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl);
                 }
             },
             TyKind::Rptr(lifetime, mut_ty) => {
                 if_chain! {
                 if let TyKind::Path(None, path) = &mut_ty.ty.kind;
-                if let PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, _) = p.pat.kind;
+                if let PatKind::Ident(BindingAnnotation::NONE, _, _) = p.pat.kind;
                     then {
                         check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl);
                     }
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs b/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs
index 05c012b92e8..b8855e5adbf 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs
@@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowedRef {
             if let PatKind::Ref(sub_pat, Mutability::Not) = pat.kind;
 
             // Check sub_pat got a `ref` keyword (excluding `ref mut`).
-            if let PatKind::Binding(BindingAnnotation::Ref, .., spanned_name, _) = sub_pat.kind;
+            if let PatKind::Binding(BindingAnnotation::REF, .., spanned_name, _) = sub_pat.kind;
             let parent_id = cx.tcx.hir().get_parent_node(pat.hir_id);
             if let Some(parent_node) = cx.tcx.hir().find(parent_id);
             then {
diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
index 10e188ecb79..f8cc3fbb3cd 100644
--- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
@@ -56,12 +56,12 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
 
         if_chain! {
             // Check the method name is `for_each`.
-            if let ExprKind::MethodCall(method_name, [for_each_recv, for_each_arg], _) = expr.kind;
+            if let ExprKind::MethodCall(method_name, for_each_recv, [for_each_arg], _) = expr.kind;
             if method_name.ident.name == Symbol::intern("for_each");
             // Check `for_each` is an associated function of `Iterator`.
             if is_trait_method(cx, expr, sym::Iterator);
             // Checks the receiver of `for_each` is also a method call.
-            if let ExprKind::MethodCall(_, [iter_recv], _) = for_each_recv.kind;
+            if let ExprKind::MethodCall(_, iter_recv, [], _) = for_each_recv.kind;
             // Skip the lint if the call chain is too long. e.g. `v.field.iter().for_each()` or
             // `v.foo().iter().for_each()` must be skipped.
             if matches!(
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 ff2999b1f4a..de99f1d7078 100644
--- a/src/tools/clippy/clippy_lints/src/needless_late_init.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
@@ -373,7 +373,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit {
             if let Local {
                 init: None,
                 pat: &Pat {
-                    kind: PatKind::Binding(BindingAnnotation::Unannotated, binding_id, _, None),
+                    kind: PatKind::Binding(BindingAnnotation::NONE, binding_id, _, None),
                     ..
                 },
                 source: LocalSource::Normal,
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 0cbef1c95fe..6d17c7a7346 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -8,7 +8,9 @@ use rustc_ast::ast::Attribute;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, Diagnostic};
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{BindingAnnotation, Body, FnDecl, GenericArg, HirId, Impl, ItemKind, Node, PatKind, QPath, TyKind};
+use rustc_hir::{
+    BindingAnnotation, Body, FnDecl, GenericArg, HirId, Impl, ItemKind, Mutability, Node, PatKind, QPath, TyKind,
+};
 use rustc_hir::{HirIdMap, HirIdSet};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
@@ -188,13 +190,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                 if !implements_borrow_trait;
                 if !all_borrowable_trait;
 
-                if let PatKind::Binding(mode, canonical_id, ..) = arg.pat.kind;
+                if let PatKind::Binding(BindingAnnotation(_, Mutability::Not), canonical_id, ..) = arg.pat.kind;
                 if !moved_vars.contains(&canonical_id);
                 then {
-                    if mode == BindingAnnotation::Mutable || mode == BindingAnnotation::RefMut {
-                        continue;
-                    }
-
                     // Dereference suggestion
                     let sugg = |diag: &mut Diagnostic| {
                         if let ty::Adt(def, ..) = ty.kind() {
diff --git a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
index ed022b9d529..25fb4f0f4cf 100644
--- a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
+++ b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
@@ -43,7 +43,7 @@ declare_lint_pass!(NonOctalUnixPermissions => [NON_OCTAL_UNIX_PERMISSIONS]);
 impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         match &expr.kind {
-            ExprKind::MethodCall(path, [func, param], _) => {
+            ExprKind::MethodCall(path, func, [param], _) => {
                 let obj_ty = cx.typeck_results().expr_ty(func).peel_refs();
 
                 if_chain! {
diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
index 774a3540d1e..17d5fa2152b 100644
--- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
@@ -304,13 +304,13 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
                             }
                             return;
                         },
-                        ExprKind::MethodCall(_, args, _)
+                        ExprKind::MethodCall(_, receiver, args, _)
                             if typeck.type_dependent_def_id(parent.hir_id).map_or(false, |id| {
                                 id == param.fn_id
                                     && has_matching_substs(param.fn_kind, typeck.node_substs(parent.hir_id))
                             }) =>
                         {
-                            if let Some(idx) = args.iter().position(|arg| arg.hir_id == child_id) {
+                            if let Some(idx) = std::iter::once(receiver).chain(args.iter()).position(|arg| arg.hir_id == child_id) {
                                 param.uses.push(Usage::new(span, idx));
                             }
                             return;
diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
index e1f9b5906f6..638a514ff9b 100644
--- a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
@@ -38,7 +38,7 @@ fn symmetric_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'t
 fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) {
     let typeck = cx.typeck_results();
     let (arg, arg_span) = match expr.kind {
-        ExprKind::MethodCall(.., [arg], _)
+        ExprKind::MethodCall(_, arg, [], _)
             if typeck
                 .type_dependent_def_id(expr.hir_id)
                 .and_then(|id| cx.tcx.trait_of_item(id))
diff --git a/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs
index 0d067d1e196..827a2b26709 100644
--- a/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs
@@ -17,7 +17,7 @@ pub(crate) fn check<'tcx>(
     right: &'tcx Expr<'_>,
 ) {
     if op == BinOpKind::Div
-        && let ExprKind::MethodCall(method_path, [self_arg], _) = left.kind
+        && let ExprKind::MethodCall(method_path, self_arg, [], _) = left.kind
         && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_arg).peel_refs(), sym::Duration)
         && let Some((Constant::Int(divisor), _)) = constant(cx, cx.typeck_results(), right)
     {
diff --git a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
index 0ef793443ff..97ddcdb2479 100644
--- a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
@@ -113,7 +113,7 @@ fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     }
 
     if_chain! {
-        if let ExprKind::MethodCall(method_name, [ref self_arg, ..], _) = expr.kind;
+        if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind;
         if sym!(signum) == method_name.ident.name;
         // Check that the receiver of the signum() is a float (expressions[0] is the receiver of
         // the method call)
diff --git a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
index 1805672e372..1085e608944 100644
--- a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
@@ -185,7 +185,7 @@ fn in_impl<'tcx>(
         if let ItemKind::Impl(item) = &item.kind;
         if let Some(of_trait) = &item.of_trait;
         if let Some(seg) = of_trait.path.segments.last();
-        if let Some(Res::Def(_, trait_id)) = seg.res;
+        if let Res::Def(_, trait_id) = seg.res;
         if trait_id == bin_op;
         if let Some(generic_args) = seg.args;
         if let Some(GenericArg::Type(other_ty)) = generic_args.args.last();
diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
index 9602d0d1d2e..0315678bf97 100644
--- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
@@ -130,7 +130,7 @@ fn try_get_option_occurence<'tcx>(
             .filter_map(|(id, &c)| none_captures.get(id).map(|&c2| (c, c2)))
             .all(|(x, y)| x.is_imm_ref() && y.is_imm_ref());
         then {
-            let capture_mut = if bind_annotation == BindingAnnotation::Mutable { "mut " } else { "" };
+            let capture_mut = if bind_annotation == BindingAnnotation::MUT { "mut " } else { "" };
             let some_body = peel_blocks(if_then);
             let none_body = peel_blocks(if_else);
             let method_sugg = if eager_or_lazy::switch_to_eager_eval(cx, none_body) { "map_or" } else { "map_or_else" };
@@ -138,7 +138,7 @@ fn try_get_option_occurence<'tcx>(
             let (as_ref, as_mut) = match &expr.kind {
                 ExprKind::AddrOf(_, Mutability::Not, _) => (true, false),
                 ExprKind::AddrOf(_, Mutability::Mut, _) => (false, true),
-                _ => (bind_annotation == BindingAnnotation::Ref, bind_annotation == BindingAnnotation::RefMut),
+                _ => (bind_annotation == BindingAnnotation::REF, bind_annotation == BindingAnnotation::REF_MUT),
             };
 
             // Check if captures the closure will need conflict with borrows made in the scrutinee.
diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
index 5fa4fd74853..0960b050c24 100644
--- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
@@ -221,7 +221,7 @@ impl<'tcx> PassByRefOrValue {
                     // if function has a body and parameter is annotated with mut, ignore
                     if let Some(param) = fn_body.and_then(|body| body.params.get(index)) {
                         match param.pat.kind {
-                            PatKind::Binding(BindingAnnotation::Unannotated, _, _, _) => {},
+                            PatKind::Binding(BindingAnnotation::NONE, _, _, _) => {},
                             _ => continue,
                         }
                     }
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 3c5ea2d9414..0028e0bc6c5 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -571,7 +571,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
                 Some((Node::Stmt(_), _)) => (),
                 Some((Node::Local(l), _)) => {
                     // Only trace simple bindings. e.g `let x = y;`
-                    if let PatKind::Binding(BindingAnnotation::Unannotated, id, _, None) = l.pat.kind {
+                    if let PatKind::Binding(BindingAnnotation::NONE, id, _, None) = l.pat.kind {
                         self.bindings.insert(id, args_idx);
                     } else {
                         set_skip_flag();
@@ -591,8 +591,11 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
                             set_skip_flag();
                         }
                     },
-                    ExprKind::MethodCall(name, expr_args @ [self_arg, ..], _) => {
-                        let i = expr_args.iter().position(|arg| arg.hir_id == child_id).unwrap_or(0);
+                    ExprKind::MethodCall(name, self_arg, expr_args, _) => {
+                        let i = std::iter::once(self_arg)
+                            .chain(expr_args.iter())
+                            .position(|arg| arg.hir_id == child_id)
+                            .unwrap_or(0);
                         if i == 0 {
                             // Check if the method can be renamed.
                             let name = name.ident.as_str();
@@ -644,7 +647,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
             .filter_map(|(i, arg)| {
                 let param = &body.params[arg.idx];
                 match param.pat.kind {
-                    PatKind::Binding(BindingAnnotation::Unannotated, id, _, None)
+                    PatKind::Binding(BindingAnnotation::NONE, id, _, None)
                         if !is_lint_allowed(cx, PTR_ARG, param.hir_id) =>
                     {
                         Some((id, i))
diff --git a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
index b907f38afbb..4dc65da3ea1 100644
--- a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
@@ -93,7 +93,7 @@ fn expr_as_ptr_offset_call<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'_>,
 ) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Method)> {
-    if let ExprKind::MethodCall(path_segment, [arg_0, arg_1, ..], _) = &expr.kind {
+    if let ExprKind::MethodCall(path_segment, arg_0, [arg_1, ..], _) = &expr.kind {
         if is_expr_ty_raw_ptr(cx, arg_0) {
             if path_segment.ident.name == sym::offset {
                 return Some((arg_0, arg_1, Method::Offset));
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index b432ccb1ee3..569870ab2b7 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -9,7 +9,7 @@ use clippy_utils::{
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
-use rustc_hir::{BindingAnnotation, Expr, ExprKind, Node, PatKind, PathSegment, QPath};
+use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, Node, PatKind, PathSegment, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::Ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -86,7 +86,7 @@ fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Ex
     if_chain! {
         if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr);
         if !is_else_clause(cx.tcx, expr);
-        if let ExprKind::MethodCall(segment, [caller, ..], _) = &cond.kind;
+        if let ExprKind::MethodCall(segment, caller, ..) = &cond.kind;
         let caller_ty = cx.typeck_results().expr_ty(caller);
         let if_block = IfBlockType::IfIs(caller, caller_ty, segment.ident.name, then, r#else);
         if is_early_return(sym::Option, cx, &if_block) || is_early_return(sym::Result, cx, &if_block);
@@ -122,8 +122,9 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr:
     if_chain! {
         if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else }) = higher::IfLet::hir(cx, expr);
         if !is_else_clause(cx.tcx, expr);
-        if let PatKind::TupleStruct(ref path1, [field], None) = let_pat.kind;
-        if let PatKind::Binding(annot, bind_id, ident, None) = field.kind;
+        if let PatKind::TupleStruct(ref path1, [field], ddpos) = let_pat.kind;
+        if ddpos.as_opt_usize().is_none();
+        if let PatKind::Binding(BindingAnnotation(by_ref, _), bind_id, ident, None) = field.kind;
         let caller_ty = cx.typeck_results().expr_ty(let_expr);
         let if_block = IfBlockType::IfLet(path1, caller_ty, ident.name, let_expr, if_then, if_else);
         if (is_early_return(sym::Option, cx, &if_block) && path_to_local_id(peel_blocks(if_then), bind_id))
@@ -132,12 +133,11 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr:
         then {
             let mut applicability = Applicability::MachineApplicable;
             let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability);
-            let by_ref = matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut);
             let requires_semi = matches!(get_parent_node(cx.tcx, expr.hir_id), Some(Node::Stmt(_)));
             let sugg = format!(
                 "{}{}?{}",
                 receiver_str,
-                if by_ref { ".as_ref()" } else { "" },
+                if by_ref == ByRef::Yes { ".as_ref()" } else { "" },
                 if requires_semi { ";" } else { "" }
             );
             span_lint_and_sugg(
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 9538a810473..94dec191103 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
@@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec {
                 // finds use of `_.read(&mut v)`
                 let mut read_found = false;
                 let mut visitor = expr_visitor_no_bodies(|expr| {
-                    if let ExprKind::MethodCall(path, [_self, arg], _) = expr.kind
+                    if let ExprKind::MethodCall(path, _self, [arg], _) = expr.kind
                         && let PathSegment { ident: read_or_read_exact, .. } = *path
                         && matches!(read_or_read_exact.as_str(), "read" | "read_exact")
                         && let ExprKind::AddrOf(_, hir::Mutability::Mut, inner) = arg.kind
diff --git a/src/tools/clippy/clippy_lints/src/ref_option_ref.rs b/src/tools/clippy/clippy_lints/src/ref_option_ref.rs
index 909d6971a54..42514f861be 100644
--- a/src/tools/clippy/clippy_lints/src/ref_option_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/ref_option_ref.rs
@@ -43,8 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for RefOptionRef {
             if mut_ty.mutbl == Mutability::Not;
             if let TyKind::Path(ref qpath) = &mut_ty.ty.kind;
             let last = last_path_segment(qpath);
-            if let Some(res) = last.res;
-            if let Some(def_id) = res.opt_def_id();
+            if let Some(def_id) = last.res.opt_def_id();
 
             if cx.tcx.is_diagnostic_item(sym::Option, def_id);
             if let Some(params) = last_path_segment(qpath).args ;
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 bfb9f0d01e1..ac4e29e9dfd 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
@@ -108,7 +108,7 @@ fn get_pointee_ty_and_count_expr<'tcx>(
     };
     if_chain! {
         // Find calls to copy_{from,to}{,_nonoverlapping} and write_bytes methods
-        if let ExprKind::MethodCall(method_path, [ptr_self, .., count], _) = expr.kind;
+        if let ExprKind::MethodCall(method_path, ptr_self, [.., count], _) = expr.kind;
         let method_ident = method_path.ident.as_str();
         if METHODS.iter().any(|m| *m == method_ident);
 
diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
index b59a25e3a40..c07aa00a127 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -99,7 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit {
         // Matches statements which initializes vectors. For example: `let mut vec = Vec::with_capacity(10)`
         if_chain! {
             if let StmtKind::Local(local) = stmt.kind;
-            if let PatKind::Binding(BindingAnnotation::Mutable, local_id, _, None) = local.pat.kind;
+            if let PatKind::Binding(BindingAnnotation::MUT, local_id, _, None) = local.pat.kind;
             if let Some(init) = local.init;
             if let Some(len_arg) = Self::is_vec_with_capacity(cx, init);
 
@@ -201,7 +201,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
     fn search_slow_extend_filling(&mut self, expr: &'tcx Expr<'_>) {
         if_chain! {
             if self.initialization_found;
-            if let ExprKind::MethodCall(path, [self_arg, extend_arg], _) = expr.kind;
+            if let ExprKind::MethodCall(path, self_arg, [extend_arg], _) = expr.kind;
             if path_to_local_id(self_arg, self.vec_alloc.local_id);
             if path.ident.name == sym!(extend);
             if self.is_repeat_take(extend_arg);
@@ -215,7 +215,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
     /// Checks if the given expression is resizing a vector with 0
     fn search_slow_resize_filling(&mut self, expr: &'tcx Expr<'_>) {
         if self.initialization_found
-            && let ExprKind::MethodCall(path, [self_arg, len_arg, fill_arg], _) = expr.kind
+            && let ExprKind::MethodCall(path, self_arg, [len_arg, fill_arg], _) = expr.kind
             && path_to_local_id(self_arg, self.vec_alloc.local_id)
             && path.ident.name == sym!(resize)
             // Check that is filled with 0
@@ -224,7 +224,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
                 // Check that len expression is equals to `with_capacity` expression
                 if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) {
                     self.slow_expression = Some(InitializationType::Resize(expr));
-                } else if let ExprKind::MethodCall(path, _, _) = len_arg.kind && path.ident.as_str() == "capacity" {
+                } else if let ExprKind::MethodCall(path, ..) = len_arg.kind && path.ident.as_str() == "capacity" {
                     self.slow_expression = Some(InitializationType::Resize(expr));
                 }
             }
@@ -233,7 +233,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
     /// Returns `true` if give expression is `repeat(0).take(...)`
     fn is_repeat_take(&self, expr: &Expr<'_>) -> bool {
         if_chain! {
-            if let ExprKind::MethodCall(take_path, [recv, len_arg, ..], _) = expr.kind;
+            if let ExprKind::MethodCall(take_path, recv, [len_arg, ..], _) = expr.kind;
             if take_path.ident.name == sym!(take);
             // Check that take is applied to `repeat(0)`
             if self.is_repeat_zero(recv);
@@ -241,7 +241,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
                 // Check that len expression is equals to `with_capacity` expression
                 if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) {
                     return true;
-                } else if let ExprKind::MethodCall(path, _, _) = len_arg.kind && path.ident.as_str() == "capacity" {
+                } else if let ExprKind::MethodCall(path, ..) = len_arg.kind && path.ident.as_str() == "capacity" {
                     return true;
                 }
             }
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index 22eb06b3646..662d399ca53 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -262,7 +262,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
             let (method_names, expressions, _) = method_calls(left, 1);
             if method_names.len() == 1;
             if expressions.len() == 1;
-            if expressions[0].len() == 1;
+            if expressions[0].1.is_empty();
             if method_names[0] == sym!(as_bytes);
 
             // Check for slicer
@@ -270,7 +270,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
 
             then {
                 let mut applicability = Applicability::MachineApplicable;
-                let string_expression = &expressions[0][0];
+                let string_expression = &expressions[0].0;
 
                 let snippet_app = snippet_with_applicability(
                     cx,
@@ -291,12 +291,12 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
         }
 
         if_chain! {
-            if let ExprKind::MethodCall(path, args, _) = &e.kind;
+            if let ExprKind::MethodCall(path, receiver, ..) = &e.kind;
             if path.ident.name == sym!(as_bytes);
-            if let ExprKind::Lit(lit) = &args[0].kind;
+            if let ExprKind::Lit(lit) = &receiver.kind;
             if let LitKind::Str(lit_content, _) = &lit.node;
             then {
-                let callsite = snippet(cx, args[0].span.source_callsite(), r#""foo""#);
+                let callsite = snippet(cx, receiver.span.source_callsite(), r#""foo""#);
                 let mut applicability = Applicability::MachineApplicable;
                 if callsite.starts_with("include_str!") {
                     span_lint_and_sugg(
@@ -305,7 +305,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
                         e.span,
                         "calling `as_bytes()` on `include_str!(..)`",
                         "consider using `include_bytes!(..)` instead",
-                        snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability).replacen(
+                        snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability).replacen(
                             "include_str",
                             "include_bytes",
                             1,
@@ -314,7 +314,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
                     );
                 } else if lit_content.as_str().is_ascii()
                     && lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT
-                    && !args[0].span.from_expansion()
+                    && !receiver.span.from_expansion()
                 {
                     span_lint_and_sugg(
                         cx,
@@ -324,7 +324,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
                         "consider using a byte string literal instead",
                         format!(
                             "b{}",
-                            snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability)
+                            snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability)
                         ),
                         applicability,
                     );
@@ -333,9 +333,9 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
         }
 
         if_chain! {
-            if let ExprKind::MethodCall(path, [recv], _) = &e.kind;
+            if let ExprKind::MethodCall(path, recv, [], _) = &e.kind;
             if path.ident.name == sym!(into_bytes);
-            if let ExprKind::MethodCall(path, [recv], _) = &recv.kind;
+            if let ExprKind::MethodCall(path, recv, [], _) = &recv.kind;
             if matches!(path.ident.name.as_str(), "to_owned" | "to_string");
             if let ExprKind::Lit(lit) = &recv.kind;
             if let LitKind::Str(lit_content, _) = &lit.node;
@@ -393,7 +393,7 @@ declare_lint_pass!(StrToString => [STR_TO_STRING]);
 impl<'tcx> LateLintPass<'tcx> for StrToString {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
         if_chain! {
-            if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind;
+            if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind;
             if path.ident.name == sym::to_string;
             let ty = cx.typeck_results().expr_ty(self_arg);
             if let ty::Ref(_, ty, ..) = ty.kind();
@@ -443,7 +443,7 @@ declare_lint_pass!(StringToString => [STRING_TO_STRING]);
 impl<'tcx> LateLintPass<'tcx> for StringToString {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
         if_chain! {
-            if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind;
+            if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind;
             if path.ident.name == sym::to_string;
             let ty = cx.typeck_results().expr_ty(self_arg);
             if is_type_diagnostic_item(cx, ty, sym::String);
@@ -487,11 +487,11 @@ impl<'tcx> LateLintPass<'tcx> for TrimSplitWhitespace {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
         let tyckres = cx.typeck_results();
         if_chain! {
-            if let ExprKind::MethodCall(path, [split_recv], split_ws_span) = expr.kind;
+            if let ExprKind::MethodCall(path, split_recv, [], split_ws_span) = expr.kind;
             if path.ident.name == sym!(split_whitespace);
             if let Some(split_ws_def_id) = tyckres.type_dependent_def_id(expr.hir_id);
             if cx.tcx.is_diagnostic_item(sym::str_split_whitespace, split_ws_def_id);
-            if let ExprKind::MethodCall(path, [_trim_recv], trim_span) = split_recv.kind;
+            if let ExprKind::MethodCall(path, _trim_recv, [], trim_span) = split_recv.kind;
             if let trim_fn_name @ ("trim" | "trim_start" | "trim_end") = path.ident.name.as_str();
             if let Some(trim_def_id) = tyckres.type_dependent_def_id(split_recv.hir_id);
             if is_one_of_trim_diagnostic_items(cx, trim_def_id);
diff --git a/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs b/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
index 7bc9cf742e6..78403d9fdb7 100644
--- a/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
@@ -47,7 +47,7 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings {
             if let ExprKind::Path(path) = &func.kind;
             if let Some(did) = cx.qpath_res(path, func.hir_id).opt_def_id();
             if match_libc_symbol(cx, did, "strlen");
-            if let ExprKind::MethodCall(path, [self_arg], _) = recv.kind;
+            if let ExprKind::MethodCall(path, self_arg, [], _) = recv.kind;
             if !recv.span.from_expansion();
             if path.ident.name == sym::as_ptr;
             then {
diff --git a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
index aa6c01b3a7c..651201f34ed 100644
--- a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
+++ b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
@@ -39,19 +39,17 @@ declare_lint_pass!(ToDigitIsSome => [TO_DIGIT_IS_SOME]);
 impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         if_chain! {
-            if let hir::ExprKind::MethodCall(is_some_path, is_some_args, _) = &expr.kind;
+            if let hir::ExprKind::MethodCall(is_some_path, to_digit_expr, [], _) = &expr.kind;
             if is_some_path.ident.name.as_str() == "is_some";
-            if let [to_digit_expr] = &**is_some_args;
             then {
                 let match_result = match &to_digit_expr.kind {
-                    hir::ExprKind::MethodCall(to_digits_path, to_digit_args, _) => {
+                    hir::ExprKind::MethodCall(to_digits_path, char_arg, [radix_arg], _) => {
                         if_chain! {
-                            if let [char_arg, radix_arg] = &**to_digit_args;
                             if to_digits_path.ident.name.as_str() == "to_digit";
                             let char_arg_ty = cx.typeck_results().expr_ty_adjusted(char_arg);
                             if *char_arg_ty.kind() == ty::Char;
                             then {
-                                Some((true, char_arg, radix_arg))
+                                Some((true, *char_arg, radix_arg))
                             } else {
                                 None
                             }
@@ -59,7 +57,7 @@ impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome {
                     }
                     hir::ExprKind::Call(to_digits_call, to_digit_args) => {
                         if_chain! {
-                            if let [char_arg, radix_arg] = &**to_digit_args;
+                            if let [char_arg, radix_arg] = *to_digit_args;
                             if let hir::ExprKind::Path(to_digits_path) = &to_digits_call.kind;
                             if let to_digits_call_res = cx.qpath_res(to_digits_path, to_digits_call.hir_id);
                             if let Some(to_digits_def_id) = to_digits_call_res.opt_def_id();
diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
index 2ffa022b04f..a25be93b8d6 100644
--- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs
+++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
@@ -128,7 +128,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
                 if !bound_predicate.span.from_expansion();
                 if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind;
                 if let Some(PathSegment {
-                    res: Some(Res::SelfTy{ trait_: Some(def_id), alias_to: _ }), ..
+                    res: Res::SelfTy{ trait_: Some(def_id), alias_to: _ }, ..
                 }) = segments.first();
                 if let Some(
                     Node::Item(
diff --git a/src/tools/clippy/clippy_lints/src/uninit_vec.rs b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
index 9a41603f2f4..3f99bd3f315 100644
--- a/src/tools/clippy/clippy_lints/src/uninit_vec.rs
+++ b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
@@ -177,7 +177,7 @@ fn extract_init_or_reserve_target<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt
                     });
                 }
             },
-            ExprKind::MethodCall(path, [self_expr, _], _) if is_reserve(cx, path, self_expr) => {
+            ExprKind::MethodCall(path, self_expr, [_], _) if is_reserve(cx, path, self_expr) => {
                 return Some(TargetVec {
                     location: VecLocation::Expr(self_expr),
                     init_kind: None,
@@ -211,7 +211,7 @@ fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Opt
         }
     });
     match expr.kind {
-        ExprKind::MethodCall(path, [self_expr, _], _) => {
+        ExprKind::MethodCall(path, self_expr, [_], _) => {
             let self_type = cx.typeck_results().expr_ty(self_expr).peel_refs();
             if is_type_diagnostic_item(cx, self_type, sym::Vec) && path.ident.name.as_str() == "set_len" {
                 Some((self_expr, expr.span))
diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
index b0fce91abeb..851eef7b332 100644
--- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
@@ -144,8 +144,9 @@ fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Spa
 
 impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if let ExprKind::MethodCall(_, args, _) = expr.kind {
+        if let ExprKind::MethodCall(_, receiver, args, _) = expr.kind {
             let arg_indices = get_args_to_check(cx, expr);
+            let args = std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>();
             for (i, trait_name) in arg_indices {
                 if i < args.len() {
                     match check_arg(cx, &args[i]) {
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 aec028d5c48..ce9ebad8c89 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
@@ -19,10 +19,12 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
         && cx.typeck_results().pat_ty(local.pat).is_unit()
     {
         if (local.ty.map_or(false, |ty| !matches!(ty.kind, TyKind::Infer))
-            || matches!(local.pat.kind, PatKind::Tuple([], None)))
+            || matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none()))
             && expr_needs_inferred_result(cx, init)
         {
-            if !matches!(local.pat.kind, PatKind::Wild | PatKind::Tuple([], None)) {
+            if !matches!(local.pat.kind, PatKind::Wild)
+               && !matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none())
+            {
                 span_lint_and_then(
                     cx,
                     LET_UNIT_VALUE,
@@ -128,7 +130,7 @@ fn needs_inferred_result_ty(
     locals_to_check: &mut Vec<HirId>,
     seen_locals: &mut HirIdSet,
 ) -> bool {
-    let (id, args) = match e.kind {
+    let (id, receiver, args) = match e.kind {
         ExprKind::Call(
             Expr {
                 kind: ExprKind::Path(ref path),
@@ -137,11 +139,11 @@ fn needs_inferred_result_ty(
             },
             args,
         ) => match cx.qpath_res(path, *hir_id) {
-            Res::Def(DefKind::AssocFn | DefKind::Fn, id) => (id, args),
+            Res::Def(DefKind::AssocFn | DefKind::Fn, id) => (id, None, args),
             _ => return false,
         },
-        ExprKind::MethodCall(_, args, _) => match cx.typeck_results().type_dependent_def_id(e.hir_id) {
-            Some(id) => (id, args),
+        ExprKind::MethodCall(_, receiver, args, _) => match cx.typeck_results().type_dependent_def_id(e.hir_id) {
+            Some(id) => (id, Some(receiver), args),
             None => return false,
         },
         ExprKind::Path(QPath::Resolved(None, path)) => {
@@ -156,6 +158,11 @@ fn needs_inferred_result_ty(
     };
     let sig = cx.tcx.fn_sig(id).skip_binder();
     if let ty::Param(output_ty) = *sig.output().kind() {
+        let args: Vec<&Expr<'_>> = if let Some(receiver) = receiver {
+            std::iter::once(receiver).chain(args.iter()).collect()
+        } else {
+            args.iter().collect()
+        };
         sig.inputs().iter().zip(args).all(|(&ty, arg)| {
             !ty.is_param(output_ty.index) || each_value_source_needs_inference(cx, arg, locals_to_check, seen_locals)
         })
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
index 16da2f11b81..7ffb53dcf45 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
@@ -30,26 +30,27 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         }
     }
 
-    match expr.kind {
-        ExprKind::Call(_, args) | ExprKind::MethodCall(_, args, _) => {
-            let args_to_recover = args
-                .iter()
-                .filter(|arg| {
-                    if cx.typeck_results().expr_ty(arg).is_unit() && !utils::is_unit_literal(arg) {
-                        !matches!(
-                            &arg.kind,
-                            ExprKind::Match(.., MatchSource::TryDesugar) | ExprKind::Path(..)
-                        )
-                    } else {
-                        false
-                    }
-                })
-                .collect::<Vec<_>>();
-            if !args_to_recover.is_empty() && !is_from_proc_macro(cx, expr) {
-                lint_unit_args(cx, expr, &args_to_recover);
+    let args: Vec<_> = match expr.kind {
+        ExprKind::Call(_, args) => args.iter().collect(),
+        ExprKind::MethodCall(_, receiver, args, _) => std::iter::once(receiver).chain(args.iter()).collect(),
+        _ => return,
+    };
+
+    let args_to_recover = args
+        .into_iter()
+        .filter(|arg| {
+            if cx.typeck_results().expr_ty(arg).is_unit() && !utils::is_unit_literal(arg) {
+                !matches!(
+                    &arg.kind,
+                    ExprKind::Match(.., MatchSource::TryDesugar) | ExprKind::Path(..)
+                )
+            } else {
+                false
             }
-        },
-        _ => (),
+        })
+        .collect::<Vec<_>>();
+    if !args_to_recover.is_empty() && !is_from_proc_macro(cx, expr) {
+        lint_unit_args(cx, expr, &args_to_recover.as_slice());
     }
 }
 
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 04e2f301bfd..fb73c386640 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -137,12 +137,12 @@ fn insert_necessary_parens(pat: &mut P<Pat>) {
     struct Visitor;
     impl MutVisitor for Visitor {
         fn visit_pat(&mut self, pat: &mut P<Pat>) {
-            use ast::{BindingMode::*, Mutability::*};
+            use ast::BindingAnnotation;
             noop_visit_pat(pat, self);
             let target = match &mut pat.kind {
                 // `i @ a | b`, `box a | b`, and `& mut? a | b`.
                 Ident(.., Some(p)) | Box(p) | Ref(p, _) if matches!(&p.kind, Or(ps) if ps.len() > 1) => p,
-                Ref(p, Not) if matches!(p.kind, Ident(ByValue(Mut), ..)) => p, // `&(mut x)`
+                Ref(p, Mutability::Not) if matches!(p.kind, Ident(BindingAnnotation::MUT, ..)) => p, // `&(mut x)`
                 _ => return,
             };
             target.kind = Paren(P(take_pat(target)));
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 323cf83ffcf..b38d71784fc 100644
--- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
@@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount {
                     check_map_error(cx, res, expr);
                 }
             },
-            hir::ExprKind::MethodCall(path, [ref arg_0, ..], _) => match path.ident.as_str() {
+            hir::ExprKind::MethodCall(path, arg_0, ..) => match path.ident.as_str() {
                 "expect" | "unwrap" | "unwrap_or" | "unwrap_or_else" => {
                     check_map_error(cx, arg_0, expr);
                 },
@@ -94,9 +94,9 @@ fn try_remove_await<'a>(expr: &'a hir::Expr<'a>) -> Option<&hir::Expr<'a>> {
 
 fn check_map_error(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) {
     let mut call = call;
-    while let hir::ExprKind::MethodCall(path, args, _) = call.kind {
+    while let hir::ExprKind::MethodCall(path, receiver, ..) = call.kind {
         if matches!(path.ident.as_str(), "or" | "or_else" | "ok") {
-            call = &args[0];
+            call = receiver;
         } else {
             break;
         }
@@ -110,7 +110,7 @@ fn check_map_error(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<
 }
 
 fn check_method_call(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>, is_await: bool) {
-    if let hir::ExprKind::MethodCall(path, _, _) = call.kind {
+    if let hir::ExprKind::MethodCall(path, ..) = call.kind {
         let symbol = path.ident.as_str();
         let read_trait = if is_await {
             match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCREADEXT)
diff --git a/src/tools/clippy/clippy_lints/src/unused_peekable.rs b/src/tools/clippy/clippy_lints/src/unused_peekable.rs
index ac73173697e..cfc181e435b 100644
--- a/src/tools/clippy/clippy_lints/src/unused_peekable.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_peekable.rs
@@ -149,7 +149,8 @@ impl<'tcx> Visitor<'_> for PeekableVisitor<'_, 'tcx> {
                                     ident: method_name_ident,
                                     ..
                                 },
-                                [self_arg, remaining_args @ ..],
+                                self_arg,
+                                remaining_args,
                                 _,
                             ) => {
                                 let method_name = method_name_ident.name.as_str();
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index d3f9e5abfd7..9092156be15 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -154,13 +154,13 @@ fn collect_unwrap_info<'tcx>(
         return collect_unwrap_info(cx, if_expr, expr, branch, !invert, false);
     } else {
         if_chain! {
-            if let ExprKind::MethodCall(method_name, args, _) = &expr.kind;
-            if let Some(local_id) = path_to_local(&args[0]);
-            let ty = cx.typeck_results().expr_ty(&args[0]);
+            if let ExprKind::MethodCall(method_name, receiver, args, _) = &expr.kind;
+            if let Some(local_id) = path_to_local(receiver);
+            let ty = cx.typeck_results().expr_ty(receiver);
             let name = method_name.ident.as_str();
             if is_relevant_option_call(cx, ty, name) || is_relevant_result_call(cx, ty, name);
             then {
-                assert!(args.len() == 1);
+                assert!(args.len() == 0);
                 let unwrappable = match name {
                     "is_some" | "is_ok" => true,
                     "is_err" | "is_none" => false,
@@ -231,7 +231,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> {
         } else {
             // find `unwrap[_err]()` calls:
             if_chain! {
-                if let ExprKind::MethodCall(method_name, [self_arg, ..], _) = expr.kind;
+                if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind;
                 if let Some(id) = path_to_local(self_arg);
                 if [sym::unwrap, sym::expect, sym!(unwrap_err)].contains(&method_name.ident.name);
                 let call_to_unwrap = [sym::unwrap, sym::expect].contains(&method_name.ident.name);
diff --git a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
index b32be238cd5..b3ca15f7648 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
@@ -83,7 +83,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         // check for `expect`
         if let Some(arglists) = method_chain_args(expr, &["expect"]) {
-            let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
+            let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs();
             if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option)
                 || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result)
             {
@@ -93,7 +93,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> {
 
         // check for `unwrap`
         if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
-            let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
+            let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs();
             if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option)
                 || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result)
             {
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index b6738e2891d..f1b6463ad0f 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                 }
             },
 
-            ExprKind::MethodCall(name, .., [recv, ..], _) => {
+            ExprKind::MethodCall(name, recv, ..) => {
                 if is_trait_method(cx, e, sym::Into) && name.ident.as_str() == "into" {
                     let a = cx.typeck_results().expr_ty(e);
                     let b = cx.typeck_results().expr_ty(recv);
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 3ffcaa90af3..1489c96d9e9 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -6,7 +6,9 @@ use rustc_ast::ast::{LitFloatType, LitKind};
 use rustc_ast::LitIntType;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
-use rustc_hir::{ArrayLen, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind};
+use rustc_hir::{
+    ArrayLen, BindingAnnotation, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind,
+};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::{Ident, Symbol};
@@ -402,10 +404,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                 self.expr(func);
                 self.slice(args, |e| self.expr(e));
             },
-            ExprKind::MethodCall(method_name, args, _) => {
-                bind!(self, method_name, args);
-                kind!("MethodCall({method_name}, {args}, _)");
+            ExprKind::MethodCall(method_name, receiver, args, _) => {
+                bind!(self, method_name, receiver, args);
+                kind!("MethodCall({method_name}, {receiver}, {args}, _)");
                 self.ident(field!(method_name.ident));
+                self.expr(receiver);
                 self.slice(args, |e| self.expr(e));
             },
             ExprKind::Tup(elements) => {
@@ -609,10 +612,16 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
 
         match pat.value.kind {
             PatKind::Wild => kind!("Wild"),
-            PatKind::Binding(anno, .., name, sub) => {
+            PatKind::Binding(ann, _, name, sub) => {
                 bind!(self, name);
                 opt_bind!(self, sub);
-                kind!("Binding(BindingAnnotation::{anno:?}, _, {name}, {sub})");
+                let ann = match ann {
+                    BindingAnnotation::NONE => "NONE",
+                    BindingAnnotation::REF => "REF",
+                    BindingAnnotation::MUT => "MUT",
+                    BindingAnnotation::REF_MUT => "REF_MUT",
+                };
+                kind!("Binding(BindingAnnotation::{ann}, _, {name}, {sub})");
                 self.ident(name);
                 sub.if_some(|p| self.pat(p));
             },
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
index eb34085a2ab..ae1c11ef83c 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
@@ -687,7 +687,7 @@ impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass {
             if let ["expn_data", "outer_expn"] = method_names.as_slice();
             let args = arg_lists[1];
             if args.len() == 1;
-            let self_arg = &args[0];
+            let self_arg = &args.0;
             let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
             if match_type(cx, self_ty, &paths::SYNTAX_CONTEXT);
             then {
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 35db45e2b0c..8425837fd73 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
@@ -100,7 +100,7 @@ impl VecPushSearcher {
                         || get_parent_expr(cx, last_place)
                             .map_or(false, |e| matches!(e.kind, ExprKind::AddrOf(_, Mutability::Mut, _)));
                 },
-                ExprKind::MethodCall(_, [recv, ..], _)
+                ExprKind::MethodCall(_, recv, ..)
                     if recv.hir_id == e.hir_id
                         && adjusted_mut == Mutability::Mut
                         && !adjusted_ty.peel_refs().is_slice() =>
@@ -157,7 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush {
 
     fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
         if let Some(init_expr) = local.init
-            && let PatKind::Binding(BindingAnnotation::Mutable, id, name, None) = local.pat.kind
+            && let PatKind::Binding(BindingAnnotation::MUT, id, name, None) = local.pat.kind
             && !in_external_macro(cx.sess(), local.span)
             && let Some(init) = get_vec_init_kind(cx, init_expr)
             && !matches!(init, VecInitKind::WithExprCapacity(_))
@@ -201,7 +201,7 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush {
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         if let Some(searcher) = self.searcher.take() {
             if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind
-                && let ExprKind::MethodCall(name, [self_arg, _], _) = expr.kind
+                && let ExprKind::MethodCall(name, self_arg, [_], _) = expr.kind
                 && path_to_local_id(self_arg, searcher.local_id)
                 && name.ident.as_str() == "push"
             {
diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
index 8335ffae81e..e8d2d579f09 100644
--- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
+++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
@@ -118,9 +118,9 @@ fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) {
         ExprKind::Unary(UnOp::Neg, e) => (Pat::Str("-"), expr_search_pat(tcx, e).1),
         ExprKind::Lit(ref lit) => lit_search_pat(&lit.node),
         ExprKind::Array(_) | ExprKind::Repeat(..) => (Pat::Str("["), Pat::Str("]")),
-        ExprKind::Call(e, []) | ExprKind::MethodCall(_, [e], _) => (expr_search_pat(tcx, e).0, Pat::Str("(")),
+        ExprKind::Call(e, []) | ExprKind::MethodCall(_, e, [], _) => (expr_search_pat(tcx, e).0, Pat::Str("(")),
         ExprKind::Call(first, [.., last])
-        | ExprKind::MethodCall(_, [first, .., last], _)
+        | ExprKind::MethodCall(_, first, [.., last], _)
         | ExprKind::Binary(_, first, last)
         | ExprKind::Tup([first, .., last])
         | ExprKind::Assign(first, last, _)
diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs
index 7f55db3b31f..ad95369b9ef 100644
--- a/src/tools/clippy/clippy_utils/src/diagnostics.rs
+++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs
@@ -155,13 +155,7 @@ where
     });
 }
 
-pub fn span_lint_hir(
-    cx: &LateContext<'_>,
-    lint: &'static Lint,
-    hir_id: HirId,
-    sp: Span,
-    msg: &str,
-) {
+pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: &str) {
     cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |diag| {
         let mut diag = diag.build(msg);
         docs_link(&mut diag, lint);
diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
index 730724b95b9..124a00d8178 100644
--- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
+++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
@@ -45,12 +45,7 @@ impl ops::BitOrAssign for EagernessSuggestion {
 }
 
 /// Determine the eagerness of the given function call.
-fn fn_eagerness<'tcx>(
-    cx: &LateContext<'tcx>,
-    fn_id: DefId,
-    name: Symbol,
-    args: &'tcx [Expr<'_>],
-) -> EagernessSuggestion {
+fn fn_eagerness<'tcx>(cx: &LateContext<'tcx>, fn_id: DefId, name: Symbol, have_one_arg: bool) -> EagernessSuggestion {
     use EagernessSuggestion::{Eager, Lazy, NoChange};
     let name = name.as_str();
 
@@ -59,7 +54,7 @@ fn fn_eagerness<'tcx>(
         None => return Lazy,
     };
 
-    if (name.starts_with("as_") || name == "len" || name == "is_empty") && args.len() == 1 {
+    if (name.starts_with("as_") || name == "len" || name == "is_empty") && have_one_arg {
         if matches!(
             cx.tcx.crate_name(fn_id.krate),
             sym::std | sym::core | sym::alloc | sym::proc_macro
@@ -127,10 +122,11 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
                     },
                     Res::Def(_, id) => match path {
                         QPath::Resolved(_, p) => {
-                            self.eagerness |= fn_eagerness(self.cx, id, p.segments.last().unwrap().ident.name, args);
+                            self.eagerness |=
+                                fn_eagerness(self.cx, id, p.segments.last().unwrap().ident.name, !args.is_empty());
                         },
                         QPath::TypeRelative(_, name) => {
-                            self.eagerness |= fn_eagerness(self.cx, id, name.ident.name, args);
+                            self.eagerness |= fn_eagerness(self.cx, id, name.ident.name, !args.is_empty());
                         },
                         QPath::LangItem(..) => self.eagerness = Lazy,
                     },
@@ -141,12 +137,12 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
                     self.eagerness |= NoChange;
                     return;
                 },
-                ExprKind::MethodCall(name, args, _) => {
+                ExprKind::MethodCall(name, ..) => {
                     self.eagerness |= self
                         .cx
                         .typeck_results()
                         .type_dependent_def_id(e.hir_id)
-                        .map_or(Lazy, |id| fn_eagerness(self.cx, id, name.ident.name, args));
+                        .map_or(Lazy, |id| fn_eagerness(self.cx, id, name.ident.name, true));
                 },
                 ExprKind::Index(_, e) => {
                     let ty = self.cx.typeck_results().expr_ty_adjusted(e);
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 1834e2a2de8..ff23ed5fffa 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -6,9 +6,9 @@ use rustc_data_structures::fx::FxHasher;
 use rustc_hir::def::Res;
 use rustc_hir::HirIdMap;
 use rustc_hir::{
-    ArrayLen, BinOpKind, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard,
-    HirId, InlineAsmOperand, Let, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath,
-    Stmt, StmtKind, Ty, TyKind, TypeBinding,
+    ArrayLen, BinOpKind, BindingAnnotation, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, GenericArg,
+    GenericArgs, Guard, HirId, InlineAsmOperand, Let, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path,
+    PathSegment, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding,
 };
 use rustc_lexer::{tokenize, TokenKind};
 use rustc_lint::LateContext;
@@ -282,8 +282,14 @@ impl HirEqInterExpr<'_, '_, '_> {
                             && self.eq_expr(l.body, r.body)
                     })
             },
-            (&ExprKind::MethodCall(l_path, l_args, _), &ExprKind::MethodCall(r_path, r_args, _)) => {
-                self.inner.allow_side_effects && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args)
+            (
+                &ExprKind::MethodCall(l_path, l_receiver, l_args, _),
+                &ExprKind::MethodCall(r_path, r_receiver, r_args, _),
+            ) => {
+                self.inner.allow_side_effects
+                    && self.eq_path_segment(l_path, r_path)
+                    && self.eq_expr(l_receiver, r_receiver)
+                    && self.eq_exprs(l_args, r_args)
             },
             (&ExprKind::Repeat(le, ll), &ExprKind::Repeat(re, rl)) => {
                 self.eq_expr(le, re) && self.eq_array_length(ll, rl)
@@ -743,8 +749,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
 
                 s.hash(&mut self.s);
             },
-            ExprKind::MethodCall(path, args, ref _fn_span) => {
+            ExprKind::MethodCall(path, receiver, args, ref _fn_span) => {
                 self.hash_name(path.ident.name);
+                self.hash_expr(receiver);
                 self.hash_exprs(args);
             },
             ExprKind::ConstBlock(ref l_id) => {
@@ -815,8 +822,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
     pub fn hash_pat(&mut self, pat: &Pat<'_>) {
         std::mem::discriminant(&pat.kind).hash(&mut self.s);
         match pat.kind {
-            PatKind::Binding(ann, _, _, pat) => {
-                std::mem::discriminant(&ann).hash(&mut self.s);
+            PatKind::Binding(BindingAnnotation(by_ref, mutability), _, _, pat) => {
+                std::mem::discriminant(&by_ref).hash(&mut self.s);
+                std::mem::discriminant(&mutability).hash(&mut self.s);
                 if let Some(pat) = pat {
                     self.hash_pat(pat);
                 }
@@ -921,7 +929,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
         }
     }
 
-    pub fn hash_lifetime(&mut self, lifetime: Lifetime) {
+    pub fn hash_lifetime(&mut self, lifetime: &Lifetime) {
         std::mem::discriminant(&lifetime.name).hash(&mut self.s);
         if let LifetimeName::Param(param_id, ref name) = lifetime.name {
             std::mem::discriminant(name).hash(&mut self.s);
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index f3a08e98688..3cf043f22df 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -192,7 +192,7 @@ pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<
     let hir = cx.tcx.hir();
     if_chain! {
         if let Some(Node::Pat(pat)) = hir.find(hir_id);
-        if matches!(pat.kind, PatKind::Binding(BindingAnnotation::Unannotated, ..));
+        if matches!(pat.kind, PatKind::Binding(BindingAnnotation::NONE, ..));
         let parent = hir.get_parent_node(hir_id);
         if let Some(Node::Local(local)) = hir.find(parent);
         then {
@@ -1036,21 +1036,21 @@ pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'
 pub fn method_calls<'tcx>(
     expr: &'tcx Expr<'tcx>,
     max_depth: usize,
-) -> (Vec<Symbol>, Vec<&'tcx [Expr<'tcx>]>, Vec<Span>) {
+) -> (Vec<Symbol>, Vec<(&'tcx Expr<'tcx>, &'tcx [Expr<'tcx>])>, Vec<Span>) {
     let mut method_names = Vec::with_capacity(max_depth);
     let mut arg_lists = Vec::with_capacity(max_depth);
     let mut spans = Vec::with_capacity(max_depth);
 
     let mut current = expr;
     for _ in 0..max_depth {
-        if let ExprKind::MethodCall(path, args, _) = &current.kind {
-            if args.iter().any(|e| e.span.from_expansion()) {
+        if let ExprKind::MethodCall(path, receiver, args, _) = &current.kind {
+            if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) {
                 break;
             }
             method_names.push(path.ident.name);
-            arg_lists.push(&**args);
+            arg_lists.push((*receiver, &**args));
             spans.push(path.ident.span);
-            current = &args[0];
+            current = receiver;
         } else {
             break;
         }
@@ -1065,18 +1065,18 @@ pub fn method_calls<'tcx>(
 /// `method_chain_args(expr, &["bar", "baz"])` will return a `Vec`
 /// containing the `Expr`s for
 /// `.bar()` and `.baz()`
-pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec<&'a [Expr<'a>]>> {
+pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec<(&'a Expr<'a>, &'a [Expr<'a>])>> {
     let mut current = expr;
     let mut matched = Vec::with_capacity(methods.len());
     for method_name in methods.iter().rev() {
         // method chains are stored last -> first
-        if let ExprKind::MethodCall(path, args, _) = current.kind {
+        if let ExprKind::MethodCall(path, receiver, args, _) = current.kind {
             if path.ident.name.as_str() == *method_name {
-                if args.iter().any(|e| e.span.from_expansion()) {
+                if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) {
                     return None;
                 }
-                matched.push(args); // build up `matched` backwards
-                current = &args[0]; // go to parent expression
+                matched.push((receiver, args)); // build up `matched` backwards
+                current = receiver; // go to parent expression
             } else {
                 return None;
             }
@@ -1239,8 +1239,10 @@ pub fn get_enclosing_loop_or_multi_call_closure<'tcx>(
                                     ty_is_fn_once_param(cx.tcx, ty.skip_binder(), predicates).then_some(())
                                 })
                             },
-                            ExprKind::MethodCall(_, args, _) => {
-                                let i = args.iter().position(|arg| arg.hir_id == id)?;
+                            ExprKind::MethodCall(_, receiver, args, _) => {
+                                let i = std::iter::once(receiver)
+                                    .chain(args.iter())
+                                    .position(|arg| arg.hir_id == id)?;
                                 let id = cx.typeck_results().type_dependent_def_id(e.hir_id)?;
                                 let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i];
                                 ty_is_fn_once_param(cx.tcx, ty, cx.tcx.param_env(id).caller_bounds()).then_some(())
@@ -1550,7 +1552,8 @@ pub fn iter_input_pats<'tcx>(decl: &FnDecl<'_>, body: &'tcx Body<'_>) -> impl It
 pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
     fn is_ok(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
         if_chain! {
-            if let PatKind::TupleStruct(ref path, pat, None) = arm.pat.kind;
+            if let PatKind::TupleStruct(ref path, pat, ddpos) = arm.pat.kind;
+            if ddpos.as_opt_usize().is_none();
             if is_lang_ctor(cx, path, ResultOk);
             if let PatKind::Binding(_, hir_id, _, None) = pat[0].kind;
             if path_to_local_id(arm.body, hir_id);
diff --git a/src/tools/clippy/clippy_utils/src/ptr.rs b/src/tools/clippy/clippy_utils/src/ptr.rs
index 649b7b9940a..0226f74906b 100644
--- a/src/tools/clippy/clippy_utils/src/ptr.rs
+++ b/src/tools/clippy/clippy_utils/src/ptr.rs
@@ -36,7 +36,7 @@ fn extract_clone_suggestions<'tcx>(
         if abort {
             return false;
         }
-        if let ExprKind::MethodCall(seg, [recv], _) = expr.kind {
+        if let ExprKind::MethodCall(seg, recv, [], _) = expr.kind {
             if path_to_local_id(recv, id) {
                 if seg.ident.name.as_str() == "capacity" {
                     abort = true;
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 74c222bbcbe..b22a9c81746 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
@@ -7,7 +7,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::mir::{
     Body, CastKind, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind, Terminator,
-    TerminatorKind,
+    TerminatorKind, NonDivergingIntrinsic
 };
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt};
@@ -212,11 +212,18 @@ fn check_statement<'tcx>(
             check_place(tcx, **place, span, body)
         },
 
-        StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { dst, src, count }) => {
+        StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => {
+            check_operand(tcx, op, span, body)
+        },
+
+        StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(
+            rustc_middle::mir::CopyNonOverlapping { dst, src, count },
+        )) => {
             check_operand(tcx, dst, span, body)?;
             check_operand(tcx, src, span, body)?;
             check_operand(tcx, count, span, body)
         },
+
         // These are all NOPs
         StatementKind::StorageLive(_)
         | StatementKind::StorageDead(_)
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index 081c98e2f3c..cca71bbf76e 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -373,12 +373,14 @@ fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String {
         | AssocOp::LessEqual
         | AssocOp::NotEqual
         | AssocOp::Greater
-        | AssocOp::GreaterEqual => format!(
-            "{} {} {}",
-            lhs,
-            op.to_ast_binop().expect("Those are AST ops").to_string(),
-            rhs
-        ),
+        | AssocOp::GreaterEqual => {
+            format!(
+                "{} {} {}",
+                lhs,
+                op.to_ast_binop().expect("Those are AST ops").to_string(),
+                rhs
+            )
+        },
         AssocOp::Assign => format!("{} = {}", lhs, rhs),
         AssocOp::AssignOp(op) => {
             format!("{} {}= {}", lhs, token_kind_to_string(&token::BinOp(op)), rhs)
@@ -868,15 +870,15 @@ impl<'tcx> DerefDelegate<'_, 'tcx> {
     /// indicates whether the function from `parent_expr` takes its args by double reference
     fn func_takes_arg_by_double_ref(&self, parent_expr: &'tcx hir::Expr<'_>, cmt_hir_id: HirId) -> bool {
         let ty = match parent_expr.kind {
-            ExprKind::MethodCall(_, call_args, _) => {
+            ExprKind::MethodCall(_, receiver, call_args, _) => {
                 if let Some(sig) = self
                     .cx
                     .typeck_results()
                     .type_dependent_def_id(parent_expr.hir_id)
                     .map(|did| self.cx.tcx.fn_sig(did).skip_binder())
                 {
-                    call_args
-                        .iter()
+                    std::iter::once(receiver)
+                        .chain(call_args.iter())
                         .position(|arg| arg.hir_id == cmt_hir_id)
                         .map(|i| sig.inputs()[i])
                 } else {
@@ -933,14 +935,14 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
                     match &parent_expr.kind {
                         // given expression is the self argument and will be handled completely by the compiler
                         // i.e.: `|x| x.is_something()`
-                        ExprKind::MethodCall(_, [self_expr, ..], _) if self_expr.hir_id == cmt.hir_id => {
+                        ExprKind::MethodCall(_, self_expr, ..) if self_expr.hir_id == cmt.hir_id => {
                             let _ = write!(self.suggestion_start, "{}{}", start_snip, ident_str_with_proj);
                             self.next_pos = span.hi();
                             return;
                         },
                         // item is used in a call
                         // i.e.: `Call`: `|x| please(x)` or `MethodCall`: `|x| [1, 2, 3].contains(x)`
-                        ExprKind::Call(_, [call_args @ ..]) | ExprKind::MethodCall(_, [_, call_args @ ..], _) => {
+                        ExprKind::Call(_, [call_args @ ..]) | ExprKind::MethodCall(_, _, [call_args @ ..], _) => {
                             let expr = self.cx.tcx.hir().expect_expr(cmt.hir_id);
                             let arg_ty_kind = self.cx.typeck_results().expr_ty(expr).kind();
 
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index bae8ad9f565..6a62002a4d1 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -620,7 +620,13 @@ pub fn for_each_unconsumed_temporary<'tcx, B>(
                     helper(typeck, true, arg, f)?;
                 }
             },
-            ExprKind::MethodCall(_, args, _) | ExprKind::Tup(args) | ExprKind::Array(args) => {
+            ExprKind::MethodCall(_, receiver, args, _) => {
+                helper(typeck, true, receiver, f)?;
+                for arg in args {
+                    helper(typeck, true, arg, f)?;
+                }
+            },
+            ExprKind::Tup(args) | ExprKind::Array(args) => {
                 for arg in args {
                     helper(typeck, true, arg, f)?;
                 }
diff --git a/src/tools/clippy/tests/ui/author.stdout b/src/tools/clippy/tests/ui/author.stdout
index 3125863036b..597318a556b 100644
--- a/src/tools/clippy/tests/ui/author.stdout
+++ b/src/tools/clippy/tests/ui/author.stdout
@@ -6,7 +6,7 @@ if_chain! {
     if match_qpath(qpath, &["char"]);
     if let ExprKind::Lit(ref lit) = expr.kind;
     if let LitKind::Int(69, LitIntType::Unsuffixed) = lit.node;
-    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local.pat.kind;
+    if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind;
     if name.as_str() == "x";
     then {
         // report your lint here
diff --git a/src/tools/clippy/tests/ui/author/blocks.stdout b/src/tools/clippy/tests/ui/author/blocks.stdout
index 2fc4a7d1f7f..a529981e2e6 100644
--- a/src/tools/clippy/tests/ui/author/blocks.stdout
+++ b/src/tools/clippy/tests/ui/author/blocks.stdout
@@ -5,13 +5,13 @@ if_chain! {
     if let Some(init) = local.init;
     if let ExprKind::Lit(ref lit) = init.kind;
     if let LitKind::Int(42, LitIntType::Signed(IntTy::I32)) = lit.node;
-    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local.pat.kind;
+    if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind;
     if name.as_str() == "x";
     if let StmtKind::Local(local1) = block.stmts[1].kind;
     if let Some(init1) = local1.init;
     if let ExprKind::Lit(ref lit1) = init1.kind;
     if let LitKind::Float(_, LitFloatType::Suffixed(FloatTy::F32)) = lit1.node;
-    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local1.pat.kind;
+    if let PatKind::Binding(BindingAnnotation::NONE, _, name1, None) = local1.pat.kind;
     if name1.as_str() == "_t";
     if let StmtKind::Semi(e) = block.stmts[2].kind;
     if let ExprKind::Unary(UnOp::Neg, inner) = e.kind;
@@ -31,7 +31,7 @@ if_chain! {
     if let ExprKind::Path(ref qpath) = func.kind;
     if match_qpath(qpath, &["String", "new"]);
     if args.is_empty();
-    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local.pat.kind;
+    if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind;
     if name.as_str() == "expr";
     if let Some(trailing_expr) = block.expr;
     if let ExprKind::Call(func1, args1) = trailing_expr.kind;
diff --git a/src/tools/clippy/tests/ui/author/loop.stdout b/src/tools/clippy/tests/ui/author/loop.stdout
index 3d9560f697a..ceb53fcd496 100644
--- a/src/tools/clippy/tests/ui/author/loop.stdout
+++ b/src/tools/clippy/tests/ui/author/loop.stdout
@@ -1,6 +1,6 @@
 if_chain! {
     if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::ForLoop::hir(expr);
-    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = pat.kind;
+    if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = pat.kind;
     if name.as_str() == "y";
     if let ExprKind::Struct(qpath, fields, None) = arg.kind;
     if matches!(qpath, QPath::LangItem(LangItem::Range, _));
@@ -17,7 +17,7 @@ if_chain! {
     if let Some(init) = local.init;
     if let ExprKind::Path(ref qpath1) = init.kind;
     if match_qpath(qpath1, &["y"]);
-    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local.pat.kind;
+    if let PatKind::Binding(BindingAnnotation::NONE, _, name1, None) = local.pat.kind;
     if name1.as_str() == "z";
     if block.expr.is_none();
     then {
diff --git a/src/tools/clippy/tests/ui/author/matches.stdout b/src/tools/clippy/tests/ui/author/matches.stdout
index 38444a0094c..2cf69a035b4 100644
--- a/src/tools/clippy/tests/ui/author/matches.stdout
+++ b/src/tools/clippy/tests/ui/author/matches.stdout
@@ -21,7 +21,7 @@ if_chain! {
     if let Some(init1) = local1.init;
     if let ExprKind::Lit(ref lit4) = init1.kind;
     if let LitKind::Int(3, LitIntType::Unsuffixed) = lit4.node;
-    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local1.pat.kind;
+    if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local1.pat.kind;
     if name.as_str() == "x";
     if let Some(trailing_expr) = block.expr;
     if let ExprKind::Path(ref qpath) = trailing_expr.kind;
@@ -30,7 +30,7 @@ if_chain! {
     if arms[2].guard.is_none();
     if let ExprKind::Lit(ref lit5) = arms[2].body.kind;
     if let LitKind::Int(1, LitIntType::Unsuffixed) = lit5.node;
-    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local.pat.kind;
+    if let PatKind::Binding(BindingAnnotation::NONE, _, name1, None) = local.pat.kind;
     if name1.as_str() == "a";
     then {
         // report your lint here
diff --git a/src/tools/clippy/tests/ui/author/struct.stdout b/src/tools/clippy/tests/ui/author/struct.stdout
index 5e78b7c9de7..b5bbc9e213c 100644
--- a/src/tools/clippy/tests/ui/author/struct.stdout
+++ b/src/tools/clippy/tests/ui/author/struct.stdout
@@ -53,11 +53,11 @@ if_chain! {
     }
 }
 if_chain! {
-    if let ExprKind::MethodCall(method_name, args, _) = expr.kind;
+    if let ExprKind::MethodCall(method_name, receiver, args, _) = expr.kind;
     if method_name.ident.as_str() == "test";
-    if args.len() == 1;
-    if let ExprKind::Path(ref qpath) = args[0].kind;
+    if let ExprKind::Path(ref qpath) = receiver.kind;
     if match_qpath(qpath, &["test_method_call"]);
+    if args.is_empty();
     then {
         // report your lint here
     }
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 8f097f47b45..3ff1cbf20cd 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -897,15 +897,27 @@ pub fn make_test_description<R: Read>(
     let has_hwasan = util::HWASAN_SUPPORTED_TARGETS.contains(&&*config.target);
     let has_memtag = util::MEMTAG_SUPPORTED_TARGETS.contains(&&*config.target);
     let has_shadow_call_stack = util::SHADOWCALLSTACK_SUPPORTED_TARGETS.contains(&&*config.target);
-    // for `-Z gcc-ld=lld`
+
+    // For tests using the `needs-rust-lld` directive (e.g. for `-Zgcc-ld=lld`), we need to find
+    // whether `rust-lld` is present in the compiler under test.
+    //
+    // The --compile-lib-path is the path to host shared libraries, but depends on the OS. For
+    // example:
+    // - on linux, it can be <sysroot>/lib
+    // - on windows, it can be <sysroot>/bin
+    //
+    // However, `rust-lld` is only located under the lib path, so we look for it there.
     let has_rust_lld = config
         .compile_lib_path
+        .parent()
+        .expect("couldn't traverse to the parent of the specified --compile-lib-path")
+        .join("lib")
         .join("rustlib")
         .join(&config.target)
         .join("bin")
-        .join("gcc-ld")
-        .join(if config.host.contains("windows") { "ld.exe" } else { "ld" })
+        .join(if config.host.contains("windows") { "rust-lld.exe" } else { "rust-lld" })
         .exists();
+
     iter_header(path, src, &mut |revision, ln| {
         if revision.is_some() && revision != cfg {
             return;
diff --git a/src/tools/lld-wrapper/src/main.rs b/src/tools/lld-wrapper/src/main.rs
index 1795f3d7fe5..b5e977b2637 100644
--- a/src/tools/lld-wrapper/src/main.rs
+++ b/src/tools/lld-wrapper/src/main.rs
@@ -11,9 +11,10 @@
 //! obtained from the wrapper's name as the first two arguments.
 //! On Windows it spawns a `..\rust-lld.exe` child process.
 
+use std::env::{self, consts::EXE_SUFFIX};
 use std::fmt::Display;
 use std::path::{Path, PathBuf};
-use std::{env, process};
+use std::process;
 
 trait UnwrapOrExitWith<T> {
     fn unwrap_or_exit_with(self, context: &str) -> T;
@@ -42,7 +43,7 @@ impl<T, E: Display> UnwrapOrExitWith<T> for Result<T, E> {
 /// Exits if the parent directory cannot be determined.
 fn get_rust_lld_path(current_exe_path: &Path) -> PathBuf {
     let mut rust_lld_exe_name = "rust-lld".to_owned();
-    rust_lld_exe_name.push_str(env::consts::EXE_SUFFIX);
+    rust_lld_exe_name.push_str(EXE_SUFFIX);
     let mut rust_lld_path = current_exe_path
         .parent()
         .unwrap_or_exit_with("directory containing current executable could not be determined")
@@ -55,13 +56,14 @@ fn get_rust_lld_path(current_exe_path: &Path) -> PathBuf {
 
 /// Extract LLD flavor name from the lld-wrapper executable name.
 fn get_lld_flavor(current_exe_path: &Path) -> Result<&'static str, String> {
-    let stem = current_exe_path.file_stem();
-    Ok(match stem.and_then(|s| s.to_str()) {
+    let file = current_exe_path.file_name();
+    let stem = file.and_then(|s| s.to_str()).map(|s| s.trim_end_matches(EXE_SUFFIX));
+    Ok(match stem {
         Some("ld.lld") => "gnu",
         Some("ld64.lld") => "darwin",
         Some("lld-link") => "link",
         Some("wasm-ld") => "wasm",
-        _ => return Err(format!("{:?}", stem)),
+        _ => return Err(format!("{:?}", file)),
     })
 }
 
diff --git a/src/tools/miri b/src/tools/miri
-Subproject dba35d2be72f4b78343d1a0f0b4737306f31067
+Subproject ef3f649e49607a1fad64eb0a5139110df3efa2a
diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml
index a70252fa65a..1563ee0b143 100644
--- a/src/tools/rust-analyzer/.github/workflows/ci.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml
@@ -6,15 +6,15 @@ on:
   pull_request:
   push:
     branches:
-    - auto
-    - try
+      - auto
+      - try
 
 env:
   CARGO_INCREMENTAL: 0
   CARGO_NET_RETRY: 10
   CI: 1
   RUST_BACKTRACE: short
-  RUSTFLAGS: "-D warnings -W unreachable-pub -W rust-2021-compatibility"
+  RUSTFLAGS: "-D warnings -W unreachable-pub -W bare-trait-objects"
   RUSTUP_MAX_RETRIES: 10
 
 jobs:
@@ -31,25 +31,25 @@ jobs:
         os: [ubuntu-latest, windows-latest, macos-latest]
 
     steps:
-    - name: Checkout repository
-      uses: actions/checkout@v3
-      with:
-        ref: ${{ github.event.pull_request.head.sha }}
-        fetch-depth: 20
+      - name: Checkout repository
+        uses: actions/checkout@v3
+        with:
+          ref: ${{ github.event.pull_request.head.sha }}
+          fetch-depth: 20
 
-    - name: Install Rust toolchain
-      run: |
-        rustup update --no-self-update stable
-        rustup component add rustfmt rust-src
+      - name: Install Rust toolchain
+        run: |
+          rustup update --no-self-update stable
+          rustup component add rustfmt rust-src
 
-    - name: Cache Dependencies
-      uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72
+      - name: Cache Dependencies
+        uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72
 
-    - name: Compile
-      run: cargo test --no-run --locked
+      - name: Compile
+        run: cargo test --no-run --locked
 
-    - name: Test
-      run: cargo test -- --nocapture --quiet
+      - name: Test
+        run: cargo test -- --nocapture --quiet
 
   # Weird targets to catch non-portable code
   rust-cross:
@@ -64,25 +64,25 @@ jobs:
       targets_ide: "wasm32-unknown-unknown"
 
     steps:
-    - name: Checkout repository
-      uses: actions/checkout@v3
-
-    - name: Install Rust toolchain
-      run: |
-        rustup update --no-self-update stable
-        rustup target add ${{ env.targets }} ${{ env.targets_ide }}
-
-    - name: Cache Dependencies
-      uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72
-
-    - name: Check
-      run: |
-        for target in ${{ env.targets }}; do
-          cargo check --target=$target --all-targets
-        done
-        for target in ${{ env.targets_ide }}; do
-          cargo check -p ide --target=$target --all-targets
-        done
+      - name: Checkout repository
+        uses: actions/checkout@v3
+
+      - name: Install Rust toolchain
+        run: |
+          rustup update --no-self-update stable
+          rustup target add ${{ env.targets }} ${{ env.targets_ide }}
+
+      - name: Cache Dependencies
+        uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72
+
+      - name: Check
+        run: |
+          for target in ${{ env.targets }}; do
+            cargo check --target=$target --all-targets
+          done
+          for target in ${{ env.targets_ide }}; do
+            cargo check -p ide --target=$target --all-targets
+          done
 
   typescript:
     if: github.repository == 'rust-lang/rust-analyzer'
@@ -95,47 +95,47 @@ jobs:
     runs-on: ${{ matrix.os }}
 
     steps:
-    - name: Checkout repository
-      uses: actions/checkout@v3
-
-    - name: Install Nodejs
-      uses: actions/setup-node@v1
-      with:
-        node-version: 16.x
-
-    - name: Install xvfb
-      if: matrix.os == 'ubuntu-latest'
-      run: sudo apt-get install -y xvfb
-
-    - run: npm ci
-      working-directory: ./editors/code
-
-#    - run: npm audit || { sleep 10 && npm audit; } || { sleep 30 && npm audit; }
-#      if: runner.os == 'Linux'
-#      working-directory: ./editors/code
-
-    - run: npm run lint
-      working-directory: ./editors/code
-
-    - name: Run VS Code tests (Linux)
-      if: matrix.os == 'ubuntu-latest'
-      env:
-        VSCODE_CLI: 1
-      run: xvfb-run npm test
-      working-directory: ./editors/code
-
-    - name: Run VS Code tests (Windows)
-      if: matrix.os == 'windows-latest'
-      env:
-        VSCODE_CLI: 1
-      run: npm test
-      working-directory: ./editors/code
-
-    - run: npm run pretest
-      working-directory: ./editors/code
-
-    - run: npm run package --scripts-prepend-node-path
-      working-directory: ./editors/code
+      - name: Checkout repository
+        uses: actions/checkout@v3
+
+      - name: Install Nodejs
+        uses: actions/setup-node@v1
+        with:
+          node-version: 16.x
+
+      - name: Install xvfb
+        if: matrix.os == 'ubuntu-latest'
+        run: sudo apt-get install -y xvfb
+
+      - run: npm ci
+        working-directory: ./editors/code
+
+      #    - run: npm audit || { sleep 10 && npm audit; } || { sleep 30 && npm audit; }
+      #      if: runner.os == 'Linux'
+      #      working-directory: ./editors/code
+
+      - run: npm run lint
+        working-directory: ./editors/code
+
+      - name: Run VS Code tests (Linux)
+        if: matrix.os == 'ubuntu-latest'
+        env:
+          VSCODE_CLI: 1
+        run: xvfb-run npm test
+        working-directory: ./editors/code
+
+      - name: Run VS Code tests (Windows)
+        if: matrix.os == 'windows-latest'
+        env:
+          VSCODE_CLI: 1
+        run: npm test
+        working-directory: ./editors/code
+
+      - run: npm run pretest
+        working-directory: ./editors/code
+
+      - run: npm run package --scripts-prepend-node-path
+        working-directory: ./editors/code
 
   end-success:
     name: bors build finished
diff --git a/src/tools/rust-analyzer/.github/workflows/release.yaml b/src/tools/rust-analyzer/.github/workflows/release.yaml
index b2e5db6f689..303a10615bb 100644
--- a/src/tools/rust-analyzer/.github/workflows/release.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/release.yaml
@@ -248,7 +248,7 @@ jobs:
         if: github.ref == 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
         working-directory: ./editors/code
         # token from https://dev.azure.com/rust-analyzer/
-        run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix
+        run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix || true
 
       - name: Publish Extension (Code Marketplace, nightly)
         if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
@@ -258,4 +258,4 @@ jobs:
       - name: Publish Extension (OpenVSX, nightly)
         if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
         working-directory: ./editors/code
-        run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix
+        run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix || true
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
index 1d818d96267..22f5fb99266 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
@@ -250,6 +250,10 @@ pub type PatSource = InFile<PatPtr>;
 
 pub type LabelPtr = AstPtr<ast::Label>;
 pub type LabelSource = InFile<LabelPtr>;
+
+pub type FieldPtr = AstPtr<ast::RecordExprField>;
+pub type FieldSource = InFile<FieldPtr>;
+
 /// An item body together with the mapping from syntax nodes to HIR expression
 /// IDs. This is needed to go from e.g. a position in a file to the HIR
 /// expression containing it; but for type inference etc., we want to operate on
@@ -264,18 +268,18 @@ pub type LabelSource = InFile<LabelPtr>;
 #[derive(Default, Debug, Eq, PartialEq)]
 pub struct BodySourceMap {
     expr_map: FxHashMap<ExprSource, ExprId>,
-    expr_map_back: ArenaMap<ExprId, Result<ExprSource, SyntheticSyntax>>,
+    expr_map_back: ArenaMap<ExprId, ExprSource>,
 
     pat_map: FxHashMap<PatSource, PatId>,
-    pat_map_back: ArenaMap<PatId, Result<PatSource, SyntheticSyntax>>,
+    pat_map_back: ArenaMap<PatId, PatSource>,
 
     label_map: FxHashMap<LabelSource, LabelId>,
     label_map_back: ArenaMap<LabelId, LabelSource>,
 
     /// We don't create explicit nodes for record fields (`S { record_field: 92 }`).
     /// Instead, we use id of expression (`92`) to identify the field.
-    field_map: FxHashMap<InFile<AstPtr<ast::RecordExprField>>, ExprId>,
-    field_map_back: FxHashMap<ExprId, InFile<AstPtr<ast::RecordExprField>>>,
+    field_map: FxHashMap<FieldSource, ExprId>,
+    field_map_back: FxHashMap<ExprId, FieldSource>,
 
     expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>,
 
@@ -420,7 +424,7 @@ impl Index<LabelId> for Body {
 // Perhaps `expr_syntax` and `expr_id`?
 impl BodySourceMap {
     pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> {
-        self.expr_map_back[expr].clone()
+        self.expr_map_back.get(expr).cloned().ok_or(SyntheticSyntax)
     }
 
     pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> {
@@ -434,7 +438,7 @@ impl BodySourceMap {
     }
 
     pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> {
-        self.pat_map_back[pat].clone()
+        self.pat_map_back.get(pat).cloned().ok_or(SyntheticSyntax)
     }
 
     pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<PatId> {
@@ -456,9 +460,10 @@ impl BodySourceMap {
         self.label_map.get(&src).cloned()
     }
 
-    pub fn field_syntax(&self, expr: ExprId) -> InFile<AstPtr<ast::RecordExprField>> {
+    pub fn field_syntax(&self, expr: ExprId) -> FieldSource {
         self.field_map_back[&expr].clone()
     }
+
     pub fn node_field(&self, node: InFile<&ast::RecordExprField>) -> Option<ExprId> {
         let src = node.map(AstPtr::new);
         self.field_map.get(&src).cloned()
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
index f6ec8bf7e9e..3b3297f7811 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
@@ -24,7 +24,7 @@ use syntax::{
 
 use crate::{
     adt::StructKind,
-    body::{Body, BodySourceMap, Expander, LabelSource, PatPtr, SyntheticSyntax},
+    body::{Body, BodySourceMap, Expander, ExprPtr, LabelPtr, LabelSource, PatPtr},
     body::{BodyDiagnostic, ExprSource, PatSource},
     builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
     db::DefDatabase,
@@ -150,21 +150,21 @@ impl ExprCollector<'_> {
         LowerCtx::new(self.db, self.expander.current_file_id)
     }
 
-    fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId {
+    fn alloc_expr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId {
         let src = self.expander.to_source(ptr);
-        let id = self.make_expr(expr, Ok(src.clone()));
+        let id = self.make_expr(expr, src.clone());
         self.source_map.expr_map.insert(src, id);
         id
     }
     // desugared exprs don't have ptr, that's wrong and should be fixed
     // somehow.
     fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId {
-        self.make_expr(expr, Err(SyntheticSyntax))
+        self.body.exprs.alloc(expr)
     }
     fn missing_expr(&mut self) -> ExprId {
         self.alloc_expr_desugared(Expr::Missing)
     }
-    fn make_expr(&mut self, expr: Expr, src: Result<ExprSource, SyntheticSyntax>) -> ExprId {
+    fn make_expr(&mut self, expr: Expr, src: ExprSource) -> ExprId {
         let id = self.body.exprs.alloc(expr);
         self.source_map.expr_map_back.insert(id, src);
         id
@@ -172,20 +172,20 @@ impl ExprCollector<'_> {
 
     fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
         let src = self.expander.to_source(ptr);
-        let id = self.make_pat(pat, Ok(src.clone()));
+        let id = self.make_pat(pat, src.clone());
         self.source_map.pat_map.insert(src, id);
         id
     }
     fn missing_pat(&mut self) -> PatId {
-        self.make_pat(Pat::Missing, Err(SyntheticSyntax))
+        self.body.pats.alloc(Pat::Missing)
     }
-    fn make_pat(&mut self, pat: Pat, src: Result<PatSource, SyntheticSyntax>) -> PatId {
+    fn make_pat(&mut self, pat: Pat, src: PatSource) -> PatId {
         let id = self.body.pats.alloc(pat);
         self.source_map.pat_map_back.insert(id, src);
         id
     }
 
-    fn alloc_label(&mut self, label: Label, ptr: AstPtr<ast::Label>) -> LabelId {
+    fn alloc_label(&mut self, label: Label, ptr: LabelPtr) -> LabelId {
         let src = self.expander.to_source(ptr);
         let id = self.make_label(label, src.clone());
         self.source_map.label_map.insert(src, id);
@@ -550,20 +550,6 @@ impl ExprCollector<'_> {
                     None => self.alloc_expr(Expr::Missing, syntax_ptr),
                 }
             }
-            ast::Expr::MacroStmts(e) => {
-                let statements: Box<[_]> =
-                    e.statements().filter_map(|s| self.collect_stmt(s)).collect();
-                let tail = e.expr().map(|e| self.collect_expr(e));
-
-                if e.syntax().children().next().is_none() {
-                    // HACK: make sure that macros that expand to nothing aren't treated as a `()`
-                    // expression when used in block tail position.
-                    cov_mark::hit!(empty_macro_in_trailing_position_is_removed);
-                    return None;
-                }
-
-                self.alloc_expr(Expr::MacroStmts { tail, statements }, syntax_ptr)
-            }
             ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),
         })
     }
@@ -640,11 +626,46 @@ impl ExprCollector<'_> {
         }
     }
 
-    fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Statement> {
+    fn collect_macro_as_stmt(
+        &mut self,
+        statements: &mut Vec<Statement>,
+        mac: ast::MacroExpr,
+    ) -> Option<ExprId> {
+        let mac_call = mac.macro_call()?;
+        let syntax_ptr = AstPtr::new(&ast::Expr::from(mac));
+        let macro_ptr = AstPtr::new(&mac_call);
+        let expansion = self.collect_macro_call(
+            mac_call,
+            macro_ptr,
+            false,
+            |this, expansion: Option<ast::MacroStmts>| match expansion {
+                Some(expansion) => {
+                    expansion.statements().for_each(|stmt| this.collect_stmt(statements, stmt));
+                    expansion.expr().and_then(|expr| match expr {
+                        ast::Expr::MacroExpr(mac) => this.collect_macro_as_stmt(statements, mac),
+                        expr => Some(this.collect_expr(expr)),
+                    })
+                }
+                None => None,
+            },
+        );
+        match expansion {
+            Some(tail) => {
+                // Make the macro-call point to its expanded expression so we can query
+                // semantics on syntax pointers to the macro
+                let src = self.expander.to_source(syntax_ptr);
+                self.source_map.expr_map.insert(src, tail);
+                Some(tail)
+            }
+            None => None,
+        }
+    }
+
+    fn collect_stmt(&mut self, statements: &mut Vec<Statement>, s: ast::Stmt) {
         match s {
             ast::Stmt::LetStmt(stmt) => {
                 if self.check_cfg(&stmt).is_none() {
-                    return None;
+                    return;
                 }
                 let pat = self.collect_pat_opt(stmt.pat());
                 let type_ref =
@@ -654,61 +675,26 @@ impl ExprCollector<'_> {
                     .let_else()
                     .and_then(|let_else| let_else.block_expr())
                     .map(|block| self.collect_block(block));
-                Some(Statement::Let { pat, type_ref, initializer, else_branch })
+                statements.push(Statement::Let { pat, type_ref, initializer, else_branch });
             }
             ast::Stmt::ExprStmt(stmt) => {
                 let expr = stmt.expr();
-                if let Some(expr) = &expr {
-                    if self.check_cfg(expr).is_none() {
-                        return None;
-                    }
+                match &expr {
+                    Some(expr) if self.check_cfg(expr).is_none() => return,
+                    _ => (),
                 }
                 let has_semi = stmt.semicolon_token().is_some();
                 // Note that macro could be expanded to multiple statements
-                if let Some(expr @ ast::Expr::MacroExpr(mac)) = &expr {
-                    let mac_call = mac.macro_call()?;
-                    let syntax_ptr = AstPtr::new(expr);
-                    let macro_ptr = AstPtr::new(&mac_call);
-                    let stmt = self.collect_macro_call(
-                        mac_call,
-                        macro_ptr,
-                        false,
-                        |this, expansion: Option<ast::MacroStmts>| match expansion {
-                            Some(expansion) => {
-                                let statements = expansion
-                                    .statements()
-                                    .filter_map(|stmt| this.collect_stmt(stmt))
-                                    .collect();
-                                let tail = expansion.expr().map(|expr| this.collect_expr(expr));
-
-                                let mac_stmts = this.alloc_expr(
-                                    Expr::MacroStmts { tail, statements },
-                                    AstPtr::new(&ast::Expr::MacroStmts(expansion)),
-                                );
-
-                                Some(mac_stmts)
-                            }
-                            None => None,
-                        },
-                    );
-
-                    let expr = match stmt {
-                        Some(expr) => {
-                            // Make the macro-call point to its expanded expression so we can query
-                            // semantics on syntax pointers to the macro
-                            let src = self.expander.to_source(syntax_ptr);
-                            self.source_map.expr_map.insert(src, expr);
-                            expr
-                        }
-                        None => self.alloc_expr(Expr::Missing, syntax_ptr),
-                    };
-                    Some(Statement::Expr { expr, has_semi })
+                if let Some(ast::Expr::MacroExpr(mac)) = expr {
+                    if let Some(expr) = self.collect_macro_as_stmt(statements, mac) {
+                        statements.push(Statement::Expr { expr, has_semi })
+                    }
                 } else {
                     let expr = self.collect_expr_opt(expr);
-                    Some(Statement::Expr { expr, has_semi })
+                    statements.push(Statement::Expr { expr, has_semi });
                 }
             }
-            ast::Stmt::Item(_item) => None,
+            ast::Stmt::Item(_item) => (),
         }
     }
 
@@ -729,9 +715,12 @@ impl ExprCollector<'_> {
         let prev_def_map = mem::replace(&mut self.expander.def_map, def_map);
         let prev_local_module = mem::replace(&mut self.expander.module, module);
 
-        let mut statements: Vec<_> =
-            block.statements().filter_map(|s| self.collect_stmt(s)).collect();
-        let tail = block.tail_expr().and_then(|e| self.maybe_collect_expr(e));
+        let mut statements = Vec::new();
+        block.statements().for_each(|s| self.collect_stmt(&mut statements, s));
+        let tail = block.tail_expr().and_then(|e| match e {
+            ast::Expr::MacroExpr(mac) => self.collect_macro_as_stmt(&mut statements, mac),
+            expr => self.maybe_collect_expr(expr),
+        });
         let tail = tail.or_else(|| {
             let stmt = statements.pop()?;
             if let Statement::Expr { expr, has_semi: false } = stmt {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
index ddd476efe5c..f2fed954444 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
@@ -422,19 +422,6 @@ impl<'a> Printer<'a> {
                 }
                 w!(self, "}}");
             }
-            Expr::MacroStmts { statements, tail } => {
-                w!(self, "{{ // macro statements");
-                self.indented(|p| {
-                    for stmt in statements.iter() {
-                        p.print_stmt(stmt);
-                    }
-                    if let Some(tail) = tail {
-                        p.print_expr(*tail);
-                    }
-                });
-                self.newline();
-                w!(self, "}}");
-            }
         }
     }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
index f4c390dce26..45f64ebb060 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
@@ -47,16 +47,9 @@ pub struct ScopeData {
 impl ExprScopes {
     pub(crate) fn expr_scopes_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc<ExprScopes> {
         let body = db.body(def);
-        Arc::new(ExprScopes::new(&*body))
-    }
-
-    fn new(body: &Body) -> ExprScopes {
-        let mut scopes =
-            ExprScopes { scopes: Arena::default(), scope_by_expr: FxHashMap::default() };
-        let mut root = scopes.root_scope();
-        scopes.add_params_bindings(body, root, &body.params);
-        compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root);
-        scopes
+        let mut scopes = ExprScopes::new(&*body);
+        scopes.shrink_to_fit();
+        Arc::new(scopes)
     }
 
     pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] {
@@ -89,6 +82,17 @@ impl ExprScopes {
     pub fn scope_by_expr(&self) -> &FxHashMap<ExprId, ScopeId> {
         &self.scope_by_expr
     }
+}
+
+impl ExprScopes {
+    fn new(body: &Body) -> ExprScopes {
+        let mut scopes =
+            ExprScopes { scopes: Arena::default(), scope_by_expr: FxHashMap::default() };
+        let mut root = scopes.root_scope();
+        scopes.add_params_bindings(body, root, &body.params);
+        compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root);
+        scopes
+    }
 
     fn root_scope(&mut self) -> ScopeId {
         self.scopes.alloc(ScopeData { parent: None, block: None, label: None, entries: vec![] })
@@ -138,6 +142,13 @@ impl ExprScopes {
     fn set_scope(&mut self, node: ExprId, scope: ScopeId) {
         self.scope_by_expr.insert(node, scope);
     }
+
+    fn shrink_to_fit(&mut self) {
+        let ExprScopes { scopes, scope_by_expr } = self;
+        scopes.shrink_to_fit();
+        scopes.values_mut().for_each(|it| it.entries.shrink_to_fit());
+        scope_by_expr.shrink_to_fit();
+    }
 }
 
 fn compute_block_scopes(
@@ -176,9 +187,6 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope
 
     scopes.set_scope(expr, *scope);
     match &body[expr] {
-        Expr::MacroStmts { statements, tail } => {
-            compute_block_scopes(statements, *tail, body, scopes, scope);
-        }
         Expr::Block { statements, tail, id, label } => {
             let mut scope = scopes.new_block_scope(*scope, *id, make_label(label));
             // Overwrite the old scope for the block expr, so that every block scope can be found
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr.rs
index 4381b43c258..419d3feec3b 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr.rs
@@ -206,10 +206,6 @@ pub enum Expr {
     Unsafe {
         body: ExprId,
     },
-    MacroStmts {
-        statements: Box<[Statement]>,
-        tail: Option<ExprId>,
-    },
     Array(Array),
     Literal(Literal),
     Underscore,
@@ -263,7 +259,7 @@ impl Expr {
             Expr::Let { expr, .. } => {
                 f(*expr);
             }
-            Expr::MacroStmts { tail, statements } | Expr::Block { statements, tail, .. } => {
+            Expr::Block { statements, tail, .. } => {
                 for stmt in statements.iter() {
                     match stmt {
                         Statement::Let { initializer, .. } => {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
index 6eb530ecc54..9b4ce9f97c8 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
@@ -64,7 +64,7 @@ use hir_expand::{name::Name, InFile, MacroCallId, MacroDefId};
 use itertools::Itertools;
 use la_arena::Arena;
 use profile::Count;
-use rustc_hash::FxHashMap;
+use rustc_hash::{FxHashMap, FxHashSet};
 use stdx::format_to;
 use syntax::{ast, SmolStr};
 
@@ -98,7 +98,11 @@ pub struct DefMap {
     /// The prelude module for this crate. This either comes from an import
     /// marked with the `prelude_import` attribute, or (in the normal case) from
     /// a dependency (`std` or `core`).
+    /// The prelude is empty for non-block DefMaps (unless `#[prelude_import]` was used,
+    /// but that attribute is nightly and when used in a block, it affects resolution globally
+    /// so we aren't handling this correctly anyways).
     prelude: Option<ModuleId>,
+    /// The extern prelude is only populated for non-block DefMaps
     extern_prelude: FxHashMap<Name, ModuleId>,
 
     /// Side table for resolving derive helpers.
@@ -114,6 +118,8 @@ pub struct DefMap {
     registered_attrs: Vec<SmolStr>,
     /// Custom tool modules registered with `#![register_tool]`.
     registered_tools: Vec<SmolStr>,
+    /// Unstable features of Rust enabled with `#![feature(A, B)]`.
+    unstable_features: FxHashSet<SmolStr>,
 
     edition: Edition,
     recursion_limit: Option<u32>,
@@ -284,6 +290,7 @@ impl DefMap {
             modules,
             registered_attrs: Vec::new(),
             registered_tools: Vec::new(),
+            unstable_features: FxHashSet::default(),
             diagnostics: Vec::new(),
         }
     }
@@ -314,6 +321,10 @@ impl DefMap {
         &self.registered_attrs
     }
 
+    pub fn is_unstable_feature_enabled(&self, feature: &str) -> bool {
+        self.unstable_features.contains(feature)
+    }
+
     pub fn root(&self) -> LocalModuleId {
         self.root
     }
@@ -479,6 +490,7 @@ impl DefMap {
             registered_tools,
             fn_proc_macro_mapping,
             derive_helpers_in_scope,
+            unstable_features,
             proc_macro_loading_error: _,
             block: _,
             edition: _,
@@ -496,6 +508,7 @@ impl DefMap {
         registered_tools.shrink_to_fit();
         fn_proc_macro_mapping.shrink_to_fit();
         derive_helpers_in_scope.shrink_to_fit();
+        unstable_features.shrink_to_fit();
         for (_, module) in modules.iter_mut() {
             module.children.shrink_to_fit();
             module.scope.shrink_to_fit();
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
index 8a6bb929c3d..495bbe4579f 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
@@ -294,6 +294,17 @@ impl DefCollector<'_> {
                     continue;
                 }
 
+                if *attr_name == hir_expand::name![feature] {
+                    let features =
+                        attr.parse_path_comma_token_tree().into_iter().flatten().filter_map(
+                            |feat| match feat.segments() {
+                                [name] => Some(name.to_smol_str()),
+                                _ => None,
+                            },
+                        );
+                    self.def_map.unstable_features.extend(features);
+                }
+
                 let attr_is_register_like = *attr_name == hir_expand::name![register_attr]
                     || *attr_name == hir_expand::name![register_tool];
                 if !attr_is_register_like {
@@ -501,10 +512,9 @@ impl DefCollector<'_> {
             Edition::Edition2021 => name![rust_2021],
         };
 
-        let path_kind = if self.def_map.edition == Edition::Edition2015 {
-            PathKind::Plain
-        } else {
-            PathKind::Abs
+        let path_kind = match self.def_map.edition {
+            Edition::Edition2015 => PathKind::Plain,
+            _ => PathKind::Abs,
         };
         let path =
             ModPath::from_segments(path_kind, [krate.clone(), name![prelude], edition].into_iter());
@@ -524,7 +534,6 @@ impl DefCollector<'_> {
             match per_ns.types {
                 Some((ModuleDefId::ModuleId(m), _)) => {
                     self.def_map.prelude = Some(m);
-                    return;
                 }
                 types => {
                     tracing::debug!(
@@ -839,7 +848,10 @@ impl DefCollector<'_> {
                 tracing::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
 
                 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
-                if import.is_extern_crate && module_id == self.def_map.root {
+                if import.is_extern_crate
+                    && self.def_map.block.is_none()
+                    && module_id == self.def_map.root
+                {
                     if let (Some(ModuleDefId::ModuleId(def)), Some(name)) = (def.take_types(), name)
                     {
                         self.def_map.extern_prelude.insert(name.clone(), def);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs
index 99f7f1b549e..ca7bcc814e8 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs
@@ -65,6 +65,7 @@ impl ModDir {
         name: &Name,
         attr_path: Option<&SmolStr>,
     ) -> Result<(FileId, bool, ModDir), Box<[String]>> {
+        let name = name.unescaped();
         let orig_file_id = file_id.original_file(db.upcast());
 
         let mut candidate_files = ArrayVec::<_, 2>::new();
@@ -73,12 +74,10 @@ impl ModDir {
                 candidate_files.push(self.dir_path.join_attr(attr_path, self.root_non_dir_owner))
             }
             None if file_id.is_include_macro(db.upcast()) => {
-                let name = name.unescaped();
                 candidate_files.push(format!("{}.rs", name));
                 candidate_files.push(format!("{}/mod.rs", name));
             }
             None => {
-                let name = name.unescaped();
                 candidate_files.push(format!("{}{}.rs", self.dir_path.0, name));
                 candidate_files.push(format!("{}{}/mod.rs", self.dir_path.0, name));
             }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs
index 3fa585574de..ba3bf8b5a5c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs
@@ -127,7 +127,15 @@ mod r#async;
 use self::r#async::Bar;
 
 //- /async.rs
+mod foo;
+mod r#async;
 pub struct Bar;
+
+//- /async/foo.rs
+pub struct Foo;
+
+//- /async/async.rs
+pub struct Baz;
 "#,
         expect![[r#"
             crate
@@ -136,6 +144,14 @@ pub struct Bar;
 
             crate::r#async
             Bar: t v
+            foo: t
+            r#async: t
+
+            crate::r#async::foo
+            Foo: t v
+
+            crate::r#async::r#async
+            Baz: t v
         "#]],
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
index 3163fa0f93f..8aa5973cac5 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -31,12 +31,10 @@ pub struct Resolver {
     ///
     /// When using, you generally want to process the scopes in reverse order,
     /// there's `scopes` *method* for that.
-    ///
-    /// Invariant: There exists at least one Scope::ModuleScope at the start of the vec.
     scopes: Vec<Scope>,
+    module_scope: ModuleItemMap,
 }
 
-// FIXME how to store these best
 #[derive(Debug, Clone)]
 struct ModuleItemMap {
     def_map: Arc<DefMap>,
@@ -53,7 +51,7 @@ struct ExprScope {
 #[derive(Debug, Clone)]
 enum Scope {
     /// All the items and imported names of a module
-    ModuleScope(ModuleItemMap),
+    BlockScope(ModuleItemMap),
     /// Brings the generic parameters of an item into scope
     GenericParams { def: GenericDefId, params: Interned<GenericParams> },
     /// Brings `Self` in `impl` block into scope
@@ -127,24 +125,6 @@ impl Resolver {
         }
     }
 
-    fn scopes(&self) -> impl Iterator<Item = &Scope> {
-        self.scopes.iter().rev()
-    }
-
-    fn resolve_module_path(
-        &self,
-        db: &dyn DefDatabase,
-        path: &ModPath,
-        shadow: BuiltinShadowMode,
-    ) -> PerNs {
-        let (item_map, module) = self.module_scope();
-        let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow);
-        if segment_index.is_some() {
-            return PerNs::none();
-        }
-        module_res
-    }
-
     pub fn resolve_module_path_in_items(&self, db: &dyn DefDatabase, path: &ModPath) -> PerNs {
         self.resolve_module_path(db, path, BuiltinShadowMode::Module)
     }
@@ -155,7 +135,7 @@ impl Resolver {
         db: &dyn DefDatabase,
         path: &ModPath,
     ) -> Option<PerNs> {
-        let (item_map, module) = self.module_scope();
+        let (item_map, module) = self.item_scope();
         let (module_res, idx) = item_map.resolve_path(db, module, path, BuiltinShadowMode::Module);
         match module_res.take_types()? {
             ModuleDefId::TraitId(it) => {
@@ -183,37 +163,38 @@ impl Resolver {
     ) -> Option<(TypeNs, Option<usize>)> {
         let first_name = path.segments().first()?;
         let skip_to_mod = path.kind != PathKind::Plain;
+        if skip_to_mod {
+            return self.module_scope.resolve_path_in_type_ns(db, path);
+        }
+
+        let remaining_idx = || if path.segments().len() == 1 { None } else { Some(1) };
+
         for scope in self.scopes() {
             match scope {
                 Scope::ExprScope(_) => continue,
-                Scope::GenericParams { .. } | Scope::ImplDefScope(_) if skip_to_mod => continue,
-
                 Scope::GenericParams { params, def } => {
                     if let Some(id) = params.find_type_by_name(first_name, *def) {
-                        let idx = if path.segments().len() == 1 { None } else { Some(1) };
-                        return Some((TypeNs::GenericParam(id), idx));
+                        return Some((TypeNs::GenericParam(id), remaining_idx()));
                     }
                 }
-                Scope::ImplDefScope(impl_) => {
+                &Scope::ImplDefScope(impl_) => {
                     if first_name == &name![Self] {
-                        let idx = if path.segments().len() == 1 { None } else { Some(1) };
-                        return Some((TypeNs::SelfType(*impl_), idx));
+                        return Some((TypeNs::SelfType(impl_), remaining_idx()));
                     }
                 }
-                Scope::AdtScope(adt) => {
+                &Scope::AdtScope(adt) => {
                     if first_name == &name![Self] {
-                        let idx = if path.segments().len() == 1 { None } else { Some(1) };
-                        return Some((TypeNs::AdtSelfType(*adt), idx));
+                        return Some((TypeNs::AdtSelfType(adt), remaining_idx()));
                     }
                 }
-                Scope::ModuleScope(m) => {
+                Scope::BlockScope(m) => {
                     if let Some(res) = m.resolve_path_in_type_ns(db, path) {
                         return Some(res);
                     }
                 }
             }
         }
-        None
+        self.module_scope.resolve_path_in_type_ns(db, path)
     }
 
     pub fn resolve_path_in_type_ns_fully(
@@ -235,7 +216,7 @@ impl Resolver {
     ) -> Option<Visibility> {
         match visibility {
             RawVisibility::Module(_) => {
-                let (item_map, module) = self.module_scope();
+                let (item_map, module) = self.item_scope();
                 item_map.resolve_visibility(db, module, visibility)
             }
             RawVisibility::Public => Some(Visibility::Public),
@@ -251,18 +232,14 @@ impl Resolver {
         let tmp = name![self];
         let first_name = if path.is_self() { &tmp } else { path.segments().first()? };
         let skip_to_mod = path.kind != PathKind::Plain && !path.is_self();
+        if skip_to_mod {
+            return self.module_scope.resolve_path_in_value_ns(db, path);
+        }
+
         for scope in self.scopes() {
             match scope {
-                Scope::AdtScope(_)
-                | Scope::ExprScope(_)
-                | Scope::GenericParams { .. }
-                | Scope::ImplDefScope(_)
-                    if skip_to_mod =>
-                {
-                    continue
-                }
-
-                Scope::ExprScope(scope) if n_segments <= 1 => {
+                Scope::ExprScope(_) if n_segments > 1 => continue,
+                Scope::ExprScope(scope) => {
                     let entry = scope
                         .expr_scopes
                         .entries(scope.scope_id)
@@ -273,44 +250,39 @@ impl Resolver {
                         return Some(ResolveValueResult::ValueNs(ValueNs::LocalBinding(e.pat())));
                     }
                 }
-                Scope::ExprScope(_) => continue,
-
                 Scope::GenericParams { params, def } if n_segments > 1 => {
                     if let Some(id) = params.find_type_by_name(first_name, *def) {
                         let ty = TypeNs::GenericParam(id);
                         return Some(ResolveValueResult::Partial(ty, 1));
                     }
                 }
-                Scope::GenericParams { params, def } if n_segments == 1 => {
+                Scope::GenericParams { .. } if n_segments != 1 => continue,
+                Scope::GenericParams { params, def } => {
                     if let Some(id) = params.find_const_by_name(first_name, *def) {
                         let val = ValueNs::GenericParam(id);
                         return Some(ResolveValueResult::ValueNs(val));
                     }
                 }
-                Scope::GenericParams { .. } => continue,
 
-                Scope::ImplDefScope(impl_) => {
+                &Scope::ImplDefScope(impl_) => {
                     if first_name == &name![Self] {
-                        if n_segments > 1 {
-                            let ty = TypeNs::SelfType(*impl_);
-                            return Some(ResolveValueResult::Partial(ty, 1));
+                        return Some(if n_segments > 1 {
+                            ResolveValueResult::Partial(TypeNs::SelfType(impl_), 1)
                         } else {
-                            return Some(ResolveValueResult::ValueNs(ValueNs::ImplSelf(*impl_)));
-                        }
+                            ResolveValueResult::ValueNs(ValueNs::ImplSelf(impl_))
+                        });
                     }
                 }
+                // bare `Self` doesn't work in the value namespace in a struct/enum definition
+                Scope::AdtScope(_) if n_segments == 1 => continue,
                 Scope::AdtScope(adt) => {
-                    if n_segments == 1 {
-                        // bare `Self` doesn't work in the value namespace in a struct/enum definition
-                        continue;
-                    }
                     if first_name == &name![Self] {
                         let ty = TypeNs::AdtSelfType(*adt);
                         return Some(ResolveValueResult::Partial(ty, 1));
                     }
                 }
 
-                Scope::ModuleScope(m) => {
+                Scope::BlockScope(m) => {
                     if let Some(def) = m.resolve_path_in_value_ns(db, path) {
                         return Some(def);
                     }
@@ -318,15 +290,16 @@ impl Resolver {
             }
         }
 
+        if let res @ Some(_) = self.module_scope.resolve_path_in_value_ns(db, path) {
+            return res;
+        }
+
         // If a path of the shape `u16::from_le_bytes` failed to resolve at all, then we fall back
         // to resolving to the primitive type, to allow this to still work in the presence of
         // `use core::u16;`.
         if path.kind == PathKind::Plain && path.segments().len() > 1 {
-            match BuiltinType::by_name(&path.segments()[0]) {
-                Some(builtin) => {
-                    return Some(ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1));
-                }
-                None => {}
+            if let Some(builtin) = BuiltinType::by_name(&path.segments()[0]) {
+                return Some(ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1));
             }
         }
 
@@ -345,7 +318,7 @@ impl Resolver {
     }
 
     pub fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroId> {
-        let (item_map, module) = self.module_scope();
+        let (item_map, module) = self.item_scope();
         item_map.resolve_path(db, module, path, BuiltinShadowMode::Other).0.take_macros()
     }
 
@@ -395,30 +368,43 @@ impl Resolver {
         for scope in self.scopes() {
             scope.process_names(&mut res, db);
         }
+        let ModuleItemMap { ref def_map, module_id } = self.module_scope;
+        // FIXME: should we provide `self` here?
+        // f(
+        //     Name::self_param(),
+        //     PerNs::types(Resolution::Def {
+        //         def: m.module.into(),
+        //     }),
+        // );
+        def_map[module_id].scope.entries().for_each(|(name, def)| {
+            res.add_per_ns(name, def);
+        });
+        def_map[module_id].scope.legacy_macros().for_each(|(name, macs)| {
+            macs.iter().for_each(|&mac| {
+                res.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(MacroId::from(mac))));
+            })
+        });
+        def_map.extern_prelude().for_each(|(name, &def)| {
+            res.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def)));
+        });
+        BUILTIN_SCOPE.iter().for_each(|(name, &def)| {
+            res.add_per_ns(name, def);
+        });
+        if let Some(prelude) = def_map.prelude() {
+            let prelude_def_map = prelude.def_map(db);
+            for (name, def) in prelude_def_map[prelude.local_id].scope.entries() {
+                res.add_per_ns(name, def)
+            }
+        }
         res.map
     }
 
     pub fn traits_in_scope(&self, db: &dyn DefDatabase) -> FxHashSet<TraitId> {
         let mut traits = FxHashSet::default();
+
         for scope in self.scopes() {
             match scope {
-                Scope::ModuleScope(m) => {
-                    if let Some(prelude) = m.def_map.prelude() {
-                        let prelude_def_map = prelude.def_map(db);
-                        traits.extend(prelude_def_map[prelude.local_id].scope.traits());
-                    }
-                    traits.extend(m.def_map[m.module_id].scope.traits());
-
-                    // Add all traits that are in scope because of the containing DefMaps
-                    m.def_map.with_ancestor_maps(db, m.module_id, &mut |def_map, module| {
-                        if let Some(prelude) = def_map.prelude() {
-                            let prelude_def_map = prelude.def_map(db);
-                            traits.extend(prelude_def_map[prelude.local_id].scope.traits());
-                        }
-                        traits.extend(def_map[module].scope.traits());
-                        None::<()>
-                    });
-                }
+                Scope::BlockScope(m) => traits.extend(m.def_map[m.module_id].scope.traits()),
                 &Scope::ImplDefScope(impl_) => {
                     if let Some(target_trait) = &db.impl_data(impl_).target_trait {
                         if let Some(TypeNs::TraitId(trait_)) =
@@ -431,35 +417,28 @@ impl Resolver {
                 _ => (),
             }
         }
-        traits
-    }
 
-    fn module_scope(&self) -> (&DefMap, LocalModuleId) {
-        self.scopes()
-            .find_map(|scope| match scope {
-                Scope::ModuleScope(m) => Some((&*m.def_map, m.module_id)),
-                _ => None,
-            })
-            .expect("module scope invariant violated")
+        // Fill in the prelude traits
+        if let Some(prelude) = self.module_scope.def_map.prelude() {
+            let prelude_def_map = prelude.def_map(db);
+            traits.extend(prelude_def_map[prelude.local_id].scope.traits());
+        }
+        // Fill in module visible traits
+        traits.extend(self.module_scope.def_map[self.module_scope.module_id].scope.traits());
+        traits
     }
 
     pub fn module(&self) -> ModuleId {
-        let (def_map, local_id) = self.module_scope();
+        let (def_map, local_id) = self.item_scope();
         def_map.module_id(local_id)
     }
 
     pub fn krate(&self) -> CrateId {
-        self.def_map().krate()
+        self.module_scope.def_map.krate()
     }
 
     pub fn def_map(&self) -> &DefMap {
-        self.scopes
-            .get(0)
-            .and_then(|scope| match scope {
-                Scope::ModuleScope(m) => Some(&m.def_map),
-                _ => None,
-            })
-            .expect("module scope invariant violated")
+        self.item_scope().0
     }
 
     pub fn where_predicates_in_scope(
@@ -488,6 +467,36 @@ impl Resolver {
     }
 }
 
+impl Resolver {
+    fn scopes(&self) -> impl Iterator<Item = &Scope> {
+        self.scopes.iter().rev()
+    }
+
+    fn resolve_module_path(
+        &self,
+        db: &dyn DefDatabase,
+        path: &ModPath,
+        shadow: BuiltinShadowMode,
+    ) -> PerNs {
+        let (item_map, module) = self.item_scope();
+        let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow);
+        if segment_index.is_some() {
+            return PerNs::none();
+        }
+        module_res
+    }
+
+    /// The innermost block scope that contains items or the module scope that contains this resolver.
+    fn item_scope(&self) -> (&DefMap, LocalModuleId) {
+        self.scopes()
+            .find_map(|scope| match scope {
+                Scope::BlockScope(m) => Some((&*m.def_map, m.module_id)),
+                _ => None,
+            })
+            .unwrap_or((&self.module_scope.def_map, self.module_scope.module_id))
+    }
+}
+
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub enum ScopeDef {
     ModuleDef(ModuleDefId),
@@ -502,14 +511,7 @@ pub enum ScopeDef {
 impl Scope {
     fn process_names(&self, acc: &mut ScopeNames, db: &dyn DefDatabase) {
         match self {
-            Scope::ModuleScope(m) => {
-                // FIXME: should we provide `self` here?
-                // f(
-                //     Name::self_param(),
-                //     PerNs::types(Resolution::Def {
-                //         def: m.module.into(),
-                //     }),
-                // );
+            Scope::BlockScope(m) => {
                 m.def_map[m.module_id].scope.entries().for_each(|(name, def)| {
                     acc.add_per_ns(name, def);
                 });
@@ -521,18 +523,6 @@ impl Scope {
                         );
                     })
                 });
-                m.def_map.extern_prelude().for_each(|(name, &def)| {
-                    acc.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def)));
-                });
-                BUILTIN_SCOPE.iter().for_each(|(name, &def)| {
-                    acc.add_per_ns(name, def);
-                });
-                if let Some(prelude) = m.def_map.prelude() {
-                    let prelude_def_map = prelude.def_map(db);
-                    for (name, def) in prelude_def_map[prelude.local_id].scope.entries() {
-                        acc.add_per_ns(name, def)
-                    }
-                }
             }
             Scope::GenericParams { params, def: parent } => {
                 let parent = *parent;
@@ -596,7 +586,7 @@ pub fn resolver_for_scope(
         if let Some(block) = scopes.block(scope) {
             if let Some(def_map) = db.block_def_map(block) {
                 let root = def_map.root();
-                r = r.push_module_scope(def_map, root);
+                r = r.push_block_scope(def_map, root);
                 // FIXME: This adds as many module scopes as there are blocks, but resolving in each
                 // already traverses all parents, so this is O(n²). I think we could only store the
                 // innermost module scope instead?
@@ -623,8 +613,8 @@ impl Resolver {
         self.push_scope(Scope::ImplDefScope(impl_def))
     }
 
-    fn push_module_scope(self, def_map: Arc<DefMap>, module_id: LocalModuleId) -> Resolver {
-        self.push_scope(Scope::ModuleScope(ModuleItemMap { def_map, module_id }))
+    fn push_block_scope(self, def_map: Arc<DefMap>, module_id: LocalModuleId) -> Resolver {
+        self.push_scope(Scope::BlockScope(ModuleItemMap { def_map, module_id }))
     }
 
     fn push_expr_scope(
@@ -768,14 +758,19 @@ pub trait HasResolver: Copy {
 impl HasResolver for ModuleId {
     fn resolver(self, db: &dyn DefDatabase) -> Resolver {
         let mut def_map = self.def_map(db);
-        let mut modules: SmallVec<[_; 2]> = smallvec![(def_map.clone(), self.local_id)];
+        let mut modules: SmallVec<[_; 1]> = smallvec![];
+        let mut module_id = self.local_id;
         while let Some(parent) = def_map.parent() {
+            modules.push((def_map, module_id));
             def_map = parent.def_map(db);
-            modules.push((def_map.clone(), parent.local_id));
+            module_id = parent.local_id;
         }
-        let mut resolver = Resolver { scopes: Vec::with_capacity(modules.len()) };
+        let mut resolver = Resolver {
+            scopes: Vec::with_capacity(modules.len()),
+            module_scope: ModuleItemMap { def_map, module_id },
+        };
         for (def_map, module) in modules.into_iter().rev() {
-            resolver = resolver.push_module_scope(def_map, module);
+            resolver = resolver.push_block_scope(def_map, module);
         }
         resolver
     }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
index d753d88470c..fc128102f22 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
@@ -969,7 +969,7 @@ impl ExpandTo {
         if parent.kind() == MACRO_EXPR
             && parent
                 .parent()
-                .map_or(true, |p| matches!(p.kind(), EXPR_STMT | STMT_LIST | MACRO_STMTS))
+                .map_or(false, |p| matches!(p.kind(), EXPR_STMT | STMT_LIST | MACRO_STMTS))
         {
             return ExpandTo::Statements;
         }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
index 2b859f77509..4ce21a57967 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
@@ -336,6 +336,7 @@ pub mod known {
         test,
         test_case,
         recursion_limit,
+        feature,
         // Safe intrinsics
         abort,
         add_with_overflow,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
index b6f226dbfd2..344036dd813 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
@@ -104,8 +104,7 @@ pub(crate) fn deref(table: &mut InferenceTable<'_>, ty: Ty) -> Option<Ty> {
 
 fn builtin_deref(ty: &Ty) -> Option<&Ty> {
     match ty.kind(Interner) {
-        TyKind::Ref(.., ty) => Some(ty),
-        TyKind::Raw(.., ty) => Some(ty),
+        TyKind::Ref(.., ty) | TyKind::Raw(.., ty) => Some(ty),
         _ => None,
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
index 642e03edd23..c8df4c796ef 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
@@ -159,12 +159,7 @@ impl ExprValidator {
         }
 
         let pattern_arena = Arena::new();
-        let cx = MatchCheckCtx {
-            module: self.owner.module(db.upcast()),
-            body: self.owner,
-            db,
-            pattern_arena: &pattern_arena,
-        };
+        let cx = MatchCheckCtx::new(self.owner.module(db.upcast()), self.owner, db, &pattern_arena);
 
         let mut m_arms = Vec::with_capacity(arms.len());
         let mut has_lowering_errors = false;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs
index bbbe539c13f..47d60fc41e7 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs
@@ -52,7 +52,10 @@ use hir_def::{EnumVariantId, HasModule, LocalFieldId, VariantId};
 use smallvec::{smallvec, SmallVec};
 use stdx::never;
 
-use crate::{infer::normalize, AdtId, Interner, Scalar, Ty, TyExt, TyKind};
+use crate::{
+    infer::normalize, inhabitedness::is_enum_variant_uninhabited_from, AdtId, Interner, Scalar, Ty,
+    TyExt, TyKind,
+};
 
 use super::{
     is_box,
@@ -557,8 +560,8 @@ impl SplitWildcard {
             TyKind::Scalar(Scalar::Bool) => smallvec![make_range(0, 1, Scalar::Bool)],
             // TyKind::Array(..) if ... => unhandled(),
             TyKind::Array(..) | TyKind::Slice(..) => unhandled(),
-            &TyKind::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), ..) => {
-                let enum_data = cx.db.enum_data(enum_id);
+            TyKind::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), subst) => {
+                let enum_data = cx.db.enum_data(*enum_id);
 
                 // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an
                 // additional "unknown" constructor.
@@ -591,14 +594,15 @@ impl SplitWildcard {
                 let mut ctors: SmallVec<[_; 1]> = enum_data
                     .variants
                     .iter()
-                    .filter(|&(_, _v)| {
+                    .map(|(local_id, _)| EnumVariantId { parent: *enum_id, local_id })
+                    .filter(|&variant| {
                         // If `exhaustive_patterns` is enabled, we exclude variants known to be
                         // uninhabited.
                         let is_uninhabited = is_exhaustive_pat_feature
-                            && unimplemented!("after MatchCheckCtx.feature_exhaustive_patterns()");
+                            && is_enum_variant_uninhabited_from(variant, subst, cx.module, cx.db);
                         !is_uninhabited
                     })
-                    .map(|(local_id, _)| Variant(EnumVariantId { parent: enum_id, local_id }))
+                    .map(Variant)
                     .collect();
 
                 if is_secretly_empty || is_declared_nonexhaustive {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/usefulness.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/usefulness.rs
index 1221327b951..c4d709a975b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/usefulness.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/usefulness.rs
@@ -277,7 +277,7 @@ use hir_def::{AdtId, DefWithBodyId, HasModule, ModuleId};
 use smallvec::{smallvec, SmallVec};
 use typed_arena::Arena;
 
-use crate::{db::HirDatabase, Ty, TyExt};
+use crate::{db::HirDatabase, inhabitedness::is_ty_uninhabited_from, Ty, TyExt};
 
 use super::deconstruct_pat::{Constructor, DeconstructedPat, Fields, SplitWildcard};
 
@@ -289,13 +289,27 @@ pub(crate) struct MatchCheckCtx<'a, 'p> {
     pub(crate) db: &'a dyn HirDatabase,
     /// Lowered patterns from arms plus generated by the check.
     pub(crate) pattern_arena: &'p Arena<DeconstructedPat<'p>>,
+    exhaustive_patterns: bool,
 }
 
 impl<'a, 'p> MatchCheckCtx<'a, 'p> {
-    pub(super) fn is_uninhabited(&self, _ty: &Ty) -> bool {
-        // FIXME(iDawer) implement exhaustive_patterns feature. More info in:
-        // Tracking issue for RFC 1872: exhaustive_patterns feature https://github.com/rust-lang/rust/issues/51085
-        false
+    pub(crate) fn new(
+        module: ModuleId,
+        body: DefWithBodyId,
+        db: &'a dyn HirDatabase,
+        pattern_arena: &'p Arena<DeconstructedPat<'p>>,
+    ) -> Self {
+        let def_map = db.crate_def_map(module.krate());
+        let exhaustive_patterns = def_map.is_unstable_feature_enabled("exhaustive_patterns");
+        Self { module, body, db, pattern_arena, exhaustive_patterns }
+    }
+
+    pub(super) fn is_uninhabited(&self, ty: &Ty) -> bool {
+        if self.feature_exhaustive_patterns() {
+            is_ty_uninhabited_from(ty, self.module, self.db)
+        } else {
+            false
+        }
     }
 
     /// Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`.
@@ -311,10 +325,9 @@ impl<'a, 'p> MatchCheckCtx<'a, 'p> {
         }
     }
 
-    // Rust feature described as "Allows exhaustive pattern matching on types that contain uninhabited types."
+    // Rust's unstable feature described as "Allows exhaustive pattern matching on types that contain uninhabited types."
     pub(super) fn feature_exhaustive_patterns(&self) -> bool {
-        // FIXME see MatchCheckCtx::is_uninhabited
-        false
+        self.exhaustive_patterns
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
index 5df48e5fdcb..10ffde87eef 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -182,7 +182,7 @@ pub(crate) type InferResult<T> = Result<InferOk<T>, TypeError>;
 #[derive(Debug, PartialEq, Eq, Clone)]
 pub enum InferenceDiagnostic {
     NoSuchField { expr: ExprId },
-    BreakOutsideOfLoop { expr: ExprId },
+    BreakOutsideOfLoop { expr: ExprId, is_break: bool },
     MismatchedArgCount { call_expr: ExprId, expected: usize, found: usize },
 }
 
@@ -418,18 +418,45 @@ pub(crate) struct InferenceContext<'a> {
 
 #[derive(Clone, Debug)]
 struct BreakableContext {
+    /// Whether this context contains at least one break expression.
     may_break: bool,
+    /// The coercion target of the context.
     coerce: CoerceMany,
+    /// The optional label of the context.
     label: Option<name::Name>,
+    kind: BreakableKind,
+}
+
+#[derive(Clone, Debug)]
+enum BreakableKind {
+    Block,
+    Loop,
+    /// A border is something like an async block, closure etc. Anything that prevents
+    /// breaking/continuing through
+    Border,
 }
 
 fn find_breakable<'c>(
     ctxs: &'c mut [BreakableContext],
     label: Option<&name::Name>,
 ) -> Option<&'c mut BreakableContext> {
+    let mut ctxs = ctxs
+        .iter_mut()
+        .rev()
+        .take_while(|it| matches!(it.kind, BreakableKind::Block | BreakableKind::Loop));
+    match label {
+        Some(_) => ctxs.find(|ctx| ctx.label.as_ref() == label),
+        None => ctxs.find(|ctx| matches!(ctx.kind, BreakableKind::Loop)),
+    }
+}
+
+fn find_continuable<'c>(
+    ctxs: &'c mut [BreakableContext],
+    label: Option<&name::Name>,
+) -> Option<&'c mut BreakableContext> {
     match label {
-        Some(_) => ctxs.iter_mut().rev().find(|ctx| ctx.label.as_ref() == label),
-        None => ctxs.last_mut(),
+        Some(_) => find_breakable(ctxs, label).filter(|it| matches!(it.kind, BreakableKind::Loop)),
+        None => find_breakable(ctxs, label),
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
index 2a13106390d..2d04a864a2c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
@@ -10,7 +10,7 @@ use chalk_ir::{
     cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind,
 };
 use hir_def::{
-    expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, Literal, Statement, UnaryOp},
+    expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, LabelId, Literal, Statement, UnaryOp},
     generics::TypeOrConstParamData,
     path::{GenericArg, GenericArgs},
     resolver::resolver_for_expr,
@@ -23,7 +23,7 @@ use syntax::ast::RangeOp;
 use crate::{
     autoderef::{self, Autoderef},
     consteval,
-    infer::coerce::CoerceMany,
+    infer::{coerce::CoerceMany, find_continuable, BreakableKind},
     lower::{
         const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode,
     },
@@ -120,32 +120,37 @@ impl<'a> InferenceContext<'a> {
                 let ty = match label {
                     Some(_) => {
                         let break_ty = self.table.new_type_var();
-                        self.breakables.push(BreakableContext {
-                            may_break: false,
-                            coerce: CoerceMany::new(break_ty.clone()),
-                            label: label.map(|label| self.body[label].name.clone()),
-                        });
-                        let ty = self.infer_block(
-                            tgt_expr,
-                            statements,
-                            *tail,
-                            &Expectation::has_type(break_ty),
+                        let (breaks, ty) = self.with_breakable_ctx(
+                            BreakableKind::Block,
+                            break_ty.clone(),
+                            *label,
+                            |this| {
+                                this.infer_block(
+                                    tgt_expr,
+                                    statements,
+                                    *tail,
+                                    &Expectation::has_type(break_ty),
+                                )
+                            },
                         );
-                        let ctxt = self.breakables.pop().expect("breakable stack broken");
-                        if ctxt.may_break {
-                            ctxt.coerce.complete()
-                        } else {
-                            ty
-                        }
+                        breaks.unwrap_or(ty)
                     }
                     None => self.infer_block(tgt_expr, statements, *tail, expected),
                 };
                 self.resolver = old_resolver;
                 ty
             }
-            Expr::Unsafe { body } | Expr::Const { body } => self.infer_expr(*body, expected),
+            Expr::Unsafe { body } => self.infer_expr(*body, expected),
+            Expr::Const { body } => {
+                self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
+                    this.infer_expr(*body, expected)
+                })
+                .1
+            }
             Expr::TryBlock { body } => {
-                let _inner = self.infer_expr(*body, expected);
+                self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
+                    let _inner = this.infer_expr(*body, expected);
+                });
                 // FIXME should be std::result::Result<{inner}, _>
                 self.err_ty()
             }
@@ -154,7 +159,10 @@ impl<'a> InferenceContext<'a> {
                 let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
                 let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
 
-                let inner_ty = self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
+                let (_, inner_ty) =
+                    self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
+                        this.infer_expr_coerce(*body, &Expectation::has_type(ret_ty))
+                    });
 
                 self.diverges = prev_diverges;
                 self.return_ty = prev_ret_ty;
@@ -166,54 +174,44 @@ impl<'a> InferenceContext<'a> {
                 TyKind::OpaqueType(opaque_ty_id, Substitution::from1(Interner, inner_ty))
                     .intern(Interner)
             }
-            Expr::Loop { body, label } => {
-                self.breakables.push(BreakableContext {
-                    may_break: false,
-                    coerce: CoerceMany::new(self.table.new_type_var()),
-                    label: label.map(|label| self.body[label].name.clone()),
-                });
-                self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit()));
-
-                let ctxt = self.breakables.pop().expect("breakable stack broken");
+            &Expr::Loop { body, label } => {
+                let ty = self.table.new_type_var();
+                let (breaks, ()) =
+                    self.with_breakable_ctx(BreakableKind::Loop, ty, label, |this| {
+                        this.infer_expr(body, &Expectation::has_type(TyBuilder::unit()));
+                    });
 
-                if ctxt.may_break {
-                    self.diverges = Diverges::Maybe;
-                    ctxt.coerce.complete()
-                } else {
-                    TyKind::Never.intern(Interner)
+                match breaks {
+                    Some(breaks) => {
+                        self.diverges = Diverges::Maybe;
+                        breaks
+                    }
+                    None => TyKind::Never.intern(Interner),
                 }
             }
-            Expr::While { condition, body, label } => {
-                self.breakables.push(BreakableContext {
-                    may_break: false,
-                    coerce: CoerceMany::new(self.err_ty()),
-                    label: label.map(|label| self.body[label].name.clone()),
+            &Expr::While { condition, body, label } => {
+                self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| {
+                    this.infer_expr(
+                        condition,
+                        &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
+                    );
+                    this.infer_expr(body, &Expectation::has_type(TyBuilder::unit()));
                 });
-                self.infer_expr(
-                    *condition,
-                    &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
-                );
-                self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit()));
-                let _ctxt = self.breakables.pop().expect("breakable stack broken");
+
                 // the body may not run, so it diverging doesn't mean we diverge
                 self.diverges = Diverges::Maybe;
                 TyBuilder::unit()
             }
-            Expr::For { iterable, body, pat, label } => {
-                let iterable_ty = self.infer_expr(*iterable, &Expectation::none());
-
-                self.breakables.push(BreakableContext {
-                    may_break: false,
-                    coerce: CoerceMany::new(self.err_ty()),
-                    label: label.map(|label| self.body[label].name.clone()),
-                });
+            &Expr::For { iterable, body, pat, label } => {
+                let iterable_ty = self.infer_expr(iterable, &Expectation::none());
                 let pat_ty =
                     self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item());
 
-                self.infer_pat(*pat, &pat_ty, BindingMode::default());
+                self.infer_pat(pat, &pat_ty, BindingMode::default());
+                self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| {
+                    this.infer_expr(body, &Expectation::has_type(TyBuilder::unit()));
+                });
 
-                self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit()));
-                let _ctxt = self.breakables.pop().expect("breakable stack broken");
                 // the body may not run, so it diverging doesn't mean we diverge
                 self.diverges = Diverges::Maybe;
                 TyBuilder::unit()
@@ -269,7 +267,9 @@ impl<'a> InferenceContext<'a> {
                 let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
                 let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
 
-                self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
+                self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
+                    this.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
+                });
 
                 self.diverges = prev_diverges;
                 self.return_ty = prev_ret_ty;
@@ -372,37 +372,45 @@ impl<'a> InferenceContext<'a> {
                 let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr);
                 self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or_else(|| self.err_ty())
             }
-            Expr::Continue { .. } => TyKind::Never.intern(Interner),
-            Expr::Break { expr, label } => {
-                let mut coerce = match find_breakable(&mut self.breakables, label.as_ref()) {
-                    Some(ctxt) => {
-                        // avoiding the borrowck
-                        mem::replace(
-                            &mut ctxt.coerce,
-                            CoerceMany::new(self.result.standard_types.unknown.clone()),
-                        )
-                    }
-                    None => CoerceMany::new(self.result.standard_types.unknown.clone()),
+            Expr::Continue { label } => {
+                if let None = find_continuable(&mut self.breakables, label.as_ref()) {
+                    self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
+                        expr: tgt_expr,
+                        is_break: false,
+                    });
                 };
-
+                TyKind::Never.intern(Interner)
+            }
+            Expr::Break { expr, label } => {
                 let val_ty = if let Some(expr) = *expr {
                     self.infer_expr(expr, &Expectation::none())
                 } else {
                     TyBuilder::unit()
                 };
 
-                // FIXME: create a synthetic `()` during lowering so we have something to refer to here?
-                coerce.coerce(self, *expr, &val_ty);
+                match find_breakable(&mut self.breakables, label.as_ref()) {
+                    Some(ctxt) => {
+                        // avoiding the borrowck
+                        let mut coerce = mem::replace(
+                            &mut ctxt.coerce,
+                            CoerceMany::new(self.result.standard_types.unknown.clone()),
+                        );
 
-                if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) {
-                    ctxt.coerce = coerce;
-                    ctxt.may_break = true;
-                } else {
-                    self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
-                        expr: tgt_expr,
-                    });
-                };
+                        // FIXME: create a synthetic `()` during lowering so we have something to refer to here?
+                        coerce.coerce(self, *expr, &val_ty);
 
+                        let ctxt = find_breakable(&mut self.breakables, label.as_ref())
+                            .expect("breakable stack changed during coercion");
+                        ctxt.coerce = coerce;
+                        ctxt.may_break = true;
+                    }
+                    None => {
+                        self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
+                            expr: tgt_expr,
+                            is_break: true,
+                        });
+                    }
+                }
                 TyKind::Never.intern(Interner)
             }
             Expr::Return { expr } => {
@@ -794,9 +802,6 @@ impl<'a> InferenceContext<'a> {
                     None => self.table.new_float_var(),
                 },
             },
-            Expr::MacroStmts { tail, statements } => {
-                self.infer_block(tgt_expr, statements, *tail, expected)
-            }
             Expr::Underscore => {
                 // Underscore expressions may only appear in assignee expressions,
                 // which are handled by `infer_assignee_expr()`, so any underscore
@@ -1475,4 +1480,20 @@ impl<'a> InferenceContext<'a> {
             },
         })
     }
+
+    fn with_breakable_ctx<T>(
+        &mut self,
+        kind: BreakableKind,
+        ty: Ty,
+        label: Option<LabelId>,
+        cb: impl FnOnce(&mut Self) -> T,
+    ) -> (Option<Ty>, T) {
+        self.breakables.push({
+            let label = label.map(|label| self.body[label].name.clone());
+            BreakableContext { kind, may_break: false, coerce: CoerceMany::new(ty), label }
+        });
+        let res = cb(self);
+        let ctx = self.breakables.pop().expect("breakable stack broken");
+        (ctx.may_break.then(|| ctx.coerce.complete()), res)
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs
new file mode 100644
index 00000000000..0c547192ac0
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs
@@ -0,0 +1,173 @@
+//! Type inhabitedness logic.
+use std::ops::ControlFlow::{self, Break, Continue};
+
+use chalk_ir::{
+    visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
+    DebruijnIndex,
+};
+use hir_def::{
+    adt::VariantData, attr::Attrs, type_ref::ConstScalar, visibility::Visibility, AdtId,
+    EnumVariantId, HasModule, Lookup, ModuleId, VariantId,
+};
+
+use crate::{
+    db::HirDatabase, Binders, ConcreteConst, Const, ConstValue, Interner, Substitution, Ty, TyKind,
+};
+
+/// Checks whether a type is visibly uninhabited from a particular module.
+pub(crate) fn is_ty_uninhabited_from(ty: &Ty, target_mod: ModuleId, db: &dyn HirDatabase) -> bool {
+    let mut uninhabited_from = UninhabitedFrom { target_mod, db };
+    let inhabitedness = ty.visit_with(&mut uninhabited_from, DebruijnIndex::INNERMOST);
+    inhabitedness == BREAK_VISIBLY_UNINHABITED
+}
+
+/// Checks whether a variant is visibly uninhabited from a particular module.
+pub(crate) fn is_enum_variant_uninhabited_from(
+    variant: EnumVariantId,
+    subst: &Substitution,
+    target_mod: ModuleId,
+    db: &dyn HirDatabase,
+) -> bool {
+    let enum_data = db.enum_data(variant.parent);
+    let vars_attrs = db.variants_attrs(variant.parent);
+    let is_local = variant.parent.lookup(db.upcast()).container.krate() == target_mod.krate();
+
+    let mut uninhabited_from = UninhabitedFrom { target_mod, db };
+    let inhabitedness = uninhabited_from.visit_variant(
+        variant.into(),
+        &enum_data.variants[variant.local_id].variant_data,
+        subst,
+        &vars_attrs[variant.local_id],
+        is_local,
+    );
+    inhabitedness == BREAK_VISIBLY_UNINHABITED
+}
+
+struct UninhabitedFrom<'a> {
+    target_mod: ModuleId,
+    db: &'a dyn HirDatabase,
+}
+
+const CONTINUE_OPAQUELY_INHABITED: ControlFlow<VisiblyUninhabited> = Continue(());
+const BREAK_VISIBLY_UNINHABITED: ControlFlow<VisiblyUninhabited> = Break(VisiblyUninhabited);
+#[derive(PartialEq, Eq)]
+struct VisiblyUninhabited;
+
+impl TypeVisitor<Interner> for UninhabitedFrom<'_> {
+    type BreakTy = VisiblyUninhabited;
+
+    fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = VisiblyUninhabited> {
+        self
+    }
+
+    fn visit_ty(
+        &mut self,
+        ty: &Ty,
+        outer_binder: DebruijnIndex,
+    ) -> ControlFlow<VisiblyUninhabited> {
+        match ty.kind(Interner) {
+            TyKind::Adt(adt, subst) => self.visit_adt(adt.0, subst),
+            TyKind::Never => BREAK_VISIBLY_UNINHABITED,
+            TyKind::Tuple(..) => ty.super_visit_with(self, outer_binder),
+            TyKind::Array(item_ty, len) => match try_usize_const(len) {
+                Some(0) | None => CONTINUE_OPAQUELY_INHABITED,
+                Some(1..) => item_ty.super_visit_with(self, outer_binder),
+            },
+
+            TyKind::Ref(..) | _ => CONTINUE_OPAQUELY_INHABITED,
+        }
+    }
+
+    fn interner(&self) -> Interner {
+        Interner
+    }
+}
+
+impl UninhabitedFrom<'_> {
+    fn visit_adt(&mut self, adt: AdtId, subst: &Substitution) -> ControlFlow<VisiblyUninhabited> {
+        let attrs = self.db.attrs(adt.into());
+        let adt_non_exhaustive = attrs.by_key("non_exhaustive").exists();
+        let is_local = adt.module(self.db.upcast()).krate() == self.target_mod.krate();
+        if adt_non_exhaustive && !is_local {
+            return CONTINUE_OPAQUELY_INHABITED;
+        }
+
+        // An ADT is uninhabited iff all its variants uninhabited.
+        match adt {
+            // rustc: For now, `union`s are never considered uninhabited.
+            AdtId::UnionId(_) => CONTINUE_OPAQUELY_INHABITED,
+            AdtId::StructId(s) => {
+                let struct_data = self.db.struct_data(s);
+                self.visit_variant(s.into(), &struct_data.variant_data, subst, &attrs, is_local)
+            }
+            AdtId::EnumId(e) => {
+                let vars_attrs = self.db.variants_attrs(e);
+                let enum_data = self.db.enum_data(e);
+
+                for (local_id, enum_var) in enum_data.variants.iter() {
+                    let variant_inhabitedness = self.visit_variant(
+                        EnumVariantId { parent: e, local_id }.into(),
+                        &enum_var.variant_data,
+                        subst,
+                        &vars_attrs[local_id],
+                        is_local,
+                    );
+                    match variant_inhabitedness {
+                        Break(VisiblyUninhabited) => continue,
+                        Continue(()) => return CONTINUE_OPAQUELY_INHABITED,
+                    }
+                }
+                BREAK_VISIBLY_UNINHABITED
+            }
+        }
+    }
+
+    fn visit_variant(
+        &mut self,
+        variant: VariantId,
+        variant_data: &VariantData,
+        subst: &Substitution,
+        attrs: &Attrs,
+        is_local: bool,
+    ) -> ControlFlow<VisiblyUninhabited> {
+        let non_exhaustive_field_list = attrs.by_key("non_exhaustive").exists();
+        if non_exhaustive_field_list && !is_local {
+            return CONTINUE_OPAQUELY_INHABITED;
+        }
+
+        let is_enum = matches!(variant, VariantId::EnumVariantId(..));
+        let field_tys = self.db.field_types(variant);
+        let field_vis = self.db.field_visibilities(variant);
+
+        for (fid, _) in variant_data.fields().iter() {
+            self.visit_field(field_vis[fid], &field_tys[fid], subst, is_enum)?;
+        }
+        CONTINUE_OPAQUELY_INHABITED
+    }
+
+    fn visit_field(
+        &mut self,
+        vis: Visibility,
+        ty: &Binders<Ty>,
+        subst: &Substitution,
+        is_enum: bool,
+    ) -> ControlFlow<VisiblyUninhabited> {
+        if is_enum || vis.is_visible_from(self.db.upcast(), self.target_mod) {
+            let ty = ty.clone().substitute(Interner, subst);
+            ty.visit_with(self, DebruijnIndex::INNERMOST)
+        } else {
+            CONTINUE_OPAQUELY_INHABITED
+        }
+    }
+}
+
+fn try_usize_const(c: &Const) -> Option<u128> {
+    let data = &c.data(Interner);
+    if data.ty.kind(Interner) != &TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)) {
+        return None;
+    }
+    match data.value {
+        ConstValue::Concrete(ConcreteConst { interned: ConstScalar::UInt(value) }) => Some(value),
+        _ => None,
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
index 5a5d610e360..a82a331d4b8 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
@@ -14,6 +14,7 @@ mod chalk_db;
 mod chalk_ext;
 pub mod consteval;
 mod infer;
+mod inhabitedness;
 mod interner;
 mod lower;
 mod mapping;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
index 3f6d0844e9c..4a37a794533 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -1,8 +1,8 @@
 //! Methods for lowering the HIR to types. There are two main cases here:
 //!
 //!  - Lowering a type reference like `&usize` or `Option<foo::bar::Baz>` to a
-//!    type: The entry point for this is `Ty::from_hir`.
-//!  - Building the type for an item: This happens through the `type_for_def` query.
+//!    type: The entry point for this is `TyLoweringContext::lower_ty`.
+//!  - Building the type for an item: This happens through the `ty` query.
 //!
 //! This usually involves resolving names, collecting generic arguments etc.
 use std::{
@@ -47,7 +47,7 @@ use crate::{
     consteval::{intern_const_scalar, path_to_const, unknown_const, unknown_const_as_generic},
     db::HirDatabase,
     make_binders,
-    mapping::ToChalk,
+    mapping::{from_chalk_trait_id, ToChalk},
     static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
     utils::Generics,
     utils::{all_super_trait_refs, associated_type_by_name_including_super_traits, generics},
@@ -332,7 +332,10 @@ impl<'a> TyLoweringContext<'a> {
             TypeRef::Macro(macro_call) => {
                 let (mut expander, recursion_start) = {
                     match RefMut::filter_map(self.expander.borrow_mut(), Option::as_mut) {
+                        // There already is an expander here, this means we are already recursing
                         Ok(expander) => (expander, false),
+                        // No expander was created yet, so we are at the start of the expansion recursion
+                        // and therefore have to create an expander.
                         Err(expander) => (
                             RefMut::map(expander, |it| {
                                 it.insert(Expander::new(
@@ -362,9 +365,14 @@ impl<'a> TyLoweringContext<'a> {
                                 .exit(self.db.upcast(), mark);
                             Some(ty)
                         }
-                        _ => None,
+                        _ => {
+                            drop(expander);
+                            None
+                        }
                     }
                 };
+
+                // drop the expander, resetting it to pre-recursion state
                 if recursion_start {
                     *self.expander.borrow_mut() = None;
                 }
@@ -974,13 +982,44 @@ impl<'a> TyLoweringContext<'a> {
     fn lower_dyn_trait(&self, bounds: &[Interned<TypeBound>]) -> Ty {
         let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
         let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
-            QuantifiedWhereClauses::from_iter(
+            let bounds =
+                bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false));
+
+            let mut auto_traits = SmallVec::<[_; 8]>::new();
+            let mut regular_traits = SmallVec::<[_; 2]>::new();
+            let mut other_bounds = SmallVec::<[_; 8]>::new();
+            for bound in bounds {
+                if let Some(id) = bound.trait_id() {
+                    if ctx.db.trait_data(from_chalk_trait_id(id)).is_auto {
+                        auto_traits.push(bound);
+                    } else {
+                        regular_traits.push(bound);
+                    }
+                } else {
+                    other_bounds.push(bound);
+                }
+            }
+
+            if regular_traits.len() > 1 {
+                return None;
+            }
+
+            auto_traits.sort_unstable_by_key(|b| b.trait_id().unwrap());
+            auto_traits.dedup();
+
+            Some(QuantifiedWhereClauses::from_iter(
                 Interner,
-                bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)),
-            )
+                regular_traits.into_iter().chain(other_bounds).chain(auto_traits),
+            ))
         });
-        let bounds = crate::make_single_type_binders(bounds);
-        TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
+
+        if let Some(bounds) = bounds {
+            let bounds = crate::make_single_type_binders(bounds);
+            TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
+        } else {
+            // FIXME: report error (additional non-auto traits)
+            TyKind::Error.intern(Interner)
+        }
     }
 
     fn lower_impl_trait(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs
index a1ab6060e79..b3adafaafd3 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs
@@ -193,8 +193,6 @@ fn expr_macro_def_expanded_in_various_places() {
             !0..6 '1isize': isize
             !0..6 '1isize': isize
             !0..6 '1isize': isize
-            !0..6 '1isize': isize
-            !0..6 '1isize': isize
             39..442 '{     ...!(); }': ()
             73..94 'spam!(...am!())': {unknown}
             100..119 'for _ ...!() {}': ()
@@ -276,8 +274,6 @@ fn expr_macro_rules_expanded_in_various_places() {
             !0..6 '1isize': isize
             !0..6 '1isize': isize
             !0..6 '1isize': isize
-            !0..6 '1isize': isize
-            !0..6 '1isize': isize
             53..456 '{     ...!(); }': ()
             87..108 'spam!(...am!())': {unknown}
             114..133 'for _ ...!() {}': ()
@@ -312,7 +308,6 @@ fn expr_macro_expanded_in_stmts() {
         }
         "#,
         expect![[r#"
-            !0..8 'leta=();': ()
             !3..4 'a': ()
             !5..7 '()': ()
             57..84 '{     ...); } }': ()
@@ -321,7 +316,7 @@ fn expr_macro_expanded_in_stmts() {
 }
 
 #[test]
-fn recurisve_macro_expanded_in_stmts() {
+fn recursive_macro_expanded_in_stmts() {
     check_infer(
         r#"
         macro_rules! ng {
@@ -340,11 +335,6 @@ fn recurisve_macro_expanded_in_stmts() {
         }
         "#,
         expect![[r#"
-            !0..7 'leta=3;': ()
-            !0..13 'ng!{[leta=3]}': ()
-            !0..13 'ng!{[leta=]3}': ()
-            !0..13 'ng!{[leta]=3}': ()
-            !0..13 'ng!{[let]a=3}': ()
             !3..4 'a': i32
             !5..6 '3': i32
             196..237 '{     ...= a; }': ()
@@ -369,8 +359,6 @@ fn recursive_inner_item_macro_rules() {
         "#,
         expect![[r#"
             !0..1 '1': i32
-            !0..7 'mac!($)': ()
-            !0..26 'macro_...>{1};}': ()
             107..143 '{     ...!(); }': ()
             129..130 'a': i32
         "#]],
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
index c7895db1afb..23e51a9c16a 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
@@ -573,7 +573,6 @@ fn issue_6811() {
         }
         "#,
         expect![[r#"
-            !0..16 'let_a=...t_b=1;': ()
             !3..5 '_a': i32
             !6..7 '1': i32
             !11..13 '_b': i32
@@ -1679,7 +1678,6 @@ fn main() {
 
 #[test]
 fn trailing_empty_macro() {
-    cov_mark::check!(empty_macro_in_trailing_position_is_removed);
     check_no_mismatches(
         r#"
 macro_rules! m2 {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
index 5b08f552109..4ea103e5d9e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
@@ -2549,7 +2549,6 @@ impl B for Astruct {}
         expect![[r#"
             569..573 'self': Box<[T], A>
             602..634 '{     ...     }': Vec<T, A>
-            612..628 'unimpl...ted!()': Vec<T, A>
             648..761 '{     ...t]); }': ()
             658..661 'vec': Vec<i32, Global>
             664..679 '<[_]>::into_vec': fn into_vec<i32, Global>(Box<[i32], Global>) -> Vec<i32, Global>
@@ -3070,3 +3069,17 @@ fn main() {
         "#,
     );
 }
+
+#[test]
+fn nested_break() {
+    check_no_mismatches(
+        r#"
+fn func() {
+    let int = loop {
+        break 0;
+        break (break 0);
+    };
+}
+    "#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
index 0f37970e2b3..e67c27aa2db 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
@@ -3833,3 +3833,95 @@ fn test() {
 "#,
     )
 }
+
+#[test]
+fn dyn_multiple_auto_traits_in_different_order() {
+    check_no_mismatches(
+        r#"
+auto trait Send {}
+auto trait Sync {}
+
+fn f(t: &(dyn Sync + Send)) {}
+fn g(t: &(dyn Send + Sync)) {
+    f(t);
+}
+        "#,
+    );
+
+    check_no_mismatches(
+        r#"
+auto trait Send {}
+auto trait Sync {}
+trait T {}
+
+fn f(t: &(dyn T + Send + Sync)) {}
+fn g(t: &(dyn Sync + T + Send)) {
+    f(t);
+}
+        "#,
+    );
+
+    check_infer_with_mismatches(
+        r#"
+auto trait Send {}
+auto trait Sync {}
+trait T1 {}
+trait T2 {}
+
+fn f(t: &(dyn T1 + T2 + Send + Sync)) {}
+fn g(t: &(dyn Sync + T2 + T1 + Send)) {
+    f(t);
+}
+        "#,
+        expect![[r#"
+            68..69 't': &{unknown}
+            101..103 '{}': ()
+            109..110 't': &{unknown}
+            142..155 '{     f(t); }': ()
+            148..149 'f': fn f(&{unknown})
+            148..152 'f(t)': ()
+            150..151 't': &{unknown}
+        "#]],
+    );
+
+    check_no_mismatches(
+        r#"
+auto trait Send {}
+auto trait Sync {}
+trait T {
+    type Proj: Send + Sync;
+}
+
+fn f(t: &(dyn T<Proj = ()>  + Send + Sync)) {}
+fn g(t: &(dyn Sync + T<Proj = ()> + Send)) {
+    f(t);
+}
+        "#,
+    );
+}
+
+#[test]
+fn dyn_duplicate_auto_trait() {
+    check_no_mismatches(
+        r#"
+auto trait Send {}
+
+fn f(t: &(dyn Send + Send)) {}
+fn g(t: &(dyn Send)) {
+    f(t);
+}
+        "#,
+    );
+
+    check_no_mismatches(
+        r#"
+auto trait Send {}
+trait T {}
+
+fn f(t: &(dyn T + Send + Send)) {}
+fn g(t: &(dyn T + Send)) {
+    f(t);
+}
+        "#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
index 50374f4b3fe..5edc16d8bce 100644
--- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
@@ -124,6 +124,7 @@ pub struct NoSuchField {
 #[derive(Debug)]
 pub struct BreakOutsideOfLoop {
     pub expr: InFile<AstPtr<ast::Expr>>,
+    pub is_break: bool,
 }
 
 #[derive(Debug)]
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index 6dccf2ed20b..e4bb63a8647 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -1216,11 +1216,11 @@ impl DefWithBody {
                     let field = source_map.field_syntax(*expr);
                     acc.push(NoSuchField { field }.into())
                 }
-                hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr } => {
+                &hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break } => {
                     let expr = source_map
-                        .expr_syntax(*expr)
+                        .expr_syntax(expr)
                         .expect("break outside of loop in synthetic syntax");
-                    acc.push(BreakOutsideOfLoop { expr }.into())
+                    acc.push(BreakOutsideOfLoop { expr, is_break }.into())
                 }
                 hir_ty::InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
                     match source_map.expr_syntax(*call_expr) {
diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
index bd35af06e23..342912b678a 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -140,11 +140,19 @@ impl SourceAnalyzer {
     ) -> Option<InFile<ast::Expr>> {
         let macro_file = self.body_source_map()?.node_macro_file(expr.as_ref())?;
         let expanded = db.parse_or_expand(macro_file)?;
-
-        let res = match ast::MacroCall::cast(expanded.clone()) {
-            Some(call) => self.expand_expr(db, InFile::new(macro_file, call))?,
-            _ => InFile::new(macro_file, ast::Expr::cast(expanded)?),
+        let res = if let Some(stmts) = ast::MacroStmts::cast(expanded.clone()) {
+            match stmts.expr()? {
+                ast::Expr::MacroExpr(mac) => {
+                    self.expand_expr(db, InFile::new(macro_file, mac.macro_call()?))?
+                }
+                expr => InFile::new(macro_file, expr),
+            }
+        } else if let Some(call) = ast::MacroCall::cast(expanded.clone()) {
+            self.expand_expr(db, InFile::new(macro_file, call))?
+        } else {
+            InFile::new(macro_file, ast::Expr::cast(expanded)?)
         };
+
         Some(res)
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs
new file mode 100644
index 00000000000..54a7f480a4e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs
@@ -0,0 +1,294 @@
+use syntax::ast::{self, AstNode};
+
+use crate::{AssistContext, AssistId, AssistKind, Assists};
+
+// Assist: convert_two_arm_bool_match_to_matches_macro
+//
+// Convert 2-arm match that evaluates to a boolean into the equivalent matches! invocation.
+//
+// ```
+// fn main() {
+//     match scrutinee$0 {
+//         Some(val) if val.cond() => true,
+//         _ => false,
+//     }
+// }
+// ```
+// ->
+// ```
+// fn main() {
+//     matches!(scrutinee, Some(val) if val.cond())
+// }
+// ```
+pub(crate) fn convert_two_arm_bool_match_to_matches_macro(
+    acc: &mut Assists,
+    ctx: &AssistContext<'_>,
+) -> Option<()> {
+    let match_expr = ctx.find_node_at_offset::<ast::MatchExpr>()?;
+    let match_arm_list = match_expr.match_arm_list()?;
+    let mut arms = match_arm_list.arms();
+    let first_arm = arms.next()?;
+    let second_arm = arms.next()?;
+    if arms.next().is_some() {
+        cov_mark::hit!(non_two_arm_match);
+        return None;
+    }
+    let first_arm_expr = first_arm.expr();
+    let second_arm_expr = second_arm.expr();
+
+    let invert_matches = if is_bool_literal_expr(&first_arm_expr, true)
+        && is_bool_literal_expr(&second_arm_expr, false)
+    {
+        false
+    } else if is_bool_literal_expr(&first_arm_expr, false)
+        && is_bool_literal_expr(&second_arm_expr, true)
+    {
+        true
+    } else {
+        cov_mark::hit!(non_invert_bool_literal_arms);
+        return None;
+    };
+
+    let target_range = ctx.sema.original_range(match_expr.syntax()).range;
+    let expr = match_expr.expr()?;
+
+    acc.add(
+        AssistId("convert_two_arm_bool_match_to_matches_macro", AssistKind::RefactorRewrite),
+        "Convert to matches!",
+        target_range,
+        |builder| {
+            let mut arm_str = String::new();
+            if let Some(ref pat) = first_arm.pat() {
+                arm_str += &pat.to_string();
+            }
+            if let Some(ref guard) = first_arm.guard() {
+                arm_str += &format!(" {}", &guard.to_string());
+            }
+            if invert_matches {
+                builder.replace(target_range, format!("!matches!({}, {})", expr, arm_str));
+            } else {
+                builder.replace(target_range, format!("matches!({}, {})", expr, arm_str));
+            }
+        },
+    )
+}
+
+fn is_bool_literal_expr(expr: &Option<ast::Expr>, expect_bool: bool) -> bool {
+    if let Some(ast::Expr::Literal(lit)) = expr {
+        if let ast::LiteralKind::Bool(b) = lit.kind() {
+            return b == expect_bool;
+        }
+    }
+
+    return false;
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
+
+    use super::convert_two_arm_bool_match_to_matches_macro;
+
+    #[test]
+    fn not_applicable_outside_of_range_left() {
+        check_assist_not_applicable(
+            convert_two_arm_bool_match_to_matches_macro,
+            r#"
+fn foo(a: Option<u32>) -> bool {
+    $0 match a {
+        Some(_val) => true,
+        _ => false
+    }
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn not_applicable_non_two_arm_match() {
+        cov_mark::check!(non_two_arm_match);
+        check_assist_not_applicable(
+            convert_two_arm_bool_match_to_matches_macro,
+            r#"
+fn foo(a: Option<u32>) -> bool {
+    match a$0 {
+        Some(3) => true,
+        Some(4) => true,
+        _ => false
+    }
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn not_applicable_non_bool_literal_arms() {
+        cov_mark::check!(non_invert_bool_literal_arms);
+        check_assist_not_applicable(
+            convert_two_arm_bool_match_to_matches_macro,
+            r#"
+fn foo(a: Option<u32>) -> bool {
+    match a$0 {
+        Some(val) => val == 3,
+        _ => false
+    }
+}
+        "#,
+        );
+    }
+    #[test]
+    fn not_applicable_both_false_arms() {
+        cov_mark::check!(non_invert_bool_literal_arms);
+        check_assist_not_applicable(
+            convert_two_arm_bool_match_to_matches_macro,
+            r#"
+fn foo(a: Option<u32>) -> bool {
+    match a$0 {
+        Some(val) => false,
+        _ => false
+    }
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn not_applicable_both_true_arms() {
+        cov_mark::check!(non_invert_bool_literal_arms);
+        check_assist_not_applicable(
+            convert_two_arm_bool_match_to_matches_macro,
+            r#"
+fn foo(a: Option<u32>) -> bool {
+    match a$0 {
+        Some(val) => true,
+        _ => true
+    }
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn convert_simple_case() {
+        check_assist(
+            convert_two_arm_bool_match_to_matches_macro,
+            r#"
+fn foo(a: Option<u32>) -> bool {
+    match a$0 {
+        Some(_val) => true,
+        _ => false
+    }
+}
+"#,
+            r#"
+fn foo(a: Option<u32>) -> bool {
+    matches!(a, Some(_val))
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn convert_simple_invert_case() {
+        check_assist(
+            convert_two_arm_bool_match_to_matches_macro,
+            r#"
+fn foo(a: Option<u32>) -> bool {
+    match a$0 {
+        Some(_val) => false,
+        _ => true
+    }
+}
+"#,
+            r#"
+fn foo(a: Option<u32>) -> bool {
+    !matches!(a, Some(_val))
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn convert_with_guard_case() {
+        check_assist(
+            convert_two_arm_bool_match_to_matches_macro,
+            r#"
+fn foo(a: Option<u32>) -> bool {
+    match a$0 {
+        Some(val) if val > 3 => true,
+        _ => false
+    }
+}
+"#,
+            r#"
+fn foo(a: Option<u32>) -> bool {
+    matches!(a, Some(val) if val > 3)
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn convert_enum_match_cases() {
+        check_assist(
+            convert_two_arm_bool_match_to_matches_macro,
+            r#"
+enum X { A, B }
+
+fn foo(a: X) -> bool {
+    match a$0 {
+        X::A => true,
+        _ => false
+    }
+}
+"#,
+            r#"
+enum X { A, B }
+
+fn foo(a: X) -> bool {
+    matches!(a, X::A)
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn convert_target_simple() {
+        check_assist_target(
+            convert_two_arm_bool_match_to_matches_macro,
+            r#"
+fn foo(a: Option<u32>) -> bool {
+    match a$0 {
+        Some(val) => true,
+        _ => false
+    }
+}
+"#,
+            r#"match a {
+        Some(val) => true,
+        _ => false
+    }"#,
+        );
+    }
+
+    #[test]
+    fn convert_target_complex() {
+        check_assist_target(
+            convert_two_arm_bool_match_to_matches_macro,
+            r#"
+enum E { X, Y }
+
+fn main() {
+    match E::X$0 {
+        E::X => true,
+        _ => false,
+    }
+}
+"#,
+            "match E::X {
+        E::X => true,
+        _ => false,
+    }",
+        );
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
index dfb56521264..ddc2052e7aa 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -101,21 +101,22 @@ pub(crate) fn extract_struct_from_enum_variant(
                 });
             }
 
-            let indent = enum_ast.indent_level();
             let generic_params = enum_ast
                 .generic_param_list()
                 .and_then(|known_generics| extract_generic_params(&known_generics, &field_list));
             let generics = generic_params.as_ref().map(|generics| generics.clone_for_update());
             let def =
                 create_struct_def(variant_name.clone(), &variant, &field_list, generics, &enum_ast);
+
+            let enum_ast = variant.parent_enum();
+            let indent = enum_ast.indent_level();
             def.reindent_to(indent);
 
-            let start_offset = &variant.parent_enum().syntax().clone();
-            ted::insert_all_raw(
-                ted::Position::before(start_offset),
+            ted::insert_all(
+                ted::Position::before(enum_ast.syntax()),
                 vec![
                     def.syntax().clone().into(),
-                    make::tokens::whitespace(&format!("\n\n{}", indent)).into(),
+                    make::tokens::whitespace(&format!("\n\n{indent}")).into(),
                 ],
             );
 
@@ -227,7 +228,7 @@ fn tag_generics_in_variant(ty: &ast::Type, generics: &mut [(ast::GenericParam, b
 }
 
 fn create_struct_def(
-    variant_name: ast::Name,
+    name: ast::Name,
     variant: &ast::Variant,
     field_list: &Either<ast::RecordFieldList, ast::TupleFieldList>,
     generics: Option<ast::GenericParamList>,
@@ -269,43 +270,27 @@ fn create_struct_def(
             field_list.into()
         }
     };
-
     field_list.reindent_to(IndentLevel::single());
 
-    let strukt = make::struct_(enum_vis, variant_name, generics, field_list).clone_for_update();
-
-    // FIXME: Consider making this an actual function somewhere (like in `AttrsOwnerEdit`) after some deliberation
-    let attrs_and_docs = |node: &SyntaxNode| {
-        let mut select_next_ws = false;
-        node.children_with_tokens().filter(move |child| {
-            let accept = match child.kind() {
-                ATTR | COMMENT => {
-                    select_next_ws = true;
-                    return true;
-                }
-                WHITESPACE if select_next_ws => true,
-                _ => false,
-            };
-            select_next_ws = false;
-
-            accept
-        })
-    };
+    let strukt = make::struct_(enum_vis, name, generics, field_list).clone_for_update();
 
-    // copy attributes & comments from variant
-    let variant_attrs = attrs_and_docs(variant.syntax())
-        .map(|tok| match tok.kind() {
-            WHITESPACE => make::tokens::single_newline().into(),
-            _ => tok,
-        })
-        .collect();
-    ted::insert_all(ted::Position::first_child_of(strukt.syntax()), variant_attrs);
+    // take comments from variant
+    ted::insert_all(
+        ted::Position::first_child_of(strukt.syntax()),
+        take_all_comments(variant.syntax()),
+    );
 
     // copy attributes from enum
     ted::insert_all(
         ted::Position::first_child_of(strukt.syntax()),
-        enum_.attrs().map(|it| it.syntax().clone_for_update().into()).collect(),
+        enum_
+            .attrs()
+            .flat_map(|it| {
+                vec![it.syntax().clone_for_update().into(), make::tokens::single_newline().into()]
+            })
+            .collect(),
     );
+
     strukt
 }
 
@@ -346,16 +331,48 @@ fn update_variant(variant: &ast::Variant, generics: Option<ast::GenericParamList
         })
         .unwrap_or_else(|| make::ty(&name.text()));
 
+    // change from a record to a tuple field list
     let tuple_field = make::tuple_field(None, ty);
-    let replacement = make::variant(
-        name,
-        Some(ast::FieldList::TupleFieldList(make::tuple_field_list(iter::once(tuple_field)))),
-    )
-    .clone_for_update();
-    ted::replace(variant.syntax(), replacement.syntax());
+    let field_list = make::tuple_field_list(iter::once(tuple_field)).clone_for_update();
+    ted::replace(variant.field_list()?.syntax(), field_list.syntax());
+
+    // remove any ws after the name
+    if let Some(ws) = name
+        .syntax()
+        .siblings_with_tokens(syntax::Direction::Next)
+        .find_map(|tok| tok.into_token().filter(|tok| tok.kind() == WHITESPACE))
+    {
+        ted::remove(SyntaxElement::Token(ws));
+    }
+
     Some(())
 }
 
+// Note: this also detaches whitespace after comments,
+// since `SyntaxNode::splice_children` (and by extension `ted::insert_all_raw`)
+// detaches nodes. If we only took the comments, we'd leave behind the old whitespace.
+fn take_all_comments(node: &SyntaxNode) -> Vec<SyntaxElement> {
+    let mut remove_next_ws = false;
+    node.children_with_tokens()
+        .filter_map(move |child| match child.kind() {
+            COMMENT => {
+                remove_next_ws = true;
+                child.detach();
+                Some(child)
+            }
+            WHITESPACE if remove_next_ws => {
+                remove_next_ws = false;
+                child.detach();
+                Some(make::tokens::single_newline().into())
+            }
+            _ => {
+                remove_next_ws = false;
+                None
+            }
+        })
+        .collect()
+}
+
 fn apply_references(
     insert_use_cfg: InsertUseConfig,
     segment: ast::PathSegment,
@@ -480,10 +497,14 @@ enum En<T> { Var(Var<T>) }"#,
     fn test_extract_struct_carries_over_attributes() {
         check_assist(
             extract_struct_from_enum_variant,
-            r#"#[derive(Debug)]
+            r#"
+#[derive(Debug)]
 #[derive(Clone)]
 enum Enum { Variant{ field: u32$0 } }"#,
-            r#"#[derive(Debug)]#[derive(Clone)] struct Variant{ field: u32 }
+            r#"
+#[derive(Debug)]
+#[derive(Clone)]
+struct Variant{ field: u32 }
 
 #[derive(Debug)]
 #[derive(Clone)]
@@ -614,7 +635,7 @@ enum A { One(One) }"#,
     }
 
     #[test]
-    fn test_extract_struct_keep_comments_and_attrs_on_variant_struct() {
+    fn test_extract_struct_move_struct_variant_comments() {
         check_assist(
             extract_struct_from_enum_variant,
             r#"
@@ -631,19 +652,19 @@ enum A {
 /* comment */
 // other
 /// comment
-#[attr]
 struct One{
     a: u32
 }
 
 enum A {
+    #[attr]
     One(One)
 }"#,
         );
     }
 
     #[test]
-    fn test_extract_struct_keep_comments_and_attrs_on_variant_tuple() {
+    fn test_extract_struct_move_tuple_variant_comments() {
         check_assist(
             extract_struct_from_enum_variant,
             r#"
@@ -658,10 +679,10 @@ enum A {
 /* comment */
 // other
 /// comment
-#[attr]
 struct One(u32, u32);
 
 enum A {
+    #[attr]
     One(One)
 }"#,
         );
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_or_with_or_else.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_or_with_or_else.rs
new file mode 100644
index 00000000000..7d91be62101
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_or_with_or_else.rs
@@ -0,0 +1,364 @@
+use ide_db::{
+    assists::{AssistId, AssistKind},
+    famous_defs::FamousDefs,
+};
+use syntax::{
+    ast::{self, make, Expr, HasArgList},
+    AstNode,
+};
+
+use crate::{AssistContext, Assists};
+
+// Assist: replace_or_with_or_else
+//
+// Replace `unwrap_or` with `unwrap_or_else` and `ok_or` with `ok_or_else`.
+//
+// ```
+// # //- minicore:option
+// fn foo() {
+//     let a = Some(1);
+//     a.unwra$0p_or(2);
+// }
+// ```
+// ->
+// ```
+// fn foo() {
+//     let a = Some(1);
+//     a.unwrap_or_else(|| 2);
+// }
+// ```
+pub(crate) fn replace_or_with_or_else(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+    let call: ast::MethodCallExpr = ctx.find_node_at_offset()?;
+
+    let kind = is_option_or_result(call.receiver()?, ctx)?;
+
+    let (name, arg_list) = (call.name_ref()?, call.arg_list()?);
+
+    let mut map_or = false;
+
+    let replace = match &*name.text() {
+        "unwrap_or" => "unwrap_or_else".to_string(),
+        "or" => "or_else".to_string(),
+        "ok_or" if kind == Kind::Option => "ok_or_else".to_string(),
+        "map_or" => {
+            map_or = true;
+            "map_or_else".to_string()
+        }
+        _ => return None,
+    };
+
+    let arg = match arg_list.args().collect::<Vec<_>>().as_slice() {
+        [] => make::arg_list(Vec::new()),
+        [first] => {
+            let param = into_closure(first);
+            make::arg_list(vec![param])
+        }
+        [first, second] if map_or => {
+            let param = into_closure(first);
+            make::arg_list(vec![param, second.clone()])
+        }
+        _ => return None,
+    };
+
+    acc.add(
+        AssistId("replace_or_with_or_else", AssistKind::RefactorRewrite),
+        format!("Replace {} with {}", name.text(), replace),
+        call.syntax().text_range(),
+        |builder| {
+            builder.replace(name.syntax().text_range(), replace);
+            builder.replace_ast(arg_list, arg)
+        },
+    )
+}
+
+fn into_closure(param: &Expr) -> Expr {
+    (|| {
+        if let ast::Expr::CallExpr(call) = param {
+            if call.arg_list()?.args().count() == 0 {
+                Some(call.expr()?.clone())
+            } else {
+                None
+            }
+        } else {
+            None
+        }
+    })()
+    .unwrap_or_else(|| make::expr_closure(None, param.clone()))
+}
+
+// Assist: replace_or_else_with_or
+//
+// Replace `unwrap_or_else` with `unwrap_or` and `ok_or_else` with `ok_or`.
+//
+// ```
+// # //- minicore:option
+// fn foo() {
+//     let a = Some(1);
+//     a.unwra$0p_or_else(|| 2);
+// }
+// ```
+// ->
+// ```
+// fn foo() {
+//     let a = Some(1);
+//     a.unwrap_or(2);
+// }
+// ```
+pub(crate) fn replace_or_else_with_or(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+    let call: ast::MethodCallExpr = ctx.find_node_at_offset()?;
+
+    let kind = is_option_or_result(call.receiver()?, ctx)?;
+
+    let (name, arg_list) = (call.name_ref()?, call.arg_list()?);
+
+    let mut map_or = false;
+    let replace = match &*name.text() {
+        "unwrap_or_else" => "unwrap_or".to_string(),
+        "or_else" => "or".to_string(),
+        "ok_or_else" if kind == Kind::Option => "ok_or".to_string(),
+        "map_or_else" => {
+            map_or = true;
+            "map_or".to_string()
+        }
+        _ => return None,
+    };
+
+    let arg = match arg_list.args().collect::<Vec<_>>().as_slice() {
+        [] => make::arg_list(Vec::new()),
+        [first] => {
+            let param = into_call(first);
+            make::arg_list(vec![param])
+        }
+        [first, second] if map_or => {
+            let param = into_call(first);
+            make::arg_list(vec![param, second.clone()])
+        }
+        _ => return None,
+    };
+
+    acc.add(
+        AssistId("replace_or_else_with_or", AssistKind::RefactorRewrite),
+        format!("Replace {} with {}", name.text(), replace),
+        call.syntax().text_range(),
+        |builder| {
+            builder.replace(name.syntax().text_range(), replace);
+            builder.replace_ast(arg_list, arg)
+        },
+    )
+}
+
+fn into_call(param: &Expr) -> Expr {
+    (|| {
+        if let ast::Expr::ClosureExpr(closure) = param {
+            if closure.param_list()?.params().count() == 0 {
+                Some(closure.body()?.clone())
+            } else {
+                None
+            }
+        } else {
+            None
+        }
+    })()
+    .unwrap_or_else(|| make::expr_call(param.clone(), make::arg_list(Vec::new())))
+}
+
+#[derive(PartialEq, Eq)]
+enum Kind {
+    Option,
+    Result,
+}
+
+fn is_option_or_result(receiver: Expr, ctx: &AssistContext<'_>) -> Option<Kind> {
+    let ty = ctx.sema.type_of_expr(&receiver)?.adjusted().as_adt()?.as_enum()?;
+    let option_enum =
+        FamousDefs(&ctx.sema, ctx.sema.scope(receiver.syntax())?.krate()).core_option_Option();
+
+    if let Some(option_enum) = option_enum {
+        if ty == option_enum {
+            return Some(Kind::Option);
+        }
+    }
+
+    let result_enum =
+        FamousDefs(&ctx.sema, ctx.sema.scope(receiver.syntax())?.krate()).core_result_Result();
+
+    if let Some(result_enum) = result_enum {
+        if ty == result_enum {
+            return Some(Kind::Result);
+        }
+    }
+
+    None
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::{check_assist, check_assist_not_applicable};
+
+    use super::*;
+
+    #[test]
+    fn replace_or_with_or_else_simple() {
+        check_assist(
+            replace_or_with_or_else,
+            r#"
+//- minicore: option
+fn foo() {
+    let foo = Some(1);
+    return foo.unwrap_$0or(2);
+}
+"#,
+            r#"
+fn foo() {
+    let foo = Some(1);
+    return foo.unwrap_or_else(|| 2);
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn replace_or_with_or_else_call() {
+        check_assist(
+            replace_or_with_or_else,
+            r#"
+//- minicore: option
+fn foo() {
+    let foo = Some(1);
+    return foo.unwrap_$0or(x());
+}
+"#,
+            r#"
+fn foo() {
+    let foo = Some(1);
+    return foo.unwrap_or_else(x);
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn replace_or_with_or_else_block() {
+        check_assist(
+            replace_or_with_or_else,
+            r#"
+//- minicore: option
+fn foo() {
+    let foo = Some(1);
+    return foo.unwrap_$0or({
+        let mut x = bar();
+        for i in 0..10 {
+            x += i;
+        }
+        x
+    });
+}
+"#,
+            r#"
+fn foo() {
+    let foo = Some(1);
+    return foo.unwrap_or_else(|| {
+        let mut x = bar();
+        for i in 0..10 {
+            x += i;
+        }
+        x
+    });
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn replace_or_else_with_or_simple() {
+        check_assist(
+            replace_or_else_with_or,
+            r#"
+//- minicore: option
+fn foo() {
+    let foo = Some(1);
+    return foo.unwrap_$0or_else(|| 2);
+}
+"#,
+            r#"
+fn foo() {
+    let foo = Some(1);
+    return foo.unwrap_or(2);
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn replace_or_else_with_or_call() {
+        check_assist(
+            replace_or_else_with_or,
+            r#"
+//- minicore: option
+fn foo() {
+    let foo = Some(1);
+    return foo.unwrap_$0or_else(x);
+}
+"#,
+            r#"
+fn foo() {
+    let foo = Some(1);
+    return foo.unwrap_or(x());
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn replace_or_else_with_or_result() {
+        check_assist(
+            replace_or_else_with_or,
+            r#"
+//- minicore: result
+fn foo() {
+    let foo = Ok(1);
+    return foo.unwrap_$0or_else(x);
+}
+"#,
+            r#"
+fn foo() {
+    let foo = Ok(1);
+    return foo.unwrap_or(x());
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn replace_or_else_with_or_map() {
+        check_assist(
+            replace_or_else_with_or,
+            r#"
+//- minicore: result
+fn foo() {
+    let foo = Ok("foo");
+    return foo.map$0_or_else(|| 42, |v| v.len());
+}
+"#,
+            r#"
+fn foo() {
+    let foo = Ok("foo");
+    return foo.map_or(42, |v| v.len());
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn replace_or_else_with_or_not_applicable() {
+        check_assist_not_applicable(
+            replace_or_else_with_or,
+            r#"
+fn foo() {
+    let foo = Ok(1);
+    return foo.unwrap_$0or_else(x);
+}
+"#,
+        )
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs
index 5242f3b5100..521447c26df 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs
@@ -1,5 +1,6 @@
+use hir::HirDisplay;
 use syntax::{
-    ast::{Expr, GenericArg},
+    ast::{Expr, GenericArg, GenericArgList},
     ast::{LetStmt, Type::InferType},
     AstNode, TextRange,
 };
@@ -34,21 +35,7 @@ pub(crate) fn replace_turbofish_with_explicit_type(
 
     let initializer = let_stmt.initializer()?;
 
-    let generic_args = match &initializer {
-        Expr::MethodCallExpr(ce) => ce.generic_arg_list()?,
-        Expr::CallExpr(ce) => {
-            if let Expr::PathExpr(pe) = ce.expr()? {
-                pe.path()?.segment()?.generic_arg_list()?
-            } else {
-                cov_mark::hit!(not_applicable_if_non_path_function_call);
-                return None;
-            }
-        }
-        _ => {
-            cov_mark::hit!(not_applicable_if_non_function_call_initializer);
-            return None;
-        }
-    };
+    let generic_args = generic_arg_list(&initializer)?;
 
     // Find range of ::<_>
     let colon2 = generic_args.coloncolon_token()?;
@@ -65,7 +52,16 @@ pub(crate) fn replace_turbofish_with_explicit_type(
 
     // An improvement would be to check that this is correctly part of the return value of the
     // function call, or sub in the actual return type.
-    let turbofish_type = &turbofish_args[0];
+    let returned_type = match ctx.sema.type_of_expr(&initializer) {
+        Some(returned_type) if !returned_type.original.contains_unknown() => {
+            let module = ctx.sema.scope(let_stmt.syntax())?.module();
+            returned_type.original.display_source_code(ctx.db(), module.into()).ok()?
+        }
+        _ => {
+            cov_mark::hit!(fallback_to_turbofish_type_if_type_info_not_available);
+            turbofish_args[0].to_string()
+        }
+    };
 
     let initializer_start = initializer.syntax().text_range().start();
     if ctx.offset() > turbofish_range.end() || ctx.offset() < initializer_start {
@@ -83,7 +79,7 @@ pub(crate) fn replace_turbofish_with_explicit_type(
             "Replace turbofish with explicit type",
             TextRange::new(initializer_start, turbofish_range.end()),
             |builder| {
-                builder.insert(ident_range.end(), format!(": {}", turbofish_type));
+                builder.insert(ident_range.end(), format!(": {}", returned_type));
                 builder.delete(turbofish_range);
             },
         );
@@ -98,7 +94,7 @@ pub(crate) fn replace_turbofish_with_explicit_type(
             "Replace `_` with turbofish type",
             turbofish_range,
             |builder| {
-                builder.replace(underscore_range, turbofish_type.to_string());
+                builder.replace(underscore_range, returned_type);
                 builder.delete(turbofish_range);
             },
         );
@@ -107,6 +103,26 @@ pub(crate) fn replace_turbofish_with_explicit_type(
     None
 }
 
+fn generic_arg_list(expr: &Expr) -> Option<GenericArgList> {
+    match expr {
+        Expr::MethodCallExpr(expr) => expr.generic_arg_list(),
+        Expr::CallExpr(expr) => {
+            if let Expr::PathExpr(pe) = expr.expr()? {
+                pe.path()?.segment()?.generic_arg_list()
+            } else {
+                cov_mark::hit!(not_applicable_if_non_path_function_call);
+                return None;
+            }
+        }
+        Expr::AwaitExpr(expr) => generic_arg_list(&expr.expr()?),
+        Expr::TryExpr(expr) => generic_arg_list(&expr.expr()?),
+        _ => {
+            cov_mark::hit!(not_applicable_if_non_function_call_initializer);
+            None
+        }
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -115,6 +131,7 @@ mod tests {
 
     #[test]
     fn replaces_turbofish_for_vec_string() {
+        cov_mark::check!(fallback_to_turbofish_type_if_type_info_not_available);
         check_assist(
             replace_turbofish_with_explicit_type,
             r#"
@@ -135,6 +152,7 @@ fn main() {
     #[test]
     fn replaces_method_calls() {
         // foo.make() is a method call which uses a different expr in the let initializer
+        cov_mark::check!(fallback_to_turbofish_type_if_type_info_not_available);
         check_assist(
             replace_turbofish_with_explicit_type,
             r#"
@@ -240,4 +258,108 @@ fn main() {
 "#,
         );
     }
+
+    #[test]
+    fn replaces_turbofish_for_known_type() {
+        check_assist(
+            replace_turbofish_with_explicit_type,
+            r#"
+fn make<T>() -> T {}
+fn main() {
+    let a = make$0::<i32>();
+}
+"#,
+            r#"
+fn make<T>() -> T {}
+fn main() {
+    let a: i32 = make();
+}
+"#,
+        );
+        check_assist(
+            replace_turbofish_with_explicit_type,
+            r#"
+//- minicore: option
+fn make<T>() -> T {}
+fn main() {
+    let a = make$0::<Option<bool>>();
+}
+"#,
+            r#"
+fn make<T>() -> T {}
+fn main() {
+    let a: Option<bool> = make();
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn replaces_turbofish_not_same_type() {
+        check_assist(
+            replace_turbofish_with_explicit_type,
+            r#"
+//- minicore: option
+fn make<T>() -> Option<T> {}
+fn main() {
+    let a = make$0::<u128>();
+}
+"#,
+            r#"
+fn make<T>() -> Option<T> {}
+fn main() {
+    let a: Option<u128> = make();
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn replaces_turbofish_for_type_with_defaulted_generic_param() {
+        check_assist(
+            replace_turbofish_with_explicit_type,
+            r#"
+struct HasDefault<T, U = i32>(T, U);
+fn make<T>() -> HasDefault<T> {}
+fn main() {
+    let a = make$0::<bool>();
+}
+"#,
+            r#"
+struct HasDefault<T, U = i32>(T, U);
+fn make<T>() -> HasDefault<T> {}
+fn main() {
+    let a: HasDefault<bool> = make();
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn replaces_turbofish_try_await() {
+        check_assist(
+            replace_turbofish_with_explicit_type,
+            r#"
+//- minicore: option, future
+struct Fut<T>(T);
+impl<T> core::future::Future for Fut<T> {
+    type Output = Option<T>;
+}
+fn make<T>() -> Fut<T> {}
+fn main() {
+    let a = make$0::<bool>().await?;
+}
+"#,
+            r#"
+struct Fut<T>(T);
+impl<T> core::future::Future for Fut<T> {
+    type Output = Option<T>;
+}
+fn make<T>() -> Fut<T> {}
+fn main() {
+    let a: bool = make().await?;
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs
new file mode 100644
index 00000000000..9565f0ee6f2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs
@@ -0,0 +1,293 @@
+use syntax::{
+    algo::neighbor,
+    ast::{self, edit::IndentLevel, make, AstNode},
+    ted::{self, Position},
+    Direction, SyntaxKind, T,
+};
+
+use crate::{AssistContext, AssistId, AssistKind, Assists};
+
+// Assist: unmerge_match_arm
+//
+// Splits the current match with a `|` pattern into two arms with identical bodies.
+//
+// ```
+// enum Action { Move { distance: u32 }, Stop }
+//
+// fn handle(action: Action) {
+//     match action {
+//         Action::Move(..) $0| Action::Stop => foo(),
+//     }
+// }
+// ```
+// ->
+// ```
+// enum Action { Move { distance: u32 }, Stop }
+//
+// fn handle(action: Action) {
+//     match action {
+//         Action::Move(..) => foo(),
+//         Action::Stop => foo(),
+//     }
+// }
+// ```
+pub(crate) fn unmerge_match_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+    let pipe_token = ctx.find_token_syntax_at_offset(T![|])?;
+    let or_pat = ast::OrPat::cast(pipe_token.parent()?)?.clone_for_update();
+    let match_arm = ast::MatchArm::cast(or_pat.syntax().parent()?)?;
+    let match_arm_body = match_arm.expr()?;
+
+    // We don't need to check for leading pipe because it is directly under `MatchArm`
+    // without `OrPat`.
+
+    let new_parent = match_arm.syntax().parent()?;
+    let old_parent_range = new_parent.text_range();
+
+    acc.add(
+        AssistId("unmerge_match_arm", AssistKind::RefactorRewrite),
+        "Unmerge match arm",
+        pipe_token.text_range(),
+        |edit| {
+            let pats_after = pipe_token
+                .siblings_with_tokens(Direction::Next)
+                .filter_map(|it| ast::Pat::cast(it.into_node()?));
+            // FIXME: We should add a leading pipe if the original arm has one.
+            let new_match_arm = make::match_arm(
+                pats_after,
+                match_arm.guard().and_then(|guard| guard.condition()),
+                match_arm_body,
+            )
+            .clone_for_update();
+
+            let mut pipe_index = pipe_token.index();
+            if pipe_token
+                .prev_sibling_or_token()
+                .map_or(false, |it| it.kind() == SyntaxKind::WHITESPACE)
+            {
+                pipe_index -= 1;
+            }
+            or_pat.syntax().splice_children(
+                pipe_index..or_pat.syntax().children_with_tokens().count(),
+                Vec::new(),
+            );
+
+            let mut insert_after_old_arm = Vec::new();
+
+            // A comma can be:
+            //  - After the arm. In this case we always want to insert a comma after the newly
+            //    inserted arm.
+            //  - Missing after the arm, with no arms after. In this case we want to insert a
+            //    comma before the newly inserted arm. It can not be necessary if there arm
+            //    body is a block, but we don't bother to check that.
+            //  - Missing after the arm with arms after, if the arm body is a block. In this case
+            //    we don't want to insert a comma at all.
+            let has_comma_after =
+                std::iter::successors(match_arm.syntax().last_child_or_token(), |it| {
+                    it.prev_sibling_or_token()
+                })
+                .map(|it| it.kind())
+                .skip_while(|it| it.is_trivia())
+                .next()
+                    == Some(T![,]);
+            let has_arms_after = neighbor(&match_arm, Direction::Next).is_some();
+            if !has_comma_after && !has_arms_after {
+                insert_after_old_arm.push(make::token(T![,]).into());
+            }
+
+            let indent = IndentLevel::from_node(match_arm.syntax());
+            insert_after_old_arm.push(make::tokens::whitespace(&format!("\n{indent}")).into());
+
+            insert_after_old_arm.push(new_match_arm.syntax().clone().into());
+
+            ted::insert_all_raw(Position::after(match_arm.syntax()), insert_after_old_arm);
+
+            if has_comma_after {
+                ted::insert_raw(
+                    Position::last_child_of(new_match_arm.syntax()),
+                    make::token(T![,]),
+                );
+            }
+
+            edit.replace(old_parent_range, new_parent.to_string());
+        },
+    )
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::{check_assist, check_assist_not_applicable};
+
+    use super::*;
+
+    #[test]
+    fn unmerge_match_arm_single_pipe() {
+        check_assist(
+            unmerge_match_arm,
+            r#"
+#[derive(Debug)]
+enum X { A, B, C }
+
+fn main() {
+    let x = X::A;
+    let y = match x {
+        X::A $0| X::B => { 1i32 }
+        X::C => { 2i32 }
+    };
+}
+"#,
+            r#"
+#[derive(Debug)]
+enum X { A, B, C }
+
+fn main() {
+    let x = X::A;
+    let y = match x {
+        X::A => { 1i32 }
+        X::B => { 1i32 }
+        X::C => { 2i32 }
+    };
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn unmerge_match_arm_guard() {
+        check_assist(
+            unmerge_match_arm,
+            r#"
+#[derive(Debug)]
+enum X { A, B, C }
+
+fn main() {
+    let x = X::A;
+    let y = match x {
+        X::A $0| X::B if true => { 1i32 }
+        _ => { 2i32 }
+    };
+}
+"#,
+            r#"
+#[derive(Debug)]
+enum X { A, B, C }
+
+fn main() {
+    let x = X::A;
+    let y = match x {
+        X::A if true => { 1i32 }
+        X::B if true => { 1i32 }
+        _ => { 2i32 }
+    };
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn unmerge_match_arm_leading_pipe() {
+        check_assist_not_applicable(
+            unmerge_match_arm,
+            r#"
+
+fn main() {
+    let y = match 0 {
+        |$0 0 => { 1i32 }
+        1 => { 2i32 }
+    };
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn unmerge_match_arm_multiple_pipes() {
+        check_assist(
+            unmerge_match_arm,
+            r#"
+#[derive(Debug)]
+enum X { A, B, C, D, E }
+
+fn main() {
+    let x = X::A;
+    let y = match x {
+        X::A | X::B |$0 X::C | X::D => 1i32,
+        X::E => 2i32,
+    };
+}
+"#,
+            r#"
+#[derive(Debug)]
+enum X { A, B, C, D, E }
+
+fn main() {
+    let x = X::A;
+    let y = match x {
+        X::A | X::B => 1i32,
+        X::C | X::D => 1i32,
+        X::E => 2i32,
+    };
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn unmerge_match_arm_inserts_comma_if_required() {
+        check_assist(
+            unmerge_match_arm,
+            r#"
+#[derive(Debug)]
+enum X { A, B }
+
+fn main() {
+    let x = X::A;
+    let y = match x {
+        X::A $0| X::B => 1i32
+    };
+}
+"#,
+            r#"
+#[derive(Debug)]
+enum X { A, B }
+
+fn main() {
+    let x = X::A;
+    let y = match x {
+        X::A => 1i32,
+        X::B => 1i32
+    };
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn unmerge_match_arm_inserts_comma_if_had_after() {
+        check_assist(
+            unmerge_match_arm,
+            r#"
+#[derive(Debug)]
+enum X { A, B }
+
+fn main() {
+    let x = X::A;
+    match x {
+        X::A $0| X::B => {},
+    }
+}
+"#,
+            r#"
+#[derive(Debug)]
+enum X { A, B }
+
+fn main() {
+    let x = X::A;
+    match x {
+        X::A => {},
+        X::B => {},
+    }
+}
+"#,
+        );
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
index 7fb35143fa2..e52544db5f5 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
@@ -122,6 +122,7 @@ mod handlers {
     mod convert_let_else_to_match;
     mod convert_tuple_struct_to_named_struct;
     mod convert_to_guarded_return;
+    mod convert_two_arm_bool_match_to_matches_macro;
     mod convert_while_to_loop;
     mod destructure_tuple_binding;
     mod expand_glob_import;
@@ -179,12 +180,14 @@ mod handlers {
     mod replace_try_expr_with_match;
     mod replace_derive_with_manual_impl;
     mod replace_if_let_with_match;
+    mod replace_or_with_or_else;
     mod introduce_named_generic;
     mod replace_let_with_if_let;
     mod replace_qualified_name_with_use;
     mod replace_string_with_char;
     mod replace_turbofish_with_explicit_type;
     mod split_import;
+    mod unmerge_match_arm;
     mod sort_items;
     mod toggle_ignore;
     mod unmerge_use;
@@ -215,6 +218,7 @@ mod handlers {
             convert_let_else_to_match::convert_let_else_to_match,
             convert_to_guarded_return::convert_to_guarded_return,
             convert_tuple_struct_to_named_struct::convert_tuple_struct_to_named_struct,
+            convert_two_arm_bool_match_to_matches_macro::convert_two_arm_bool_match_to_matches_macro,
             convert_while_to_loop::convert_while_to_loop,
             destructure_tuple_binding::destructure_tuple_binding,
             expand_glob_import::expand_glob_import,
@@ -273,11 +277,14 @@ mod handlers {
             replace_if_let_with_match::replace_if_let_with_match,
             replace_if_let_with_match::replace_match_with_if_let,
             replace_let_with_if_let::replace_let_with_if_let,
+            replace_or_with_or_else::replace_or_else_with_or,
+            replace_or_with_or_else::replace_or_with_or_else,
             replace_turbofish_with_explicit_type::replace_turbofish_with_explicit_type,
             replace_qualified_name_with_use::replace_qualified_name_with_use,
             sort_items::sort_items,
             split_import::split_import,
             toggle_ignore::toggle_ignore,
+            unmerge_match_arm::unmerge_match_arm,
             unmerge_use::unmerge_use,
             unnecessary_async::unnecessary_async,
             unwrap_block::unwrap_block,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
index 22319f36134..a8c8622c1c1 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
@@ -473,6 +473,26 @@ impl Point {
 }
 
 #[test]
+fn doctest_convert_two_arm_bool_match_to_matches_macro() {
+    check_doc_test(
+        "convert_two_arm_bool_match_to_matches_macro",
+        r#####"
+fn main() {
+    match scrutinee$0 {
+        Some(val) if val.cond() => true,
+        _ => false,
+    }
+}
+"#####,
+        r#####"
+fn main() {
+    matches!(scrutinee, Some(val) if val.cond())
+}
+"#####,
+    )
+}
+
+#[test]
 fn doctest_convert_while_to_loop() {
     check_doc_test(
         "convert_while_to_loop",
@@ -2010,6 +2030,46 @@ fn handle(action: Action) {
 }
 
 #[test]
+fn doctest_replace_or_else_with_or() {
+    check_doc_test(
+        "replace_or_else_with_or",
+        r#####"
+//- minicore:option
+fn foo() {
+    let a = Some(1);
+    a.unwra$0p_or_else(|| 2);
+}
+"#####,
+        r#####"
+fn foo() {
+    let a = Some(1);
+    a.unwrap_or(2);
+}
+"#####,
+    )
+}
+
+#[test]
+fn doctest_replace_or_with_or_else() {
+    check_doc_test(
+        "replace_or_with_or_else",
+        r#####"
+//- minicore:option
+fn foo() {
+    let a = Some(1);
+    a.unwra$0p_or(2);
+}
+"#####,
+        r#####"
+fn foo() {
+    let a = Some(1);
+    a.unwrap_or_else(|| 2);
+}
+"#####,
+    )
+}
+
+#[test]
 fn doctest_replace_qualified_name_with_use() {
     check_doc_test(
         "replace_qualified_name_with_use",
@@ -2208,6 +2268,32 @@ fn arithmetics {
 }
 
 #[test]
+fn doctest_unmerge_match_arm() {
+    check_doc_test(
+        "unmerge_match_arm",
+        r#####"
+enum Action { Move { distance: u32 }, Stop }
+
+fn handle(action: Action) {
+    match action {
+        Action::Move(..) $0| Action::Stop => foo(),
+    }
+}
+"#####,
+        r#####"
+enum Action { Move { distance: u32 }, Stop }
+
+fn handle(action: Action) {
+    match action {
+        Action::Move(..) => foo(),
+        Action::Stop => foo(),
+    }
+}
+"#####,
+    )
+}
+
+#[test]
 fn doctest_unmerge_use() {
     check_doc_test(
         "unmerge_use",
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
index 4d66af9e8d5..588b52cc1ee 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
@@ -282,14 +282,26 @@ pub(crate) fn complete_expr_path(
                         }
                     }
 
-                    if let Some(ty) = innermost_ret_ty {
+                    if let Some(ret_ty) = innermost_ret_ty {
                         add_keyword(
                             "return",
-                            match (in_block_expr, ty.is_unit()) {
-                                (true, true) => "return ;",
-                                (true, false) => "return;",
-                                (false, true) => "return $0",
-                                (false, false) => "return",
+                            match (ret_ty.is_unit(), in_block_expr) {
+                                (true, true) => {
+                                    cov_mark::hit!(return_unit_block);
+                                    "return;"
+                                }
+                                (true, false) => {
+                                    cov_mark::hit!(return_unit_no_block);
+                                    "return"
+                                }
+                                (false, true) => {
+                                    cov_mark::hit!(return_value_block);
+                                    "return $0;"
+                                }
+                                (false, false) => {
+                                    cov_mark::hit!(return_value_no_block);
+                                    "return $0"
+                                }
                             },
                         );
                     }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
index 925081ebf66..38e24ebc732 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
@@ -1,7 +1,7 @@
 //! Completion tests for expressions.
 use expect_test::{expect, Expect};
 
-use crate::tests::{completion_list, BASE_ITEMS_FIXTURE};
+use crate::tests::{check_edit, completion_list, BASE_ITEMS_FIXTURE};
 
 fn check(ra_fixture: &str, expect: Expect) {
     let actual = completion_list(&format!("{}{}", BASE_ITEMS_FIXTURE, ra_fixture));
@@ -670,3 +670,39 @@ fn main() {
         "#]],
     );
 }
+
+#[test]
+fn return_unit_block() {
+    cov_mark::check!(return_unit_block);
+    check_edit("return", r#"fn f() { if true { $0 } }"#, r#"fn f() { if true { return; } }"#);
+}
+
+#[test]
+fn return_unit_no_block() {
+    cov_mark::check!(return_unit_no_block);
+    check_edit(
+        "return",
+        r#"fn f() { match () { () => $0 } }"#,
+        r#"fn f() { match () { () => return } }"#,
+    );
+}
+
+#[test]
+fn return_value_block() {
+    cov_mark::check!(return_value_block);
+    check_edit(
+        "return",
+        r#"fn f() -> i32 { if true { $0 } }"#,
+        r#"fn f() -> i32 { if true { return $0; } }"#,
+    );
+}
+
+#[test]
+fn return_value_no_block() {
+    cov_mark::check!(return_value_no_block);
+    check_edit(
+        "return",
+        r#"fn f() -> i32 { match () { () => $0 } }"#,
+        r#"fn f() -> i32 { match () { () => return $0 } }"#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs
index 84bde4d44db..b890e2b58df 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs
@@ -315,7 +315,6 @@ pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) {
         | ast::Expr::IndexExpr(_)
         | ast::Expr::Literal(_)
         | ast::Expr::MacroExpr(_)
-        | ast::Expr::MacroStmts(_)
         | ast::Expr::MethodCallExpr(_)
         | ast::Expr::ParenExpr(_)
         | ast::Expr::PathExpr(_)
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs
index d12594a4ce5..0c92e706b39 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs
@@ -7,9 +7,10 @@ pub(crate) fn break_outside_of_loop(
     ctx: &DiagnosticsContext<'_>,
     d: &hir::BreakOutsideOfLoop,
 ) -> Diagnostic {
+    let construct = if d.is_break { "break" } else { "continue" };
     Diagnostic::new(
         "break-outside-of-loop",
-        "break outside of loop",
+        format!("{construct} outside of loop"),
         ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range,
     )
 }
@@ -19,11 +20,122 @@ mod tests {
     use crate::tests::check_diagnostics;
 
     #[test]
-    fn break_outside_of_loop() {
+    fn outside_of_loop() {
         check_diagnostics(
             r#"
-fn foo() { break; }
-         //^^^^^ error: break outside of loop
+fn foo() {
+    break;
+  //^^^^^ error: break outside of loop
+    break 'a;
+  //^^^^^^^^ error: break outside of loop
+    continue;
+  //^^^^^^^^ error: continue outside of loop
+    continue 'a;
+  //^^^^^^^^^^^ error: continue outside of loop
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn try_blocks_are_borders() {
+        check_diagnostics(
+            r#"
+fn foo() {
+    'a: loop {
+        try {
+                break;
+              //^^^^^ error: break outside of loop
+                break 'a;
+              //^^^^^^^^ error: break outside of loop
+                continue;
+              //^^^^^^^^ error: continue outside of loop
+                continue 'a;
+              //^^^^^^^^^^^ error: continue outside of loop
+        };
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn async_blocks_are_borders() {
+        check_diagnostics(
+            r#"
+fn foo() {
+    'a: loop {
+        try {
+                break;
+              //^^^^^ error: break outside of loop
+                break 'a;
+              //^^^^^^^^ error: break outside of loop
+                continue;
+              //^^^^^^^^ error: continue outside of loop
+                continue 'a;
+              //^^^^^^^^^^^ error: continue outside of loop
+        };
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn closures_are_borders() {
+        check_diagnostics(
+            r#"
+fn foo() {
+    'a: loop {
+        try {
+                break;
+              //^^^^^ error: break outside of loop
+                break 'a;
+              //^^^^^^^^ error: break outside of loop
+                continue;
+              //^^^^^^^^ error: continue outside of loop
+                continue 'a;
+              //^^^^^^^^^^^ error: continue outside of loop
+        };
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn blocks_pass_through() {
+        check_diagnostics(
+            r#"
+fn foo() {
+    'a: loop {
+        {
+            break;
+            break 'a;
+            continue;
+            continue 'a;
+        }
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn label_blocks() {
+        check_diagnostics(
+            r#"
+fn foo() {
+    'a: {
+        break;
+      //^^^^^ error: break outside of loop
+        break 'a;
+        continue;
+      //^^^^^^^^ error: continue outside of loop
+        continue 'a;
+      //^^^^^^^^^^^ error: continue outside of loop
+    }
+}
 "#,
         );
     }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
index 5fcaf405b14..c24430ce604 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
@@ -947,6 +947,50 @@ fn f() {
         );
     }
 
+    mod rust_unstable {
+        use super::*;
+
+        #[test]
+        fn rfc_1872_exhaustive_patterns() {
+            check_diagnostics_no_bails(
+                r"
+//- minicore: option, result
+#![feature(exhaustive_patterns)]
+enum Void {}
+fn test() {
+    match None::<!> { None => () }
+    match Result::<u8, !>::Ok(2) { Ok(_) => () }
+    match Result::<u8, Void>::Ok(2) { Ok(_) => () }
+    match (2, loop {}) {}
+    match Result::<!, !>::Ok(loop {}) {}
+    match (&loop {}) {} // https://github.com/rust-lang/rust/issues/50642#issuecomment-388234919
+    //    ^^^^^^^^^^ error: missing match arm: type `&!` is non-empty
+}",
+            );
+        }
+
+        #[test]
+        fn rfc_1872_private_uninhabitedness() {
+            check_diagnostics_no_bails(
+                r"
+//- minicore: option
+//- /lib.rs crate:lib
+#![feature(exhaustive_patterns)]
+pub struct PrivatelyUninhabited { private_field: Void }
+enum Void {}
+fn test_local(x: Option<PrivatelyUninhabited>) {
+    match x {}
+} //      ^ error: missing match arm: `None` not covered
+//- /main.rs crate:main deps:lib
+#![feature(exhaustive_patterns)]
+fn test(x: Option<lib::PrivatelyUninhabited>) {
+    match x {}
+    //    ^ error: missing match arm: `None` and `Some(_)` not covered
+}",
+            );
+        }
+    }
+
     mod false_negatives {
         //! The implementation of match checking here is a work in progress. As we roll this out, we
         //! prefer false negatives to false positives (ideally there would be no false positives). This
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
index ed19784d1fa..e9034daefa8 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
@@ -1910,7 +1910,7 @@ impl<T> Vec<T> {
 pub struct Box<T> {}
 
 trait Display {}
-trait Sync {}
+auto trait Sync {}
 
 fn main() {
     // The block expression wrapping disables the constructor hint hiding logic
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs
index 8de5d33a193..5dc9c6c82a1 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs
@@ -118,6 +118,11 @@ fn opt_path_type_args(p: &mut Parser<'_>, mode: Mode) {
     match mode {
         Mode::Use => {}
         Mode::Type => {
+            // test typepathfn_with_coloncolon
+            // type F = Start::(Middle) -> (Middle)::End;
+            if p.at(T![::]) && p.nth_at(2, T!['(']) {
+                p.bump(T![::]);
+            }
             // test path_fn_trait_args
             // type F = Box<Fn(i32) -> ()>;
             if p.at(T!['(']) {
diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
index 628fa745e75..c84f45f1f8e 100644
--- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
@@ -262,33 +262,117 @@ pub enum SyntaxKind {
 use self::SyntaxKind::*;
 impl SyntaxKind {
     pub fn is_keyword(self) -> bool {
-        match self {
-            AS_KW | ASYNC_KW | AWAIT_KW | BOX_KW | BREAK_KW | CONST_KW | CONTINUE_KW | CRATE_KW
-            | DYN_KW | ELSE_KW | ENUM_KW | EXTERN_KW | FALSE_KW | FN_KW | FOR_KW | IF_KW
-            | IMPL_KW | IN_KW | LET_KW | LOOP_KW | MACRO_KW | MATCH_KW | MOD_KW | MOVE_KW
-            | MUT_KW | PUB_KW | REF_KW | RETURN_KW | SELF_KW | SELF_TYPE_KW | STATIC_KW
-            | STRUCT_KW | SUPER_KW | TRAIT_KW | TRUE_KW | TRY_KW | TYPE_KW | UNSAFE_KW | USE_KW
-            | WHERE_KW | WHILE_KW | YIELD_KW | AUTO_KW | DEFAULT_KW | EXISTENTIAL_KW | UNION_KW
-            | RAW_KW | MACRO_RULES_KW => true,
-            _ => false,
-        }
+        matches!(
+            self,
+            AS_KW
+                | ASYNC_KW
+                | AWAIT_KW
+                | BOX_KW
+                | BREAK_KW
+                | CONST_KW
+                | CONTINUE_KW
+                | CRATE_KW
+                | DYN_KW
+                | ELSE_KW
+                | ENUM_KW
+                | EXTERN_KW
+                | FALSE_KW
+                | FN_KW
+                | FOR_KW
+                | IF_KW
+                | IMPL_KW
+                | IN_KW
+                | LET_KW
+                | LOOP_KW
+                | MACRO_KW
+                | MATCH_KW
+                | MOD_KW
+                | MOVE_KW
+                | MUT_KW
+                | PUB_KW
+                | REF_KW
+                | RETURN_KW
+                | SELF_KW
+                | SELF_TYPE_KW
+                | STATIC_KW
+                | STRUCT_KW
+                | SUPER_KW
+                | TRAIT_KW
+                | TRUE_KW
+                | TRY_KW
+                | TYPE_KW
+                | UNSAFE_KW
+                | USE_KW
+                | WHERE_KW
+                | WHILE_KW
+                | YIELD_KW
+                | AUTO_KW
+                | DEFAULT_KW
+                | EXISTENTIAL_KW
+                | UNION_KW
+                | RAW_KW
+                | MACRO_RULES_KW
+        )
     }
     pub fn is_punct(self) -> bool {
-        match self {
-            SEMICOLON | COMMA | L_PAREN | R_PAREN | L_CURLY | R_CURLY | L_BRACK | R_BRACK
-            | L_ANGLE | R_ANGLE | AT | POUND | TILDE | QUESTION | DOLLAR | AMP | PIPE | PLUS
-            | STAR | SLASH | CARET | PERCENT | UNDERSCORE | DOT | DOT2 | DOT3 | DOT2EQ | COLON
-            | COLON2 | EQ | EQ2 | FAT_ARROW | BANG | NEQ | MINUS | THIN_ARROW | LTEQ | GTEQ
-            | PLUSEQ | MINUSEQ | PIPEEQ | AMPEQ | CARETEQ | SLASHEQ | STAREQ | PERCENTEQ | AMP2
-            | PIPE2 | SHL | SHR | SHLEQ | SHREQ => true,
-            _ => false,
-        }
+        matches!(
+            self,
+            SEMICOLON
+                | COMMA
+                | L_PAREN
+                | R_PAREN
+                | L_CURLY
+                | R_CURLY
+                | L_BRACK
+                | R_BRACK
+                | L_ANGLE
+                | R_ANGLE
+                | AT
+                | POUND
+                | TILDE
+                | QUESTION
+                | DOLLAR
+                | AMP
+                | PIPE
+                | PLUS
+                | STAR
+                | SLASH
+                | CARET
+                | PERCENT
+                | UNDERSCORE
+                | DOT
+                | DOT2
+                | DOT3
+                | DOT2EQ
+                | COLON
+                | COLON2
+                | EQ
+                | EQ2
+                | FAT_ARROW
+                | BANG
+                | NEQ
+                | MINUS
+                | THIN_ARROW
+                | LTEQ
+                | GTEQ
+                | PLUSEQ
+                | MINUSEQ
+                | PIPEEQ
+                | AMPEQ
+                | CARETEQ
+                | SLASHEQ
+                | STAREQ
+                | PERCENTEQ
+                | AMP2
+                | PIPE2
+                | SHL
+                | SHR
+                | SHLEQ
+                | SHREQ
+        )
     }
     pub fn is_literal(self) -> bool {
-        match self {
-            INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE | STRING | BYTE_STRING => true,
-            _ => false,
-        }
+        matches!(self, INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE | STRING | BYTE_STRING)
     }
     pub fn from_keyword(ident: &str) -> Option<SyntaxKind> {
         let kw = match ident {
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rast
new file mode 100644
index 00000000000..b47a5a5c147
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rast
@@ -0,0 +1,43 @@
+SOURCE_FILE
+  TYPE_ALIAS
+    TYPE_KW "type"
+    WHITESPACE " "
+    NAME
+      IDENT "F"
+    WHITESPACE " "
+    EQ "="
+    WHITESPACE " "
+    PATH_TYPE
+      PATH
+        PATH
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "Start"
+            COLON2 "::"
+            PARAM_LIST
+              L_PAREN "("
+              PARAM
+                PATH_TYPE
+                  PATH
+                    PATH_SEGMENT
+                      NAME_REF
+                        IDENT "Middle"
+              R_PAREN ")"
+            WHITESPACE " "
+            RET_TYPE
+              THIN_ARROW "->"
+              WHITESPACE " "
+              PAREN_TYPE
+                L_PAREN "("
+                PATH_TYPE
+                  PATH
+                    PATH_SEGMENT
+                      NAME_REF
+                        IDENT "Middle"
+                R_PAREN ")"
+        COLON2 "::"
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "End"
+    SEMICOLON ";"
+  WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs
new file mode 100644
index 00000000000..8efd93a7ff6
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs
@@ -0,0 +1 @@
+type F = Start::(Middle) -> (Middle)::End;
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
index 706e1742dff..92df4d70fd9 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
@@ -116,6 +116,7 @@ pub(crate) struct GlobalStateSnapshot {
     pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>,
     vfs: Arc<RwLock<(vfs::Vfs, NoHashHashMap<FileId, LineEndings>)>>,
     pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
+    pub(crate) proc_macros_loaded: bool,
 }
 
 impl std::panic::UnwindSafe for GlobalStateSnapshot {}
@@ -256,6 +257,7 @@ impl GlobalState {
             check_fixes: Arc::clone(&self.diagnostics.check_fixes),
             mem_docs: self.mem_docs.clone(),
             semantic_tokens_cache: Arc::clone(&self.semantic_tokens_cache),
+            proc_macros_loaded: !self.fetch_build_data_queue.last_op_result().0.is_empty(),
         }
     }
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs
index d89f0f5a3cf..d9b669afbe8 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs
@@ -1504,7 +1504,11 @@ pub(crate) fn handle_semantic_tokens_full(
     let text = snap.analysis.file_text(file_id)?;
     let line_index = snap.file_line_index(file_id)?;
 
-    let highlights = snap.analysis.highlight(snap.config.highlighting_config(), file_id)?;
+    let mut highlight_config = snap.config.highlighting_config();
+    // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
+    highlight_config.syntactic_name_ref_highlighting = !snap.proc_macros_loaded;
+
+    let highlights = snap.analysis.highlight(highlight_config, file_id)?;
     let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
 
     // Unconditionally cache the tokens
@@ -1523,7 +1527,11 @@ pub(crate) fn handle_semantic_tokens_full_delta(
     let text = snap.analysis.file_text(file_id)?;
     let line_index = snap.file_line_index(file_id)?;
 
-    let highlights = snap.analysis.highlight(snap.config.highlighting_config(), file_id)?;
+    let mut highlight_config = snap.config.highlighting_config();
+    // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
+    highlight_config.syntactic_name_ref_highlighting = !snap.proc_macros_loaded;
+
+    let highlights = snap.analysis.highlight(highlight_config, file_id)?;
     let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights);
 
     let mut cache = snap.semantic_tokens_cache.lock();
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
index ceb2a6d703d..f23bbca6387 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -347,8 +347,8 @@ impl GlobalState {
                             error
                         })
                     })
-                    .collect();
-            }
+                    .collect()
+            };
         }
 
         let watch = match files_config.watcher {
diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram
index 62aa4783994..89479543545 100644
--- a/src/tools/rust-analyzer/crates/syntax/rust.ungram
+++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram
@@ -343,7 +343,6 @@ Expr =
 | Literal
 | LoopExpr
 | MacroExpr
-| MacroStmts
 | MatchExpr
 | MethodCallExpr
 | ParenExpr
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
index 63309a15521..449402e5f5b 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
@@ -1526,7 +1526,6 @@ pub enum Expr {
     Literal(Literal),
     LoopExpr(LoopExpr),
     MacroExpr(MacroExpr),
-    MacroStmts(MacroStmts),
     MatchExpr(MatchExpr),
     MethodCallExpr(MethodCallExpr),
     ParenExpr(ParenExpr),
@@ -3169,10 +3168,7 @@ impl From<ConstArg> for GenericArg {
 }
 impl AstNode for GenericArg {
     fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            TYPE_ARG | ASSOC_TYPE_ARG | LIFETIME_ARG | CONST_ARG => true,
-            _ => false,
-        }
+        matches!(kind, TYPE_ARG | ASSOC_TYPE_ARG | LIFETIME_ARG | CONST_ARG)
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         let res = match syntax.kind() {
@@ -3237,12 +3233,23 @@ impl From<TupleType> for Type {
 }
 impl AstNode for Type {
     fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            ARRAY_TYPE | DYN_TRAIT_TYPE | FN_PTR_TYPE | FOR_TYPE | IMPL_TRAIT_TYPE | INFER_TYPE
-            | MACRO_TYPE | NEVER_TYPE | PAREN_TYPE | PATH_TYPE | PTR_TYPE | REF_TYPE
-            | SLICE_TYPE | TUPLE_TYPE => true,
-            _ => false,
-        }
+        matches!(
+            kind,
+            ARRAY_TYPE
+                | DYN_TRAIT_TYPE
+                | FN_PTR_TYPE
+                | FOR_TYPE
+                | IMPL_TRAIT_TYPE
+                | INFER_TYPE
+                | MACRO_TYPE
+                | NEVER_TYPE
+                | PAREN_TYPE
+                | PATH_TYPE
+                | PTR_TYPE
+                | REF_TYPE
+                | SLICE_TYPE
+                | TUPLE_TYPE
+        )
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         let res = match syntax.kind() {
@@ -3334,9 +3341,6 @@ impl From<LoopExpr> for Expr {
 impl From<MacroExpr> for Expr {
     fn from(node: MacroExpr) -> Expr { Expr::MacroExpr(node) }
 }
-impl From<MacroStmts> for Expr {
-    fn from(node: MacroStmts) -> Expr { Expr::MacroStmts(node) }
-}
 impl From<MatchExpr> for Expr {
     fn from(node: MatchExpr) -> Expr { Expr::MatchExpr(node) }
 }
@@ -3384,15 +3388,41 @@ impl From<UnderscoreExpr> for Expr {
 }
 impl AstNode for Expr {
     fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            ARRAY_EXPR | AWAIT_EXPR | BIN_EXPR | BLOCK_EXPR | BOX_EXPR | BREAK_EXPR | CALL_EXPR
-            | CAST_EXPR | CLOSURE_EXPR | CONTINUE_EXPR | FIELD_EXPR | FOR_EXPR | IF_EXPR
-            | INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_EXPR | MACRO_STMTS | MATCH_EXPR
-            | METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR
-            | RECORD_EXPR | REF_EXPR | RETURN_EXPR | TRY_EXPR | TUPLE_EXPR | WHILE_EXPR
-            | YIELD_EXPR | LET_EXPR | UNDERSCORE_EXPR => true,
-            _ => false,
-        }
+        matches!(
+            kind,
+            ARRAY_EXPR
+                | AWAIT_EXPR
+                | BIN_EXPR
+                | BLOCK_EXPR
+                | BOX_EXPR
+                | BREAK_EXPR
+                | CALL_EXPR
+                | CAST_EXPR
+                | CLOSURE_EXPR
+                | CONTINUE_EXPR
+                | FIELD_EXPR
+                | FOR_EXPR
+                | IF_EXPR
+                | INDEX_EXPR
+                | LITERAL
+                | LOOP_EXPR
+                | MACRO_EXPR
+                | MATCH_EXPR
+                | METHOD_CALL_EXPR
+                | PAREN_EXPR
+                | PATH_EXPR
+                | PREFIX_EXPR
+                | RANGE_EXPR
+                | RECORD_EXPR
+                | REF_EXPR
+                | RETURN_EXPR
+                | TRY_EXPR
+                | TUPLE_EXPR
+                | WHILE_EXPR
+                | YIELD_EXPR
+                | LET_EXPR
+                | UNDERSCORE_EXPR
+        )
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         let res = match syntax.kind() {
@@ -3413,7 +3443,6 @@ impl AstNode for Expr {
             LITERAL => Expr::Literal(Literal { syntax }),
             LOOP_EXPR => Expr::LoopExpr(LoopExpr { syntax }),
             MACRO_EXPR => Expr::MacroExpr(MacroExpr { syntax }),
-            MACRO_STMTS => Expr::MacroStmts(MacroStmts { syntax }),
             MATCH_EXPR => Expr::MatchExpr(MatchExpr { syntax }),
             METHOD_CALL_EXPR => Expr::MethodCallExpr(MethodCallExpr { syntax }),
             PAREN_EXPR => Expr::ParenExpr(ParenExpr { syntax }),
@@ -3452,7 +3481,6 @@ impl AstNode for Expr {
             Expr::Literal(it) => &it.syntax,
             Expr::LoopExpr(it) => &it.syntax,
             Expr::MacroExpr(it) => &it.syntax,
-            Expr::MacroStmts(it) => &it.syntax,
             Expr::MatchExpr(it) => &it.syntax,
             Expr::MethodCallExpr(it) => &it.syntax,
             Expr::ParenExpr(it) => &it.syntax,
@@ -3521,11 +3549,25 @@ impl From<Use> for Item {
 }
 impl AstNode for Item {
     fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            CONST | ENUM | EXTERN_BLOCK | EXTERN_CRATE | FN | IMPL | MACRO_CALL | MACRO_RULES
-            | MACRO_DEF | MODULE | STATIC | STRUCT | TRAIT | TYPE_ALIAS | UNION | USE => true,
-            _ => false,
-        }
+        matches!(
+            kind,
+            CONST
+                | ENUM
+                | EXTERN_BLOCK
+                | EXTERN_CRATE
+                | FN
+                | IMPL
+                | MACRO_CALL
+                | MACRO_RULES
+                | MACRO_DEF
+                | MODULE
+                | STATIC
+                | STRUCT
+                | TRAIT
+                | TYPE_ALIAS
+                | UNION
+                | USE
+        )
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         let res = match syntax.kind() {
@@ -3629,12 +3671,25 @@ impl From<ConstBlockPat> for Pat {
 }
 impl AstNode for Pat {
     fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            IDENT_PAT | BOX_PAT | REST_PAT | LITERAL_PAT | MACRO_PAT | OR_PAT | PAREN_PAT
-            | PATH_PAT | WILDCARD_PAT | RANGE_PAT | RECORD_PAT | REF_PAT | SLICE_PAT
-            | TUPLE_PAT | TUPLE_STRUCT_PAT | CONST_BLOCK_PAT => true,
-            _ => false,
-        }
+        matches!(
+            kind,
+            IDENT_PAT
+                | BOX_PAT
+                | REST_PAT
+                | LITERAL_PAT
+                | MACRO_PAT
+                | OR_PAT
+                | PAREN_PAT
+                | PATH_PAT
+                | WILDCARD_PAT
+                | RANGE_PAT
+                | RECORD_PAT
+                | REF_PAT
+                | SLICE_PAT
+                | TUPLE_PAT
+                | TUPLE_STRUCT_PAT
+                | CONST_BLOCK_PAT
+        )
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         let res = match syntax.kind() {
@@ -3686,12 +3741,7 @@ impl From<TupleFieldList> for FieldList {
     fn from(node: TupleFieldList) -> FieldList { FieldList::TupleFieldList(node) }
 }
 impl AstNode for FieldList {
-    fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            RECORD_FIELD_LIST | TUPLE_FIELD_LIST => true,
-            _ => false,
-        }
-    }
+    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, RECORD_FIELD_LIST | TUPLE_FIELD_LIST) }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         let res = match syntax.kind() {
             RECORD_FIELD_LIST => FieldList::RecordFieldList(RecordFieldList { syntax }),
@@ -3717,12 +3767,7 @@ impl From<Union> for Adt {
     fn from(node: Union) -> Adt { Adt::Union(node) }
 }
 impl AstNode for Adt {
-    fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            ENUM | STRUCT | UNION => true,
-            _ => false,
-        }
-    }
+    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, ENUM | STRUCT | UNION) }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         let res = match syntax.kind() {
             ENUM => Adt::Enum(Enum { syntax }),
@@ -3753,12 +3798,7 @@ impl From<TypeAlias> for AssocItem {
     fn from(node: TypeAlias) -> AssocItem { AssocItem::TypeAlias(node) }
 }
 impl AstNode for AssocItem {
-    fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            CONST | FN | MACRO_CALL | TYPE_ALIAS => true,
-            _ => false,
-        }
-    }
+    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, CONST | FN | MACRO_CALL | TYPE_ALIAS) }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         let res = match syntax.kind() {
             CONST => AssocItem::Const(Const { syntax }),
@@ -3791,12 +3831,7 @@ impl From<TypeAlias> for ExternItem {
     fn from(node: TypeAlias) -> ExternItem { ExternItem::TypeAlias(node) }
 }
 impl AstNode for ExternItem {
-    fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            FN | MACRO_CALL | STATIC | TYPE_ALIAS => true,
-            _ => false,
-        }
-    }
+    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, FN | MACRO_CALL | STATIC | TYPE_ALIAS) }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         let res = match syntax.kind() {
             FN => ExternItem::Fn(Fn { syntax }),
@@ -3827,10 +3862,7 @@ impl From<TypeParam> for GenericParam {
 }
 impl AstNode for GenericParam {
     fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            CONST_PARAM | LIFETIME_PARAM | TYPE_PARAM => true,
-            _ => false,
-        }
+        matches!(kind, CONST_PARAM | LIFETIME_PARAM | TYPE_PARAM)
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         let res = match syntax.kind() {
@@ -3856,12 +3888,7 @@ impl AnyHasArgList {
     }
 }
 impl AstNode for AnyHasArgList {
-    fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            CALL_EXPR | METHOD_CALL_EXPR => true,
-            _ => false,
-        }
-    }
+    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, CALL_EXPR | METHOD_CALL_EXPR) }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         Self::can_cast(syntax.kind()).then(|| AnyHasArgList { syntax })
     }
@@ -3875,76 +3902,76 @@ impl AnyHasAttrs {
 }
 impl AstNode for AnyHasAttrs {
     fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
+        matches!(
+            kind,
             MACRO_CALL
-            | SOURCE_FILE
-            | CONST
-            | ENUM
-            | EXTERN_BLOCK
-            | EXTERN_CRATE
-            | FN
-            | IMPL
-            | MACRO_RULES
-            | MACRO_DEF
-            | MODULE
-            | STATIC
-            | STRUCT
-            | TRAIT
-            | TYPE_ALIAS
-            | UNION
-            | USE
-            | ITEM_LIST
-            | BLOCK_EXPR
-            | SELF_PARAM
-            | PARAM
-            | RECORD_FIELD
-            | TUPLE_FIELD
-            | VARIANT
-            | ASSOC_ITEM_LIST
-            | EXTERN_ITEM_LIST
-            | CONST_PARAM
-            | LIFETIME_PARAM
-            | TYPE_PARAM
-            | LET_STMT
-            | ARRAY_EXPR
-            | AWAIT_EXPR
-            | BIN_EXPR
-            | BOX_EXPR
-            | BREAK_EXPR
-            | CALL_EXPR
-            | CAST_EXPR
-            | CLOSURE_EXPR
-            | CONTINUE_EXPR
-            | FIELD_EXPR
-            | FOR_EXPR
-            | IF_EXPR
-            | INDEX_EXPR
-            | LITERAL
-            | LOOP_EXPR
-            | MATCH_EXPR
-            | METHOD_CALL_EXPR
-            | PAREN_EXPR
-            | PATH_EXPR
-            | PREFIX_EXPR
-            | RANGE_EXPR
-            | REF_EXPR
-            | RETURN_EXPR
-            | TRY_EXPR
-            | TUPLE_EXPR
-            | WHILE_EXPR
-            | YIELD_EXPR
-            | LET_EXPR
-            | UNDERSCORE_EXPR
-            | STMT_LIST
-            | RECORD_EXPR_FIELD_LIST
-            | RECORD_EXPR_FIELD
-            | MATCH_ARM_LIST
-            | MATCH_ARM
-            | IDENT_PAT
-            | REST_PAT
-            | RECORD_PAT_FIELD => true,
-            _ => false,
-        }
+                | SOURCE_FILE
+                | CONST
+                | ENUM
+                | EXTERN_BLOCK
+                | EXTERN_CRATE
+                | FN
+                | IMPL
+                | MACRO_RULES
+                | MACRO_DEF
+                | MODULE
+                | STATIC
+                | STRUCT
+                | TRAIT
+                | TYPE_ALIAS
+                | UNION
+                | USE
+                | ITEM_LIST
+                | BLOCK_EXPR
+                | SELF_PARAM
+                | PARAM
+                | RECORD_FIELD
+                | TUPLE_FIELD
+                | VARIANT
+                | ASSOC_ITEM_LIST
+                | EXTERN_ITEM_LIST
+                | CONST_PARAM
+                | LIFETIME_PARAM
+                | TYPE_PARAM
+                | LET_STMT
+                | ARRAY_EXPR
+                | AWAIT_EXPR
+                | BIN_EXPR
+                | BOX_EXPR
+                | BREAK_EXPR
+                | CALL_EXPR
+                | CAST_EXPR
+                | CLOSURE_EXPR
+                | CONTINUE_EXPR
+                | FIELD_EXPR
+                | FOR_EXPR
+                | IF_EXPR
+                | INDEX_EXPR
+                | LITERAL
+                | LOOP_EXPR
+                | MATCH_EXPR
+                | METHOD_CALL_EXPR
+                | PAREN_EXPR
+                | PATH_EXPR
+                | PREFIX_EXPR
+                | RANGE_EXPR
+                | REF_EXPR
+                | RETURN_EXPR
+                | TRY_EXPR
+                | TUPLE_EXPR
+                | WHILE_EXPR
+                | YIELD_EXPR
+                | LET_EXPR
+                | UNDERSCORE_EXPR
+                | STMT_LIST
+                | RECORD_EXPR_FIELD_LIST
+                | RECORD_EXPR_FIELD
+                | MATCH_ARM_LIST
+                | MATCH_ARM
+                | IDENT_PAT
+                | REST_PAT
+                | RECORD_PAT_FIELD
+        )
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         Self::can_cast(syntax.kind()).then(|| AnyHasAttrs { syntax })
@@ -3959,12 +3986,29 @@ impl AnyHasDocComments {
 }
 impl AstNode for AnyHasDocComments {
     fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            MACRO_CALL | SOURCE_FILE | CONST | ENUM | EXTERN_BLOCK | EXTERN_CRATE | FN | IMPL
-            | MACRO_RULES | MACRO_DEF | MODULE | STATIC | STRUCT | TRAIT | TYPE_ALIAS | UNION
-            | USE | RECORD_FIELD | TUPLE_FIELD | VARIANT => true,
-            _ => false,
-        }
+        matches!(
+            kind,
+            MACRO_CALL
+                | SOURCE_FILE
+                | CONST
+                | ENUM
+                | EXTERN_BLOCK
+                | EXTERN_CRATE
+                | FN
+                | IMPL
+                | MACRO_RULES
+                | MACRO_DEF
+                | MODULE
+                | STATIC
+                | STRUCT
+                | TRAIT
+                | TYPE_ALIAS
+                | UNION
+                | USE
+                | RECORD_FIELD
+                | TUPLE_FIELD
+                | VARIANT
+        )
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         Self::can_cast(syntax.kind()).then(|| AnyHasDocComments { syntax })
@@ -3979,10 +4023,7 @@ impl AnyHasGenericParams {
 }
 impl AstNode for AnyHasGenericParams {
     fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            ENUM | FN | IMPL | STRUCT | TRAIT | TYPE_ALIAS | UNION => true,
-            _ => false,
-        }
+        matches!(kind, ENUM | FN | IMPL | STRUCT | TRAIT | TYPE_ALIAS | UNION)
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         Self::can_cast(syntax.kind()).then(|| AnyHasGenericParams { syntax })
@@ -3996,12 +4037,7 @@ impl AnyHasLoopBody {
     }
 }
 impl AstNode for AnyHasLoopBody {
-    fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            FOR_EXPR | LOOP_EXPR | WHILE_EXPR => true,
-            _ => false,
-        }
-    }
+    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, FOR_EXPR | LOOP_EXPR | WHILE_EXPR) }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         Self::can_cast(syntax.kind()).then(|| AnyHasLoopBody { syntax })
     }
@@ -4014,12 +4050,7 @@ impl AnyHasModuleItem {
     }
 }
 impl AstNode for AnyHasModuleItem {
-    fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            MACRO_ITEMS | SOURCE_FILE | ITEM_LIST => true,
-            _ => false,
-        }
-    }
+    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, MACRO_ITEMS | SOURCE_FILE | ITEM_LIST) }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         Self::can_cast(syntax.kind()).then(|| AnyHasModuleItem { syntax })
     }
@@ -4033,12 +4064,27 @@ impl AnyHasName {
 }
 impl AstNode for AnyHasName {
     fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            CONST | ENUM | FN | MACRO_RULES | MACRO_DEF | MODULE | STATIC | STRUCT | TRAIT
-            | TYPE_ALIAS | UNION | RENAME | SELF_PARAM | RECORD_FIELD | VARIANT | CONST_PARAM
-            | TYPE_PARAM | IDENT_PAT => true,
-            _ => false,
-        }
+        matches!(
+            kind,
+            CONST
+                | ENUM
+                | FN
+                | MACRO_RULES
+                | MACRO_DEF
+                | MODULE
+                | STATIC
+                | STRUCT
+                | TRAIT
+                | TYPE_ALIAS
+                | UNION
+                | RENAME
+                | SELF_PARAM
+                | RECORD_FIELD
+                | VARIANT
+                | CONST_PARAM
+                | TYPE_PARAM
+                | IDENT_PAT
+        )
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         Self::can_cast(syntax.kind()).then(|| AnyHasName { syntax })
@@ -4053,10 +4099,10 @@ impl AnyHasTypeBounds {
 }
 impl AstNode for AnyHasTypeBounds {
     fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            ASSOC_TYPE_ARG | TRAIT | TYPE_ALIAS | LIFETIME_PARAM | TYPE_PARAM | WHERE_PRED => true,
-            _ => false,
-        }
+        matches!(
+            kind,
+            ASSOC_TYPE_ARG | TRAIT | TYPE_ALIAS | LIFETIME_PARAM | TYPE_PARAM | WHERE_PRED
+        )
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         Self::can_cast(syntax.kind()).then(|| AnyHasTypeBounds { syntax })
@@ -4071,13 +4117,26 @@ impl AnyHasVisibility {
 }
 impl AstNode for AnyHasVisibility {
     fn can_cast(kind: SyntaxKind) -> bool {
-        match kind {
-            CONST | ENUM | EXTERN_CRATE | FN | IMPL | MACRO_RULES | MACRO_DEF | MODULE | STATIC
-            | STRUCT | TRAIT | TYPE_ALIAS | UNION | USE | RECORD_FIELD | TUPLE_FIELD | VARIANT => {
-                true
-            }
-            _ => false,
-        }
+        matches!(
+            kind,
+            CONST
+                | ENUM
+                | EXTERN_CRATE
+                | FN
+                | IMPL
+                | MACRO_RULES
+                | MACRO_DEF
+                | MODULE
+                | STATIC
+                | STRUCT
+                | TRAIT
+                | TYPE_ALIAS
+                | UNION
+                | USE
+                | RECORD_FIELD
+                | TUPLE_FIELD
+                | VARIANT
+        )
     }
     fn cast(syntax: SyntaxNode) -> Option<Self> {
         Self::can_cast(syntax.kind()).then(|| AnyHasVisibility { syntax })
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
index 037de876d45..83f8bbac588 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
@@ -25,7 +25,7 @@ pub mod ext {
         return from_text(&name.text());
 
         fn from_text(text: &str) -> ast::IdentPat {
-            ast_from_text(&format!("fn f({}: ())", text))
+            ast_from_text(&format!("fn f({text}: ())"))
         }
     }
     pub fn ident_path(ident: &str) -> ast::Path {
@@ -60,10 +60,10 @@ pub mod ext {
         expr_from_text("todo!()")
     }
     pub fn expr_ty_default(ty: &ast::Type) -> ast::Expr {
-        expr_from_text(&format!("{}::default()", ty))
+        expr_from_text(&format!("{ty}::default()"))
     }
     pub fn expr_ty_new(ty: &ast::Type) -> ast::Expr {
-        expr_from_text(&format!("{}::new()", ty))
+        expr_from_text(&format!("{ty}::new()"))
     }
 
     pub fn zero_number() -> ast::Expr {
@@ -92,18 +92,20 @@ pub mod ext {
         ty_path(ident_path("bool"))
     }
     pub fn ty_option(t: ast::Type) -> ast::Type {
-        ty_from_text(&format!("Option<{}>", t))
+        ty_from_text(&format!("Option<{t}>"))
     }
     pub fn ty_result(t: ast::Type, e: ast::Type) -> ast::Type {
-        ty_from_text(&format!("Result<{}, {}>", t, e))
+        ty_from_text(&format!("Result<{t}, {e}>"))
     }
 }
 
-pub fn name(text: &str) -> ast::Name {
-    ast_from_text(&format!("mod {}{};", raw_ident_esc(text), text))
+pub fn name(name: &str) -> ast::Name {
+    let raw_escape = raw_ident_esc(name);
+    ast_from_text(&format!("mod {raw_escape}{name};"))
 }
-pub fn name_ref(text: &str) -> ast::NameRef {
-    ast_from_text(&format!("fn f() {{ {}{}; }}", raw_ident_esc(text), text))
+pub fn name_ref(name_ref: &str) -> ast::NameRef {
+    let raw_escape = raw_ident_esc(name_ref);
+    ast_from_text(&format!("fn f() {{ {raw_escape}{name_ref}; }}"))
 }
 fn raw_ident_esc(ident: &str) -> &'static str {
     let is_keyword = parser::SyntaxKind::from_keyword(ident).is_some();
@@ -118,10 +120,10 @@ pub fn lifetime(text: &str) -> ast::Lifetime {
     let mut text = text;
     let tmp;
     if never!(!text.starts_with('\'')) {
-        tmp = format!("'{}", text);
+        tmp = format!("'{text}");
         text = &tmp;
     }
-    ast_from_text(&format!("fn f<{}>() {{ }}", text))
+    ast_from_text(&format!("fn f<{text}>() {{ }}"))
 }
 
 // FIXME: replace stringly-typed constructor with a family of typed ctors, a-la
@@ -142,16 +144,16 @@ pub fn ty_tuple(types: impl IntoIterator<Item = ast::Type>) -> ast::Type {
         contents.push(',');
     }
 
-    ty_from_text(&format!("({})", contents))
+    ty_from_text(&format!("({contents})"))
 }
 pub fn ty_ref(target: ast::Type, exclusive: bool) -> ast::Type {
-    ty_from_text(&if exclusive { format!("&mut {}", target) } else { format!("&{}", target) })
+    ty_from_text(&if exclusive { format!("&mut {target}") } else { format!("&{target}") })
 }
 pub fn ty_path(path: ast::Path) -> ast::Type {
     ty_from_text(&path.to_string())
 }
 fn ty_from_text(text: &str) -> ast::Type {
-    ast_from_text(&format!("type _T = {};", text))
+    ast_from_text(&format!("type _T = {text};"))
 }
 
 pub fn assoc_item_list() -> ast::AssocItemList {
@@ -171,7 +173,7 @@ pub fn impl_(
         Some(params) => params.to_string(),
         None => String::new(),
     };
-    ast_from_text(&format!("impl{} {}{} {{}}", params, ty, ty_params))
+    ast_from_text(&format!("impl{params} {ty}{ty_params} {{}}"))
 }
 
 pub fn impl_trait(
@@ -180,7 +182,7 @@ pub fn impl_trait(
     ty_params: Option<ast::GenericParamList>,
 ) -> ast::Impl {
     let ty_params = ty_params.map_or_else(String::new, |params| params.to_string());
-    ast_from_text(&format!("impl{2} {} for {}{2} {{}}", trait_, ty, ty_params))
+    ast_from_text(&format!("impl{ty_params} {trait_} for {ty}{ty_params} {{}}"))
 }
 
 pub(crate) fn generic_arg_list() -> ast::GenericArgList {
@@ -188,13 +190,13 @@ pub(crate) fn generic_arg_list() -> ast::GenericArgList {
 }
 
 pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment {
-    ast_from_text(&format!("type __ = {};", name_ref))
+    ast_from_text(&format!("type __ = {name_ref};"))
 }
 
 pub fn path_segment_ty(type_ref: ast::Type, trait_ref: Option<ast::PathType>) -> ast::PathSegment {
     let text = match trait_ref {
-        Some(trait_ref) => format!("fn f(x: <{} as {}>) {{}}", type_ref, trait_ref),
-        None => format!("fn f(x: <{}>) {{}}", type_ref),
+        Some(trait_ref) => format!("fn f(x: <{type_ref} as {trait_ref}>) {{}}"),
+        None => format!("fn f(x: <{type_ref}>) {{}}"),
     };
     ast_from_text(&text)
 }
@@ -212,15 +214,15 @@ pub fn path_segment_crate() -> ast::PathSegment {
 }
 
 pub fn path_unqualified(segment: ast::PathSegment) -> ast::Path {
-    ast_from_text(&format!("type __ = {};", segment))
+    ast_from_text(&format!("type __ = {segment};"))
 }
 
 pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path {
-    ast_from_text(&format!("{}::{}", qual, segment))
+    ast_from_text(&format!("{qual}::{segment}"))
 }
 // FIXME: path concatenation operation doesn't make sense as AST op.
 pub fn path_concat(first: ast::Path, second: ast::Path) -> ast::Path {
-    ast_from_text(&format!("type __ = {}::{};", first, second))
+    ast_from_text(&format!("type __ = {first}::{second};"))
 }
 
 pub fn path_from_segments(
@@ -229,20 +231,20 @@ pub fn path_from_segments(
 ) -> ast::Path {
     let segments = segments.into_iter().map(|it| it.syntax().clone()).join("::");
     ast_from_text(&if is_abs {
-        format!("fn f(x: ::{}) {{}}", segments)
+        format!("fn f(x: ::{segments}) {{}}")
     } else {
-        format!("fn f(x: {}) {{}}", segments)
+        format!("fn f(x: {segments}) {{}}")
     })
 }
 
 pub fn join_paths(paths: impl IntoIterator<Item = ast::Path>) -> ast::Path {
     let paths = paths.into_iter().map(|it| it.syntax().clone()).join("::");
-    ast_from_text(&format!("type __ = {};", paths))
+    ast_from_text(&format!("type __ = {paths};"))
 }
 
 // FIXME: should not be pub
 pub fn path_from_text(text: &str) -> ast::Path {
-    ast_from_text(&format!("fn main() {{ let test = {}; }}", text))
+    ast_from_text(&format!("fn main() {{ let test = {text}; }}"))
 }
 
 pub fn use_tree_glob() -> ast::UseTree {
@@ -257,50 +259,50 @@ pub fn use_tree(
     let mut buf = "use ".to_string();
     buf += &path.syntax().to_string();
     if let Some(use_tree_list) = use_tree_list {
-        format_to!(buf, "::{}", use_tree_list);
+        format_to!(buf, "::{use_tree_list}");
     }
     if add_star {
         buf += "::*";
     }
 
     if let Some(alias) = alias {
-        format_to!(buf, " {}", alias);
+        format_to!(buf, " {alias}");
     }
     ast_from_text(&buf)
 }
 
 pub fn use_tree_list(use_trees: impl IntoIterator<Item = ast::UseTree>) -> ast::UseTreeList {
     let use_trees = use_trees.into_iter().map(|it| it.syntax().clone()).join(", ");
-    ast_from_text(&format!("use {{{}}};", use_trees))
+    ast_from_text(&format!("use {{{use_trees}}};"))
 }
 
 pub fn use_(visibility: Option<ast::Visibility>, use_tree: ast::UseTree) -> ast::Use {
     let visibility = match visibility {
         None => String::new(),
-        Some(it) => format!("{} ", it),
+        Some(it) => format!("{it} "),
     };
-    ast_from_text(&format!("{}use {};", visibility, use_tree))
+    ast_from_text(&format!("{visibility}use {use_tree};"))
 }
 
 pub fn record_expr(path: ast::Path, fields: ast::RecordExprFieldList) -> ast::RecordExpr {
-    ast_from_text(&format!("fn f() {{ {} {} }}", path, fields))
+    ast_from_text(&format!("fn f() {{ {path} {fields} }}"))
 }
 
 pub fn record_expr_field_list(
     fields: impl IntoIterator<Item = ast::RecordExprField>,
 ) -> ast::RecordExprFieldList {
     let fields = fields.into_iter().join(", ");
-    ast_from_text(&format!("fn f() {{ S {{ {} }} }}", fields))
+    ast_from_text(&format!("fn f() {{ S {{ {fields} }} }}"))
 }
 
 pub fn record_expr_field(name: ast::NameRef, expr: Option<ast::Expr>) -> ast::RecordExprField {
     return match expr {
-        Some(expr) => from_text(&format!("{}: {}", name, expr)),
+        Some(expr) => from_text(&format!("{name}: {expr}")),
         None => from_text(&name.to_string()),
     };
 
     fn from_text(text: &str) -> ast::RecordExprField {
-        ast_from_text(&format!("fn f() {{ S {{ {}, }} }}", text))
+        ast_from_text(&format!("fn f() {{ S {{ {text}, }} }}"))
     }
 }
 
@@ -311,9 +313,9 @@ pub fn record_field(
 ) -> ast::RecordField {
     let visibility = match visibility {
         None => String::new(),
-        Some(it) => format!("{} ", it),
+        Some(it) => format!("{it} "),
     };
-    ast_from_text(&format!("struct S {{ {}{}: {}, }}", visibility, name, ty))
+    ast_from_text(&format!("struct S {{ {visibility}{name}: {ty}, }}"))
 }
 
 // TODO
@@ -323,13 +325,13 @@ pub fn block_expr(
 ) -> ast::BlockExpr {
     let mut buf = "{\n".to_string();
     for stmt in stmts.into_iter() {
-        format_to!(buf, "    {}\n", stmt);
+        format_to!(buf, "    {stmt}\n");
     }
     if let Some(tail_expr) = tail_expr {
-        format_to!(buf, "    {}\n", tail_expr);
+        format_to!(buf, "    {tail_expr}\n");
     }
     buf += "}";
-    ast_from_text(&format!("fn f() {}", buf))
+    ast_from_text(&format!("fn f() {buf}"))
 }
 
 /// Ideally this function wouldn't exist since it involves manual indenting.
@@ -343,18 +345,18 @@ pub fn hacky_block_expr_with_comments(
     let mut buf = "{\n".to_string();
     for node_or_token in elements.into_iter() {
         match node_or_token {
-            rowan::NodeOrToken::Node(n) => format_to!(buf, "    {}\n", n),
+            rowan::NodeOrToken::Node(n) => format_to!(buf, "    {n}\n"),
             rowan::NodeOrToken::Token(t) if t.kind() == SyntaxKind::COMMENT => {
-                format_to!(buf, "    {}\n", t)
+                format_to!(buf, "    {t}\n")
             }
             _ => (),
         }
     }
     if let Some(tail_expr) = tail_expr {
-        format_to!(buf, "    {}\n", tail_expr);
+        format_to!(buf, "    {tail_expr}\n");
     }
     buf += "}";
-    ast_from_text(&format!("fn f() {}", buf))
+    ast_from_text(&format!("fn f() {buf}"))
 }
 
 pub fn expr_unit() -> ast::Expr {
@@ -362,7 +364,7 @@ pub fn expr_unit() -> ast::Expr {
 }
 pub fn expr_literal(text: &str) -> ast::Literal {
     assert_eq!(text.trim(), text);
-    ast_from_text(&format!("fn f() {{ let _ = {}; }}", text))
+    ast_from_text(&format!("fn f() {{ let _ = {text}; }}"))
 }
 
 pub fn expr_empty_block() -> ast::Expr {
@@ -373,41 +375,41 @@ pub fn expr_path(path: ast::Path) -> ast::Expr {
 }
 pub fn expr_continue(label: Option<ast::Lifetime>) -> ast::Expr {
     match label {
-        Some(label) => expr_from_text(&format!("continue {}", label)),
+        Some(label) => expr_from_text(&format!("continue {label}")),
         None => expr_from_text("continue"),
     }
 }
 // Consider `op: SyntaxKind` instead for nicer syntax at the call-site?
 pub fn expr_bin_op(lhs: ast::Expr, op: ast::BinaryOp, rhs: ast::Expr) -> ast::Expr {
-    expr_from_text(&format!("{} {} {}", lhs, op, rhs))
+    expr_from_text(&format!("{lhs} {op} {rhs}"))
 }
 pub fn expr_break(label: Option<ast::Lifetime>, expr: Option<ast::Expr>) -> ast::Expr {
     let mut s = String::from("break");
 
     if let Some(label) = label {
-        format_to!(s, " {}", label);
+        format_to!(s, " {label}");
     }
 
     if let Some(expr) = expr {
-        format_to!(s, " {}", expr);
+        format_to!(s, " {expr}");
     }
 
     expr_from_text(&s)
 }
 pub fn expr_return(expr: Option<ast::Expr>) -> ast::Expr {
     match expr {
-        Some(expr) => expr_from_text(&format!("return {}", expr)),
+        Some(expr) => expr_from_text(&format!("return {expr}")),
         None => expr_from_text("return"),
     }
 }
 pub fn expr_try(expr: ast::Expr) -> ast::Expr {
-    expr_from_text(&format!("{}?", expr))
+    expr_from_text(&format!("{expr}?"))
 }
 pub fn expr_await(expr: ast::Expr) -> ast::Expr {
-    expr_from_text(&format!("{}.await", expr))
+    expr_from_text(&format!("{expr}.await"))
 }
 pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::Expr {
-    expr_from_text(&format!("match {} {}", expr, match_arm_list))
+    expr_from_text(&format!("match {expr} {match_arm_list}"))
 }
 pub fn expr_if(
     condition: ast::Expr,
@@ -415,66 +417,67 @@ pub fn expr_if(
     else_branch: Option<ast::ElseBranch>,
 ) -> ast::Expr {
     let else_branch = match else_branch {
-        Some(ast::ElseBranch::Block(block)) => format!("else {}", block),
-        Some(ast::ElseBranch::IfExpr(if_expr)) => format!("else {}", if_expr),
+        Some(ast::ElseBranch::Block(block)) => format!("else {block}"),
+        Some(ast::ElseBranch::IfExpr(if_expr)) => format!("else {if_expr}"),
         None => String::new(),
     };
-    expr_from_text(&format!("if {} {} {}", condition, then_branch, else_branch))
+    expr_from_text(&format!("if {condition} {then_branch} {else_branch}"))
 }
 pub fn expr_for_loop(pat: ast::Pat, expr: ast::Expr, block: ast::BlockExpr) -> ast::Expr {
-    expr_from_text(&format!("for {} in {} {}", pat, expr, block))
+    expr_from_text(&format!("for {pat} in {expr} {block}"))
 }
 
 pub fn expr_loop(block: ast::BlockExpr) -> ast::Expr {
-    expr_from_text(&format!("loop {}", block))
+    expr_from_text(&format!("loop {block}"))
 }
 
 pub fn expr_prefix(op: SyntaxKind, expr: ast::Expr) -> ast::Expr {
     let token = token(op);
-    expr_from_text(&format!("{}{}", token, expr))
+    expr_from_text(&format!("{token}{expr}"))
 }
 pub fn expr_call(f: ast::Expr, arg_list: ast::ArgList) -> ast::Expr {
-    expr_from_text(&format!("{}{}", f, arg_list))
+    expr_from_text(&format!("{f}{arg_list}"))
 }
 pub fn expr_method_call(
     receiver: ast::Expr,
     method: ast::NameRef,
     arg_list: ast::ArgList,
 ) -> ast::Expr {
-    expr_from_text(&format!("{}.{}{}", receiver, method, arg_list))
+    expr_from_text(&format!("{receiver}.{method}{arg_list}"))
 }
 pub fn expr_macro_call(f: ast::Expr, arg_list: ast::ArgList) -> ast::Expr {
-    expr_from_text(&format!("{}!{}", f, arg_list))
+    expr_from_text(&format!("{f}!{arg_list}"))
 }
 pub fn expr_ref(expr: ast::Expr, exclusive: bool) -> ast::Expr {
-    expr_from_text(&if exclusive { format!("&mut {}", expr) } else { format!("&{}", expr) })
+    expr_from_text(&if exclusive { format!("&mut {expr}") } else { format!("&{expr}") })
 }
 pub fn expr_closure(pats: impl IntoIterator<Item = ast::Param>, expr: ast::Expr) -> ast::Expr {
     let params = pats.into_iter().join(", ");
-    expr_from_text(&format!("|{}| {}", params, expr))
+    expr_from_text(&format!("|{params}| {expr}"))
 }
 pub fn expr_field(receiver: ast::Expr, field: &str) -> ast::Expr {
-    expr_from_text(&format!("{}.{}", receiver, field))
+    expr_from_text(&format!("{receiver}.{field}"))
 }
 pub fn expr_paren(expr: ast::Expr) -> ast::Expr {
-    expr_from_text(&format!("({})", expr))
+    expr_from_text(&format!("({expr})"))
 }
 pub fn expr_tuple(elements: impl IntoIterator<Item = ast::Expr>) -> ast::Expr {
     let expr = elements.into_iter().format(", ");
-    expr_from_text(&format!("({})", expr))
+    expr_from_text(&format!("({expr})"))
 }
 pub fn expr_assignment(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr {
-    expr_from_text(&format!("{} = {}", lhs, rhs))
+    expr_from_text(&format!("{lhs} = {rhs}"))
 }
 fn expr_from_text(text: &str) -> ast::Expr {
-    ast_from_text(&format!("const C: () = {};", text))
+    ast_from_text(&format!("const C: () = {text};"))
 }
 pub fn expr_let(pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr {
-    ast_from_text(&format!("const _: () = while let {} = {} {{}};", pattern, expr))
+    ast_from_text(&format!("const _: () = while let {pattern} = {expr} {{}};"))
 }
 
 pub fn arg_list(args: impl IntoIterator<Item = ast::Expr>) -> ast::ArgList {
-    ast_from_text(&format!("fn main() {{ ()({}) }}", args.into_iter().format(", ")))
+    let args = args.into_iter().format(", ");
+    ast_from_text(&format!("fn main() {{ ()({args}) }}"))
 }
 
 pub fn ident_pat(ref_: bool, mut_: bool, name: ast::Name) -> ast::IdentPat {
@@ -485,7 +488,7 @@ pub fn ident_pat(ref_: bool, mut_: bool, name: ast::Name) -> ast::IdentPat {
     if mut_ {
         s.push_str("mut ");
     }
-    format_to!(s, "{}", name);
+    format_to!(s, "{name}");
     s.push_str(": ())");
     ast_from_text(&s)
 }
@@ -494,7 +497,7 @@ pub fn wildcard_pat() -> ast::WildcardPat {
     return from_text("_");
 
     fn from_text(text: &str) -> ast::WildcardPat {
-        ast_from_text(&format!("fn f({}: ())", text))
+        ast_from_text(&format!("fn f({text}: ())"))
     }
 }
 
@@ -502,7 +505,7 @@ pub fn literal_pat(lit: &str) -> ast::LiteralPat {
     return from_text(lit);
 
     fn from_text(text: &str) -> ast::LiteralPat {
-        ast_from_text(&format!("fn f() {{ match x {{ {} => {{}} }} }}", text))
+        ast_from_text(&format!("fn f() {{ match x {{ {text} => {{}} }} }}"))
     }
 }
 
@@ -515,10 +518,10 @@ pub fn tuple_pat(pats: impl IntoIterator<Item = ast::Pat>) -> ast::TuplePat {
     if count == 1 {
         pats_str.push(',');
     }
-    return from_text(&format!("({})", pats_str));
+    return from_text(&format!("({pats_str})"));
 
     fn from_text(text: &str) -> ast::TuplePat {
-        ast_from_text(&format!("fn f({}: ())", text))
+        ast_from_text(&format!("fn f({text}: ())"))
     }
 }
 
@@ -527,46 +530,46 @@ pub fn tuple_struct_pat(
     pats: impl IntoIterator<Item = ast::Pat>,
 ) -> ast::TupleStructPat {
     let pats_str = pats.into_iter().join(", ");
-    return from_text(&format!("{}({})", path, pats_str));
+    return from_text(&format!("{path}({pats_str})"));
 
     fn from_text(text: &str) -> ast::TupleStructPat {
-        ast_from_text(&format!("fn f({}: ())", text))
+        ast_from_text(&format!("fn f({text}: ())"))
     }
 }
 
 pub fn record_pat(path: ast::Path, pats: impl IntoIterator<Item = ast::Pat>) -> ast::RecordPat {
     let pats_str = pats.into_iter().join(", ");
-    return from_text(&format!("{} {{ {} }}", path, pats_str));
+    return from_text(&format!("{path} {{ {pats_str} }}"));
 
     fn from_text(text: &str) -> ast::RecordPat {
-        ast_from_text(&format!("fn f({}: ())", text))
+        ast_from_text(&format!("fn f({text}: ())"))
     }
 }
 
 pub fn record_pat_with_fields(path: ast::Path, fields: ast::RecordPatFieldList) -> ast::RecordPat {
-    ast_from_text(&format!("fn f({} {}: ()))", path, fields))
+    ast_from_text(&format!("fn f({path} {fields}: ()))"))
 }
 
 pub fn record_pat_field_list(
     fields: impl IntoIterator<Item = ast::RecordPatField>,
 ) -> ast::RecordPatFieldList {
     let fields = fields.into_iter().join(", ");
-    ast_from_text(&format!("fn f(S {{ {} }}: ()))", fields))
+    ast_from_text(&format!("fn f(S {{ {fields} }}: ()))"))
 }
 
 pub fn record_pat_field(name_ref: ast::NameRef, pat: ast::Pat) -> ast::RecordPatField {
-    ast_from_text(&format!("fn f(S {{ {}: {} }}: ()))", name_ref, pat))
+    ast_from_text(&format!("fn f(S {{ {name_ref}: {pat} }}: ()))"))
 }
 
 pub fn record_pat_field_shorthand(name_ref: ast::NameRef) -> ast::RecordPatField {
-    ast_from_text(&format!("fn f(S {{ {} }}: ()))", name_ref))
+    ast_from_text(&format!("fn f(S {{ {name_ref} }}: ()))"))
 }
 
 /// Returns a `BindPat` if the path has just one segment, a `PathPat` otherwise.
 pub fn path_pat(path: ast::Path) -> ast::Pat {
     return from_text(&path.to_string());
     fn from_text(text: &str) -> ast::Pat {
-        ast_from_text(&format!("fn f({}: ())", text))
+        ast_from_text(&format!("fn f({text}: ())"))
     }
 }
 
@@ -577,12 +580,12 @@ pub fn match_arm(
 ) -> ast::MatchArm {
     let pats_str = pats.into_iter().join(" | ");
     return match guard {
-        Some(guard) => from_text(&format!("{} if {} => {}", pats_str, guard, expr)),
-        None => from_text(&format!("{} => {}", pats_str, expr)),
+        Some(guard) => from_text(&format!("{pats_str} if {guard} => {expr}")),
+        None => from_text(&format!("{pats_str} => {expr}")),
     };
 
     fn from_text(text: &str) -> ast::MatchArm {
-        ast_from_text(&format!("fn f() {{ match () {{{}}} }}", text))
+        ast_from_text(&format!("fn f() {{ match () {{{text}}} }}"))
     }
 }
 
@@ -592,10 +595,10 @@ pub fn match_arm_with_guard(
     expr: ast::Expr,
 ) -> ast::MatchArm {
     let pats_str = pats.into_iter().join(" | ");
-    return from_text(&format!("{} if {} => {}", pats_str, guard, expr));
+    return from_text(&format!("{pats_str} if {guard} => {expr}"));
 
     fn from_text(text: &str) -> ast::MatchArm {
-        ast_from_text(&format!("fn f() {{ match () {{{}}} }}", text))
+        ast_from_text(&format!("fn f() {{ match () {{{text}}} }}"))
     }
 }
 
@@ -605,13 +608,14 @@ pub fn match_arm_list(arms: impl IntoIterator<Item = ast::MatchArm>) -> ast::Mat
         .map(|arm| {
             let needs_comma = arm.expr().map_or(true, |it| !it.is_block_like());
             let comma = if needs_comma { "," } else { "" };
-            format!("    {}{}\n", arm.syntax(), comma)
+            let arm = arm.syntax();
+            format!("    {arm}{comma}\n")
         })
         .collect::<String>();
     return from_text(&arms_str);
 
     fn from_text(text: &str) -> ast::MatchArmList {
-        ast_from_text(&format!("fn f() {{ match () {{\n{}}} }}", text))
+        ast_from_text(&format!("fn f() {{ match () {{\n{text}}} }}"))
     }
 }
 
@@ -620,10 +624,10 @@ pub fn where_pred(
     bounds: impl IntoIterator<Item = ast::TypeBound>,
 ) -> ast::WherePred {
     let bounds = bounds.into_iter().join(" + ");
-    return from_text(&format!("{}: {}", path, bounds));
+    return from_text(&format!("{path}: {bounds}"));
 
     fn from_text(text: &str) -> ast::WherePred {
-        ast_from_text(&format!("fn f() where {} {{ }}", text))
+        ast_from_text(&format!("fn f() where {text} {{ }}"))
     }
 }
 
@@ -632,7 +636,7 @@ pub fn where_clause(preds: impl IntoIterator<Item = ast::WherePred>) -> ast::Whe
     return from_text(preds.as_str());
 
     fn from_text(text: &str) -> ast::WhereClause {
-        ast_from_text(&format!("fn f() where {} {{ }}", text))
+        ast_from_text(&format!("fn f() where {text} {{ }}"))
     }
 }
 
@@ -642,19 +646,19 @@ pub fn let_stmt(
     initializer: Option<ast::Expr>,
 ) -> ast::LetStmt {
     let mut text = String::new();
-    format_to!(text, "let {}", pattern);
+    format_to!(text, "let {pattern}");
     if let Some(ty) = ty {
-        format_to!(text, ": {}", ty);
+        format_to!(text, ": {ty}");
     }
     match initializer {
-        Some(it) => format_to!(text, " = {};", it),
+        Some(it) => format_to!(text, " = {it};"),
         None => format_to!(text, ";"),
     };
-    ast_from_text(&format!("fn f() {{ {} }}", text))
+    ast_from_text(&format!("fn f() {{ {text} }}"))
 }
 pub fn expr_stmt(expr: ast::Expr) -> ast::ExprStmt {
     let semi = if expr.is_block_like() { "" } else { ";" };
-    ast_from_text(&format!("fn f() {{ {}{} (); }}", expr, semi))
+    ast_from_text(&format!("fn f() {{ {expr}{semi} (); }}"))
 }
 
 pub fn item_const(
@@ -665,13 +669,13 @@ pub fn item_const(
 ) -> ast::Const {
     let visibility = match visibility {
         None => String::new(),
-        Some(it) => format!("{} ", it),
+        Some(it) => format!("{it} "),
     };
-    ast_from_text(&format!("{} const {}: {} = {};", visibility, name, ty, expr))
+    ast_from_text(&format!("{visibility} const {name}: {ty} = {expr};"))
 }
 
 pub fn param(pat: ast::Pat, ty: ast::Type) -> ast::Param {
-    ast_from_text(&format!("fn f({}: {}) {{ }}", pat, ty))
+    ast_from_text(&format!("fn f({pat}: {ty}) {{ }}"))
 }
 
 pub fn self_param() -> ast::SelfParam {
@@ -679,7 +683,7 @@ pub fn self_param() -> ast::SelfParam {
 }
 
 pub fn ret_type(ty: ast::Type) -> ast::RetType {
-    ast_from_text(&format!("fn f() -> {} {{ }}", ty))
+    ast_from_text(&format!("fn f() -> {ty} {{ }}"))
 }
 
 pub fn param_list(
@@ -688,30 +692,30 @@ pub fn param_list(
 ) -> ast::ParamList {
     let args = pats.into_iter().join(", ");
     let list = match self_param {
-        Some(self_param) if args.is_empty() => format!("fn f({}) {{ }}", self_param),
-        Some(self_param) => format!("fn f({}, {}) {{ }}", self_param, args),
-        None => format!("fn f({}) {{ }}", args),
+        Some(self_param) if args.is_empty() => format!("fn f({self_param}) {{ }}"),
+        Some(self_param) => format!("fn f({self_param}, {args}) {{ }}"),
+        None => format!("fn f({args}) {{ }}"),
     };
     ast_from_text(&list)
 }
 
 pub fn type_param(name: ast::Name, ty: Option<ast::TypeBoundList>) -> ast::TypeParam {
     let bound = match ty {
-        Some(it) => format!(": {}", it),
+        Some(it) => format!(": {it}"),
         None => String::new(),
     };
-    ast_from_text(&format!("fn f<{}{}>() {{ }}", name, bound))
+    ast_from_text(&format!("fn f<{name}{bound}>() {{ }}"))
 }
 
 pub fn lifetime_param(lifetime: ast::Lifetime) -> ast::LifetimeParam {
-    ast_from_text(&format!("fn f<{}>() {{ }}", lifetime))
+    ast_from_text(&format!("fn f<{lifetime}>() {{ }}"))
 }
 
 pub fn generic_param_list(
     pats: impl IntoIterator<Item = ast::GenericParam>,
 ) -> ast::GenericParamList {
     let args = pats.into_iter().join(", ");
-    ast_from_text(&format!("fn f<{}>() {{ }}", args))
+    ast_from_text(&format!("fn f<{args}>() {{ }}"))
 }
 
 pub fn visibility_pub_crate() -> ast::Visibility {
@@ -724,33 +728,33 @@ pub fn visibility_pub() -> ast::Visibility {
 
 pub fn tuple_field_list(fields: impl IntoIterator<Item = ast::TupleField>) -> ast::TupleFieldList {
     let fields = fields.into_iter().join(", ");
-    ast_from_text(&format!("struct f({});", fields))
+    ast_from_text(&format!("struct f({fields});"))
 }
 
 pub fn record_field_list(
     fields: impl IntoIterator<Item = ast::RecordField>,
 ) -> ast::RecordFieldList {
     let fields = fields.into_iter().join(", ");
-    ast_from_text(&format!("struct f {{ {} }}", fields))
+    ast_from_text(&format!("struct f {{ {fields} }}"))
 }
 
 pub fn tuple_field(visibility: Option<ast::Visibility>, ty: ast::Type) -> ast::TupleField {
     let visibility = match visibility {
         None => String::new(),
-        Some(it) => format!("{} ", it),
+        Some(it) => format!("{it} "),
     };
-    ast_from_text(&format!("struct f({}{});", visibility, ty))
+    ast_from_text(&format!("struct f({visibility}{ty});"))
 }
 
 pub fn variant(name: ast::Name, field_list: Option<ast::FieldList>) -> ast::Variant {
     let field_list = match field_list {
         None => String::new(),
         Some(it) => match it {
-            ast::FieldList::RecordFieldList(record) => format!(" {}", record),
-            ast::FieldList::TupleFieldList(tuple) => format!("{}", tuple),
+            ast::FieldList::RecordFieldList(record) => format!(" {record}"),
+            ast::FieldList::TupleFieldList(tuple) => format!("{tuple}"),
         },
     };
-    ast_from_text(&format!("enum f {{ {}{} }}", name, field_list))
+    ast_from_text(&format!("enum f {{ {name}{field_list} }}"))
 }
 
 pub fn fn_(
@@ -763,23 +767,22 @@ pub fn fn_(
     is_async: bool,
 ) -> ast::Fn {
     let type_params = match type_params {
-        Some(type_params) => format!("{}", type_params),
+        Some(type_params) => format!("{type_params}"),
         None => "".into(),
     };
     let ret_type = match ret_type {
-        Some(ret_type) => format!("{} ", ret_type),
+        Some(ret_type) => format!("{ret_type} "),
         None => "".into(),
     };
     let visibility = match visibility {
         None => String::new(),
-        Some(it) => format!("{} ", it),
+        Some(it) => format!("{it} "),
     };
 
     let async_literal = if is_async { "async " } else { "" };
 
     ast_from_text(&format!(
-        "{}{}fn {}{}{} {}{}",
-        visibility, async_literal, fn_name, type_params, params, ret_type, body
+        "{visibility}{async_literal}fn {fn_name}{type_params}{params} {ret_type}{body}",
     ))
 }
 
@@ -793,13 +796,10 @@ pub fn struct_(
     let type_params = generic_param_list.map_or_else(String::new, |it| it.to_string());
     let visibility = match visibility {
         None => String::new(),
-        Some(it) => format!("{} ", it),
+        Some(it) => format!("{it} "),
     };
 
-    ast_from_text(&format!(
-        "{}struct {}{}{}{}",
-        visibility, strukt_name, type_params, field_list, semicolon
-    ))
+    ast_from_text(&format!("{visibility}struct {strukt_name}{type_params}{field_list}{semicolon}",))
 }
 
 #[track_caller]
@@ -808,7 +808,8 @@ fn ast_from_text<N: AstNode>(text: &str) -> N {
     let node = match parse.tree().syntax().descendants().find_map(N::cast) {
         Some(it) => it,
         None => {
-            panic!("Failed to make ast node `{}` from text {}", std::any::type_name::<N>(), text)
+            let node = std::any::type_name::<N>();
+            panic!("Failed to make ast node `{node}` from text {text}")
         }
     };
     let node = node.clone_subtree();
@@ -824,7 +825,7 @@ pub fn token(kind: SyntaxKind) -> SyntaxToken {
         .descendants_with_tokens()
         .filter_map(|it| it.into_token())
         .find(|it| it.kind() == kind)
-        .unwrap_or_else(|| panic!("unhandled token: {:?}", kind))
+        .unwrap_or_else(|| panic!("unhandled token: {kind:?}"))
 }
 
 pub mod tokens {
@@ -863,7 +864,7 @@ pub mod tokens {
 
     pub fn literal(text: &str) -> SyntaxToken {
         assert_eq!(text.trim(), text);
-        let lit: ast::Literal = super::ast_from_text(&format!("fn f() {{ let _ = {}; }}", text));
+        let lit: ast::Literal = super::ast_from_text(&format!("fn f() {{ let _ = {text}; }}"));
         lit.syntax().first_child_or_token().unwrap().into_token().unwrap()
     }
 
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs
index 28976d837b8..ba72e64425b 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs
@@ -322,7 +322,7 @@ impl ast::IntNumber {
 
     pub fn float_value(&self) -> Option<f64> {
         let (_, text, _) = self.split_into_parts();
-        text.parse::<f64>().ok()
+        text.replace('_', "").parse::<f64>().ok()
     }
 }
 
@@ -361,7 +361,7 @@ impl ast::FloatNumber {
 
     pub fn value(&self) -> Option<f64> {
         let (text, _) = self.split_into_parts();
-        text.parse::<f64>().ok()
+        text.replace('_', "").parse::<f64>().ok()
     }
 }
 
@@ -397,6 +397,15 @@ mod tests {
         assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.suffix(), expected.into());
     }
 
+    fn check_float_value(lit: &str, expected: impl Into<Option<f64>> + Copy) {
+        assert_eq!(FloatNumber { syntax: make::tokens::literal(lit) }.value(), expected.into());
+        assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.float_value(), expected.into());
+    }
+
+    fn check_int_value(lit: &str, expected: impl Into<Option<u128>>) {
+        assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.value(), expected.into());
+    }
+
     #[test]
     fn test_float_number_suffix() {
         check_float_suffix("123.0", None);
@@ -437,6 +446,14 @@ mod tests {
         check_string_value(r"\nfoobar", "\nfoobar");
         check_string_value(r"C:\\Windows\\System32\\", "C:\\Windows\\System32\\");
     }
+
+    #[test]
+    fn test_value_underscores() {
+        check_float_value("3.141592653589793_f64", 3.141592653589793_f64);
+        check_float_value("1__0.__0__f32", 10.0);
+        check_int_value("0b__1_0_", 2);
+        check_int_value("1_1_1_1_1_1", 111111);
+    }
 }
 
 impl ast::Char {
diff --git a/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs b/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs
index 6d276622510..70b54843dba 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs
@@ -169,10 +169,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String {
                 quote! {
                     impl AstNode for #name {
                         fn can_cast(kind: SyntaxKind) -> bool {
-                            match kind {
-                                #(#kinds)|* => true,
-                                _ => false,
-                            }
+                            matches!(kind, #(#kinds)|*)
                         }
                         fn cast(syntax: SyntaxNode) -> Option<Self> {
                             let res = match syntax.kind() {
@@ -253,10 +250,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String {
                     }
                     impl AstNode for #name {
                         fn can_cast(kind: SyntaxKind) -> bool {
-                            match kind {
-                                #(#kinds)|* => true,
-                                _ => false,
-                            }
+                            matches!(kind, #(#kinds)|*)
                         }
                         fn cast(syntax: SyntaxNode) -> Option<Self> {
                             Self::can_cast(syntax.kind()).then(|| #name { syntax })
@@ -410,24 +404,17 @@ fn generate_syntax_kinds(grammar: KindsSrc<'_>) -> String {
 
         impl SyntaxKind {
             pub fn is_keyword(self) -> bool {
-                match self {
-                    #(#all_keywords)|* => true,
-                    _ => false,
-                }
+                matches!(self, #(#all_keywords)|*)
             }
 
             pub fn is_punct(self) -> bool {
-                match self {
-                    #(#punctuation)|* => true,
-                    _ => false,
-                }
+
+                matches!(self, #(#punctuation)|*)
+
             }
 
             pub fn is_literal(self) -> bool {
-                match self {
-                    #(#literals)|* => true,
-                    _ => false,
-                }
+                matches!(self, #(#literals)|*)
             }
 
             pub fn from_keyword(ident: &str) -> Option<SyntaxKind> {
diff --git a/src/tools/rust-analyzer/lib/la-arena/src/lib.rs b/src/tools/rust-analyzer/lib/la-arena/src/lib.rs
index 50e8d06b660..ccaaf399176 100644
--- a/src/tools/rust-analyzer/lib/la-arena/src/lib.rs
+++ b/src/tools/rust-analyzer/lib/la-arena/src/lib.rs
@@ -322,6 +322,43 @@ impl<T> Arena<T> {
             .map(|(idx, value)| (Idx::from_raw(RawIdx(idx as u32)), value))
     }
 
+    /// Returns an iterator over the arena’s values.
+    ///
+    /// ```
+    /// let mut arena = la_arena::Arena::new();
+    /// let idx1 = arena.alloc(20);
+    /// let idx2 = arena.alloc(40);
+    /// let idx3 = arena.alloc(60);
+    ///
+    /// let mut iterator = arena.values();
+    /// assert_eq!(iterator.next(), Some(&20));
+    /// assert_eq!(iterator.next(), Some(&40));
+    /// assert_eq!(iterator.next(), Some(&60));
+    /// ```
+    pub fn values(&mut self) -> impl Iterator<Item = &T> + ExactSizeIterator + DoubleEndedIterator {
+        self.data.iter()
+    }
+
+    /// Returns an iterator over the arena’s mutable values.
+    ///
+    /// ```
+    /// let mut arena = la_arena::Arena::new();
+    /// let idx1 = arena.alloc(20);
+    ///
+    /// assert_eq!(arena[idx1], 20);
+    ///
+    /// let mut iterator = arena.values_mut();
+    /// *iterator.next().unwrap() = 10;
+    /// drop(iterator);
+    ///
+    /// assert_eq!(arena[idx1], 10);
+    /// ```
+    pub fn values_mut(
+        &mut self,
+    ) -> impl Iterator<Item = &mut T> + ExactSizeIterator + DoubleEndedIterator {
+        self.data.iter_mut()
+    }
+
     /// Reallocates the arena to make it take up as little space as possible.
     pub fn shrink_to_fit(&mut self) {
         self.data.shrink_to_fit();
diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs
index 9b74b35f314..e2fe92b28f2 100644
--- a/src/tools/rustfmt/src/patterns.rs
+++ b/src/tools/rustfmt/src/patterns.rs
@@ -1,4 +1,6 @@
-use rustc_ast::ast::{self, BindingMode, Pat, PatField, PatKind, RangeEnd, RangeSyntax};
+use rustc_ast::ast::{
+    self, BindingAnnotation, ByRef, Pat, PatField, PatKind, RangeEnd, RangeSyntax,
+};
 use rustc_ast::ptr;
 use rustc_span::{BytePos, Span};
 
@@ -99,10 +101,10 @@ impl Rewrite for Pat {
                 write_list(&items, &fmt)
             }
             PatKind::Box(ref pat) => rewrite_unary_prefix(context, "box ", &**pat, shape),
-            PatKind::Ident(binding_mode, ident, ref sub_pat) => {
-                let (prefix, mutability) = match binding_mode {
-                    BindingMode::ByRef(mutability) => ("ref", mutability),
-                    BindingMode::ByValue(mutability) => ("", mutability),
+            PatKind::Ident(BindingAnnotation(by_ref, mutability), ident, ref sub_pat) => {
+                let prefix = match by_ref {
+                    ByRef::Yes => "ref",
+                    ByRef::No => "",
                 };
                 let mut_infix = format_mutability(mutability).trim();
                 let id_str = rewrite_ident(context, ident);
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index de292d3305d..b306a527a7c 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -199,8 +199,7 @@ pub fn check(
         if channel != "nightly" && since == Version::CurrentPlaceholder {
             tidy_error!(
                 bad,
-                "The placeholder use of {kind} feature `{feature_name}` is not allowed on the {} channel",
-                version::VERSION_PLACEHOLDER
+                "The placeholder use of {kind} feature `{feature_name}` is not allowed on the {channel} channel",
             );
         }
     }
diff --git a/triagebot.toml b/triagebot.toml
index 89d1574726f..89edab91fcd 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -316,9 +316,6 @@ Examples of `T-libs-api` changes:
 * Changing observable runtime behavior of library APIs
 """
 
-[mentions."library/proc_macro/src/bridge"]
-cc = ["@rust-lang/wg-rls-2"]
-
 [mentions."src/librustdoc/clean/types.rs"]
 cc = ["@camelid"]