about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock10
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs266
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs39
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs7
-rw-r--r--compiler/rustc_borrowck/src/lib.rs13
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs10
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs19
-rw-r--r--compiler/rustc_codegen_cranelift/src/value_and_place.rs4
-rw-r--r--compiler/rustc_codegen_gcc/src/builder.rs20
-rw-r--r--compiler/rustc_codegen_gcc/src/type_of.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/type_of.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/intrinsic.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/builder.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/discriminant.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs2
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs2
-rw-r--r--compiler/rustc_const_eval/src/util/type_name.rs2
-rw-r--r--compiler/rustc_data_structures/src/hashes.rs2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0453.md4
-rw-r--r--compiler/rustc_hir/src/def_path_hash_map.rs17
-rw-r--r--compiler/rustc_hir/src/definitions.rs49
-rw-r--r--compiler/rustc_hir_typeck/src/check.rs7
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs48
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs2
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs2
-rw-r--r--compiler/rustc_infer/src/infer/outlives/components.rs2
-rw-r--r--compiler/rustc_infer/src/infer/relate/generalize.rs5
-rw-r--r--compiler/rustc_lint/src/context.rs4
-rw-r--r--compiler/rustc_lint/src/levels.rs62
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs40
-rw-r--r--compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs4
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs46
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs93
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs6
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs3
-rw-r--r--compiler/rustc_middle/src/mir/tcx.rs4
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs1
-rw-r--r--compiler/rustc_middle/src/ty/context.rs6
-rw-r--r--compiler/rustc_middle/src/ty/fast_reject.rs2
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs2
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs4
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs2
-rw-r--r--compiler/rustc_middle/src/ty/opaque_types.rs4
-rw-r--r--compiler/rustc_middle/src/ty/print/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs6
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs6
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs6
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs117
-rw-r--r--compiler/rustc_middle/src/ty/walk.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs7
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs4
-rw-r--r--compiler/rustc_mir_dataflow/src/elaborate_drops.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs4
-rw-r--r--compiler/rustc_mir_transform/src/check_unsafety.rs2
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs526
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs50
-rw-r--r--compiler/rustc_mir_transform/src/coverage/counters.rs9
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs2
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs4
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs1
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs5
-rw-r--r--compiler/rustc_next_trait_solver/src/canonicalizer.rs2
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs38
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs8
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs54
-rw-r--r--compiler/rustc_passes/src/liveness.rs38
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs2
-rw-r--r--compiler/rustc_smir/src/rustc_internal/internal.rs8
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/mir.rs4
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/ty.rs4
-rw-r--r--compiler/rustc_symbol_mangling/src/legacy.rs2
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs4
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs22
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs8
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs46
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs2
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs8
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs4
-rw-r--r--compiler/rustc_ty_utils/src/needs_drop.rs2
-rw-r--r--compiler/rustc_type_ir/src/ty_kind.rs12
-rw-r--r--compiler/stable_mir/src/mir/body.rs1
-rw-r--r--compiler/stable_mir/src/ty.rs1
-rw-r--r--config.example.toml2
-rw-r--r--library/alloc/src/raw_vec.rs4
-rw-r--r--library/alloc/src/sync.rs25
-rw-r--r--library/alloc/src/vec/mod.rs12
-rwxr-xr-xsrc/bootstrap/configure.py1
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs50
-rw-r--r--src/bootstrap/src/core/build_steps/run.rs5
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs41
-rw-r--r--src/bootstrap/src/core/build_steps/tool.rs136
-rw-r--r--src/bootstrap/src/core/builder.rs2
-rw-r--r--src/bootstrap/src/core/config/config.rs4
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs5
-rw-r--r--src/ci/docker/host-x86_64/dist-powerpc-linux/Dockerfile2
-rwxr-xr-xsrc/ci/run.sh4
-rw-r--r--src/librustdoc/html/static/js/search.js47
-rw-r--r--src/tools/clippy/CHANGELOG.md68
-rw-r--r--src/tools/clippy/Cargo.toml2
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md2
-rw-r--r--src/tools/clippy/clippy_config/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_config/src/conf.rs5
-rw-r--r--src/tools/clippy/clippy_config/src/msrvs.rs7
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_lints/src/assertions_on_constants.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/async_yields_async.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/missing_headers.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/format_push_string.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/indexing_slicing.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/ineffective_open_options.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs2
-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_async_fn.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_hash_one.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_let_else.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_utils.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs130
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map.rs89
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_filter.rs87
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs101
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs56
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_bool.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/option_if_let_else.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_async_block.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_closure_call.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs74
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/mod.rs61
-rw-r--r--src/tools/clippy/clippy_lints/src/unconditional_recursion.rs134
-rw-r--r--src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/uninhabited_references.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs1
-rw-r--r--src/tools/clippy/clippy_utils/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/attrs.rs11
-rw-r--r--src/tools/clippy/clippy_utils/src/higher.rs20
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs5
-rw-r--r--src/tools/clippy/declare_clippy_lint/Cargo.toml2
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/tests/ui-internal/disallow_struct_span_lint.rs4
-rw-r--r--src/tools/clippy/tests/ui-internal/disallow_struct_span_lint.stderr8
-rw-r--r--src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs3
-rw-r--r--src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr18
-rw-r--r--src/tools/clippy/tests/ui/assertions_on_constants.rs7
-rw-r--r--src/tools/clippy/tests/ui/assertions_on_constants.stderr10
-rw-r--r--src/tools/clippy/tests/ui/author/loop.rs6
-rw-r--r--src/tools/clippy/tests/ui/bool_comparison.fixed9
-rw-r--r--src/tools/clippy/tests/ui/bool_comparison.rs9
-rw-r--r--src/tools/clippy/tests/ui/bool_comparison.stderr20
-rw-r--r--src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs8
-rw-r--r--src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr18
-rw-r--r--src/tools/clippy/tests/ui/collapsible_if.fixed3
-rw-r--r--src/tools/clippy/tests/ui/collapsible_if.rs3
-rw-r--r--src/tools/clippy/tests/ui/collapsible_if.stderr18
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-11939.rs14
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-5497.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-5497.stderr2
-rw-r--r--src/tools/clippy/tests/ui/doc/doc-fixable.fixed2
-rw-r--r--src/tools/clippy/tests/ui/doc/doc-fixable.rs2
-rw-r--r--src/tools/clippy/tests/ui/eager_transmute.fixed72
-rw-r--r--src/tools/clippy/tests/ui/eager_transmute.rs72
-rw-r--r--src/tools/clippy/tests/ui/eager_transmute.stderr92
-rw-r--r--src/tools/clippy/tests/ui/get_unwrap.fixed3
-rw-r--r--src/tools/clippy/tests/ui/get_unwrap.rs3
-rw-r--r--src/tools/clippy/tests/ui/get_unwrap.stderr62
-rw-r--r--src/tools/clippy/tests/ui/if_then_some_else_none.rs1
-rw-r--r--src/tools/clippy/tests/ui/if_then_some_else_none.stderr10
-rw-r--r--src/tools/clippy/tests/ui/indexing_slicing_index.rs3
-rw-r--r--src/tools/clippy/tests/ui/indexing_slicing_index.stderr35
-rw-r--r--src/tools/clippy/tests/ui/infinite_loops.stderr30
-rw-r--r--src/tools/clippy/tests/ui/iter_filter_is_ok.fixed26
-rw-r--r--src/tools/clippy/tests/ui/iter_filter_is_ok.rs26
-rw-r--r--src/tools/clippy/tests/ui/iter_filter_is_ok.stderr23
-rw-r--r--src/tools/clippy/tests/ui/iter_filter_is_some.fixed27
-rw-r--r--src/tools/clippy/tests/ui/iter_filter_is_some.rs27
-rw-r--r--src/tools/clippy/tests/ui/iter_filter_is_some.stderr23
-rw-r--r--src/tools/clippy/tests/ui/manual_let_else_question_mark.fixed21
-rw-r--r--src/tools/clippy/tests/ui/manual_let_else_question_mark.rs23
-rw-r--r--src/tools/clippy/tests/ui/manual_let_else_question_mark.stderr10
-rw-r--r--src/tools/clippy/tests/ui/needless_if.fixed1
-rw-r--r--src/tools/clippy/tests/ui/needless_if.rs1
-rw-r--r--src/tools/clippy/tests/ui/needless_if.stderr14
-rw-r--r--src/tools/clippy/tests/ui/nonminimal_bool.rs7
-rw-r--r--src/tools/clippy/tests/ui/nonminimal_bool.stderr26
-rw-r--r--src/tools/clippy/tests/ui/option_filter_map.fixed6
-rw-r--r--src/tools/clippy/tests/ui/option_filter_map.rs8
-rw-r--r--src/tools/clippy/tests/ui/option_filter_map.stderr16
-rw-r--r--src/tools/clippy/tests/ui/redundant_async_block.fixed8
-rw-r--r--src/tools/clippy/tests/ui/redundant_async_block.rs8
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_if_let_true.fixed38
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_if_let_true.rs38
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_if_let_true.stderr47
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.fixed6
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.rs6
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.stderr44
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_poll.fixed6
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_poll.rs6
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_poll.stderr44
-rw-r--r--src/tools/clippy/tests/ui/result_filter_map.fixed27
-rw-r--r--src/tools/clippy/tests/ui/result_filter_map.rs35
-rw-r--r--src/tools/clippy/tests/ui/result_filter_map.stderr41
-rw-r--r--src/tools/clippy/tests/ui/unconditional_recursion.rs163
-rw-r--r--src/tools/clippy/tests/ui/unconditional_recursion.stderr251
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.fixed21
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.rs21
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.stderr53
-rw-r--r--src/tools/clippy/util/gh-pages/index.html70
-rw-r--r--tests/codegen/inherit_overflow.rs2
-rw-r--r--tests/coverage/async2.cov-map14
-rw-r--r--tests/coverage/partial_eq.cov-map8
-rw-r--r--tests/incremental/hashes/for_loops.rs4
-rw-r--r--tests/incremental/string_constant.rs2
-rw-r--r--tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir2
-rw-r--r--tests/mir-opt/const_allocation.main.GVN.after.32bit.mir (renamed from tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir)6
-rw-r--r--tests/mir-opt/const_allocation.main.GVN.after.64bit.mir (renamed from tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir)6
-rw-r--r--tests/mir-opt/const_allocation.rs4
-rw-r--r--tests/mir-opt/const_allocation2.main.GVN.after.32bit.mir (renamed from tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir)6
-rw-r--r--tests/mir-opt/const_allocation2.main.GVN.after.64bit.mir (renamed from tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir)6
-rw-r--r--tests/mir-opt/const_allocation2.rs4
-rw-r--r--tests/mir-opt/const_allocation3.main.GVN.after.32bit.mir (renamed from tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir)6
-rw-r--r--tests/mir-opt/const_allocation3.main.GVN.after.64bit.mir (renamed from tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir)6
-rw-r--r--tests/mir-opt/const_allocation3.rs4
-rw-r--r--tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff25
-rw-r--r--tests/mir-opt/const_debuginfo.rs4
-rw-r--r--tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff (renamed from tests/mir-opt/const_prop/address_of_pair.fn0.ConstProp.diff)26
-rw-r--r--tests/mir-opt/const_prop/address_of_pair.rs4
-rw-r--r--tests/mir-opt/const_prop/aggregate.foo.GVN.panic-abort.diff (renamed from tests/mir-opt/const_prop/aggregate.foo.ConstProp.panic-abort.diff)10
-rw-r--r--tests/mir-opt/const_prop/aggregate.foo.GVN.panic-unwind.diff (renamed from tests/mir-opt/const_prop/aggregate.foo.ConstProp.panic-unwind.diff)10
-rw-r--r--tests/mir-opt/const_prop/aggregate.main.GVN.panic-abort.diff (renamed from tests/mir-opt/const_prop/aggregate.main.ConstProp.panic-abort.diff)10
-rw-r--r--tests/mir-opt/const_prop/aggregate.main.GVN.panic-unwind.diff (renamed from tests/mir-opt/const_prop/aggregate.main.ConstProp.panic-unwind.diff)10
-rw-r--r--tests/mir-opt/const_prop/aggregate.rs6
-rw-r--r--tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff (renamed from tests/mir-opt/const_prop/array_index.main.ConstProp.64bit.panic-abort.diff)11
-rw-r--r--tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff (renamed from tests/mir-opt/const_prop/array_index.main.ConstProp.32bit.panic-unwind.diff)11
-rw-r--r--tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff (renamed from tests/mir-opt/const_prop/array_index.main.ConstProp.32bit.panic-abort.diff)11
-rw-r--r--tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff (renamed from tests/mir-opt/const_prop/array_index.main.ConstProp.64bit.panic-unwind.diff)11
-rw-r--r--tests/mir-opt/const_prop/array_index.rs4
-rw-r--r--tests/mir-opt/const_prop/bad_op_div_by_zero.main.GVN.panic-abort.diff (renamed from tests/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.panic-abort.diff)10
-rw-r--r--tests/mir-opt/const_prop/bad_op_div_by_zero.main.GVN.panic-unwind.diff (renamed from tests/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.panic-unwind.diff)10
-rw-r--r--tests/mir-opt/const_prop/bad_op_div_by_zero.rs4
-rw-r--r--tests/mir-opt/const_prop/bad_op_mod_by_zero.main.GVN.panic-abort.diff (renamed from tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.panic-abort.diff)10
-rw-r--r--tests/mir-opt/const_prop/bad_op_mod_by_zero.main.GVN.panic-unwind.diff (renamed from tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.panic-unwind.diff)10
-rw-r--r--tests/mir-opt/const_prop/bad_op_mod_by_zero.rs4
-rw-r--r--tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff (renamed from tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-abort.diff)16
-rw-r--r--tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff (renamed from tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-unwind.diff)16
-rw-r--r--tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff (renamed from tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-abort.diff)16
-rw-r--r--tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff (renamed from tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-unwind.diff)16
-rw-r--r--tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs4
-rw-r--r--tests/mir-opt/const_prop/boolean_identities.rs11
-rw-r--r--tests/mir-opt/const_prop/boolean_identities.test.GVN.diff (renamed from tests/mir-opt/const_prop/boolean_identities.test.ConstProp.diff)28
-rw-r--r--tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff (renamed from tests/mir-opt/const_prop/boxes.main.ConstProp.panic-abort.diff)4
-rw-r--r--tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff (renamed from tests/mir-opt/const_prop/boxes.main.ConstProp.panic-unwind.diff)4
-rw-r--r--tests/mir-opt/const_prop/boxes.rs4
-rw-r--r--tests/mir-opt/const_prop/cast.main.GVN.diff (renamed from tests/mir-opt/const_prop/cast.main.ConstProp.diff)4
-rw-r--r--tests/mir-opt/const_prop/cast.rs4
-rw-r--r--tests/mir-opt/const_prop/checked_add.main.GVN.panic-abort.diff (renamed from tests/mir-opt/const_prop/checked_add.main.ConstProp.panic-abort.diff)4
-rw-r--r--tests/mir-opt/const_prop/checked_add.main.GVN.panic-unwind.diff (renamed from tests/mir-opt/const_prop/checked_add.main.ConstProp.panic-unwind.diff)4
-rw-r--r--tests/mir-opt/const_prop/checked_add.rs4
-rw-r--r--tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-abort.diff (renamed from tests/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.panic-abort.diff)7
-rw-r--r--tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-unwind.diff (renamed from tests/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.panic-unwind.diff)7
-rw-r--r--tests/mir-opt/const_prop/control_flow_simplification.rs4
-rw-r--r--tests/mir-opt/const_prop/discriminant.main.GVN.32bit.diff (renamed from tests/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff)4
-rw-r--r--tests/mir-opt/const_prop/discriminant.main.GVN.64bit.diff (renamed from tests/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff)4
-rw-r--r--tests/mir-opt/const_prop/discriminant.rs4
-rw-r--r--tests/mir-opt/const_prop/indirect.main.GVN.panic-abort.diff (renamed from tests/mir-opt/const_prop/indirect.main.ConstProp.panic-abort.diff)4
-rw-r--r--tests/mir-opt/const_prop/indirect.main.GVN.panic-unwind.diff (renamed from tests/mir-opt/const_prop/indirect.main.ConstProp.panic-unwind.diff)4
-rw-r--r--tests/mir-opt/const_prop/indirect.rs4
-rw-r--r--tests/mir-opt/const_prop/indirect_mutation.bar.GVN.diff (renamed from tests/mir-opt/const_prop/indirect_mutation.bar.ConstProp.diff)13
-rw-r--r--tests/mir-opt/const_prop/indirect_mutation.foo.GVN.diff (renamed from tests/mir-opt/const_prop/indirect_mutation.foo.ConstProp.diff)13
-rw-r--r--tests/mir-opt/const_prop/indirect_mutation.rs8
-rw-r--r--tests/mir-opt/const_prop/inherit_overflow.main.GVN.panic-abort.diff (renamed from tests/mir-opt/const_prop/inherit_overflow.main.ConstProp.panic-abort.diff)4
-rw-r--r--tests/mir-opt/const_prop/inherit_overflow.main.GVN.panic-unwind.diff (renamed from tests/mir-opt/const_prop/inherit_overflow.main.ConstProp.panic-unwind.diff)4
-rw-r--r--tests/mir-opt/const_prop/inherit_overflow.rs4
-rw-r--r--tests/mir-opt/const_prop/invalid_constant.main.GVN.diff (renamed from tests/mir-opt/const_prop/invalid_constant.main.ConstProp.diff)13
-rw-r--r--tests/mir-opt/const_prop/invalid_constant.rs4
-rw-r--r--tests/mir-opt/const_prop/issue_66971.main.GVN.panic-abort.diff (renamed from tests/mir-opt/const_prop/issue_66971.main.ConstProp.panic-abort.diff)11
-rw-r--r--tests/mir-opt/const_prop/issue_66971.main.GVN.panic-unwind.diff (renamed from tests/mir-opt/const_prop/issue_66971.main.ConstProp.panic-unwind.diff)11
-rw-r--r--tests/mir-opt/const_prop/issue_66971.rs6
-rw-r--r--tests/mir-opt/const_prop/issue_67019.main.GVN.panic-abort.diff (renamed from tests/mir-opt/const_prop/issue_67019.main.ConstProp.panic-abort.diff)4
-rw-r--r--tests/mir-opt/const_prop/issue_67019.main.GVN.panic-unwind.diff (renamed from tests/mir-opt/const_prop/issue_67019.main.ConstProp.panic-unwind.diff)4
-rw-r--r--tests/mir-opt/const_prop/issue_67019.rs4
-rw-r--r--tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff (renamed from tests/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.panic-abort.diff)13
-rw-r--r--tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff (renamed from tests/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.panic-unwind.diff)13
-rw-r--r--tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff (renamed from tests/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.panic-abort.diff)13
-rw-r--r--tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff (renamed from tests/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.panic-unwind.diff)13
-rw-r--r--tests/mir-opt/const_prop/large_array_index.rs4
-rw-r--r--tests/mir-opt/const_prop/mult_by_zero.rs7
-rw-r--r--tests/mir-opt/const_prop/mult_by_zero.test.GVN.diff (renamed from tests/mir-opt/const_prop/mult_by_zero.test.ConstProp.diff)6
-rw-r--r--tests/mir-opt/const_prop/mutable_variable.main.GVN.diff (renamed from tests/mir-opt/const_prop/mutable_variable.main.ConstProp.diff)7
-rw-r--r--tests/mir-opt/const_prop/mutable_variable.rs6
-rw-r--r--tests/mir-opt/const_prop/mutable_variable_aggregate.main.GVN.diff (renamed from tests/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff)11
-rw-r--r--tests/mir-opt/const_prop/mutable_variable_aggregate.rs6
-rw-r--r--tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.GVN.diff (renamed from tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff)17
-rw-r--r--tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs6
-rw-r--r--tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.GVN.panic-abort.diff (renamed from tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.panic-abort.diff)7
-rw-r--r--tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.GVN.panic-unwind.diff (renamed from tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.panic-unwind.diff)7
-rw-r--r--tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.rs6
-rw-r--r--tests/mir-opt/const_prop/mutable_variable_no_prop.main.GVN.diff (renamed from tests/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff)10
-rw-r--r--tests/mir-opt/const_prop/mutable_variable_no_prop.rs4
-rw-r--r--tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-abort.diff (renamed from tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.panic-abort.diff)16
-rw-r--r--tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-unwind.diff (renamed from tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.panic-unwind.diff)16
-rw-r--r--tests/mir-opt/const_prop/mutable_variable_unprop_assign.rs9
-rw-r--r--tests/mir-opt/const_prop/offset_of.concrete.GVN.panic-abort.diff (renamed from tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-abort.diff)4
-rw-r--r--tests/mir-opt/const_prop/offset_of.concrete.GVN.panic-unwind.diff (renamed from tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-unwind.diff)4
-rw-r--r--tests/mir-opt/const_prop/offset_of.generic.GVN.panic-abort.diff (renamed from tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-abort.diff)16
-rw-r--r--tests/mir-opt/const_prop/offset_of.generic.GVN.panic-unwind.diff (renamed from tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-unwind.diff)16
-rw-r--r--tests/mir-opt/const_prop/offset_of.rs6
-rw-r--r--tests/mir-opt/const_prop/overwrite_with_const_with_params.rs4
-rw-r--r--tests/mir-opt/const_prop/overwrite_with_const_with_params.size_of.GVN.diff (renamed from tests/mir-opt/const_prop/overwrite_with_const_with_params.size_of.ConstProp.diff)4
-rw-r--r--tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-abort.diff (renamed from tests/mir-opt/const_prop/pointer_expose_address.main.ConstProp.panic-abort.diff)19
-rw-r--r--tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-unwind.diff (renamed from tests/mir-opt/const_prop/pointer_expose_address.main.ConstProp.panic-unwind.diff)19
-rw-r--r--tests/mir-opt/const_prop/pointer_expose_address.rs7
-rw-r--r--tests/mir-opt/const_prop/read_immutable_static.main.GVN.diff (renamed from tests/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff)16
-rw-r--r--tests/mir-opt/const_prop/read_immutable_static.rs4
-rw-r--r--tests/mir-opt/const_prop/ref_deref.main.GVN.diff (renamed from tests/mir-opt/const_prop/ref_deref.main.ConstProp.diff)13
-rw-r--r--tests/mir-opt/const_prop/ref_deref.rs6
-rw-r--r--tests/mir-opt/const_prop/ref_deref_project.main.GVN.diff (renamed from tests/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff)13
-rw-r--r--tests/mir-opt/const_prop/ref_deref_project.rs6
-rw-r--r--tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff (renamed from tests/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff)4
-rw-r--r--tests/mir-opt/const_prop/reify_fn_ptr.rs4
-rw-r--r--tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff (renamed from tests/mir-opt/const_prop/repeat.main.ConstProp.64bit.panic-abort.diff)11
-rw-r--r--tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff (renamed from tests/mir-opt/const_prop/repeat.main.ConstProp.64bit.panic-unwind.diff)11
-rw-r--r--tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff (renamed from tests/mir-opt/const_prop/repeat.main.ConstProp.32bit.panic-abort.diff)11
-rw-r--r--tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff (renamed from tests/mir-opt/const_prop/repeat.main.ConstProp.32bit.panic-unwind.diff)11
-rw-r--r--tests/mir-opt/const_prop/repeat.rs4
-rw-r--r--tests/mir-opt/const_prop/return_place.add.GVN.panic-abort.diff (renamed from tests/mir-opt/const_prop/return_place.add.ConstProp.panic-abort.diff)4
-rw-r--r--tests/mir-opt/const_prop/return_place.add.GVN.panic-unwind.diff (renamed from tests/mir-opt/const_prop/return_place.add.ConstProp.panic-unwind.diff)4
-rw-r--r--tests/mir-opt/const_prop/return_place.rs4
-rw-r--r--tests/mir-opt/const_prop/scalar_literal_propagation.main.GVN.panic-abort.diff (renamed from tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.panic-abort.diff)10
-rw-r--r--tests/mir-opt/const_prop/scalar_literal_propagation.main.GVN.panic-unwind.diff (renamed from tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.panic-unwind.diff)10
-rw-r--r--tests/mir-opt/const_prop/scalar_literal_propagation.rs4
-rw-r--r--tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff (renamed from tests/mir-opt/const_prop/slice_len.main.ConstProp.64bit.panic-abort.diff)32
-rw-r--r--tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff (renamed from tests/mir-opt/const_prop/slice_len.main.ConstProp.32bit.panic-unwind.diff)32
-rw-r--r--tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff (renamed from tests/mir-opt/const_prop/slice_len.main.ConstProp.32bit.panic-abort.diff)32
-rw-r--r--tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff (renamed from tests/mir-opt/const_prop/slice_len.main.ConstProp.64bit.panic-unwind.diff)32
-rw-r--r--tests/mir-opt/const_prop/slice_len.rs11
-rw-r--r--tests/mir-opt/const_prop/switch_int.main.GVN.panic-abort.diff (renamed from tests/mir-opt/const_prop/switch_int.main.ConstProp.panic-abort.diff)4
-rw-r--r--tests/mir-opt/const_prop/switch_int.main.GVN.panic-unwind.diff (renamed from tests/mir-opt/const_prop/switch_int.main.ConstProp.panic-unwind.diff)4
-rw-r--r--tests/mir-opt/const_prop/switch_int.rs4
-rw-r--r--tests/mir-opt/const_prop/transmute.from_char.GVN.32bit.diff (renamed from tests/mir-opt/const_prop/transmute.from_char.ConstProp.64bit.diff)4
-rw-r--r--tests/mir-opt/const_prop/transmute.from_char.GVN.64bit.diff (renamed from tests/mir-opt/const_prop/transmute.from_char.ConstProp.32bit.diff)4
-rw-r--r--tests/mir-opt/const_prop/transmute.invalid_bool.GVN.32bit.diff (renamed from tests/mir-opt/const_prop/transmute.invalid_bool.ConstProp.32bit.diff)4
-rw-r--r--tests/mir-opt/const_prop/transmute.invalid_bool.GVN.64bit.diff (renamed from tests/mir-opt/const_prop/transmute.invalid_bool.ConstProp.64bit.diff)4
-rw-r--r--tests/mir-opt/const_prop/transmute.invalid_char.GVN.32bit.diff (renamed from tests/mir-opt/const_prop/transmute.invalid_char.ConstProp.32bit.diff)4
-rw-r--r--tests/mir-opt/const_prop/transmute.invalid_char.GVN.64bit.diff (renamed from tests/mir-opt/const_prop/transmute.invalid_char.ConstProp.64bit.diff)4
-rw-r--r--tests/mir-opt/const_prop/transmute.less_as_i8.GVN.32bit.diff (renamed from tests/mir-opt/const_prop/transmute.less_as_i8.ConstProp.64bit.diff)4
-rw-r--r--tests/mir-opt/const_prop/transmute.less_as_i8.GVN.64bit.diff (renamed from tests/mir-opt/const_prop/transmute.less_as_i8.ConstProp.32bit.diff)4
-rw-r--r--tests/mir-opt/const_prop/transmute.rs26
-rw-r--r--tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.32bit.diff (renamed from tests/mir-opt/const_prop/transmute.undef_union_as_integer.ConstProp.64bit.diff)7
-rw-r--r--tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.64bit.diff (renamed from tests/mir-opt/const_prop/transmute.undef_union_as_integer.ConstProp.32bit.diff)7
-rw-r--r--tests/mir-opt/const_prop/transmute.unreachable_box.GVN.32bit.diff (renamed from tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.32bit.diff)4
-rw-r--r--tests/mir-opt/const_prop/transmute.unreachable_box.GVN.64bit.diff (renamed from tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.64bit.diff)4
-rw-r--r--tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.32bit.diff (renamed from tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.32bit.diff)10
-rw-r--r--tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.64bit.diff (renamed from tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.64bit.diff)10
-rw-r--r--tests/mir-opt/const_prop/transmute.unreachable_mut.GVN.32bit.diff (renamed from tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.32bit.diff)10
-rw-r--r--tests/mir-opt/const_prop/transmute.unreachable_mut.GVN.64bit.diff (renamed from tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.64bit.diff)10
-rw-r--r--tests/mir-opt/const_prop/transmute.unreachable_ref.GVN.32bit.diff (renamed from tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.32bit.diff)4
-rw-r--r--tests/mir-opt/const_prop/transmute.unreachable_ref.GVN.64bit.diff (renamed from tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.64bit.diff)4
-rw-r--r--tests/mir-opt/const_prop/transmute.valid_char.GVN.32bit.diff (renamed from tests/mir-opt/const_prop/transmute.valid_char.ConstProp.32bit.diff)4
-rw-r--r--tests/mir-opt/const_prop/transmute.valid_char.GVN.64bit.diff (renamed from tests/mir-opt/const_prop/transmute.valid_char.ConstProp.64bit.diff)4
-rw-r--r--tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-abort.diff (renamed from tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.panic-abort.diff)18
-rw-r--r--tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-unwind.diff (renamed from tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.panic-unwind.diff)18
-rw-r--r--tests/mir-opt/const_prop/tuple_literal_propagation.rs4
-rw-r--r--tests/mir-opt/const_prop/while_let_loops.change_loop_body.GVN.diff (renamed from tests/mir-opt/const_prop/while_let_loops.change_loop_body.ConstProp.diff)14
-rw-r--r--tests/mir-opt/const_prop/while_let_loops.rs4
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff24
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff24
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff24
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff24
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff (renamed from tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.32bit.panic-abort.diff)33
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff (renamed from tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.32bit.panic-unwind.diff)33
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff (renamed from tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.64bit.panic-abort.diff)33
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff (renamed from tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.64bit.panic-unwind.diff)33
-rw-r--r--tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs4
-rw-r--r--tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff6
-rw-r--r--tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff6
-rw-r--r--tests/mir-opt/dest-prop/unreachable.f.DestinationPropagation.panic-abort.diff22
-rw-r--r--tests/mir-opt/dest-prop/unreachable.f.DestinationPropagation.panic-unwind.diff22
-rw-r--r--tests/mir-opt/dest-prop/unreachable.rs2
-rw-r--r--tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff (renamed from tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.panic-abort.diff)4
-rw-r--r--tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff (renamed from tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.panic-unwind.diff)4
-rw-r--r--tests/mir-opt/funky_arms.rs2
-rw-r--r--tests/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir2
-rw-r--r--tests/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir2
-rw-r--r--tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff (renamed from tests/mir-opt/issue_101973.inner.ConstProp.panic-abort.diff)4
-rw-r--r--tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff (renamed from tests/mir-opt/issue_101973.inner.ConstProp.panic-unwind.diff)4
-rw-r--r--tests/mir-opt/issue_101973.rs4
-rw-r--r--tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.mir6
-rw-r--r--tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff6
-rw-r--r--tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff6
-rw-r--r--tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff6
-rw-r--r--tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff6
-rw-r--r--tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir6
-rw-r--r--tests/mir-opt/pre-codegen/loops.rs1
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff (renamed from tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.64bit.panic-abort.diff)4
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff (renamed from tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.64bit.panic-unwind.diff)4
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff (renamed from tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.32bit.panic-abort.diff)4
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff (renamed from tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.32bit.panic-unwind.diff)4
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.rs2
-rw-r--r--tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir6
-rw-r--r--tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir6
-rw-r--r--tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir6
-rw-r--r--tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir6
-rw-r--r--tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir6
-rw-r--r--tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir292
-rw-r--r--tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir56
-rw-r--r--tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir2
-rw-r--r--tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir2
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir6
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir6
-rw-r--r--tests/mir-opt/simplify_match.main.GVN.panic-abort.diff (renamed from tests/mir-opt/simplify_match.main.ConstProp.panic-abort.diff)4
-rw-r--r--tests/mir-opt/simplify_match.main.GVN.panic-unwind.diff (renamed from tests/mir-opt/simplify_match.main.ConstProp.panic-unwind.diff)4
-rw-r--r--tests/mir-opt/simplify_match.rs2
-rw-r--r--tests/rustdoc-js-std/asrawfd.js1
-rw-r--r--tests/rustdoc-js-std/path-maxeditdistance.js42
-rw-r--r--tests/rustdoc-js-std/path-ordering.js31
-rw-r--r--tests/rustdoc-js/exact-match.js1
-rw-r--r--tests/rustdoc-js/module-substring.js22
-rw-r--r--tests/rustdoc-js/path-maxeditdistance.js35
-rw-r--r--tests/rustdoc-js/path-maxeditdistance.rs3
-rw-r--r--tests/rustdoc-js/path-ordering.js8
-rw-r--r--tests/rustdoc-js/path-ordering.rs6
-rw-r--r--tests/ui/consts/const-eval/issue-50814-2.mir-opt.stderr6
-rw-r--r--tests/ui/error-codes/E0453.rs1
-rw-r--r--tests/ui/error-codes/E0453.stderr13
-rw-r--r--tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.rs4
-rw-r--r--tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.stderr44
-rw-r--r--tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs10
-rw-r--r--tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr126
-rw-r--r--tests/ui/feature-gates/feature-gate-strict_provenance.rs4
-rw-r--r--tests/ui/feature-gates/feature-gate-strict_provenance.stderr48
-rw-r--r--tests/ui/feature-gates/feature-gate-test_unstable_lint.rs2
-rw-r--r--tests/ui/feature-gates/feature-gate-test_unstable_lint.stderr22
-rw-r--r--tests/ui/feature-gates/feature-gate-type_privacy_lints.rs2
-rw-r--r--tests/ui/feature-gates/feature-gate-type_privacy_lints.stderr24
-rw-r--r--tests/ui/half-open-range-patterns/range_pat_interactions1.rs2
-rw-r--r--tests/ui/half-open-range-patterns/range_pat_interactions1.stderr4
-rw-r--r--tests/ui/half-open-range-patterns/range_pat_interactions2.rs2
-rw-r--r--tests/ui/half-open-range-patterns/range_pat_interactions2.stderr4
-rw-r--r--tests/ui/impl-trait/associated-impl-trait-type-issue-114325.rs55
-rw-r--r--tests/ui/impl-trait/not_general_enough_regression_106630.rs33
-rw-r--r--tests/ui/lint/crate_level_only_lint.rs6
-rw-r--r--tests/ui/lint/crate_level_only_lint.stderr54
-rw-r--r--tests/ui/lint/forbid-group-group-2.rs12
-rw-r--r--tests/ui/lint/forbid-group-group-2.stderr80
-rw-r--r--tests/ui/lint/forbid-group-member.rs4
-rw-r--r--tests/ui/lint/forbid-group-member.stderr28
-rw-r--r--tests/ui/lint/forbid-member-group.rs1
-rw-r--r--tests/ui/lint/forbid-member-group.stderr13
-rw-r--r--tests/ui/lint/issue-80988.rs4
-rw-r--r--tests/ui/lint/issue-80988.stderr28
-rw-r--r--tests/ui/lint/lint-forbid-attr.rs1
-rw-r--r--tests/ui/lint/lint-forbid-attr.stderr13
-rw-r--r--tests/ui/lint/lint-forbid-cmdline.rs1
-rw-r--r--tests/ui/lint/lint-forbid-cmdline.stderr11
-rw-r--r--tests/ui/lint/must_not_suspend/gated.rs2
-rw-r--r--tests/ui/lint/must_not_suspend/gated.stderr24
-rw-r--r--tests/ui/lint/unused/issue-119383-if-let-guard.rs9
-rw-r--r--tests/ui/lint/unused/issue-119383-if-let-guard.stderr14
-rw-r--r--tests/ui/methods/disambiguate-associated-function-first-arg.rs49
-rw-r--r--tests/ui/methods/disambiguate-associated-function-first-arg.stderr67
-rw-r--r--tests/ui/methods/method-ambiguity-no-rcvr.stderr8
-rw-r--r--tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs6
-rw-r--r--tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr12
-rw-r--r--tests/ui/parser/issues/issue-24375.rs2
-rw-r--r--tests/ui/parser/issues/issue-24375.stderr4
-rw-r--r--tests/ui/parser/match-arm-without-body.stderr8
-rw-r--r--tests/ui/parser/pat-lt-bracket-1.rs2
-rw-r--r--tests/ui/parser/pat-lt-bracket-1.stderr4
-rw-r--r--tests/ui/unknown-unstable-lints/deny-unstable-lint-command-line.stderr14
-rw-r--r--tests/ui/unknown-unstable-lints/deny-unstable-lint-inline.rs2
-rw-r--r--tests/ui/unknown-unstable-lints/deny-unstable-lint-inline.stderr22
-rw-r--r--tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.stderr14
-rw-r--r--tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.rs2
-rw-r--r--tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.stderr22
501 files changed, 4840 insertions, 3523 deletions
diff --git a/Cargo.lock b/Cargo.lock
index d2b8e747cd1..f2120495e43 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -537,7 +537,7 @@ checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
 
 [[package]]
 name = "clippy"
-version = "0.1.76"
+version = "0.1.77"
 dependencies = [
  "anstream",
  "clippy_config",
@@ -565,7 +565,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_config"
-version = "0.1.76"
+version = "0.1.77"
 dependencies = [
  "rustc-semver",
  "serde",
@@ -588,7 +588,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_lints"
-version = "0.1.76"
+version = "0.1.77"
 dependencies = [
  "arrayvec",
  "cargo_metadata 0.15.4",
@@ -613,7 +613,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_utils"
-version = "0.1.76"
+version = "0.1.77"
 dependencies = [
  "arrayvec",
  "clippy_config",
@@ -984,7 +984,7 @@ checksum = "a0afaad2b26fa326569eb264b1363e8ae3357618c43982b3f285f0774ce76b69"
 
 [[package]]
 name = "declare_clippy_lint"
-version = "0.1.76"
+version = "0.1.77"
 dependencies = [
  "itertools",
  "quote",
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index ccc6644923a..e568da9bbc0 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -183,14 +183,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))),
                     hir::MatchSource::Normal,
                 ),
-                ExprKind::Gen(capture_clause, block, GenBlockKind::Async) => self.make_async_expr(
-                    *capture_clause,
-                    e.id,
-                    None,
-                    e.span,
-                    hir::CoroutineSource::Block,
-                    |this| this.with_new_scopes(e.span, |this| this.lower_block_expr(block)),
-                ),
                 ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr),
                 ExprKind::Closure(box Closure {
                     binder,
@@ -226,6 +218,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         *fn_arg_span,
                     ),
                 },
+                ExprKind::Gen(capture_clause, block, genblock_kind) => {
+                    let desugaring_kind = match genblock_kind {
+                        GenBlockKind::Async => hir::CoroutineDesugaring::Async,
+                        GenBlockKind::Gen => hir::CoroutineDesugaring::Gen,
+                        GenBlockKind::AsyncGen => hir::CoroutineDesugaring::AsyncGen,
+                    };
+                    self.make_desugared_coroutine_expr(
+                        *capture_clause,
+                        e.id,
+                        None,
+                        e.span,
+                        desugaring_kind,
+                        hir::CoroutineSource::Block,
+                        |this| this.with_new_scopes(e.span, |this| this.lower_block_expr(block)),
+                    )
+                }
                 ExprKind::Block(blk, opt_label) => {
                     let opt_label = self.lower_label(*opt_label);
                     hir::ExprKind::Block(self.lower_block(blk, opt_label.is_some()), opt_label)
@@ -313,23 +321,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         rest,
                     )
                 }
-                ExprKind::Gen(capture_clause, block, GenBlockKind::Gen) => self.make_gen_expr(
-                    *capture_clause,
-                    e.id,
-                    None,
-                    e.span,
-                    hir::CoroutineSource::Block,
-                    |this| this.with_new_scopes(e.span, |this| this.lower_block_expr(block)),
-                ),
-                ExprKind::Gen(capture_clause, block, GenBlockKind::AsyncGen) => self
-                    .make_async_gen_expr(
-                        *capture_clause,
-                        e.id,
-                        None,
-                        e.span,
-                        hir::CoroutineSource::Block,
-                        |this| this.with_new_scopes(e.span, |this| this.lower_block_expr(block)),
-                    ),
                 ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
                 ExprKind::Err => {
                     hir::ExprKind::Err(self.dcx().span_delayed_bug(e.span, "lowered ExprKind::Err"))
@@ -612,213 +603,91 @@ impl<'hir> LoweringContext<'_, 'hir> {
         hir::Arm { hir_id, pat, guard, body, span }
     }
 
-    /// Lower an `async` construct to a coroutine that implements `Future`.
+    /// Lower/desugar a coroutine construct.
     ///
-    /// This results in:
-    ///
-    /// ```text
-    /// static move? |_task_context| -> <ret_ty> {
-    ///     <body>
-    /// }
-    /// ```
-    pub(super) fn make_async_expr(
-        &mut self,
-        capture_clause: CaptureBy,
-        closure_node_id: NodeId,
-        ret_ty: Option<hir::FnRetTy<'hir>>,
-        span: Span,
-        async_coroutine_source: hir::CoroutineSource,
-        body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
-    ) -> hir::ExprKind<'hir> {
-        let output = ret_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));
-
-        // Resume argument type: `ResumeTy`
-        let unstable_span = self.mark_span_with_reason(
-            DesugaringKind::Async,
-            self.lower_span(span),
-            Some(self.allow_gen_future.clone()),
-        );
-        let resume_ty = self.make_lang_item_qpath(hir::LangItem::ResumeTy, unstable_span);
-        let input_ty = hir::Ty {
-            hir_id: self.next_id(),
-            kind: hir::TyKind::Path(resume_ty),
-            span: unstable_span,
-        };
-
-        // The closure/coroutine `FnDecl` takes a single (resume) argument of type `input_ty`.
-        let fn_decl = self.arena.alloc(hir::FnDecl {
-            inputs: arena_vec![self; input_ty],
-            output,
-            c_variadic: false,
-            implicit_self: hir::ImplicitSelfKind::None,
-            lifetime_elision_allowed: false,
-        });
-
-        // Lower the argument pattern/ident. The ident is used again in the `.await` lowering.
-        let (pat, task_context_hid) = self.pat_ident_binding_mode(
-            span,
-            Ident::with_dummy_span(sym::_task_context),
-            hir::BindingAnnotation::MUT,
-        );
-        let param = hir::Param {
-            hir_id: self.next_id(),
-            pat,
-            ty_span: self.lower_span(span),
-            span: self.lower_span(span),
-        };
-        let params = arena_vec![self; param];
-
-        let coroutine_kind =
-            hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, async_coroutine_source);
-        let body = self.lower_body(move |this| {
-            this.coroutine_kind = Some(coroutine_kind);
-
-            let old_ctx = this.task_context;
-            this.task_context = Some(task_context_hid);
-            let res = body(this);
-            this.task_context = old_ctx;
-            (params, res)
-        });
-
-        // `static |_task_context| -> <ret_ty> { body }`:
-        hir::ExprKind::Closure(self.arena.alloc(hir::Closure {
-            def_id: self.local_def_id(closure_node_id),
-            binder: hir::ClosureBinder::Default,
-            capture_clause,
-            bound_generic_params: &[],
-            fn_decl,
-            body,
-            fn_decl_span: self.lower_span(span),
-            fn_arg_span: None,
-            kind: hir::ClosureKind::Coroutine(coroutine_kind),
-            constness: hir::Constness::NotConst,
-        }))
-    }
-
-    /// Lower a `gen` construct to a generator that implements `Iterator`.
+    /// In particular, this creates the correct async resume argument and `_task_context`.
     ///
     /// This results in:
     ///
     /// ```text
-    /// static move? |()| -> () {
+    /// static move? |<_task_context?>| -> <return_ty> {
     ///     <body>
     /// }
     /// ```
-    pub(super) fn make_gen_expr(
+    pub(super) fn make_desugared_coroutine_expr(
         &mut self,
         capture_clause: CaptureBy,
         closure_node_id: NodeId,
-        _yield_ty: Option<hir::FnRetTy<'hir>>,
+        return_ty: Option<hir::FnRetTy<'hir>>,
         span: Span,
+        desugaring_kind: hir::CoroutineDesugaring,
         coroutine_source: hir::CoroutineSource,
         body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
     ) -> hir::ExprKind<'hir> {
-        let output = hir::FnRetTy::DefaultReturn(self.lower_span(span));
-
-        // The closure/generator `FnDecl` takes a single (resume) argument of type `input_ty`.
-        let fn_decl = self.arena.alloc(hir::FnDecl {
-            inputs: &[],
-            output,
-            c_variadic: false,
-            implicit_self: hir::ImplicitSelfKind::None,
-            lifetime_elision_allowed: false,
-        });
-
-        let coroutine_kind =
-            hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, coroutine_source);
-        let body = self.lower_body(move |this| {
-            this.coroutine_kind = Some(coroutine_kind);
-
-            let res = body(this);
-            (&[], res)
-        });
-
-        // `static |()| -> () { body }`:
-        hir::ExprKind::Closure(self.arena.alloc(hir::Closure {
-            def_id: self.local_def_id(closure_node_id),
-            binder: hir::ClosureBinder::Default,
-            capture_clause,
-            bound_generic_params: &[],
-            fn_decl,
-            body,
-            fn_decl_span: self.lower_span(span),
-            fn_arg_span: None,
-            kind: hir::ClosureKind::Coroutine(coroutine_kind),
-            constness: hir::Constness::NotConst,
-        }))
-    }
+        let coroutine_kind = hir::CoroutineKind::Desugared(desugaring_kind, coroutine_source);
+
+        // The `async` desugaring takes a resume argument and maintains a `task_context`,
+        // whereas a generator does not.
+        let (inputs, params, task_context): (&[_], &[_], _) = match desugaring_kind {
+            hir::CoroutineDesugaring::Async | hir::CoroutineDesugaring::AsyncGen => {
+                // Resume argument type: `ResumeTy`
+                let unstable_span = self.mark_span_with_reason(
+                    DesugaringKind::Async,
+                    self.lower_span(span),
+                    Some(self.allow_gen_future.clone()),
+                );
+                let resume_ty = self.make_lang_item_qpath(hir::LangItem::ResumeTy, unstable_span);
+                let input_ty = hir::Ty {
+                    hir_id: self.next_id(),
+                    kind: hir::TyKind::Path(resume_ty),
+                    span: unstable_span,
+                };
+                let inputs = arena_vec![self; input_ty];
 
-    /// Lower a `async gen` construct to a generator that implements `AsyncIterator`.
-    ///
-    /// This results in:
-    ///
-    /// ```text
-    /// static move? |_task_context| -> () {
-    ///     <body>
-    /// }
-    /// ```
-    pub(super) fn make_async_gen_expr(
-        &mut self,
-        capture_clause: CaptureBy,
-        closure_node_id: NodeId,
-        _yield_ty: Option<hir::FnRetTy<'hir>>,
-        span: Span,
-        async_coroutine_source: hir::CoroutineSource,
-        body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
-    ) -> hir::ExprKind<'hir> {
-        let output = hir::FnRetTy::DefaultReturn(self.lower_span(span));
+                // Lower the argument pattern/ident. The ident is used again in the `.await` lowering.
+                let (pat, task_context_hid) = self.pat_ident_binding_mode(
+                    span,
+                    Ident::with_dummy_span(sym::_task_context),
+                    hir::BindingAnnotation::MUT,
+                );
+                let param = hir::Param {
+                    hir_id: self.next_id(),
+                    pat,
+                    ty_span: self.lower_span(span),
+                    span: self.lower_span(span),
+                };
+                let params = arena_vec![self; param];
 
-        // Resume argument type: `ResumeTy`
-        let unstable_span = self.mark_span_with_reason(
-            DesugaringKind::Async,
-            self.lower_span(span),
-            Some(self.allow_gen_future.clone()),
-        );
-        let resume_ty = self.make_lang_item_qpath(hir::LangItem::ResumeTy, unstable_span);
-        let input_ty = hir::Ty {
-            hir_id: self.next_id(),
-            kind: hir::TyKind::Path(resume_ty),
-            span: unstable_span,
+                (inputs, params, Some(task_context_hid))
+            }
+            hir::CoroutineDesugaring::Gen => (&[], &[], None),
         };
 
-        // The closure/coroutine `FnDecl` takes a single (resume) argument of type `input_ty`.
+        let output =
+            return_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));
+
         let fn_decl = self.arena.alloc(hir::FnDecl {
-            inputs: arena_vec![self; input_ty],
+            inputs,
             output,
             c_variadic: false,
             implicit_self: hir::ImplicitSelfKind::None,
             lifetime_elision_allowed: false,
         });
 
-        // Lower the argument pattern/ident. The ident is used again in the `.await` lowering.
-        let (pat, task_context_hid) = self.pat_ident_binding_mode(
-            span,
-            Ident::with_dummy_span(sym::_task_context),
-            hir::BindingAnnotation::MUT,
-        );
-        let param = hir::Param {
-            hir_id: self.next_id(),
-            pat,
-            ty_span: self.lower_span(span),
-            span: self.lower_span(span),
-        };
-        let params = arena_vec![self; param];
-
-        let coroutine_kind = hir::CoroutineKind::Desugared(
-            hir::CoroutineDesugaring::AsyncGen,
-            async_coroutine_source,
-        );
         let body = self.lower_body(move |this| {
             this.coroutine_kind = Some(coroutine_kind);
 
             let old_ctx = this.task_context;
-            this.task_context = Some(task_context_hid);
+            if task_context.is_some() {
+                this.task_context = task_context;
+            }
             let res = body(this);
             this.task_context = old_ctx;
+
             (params, res)
         });
 
-        // `static |_task_context| -> <ret_ty> { body }`:
+        // `static |<_task_context?>| -> <return_ty> { <body> }`:
         hir::ExprKind::Closure(self.arena.alloc(hir::Closure {
             def_id: self.local_def_id(closure_node_id),
             binder: hir::ClosureBinder::Default,
@@ -1203,11 +1072,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     None
                 };
 
-                let async_body = this.make_async_expr(
+                let async_body = this.make_desugared_coroutine_expr(
                     capture_clause,
                     inner_closure_id,
                     async_ret_ty,
                     body.span,
+                    hir::CoroutineDesugaring::Async,
                     hir::CoroutineSource::Closure,
                     |this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)),
                 );
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 3848f3b7782..45357aca533 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1209,33 +1209,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
                 this.expr_block(body)
             };
-            // FIXME(gen_blocks): Consider unifying the `make_*_expr` functions.
-            let coroutine_expr = match coroutine_kind {
-                CoroutineKind::Async { .. } => this.make_async_expr(
-                    CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
-                    closure_id,
-                    None,
-                    body.span,
-                    hir::CoroutineSource::Fn,
-                    mkbody,
-                ),
-                CoroutineKind::Gen { .. } => this.make_gen_expr(
-                    CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
-                    closure_id,
-                    None,
-                    body.span,
-                    hir::CoroutineSource::Fn,
-                    mkbody,
-                ),
-                CoroutineKind::AsyncGen { .. } => this.make_async_gen_expr(
-                    CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
-                    closure_id,
-                    None,
-                    body.span,
-                    hir::CoroutineSource::Fn,
-                    mkbody,
-                ),
+            let desugaring_kind = match coroutine_kind {
+                CoroutineKind::Async { .. } => hir::CoroutineDesugaring::Async,
+                CoroutineKind::Gen { .. } => hir::CoroutineDesugaring::Gen,
+                CoroutineKind::AsyncGen { .. } => hir::CoroutineDesugaring::AsyncGen,
             };
+            let coroutine_expr = this.make_desugared_coroutine_expr(
+                CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
+                closure_id,
+                None,
+                body.span,
+                desugaring_kind,
+                hir::CoroutineSource::Fn,
+                mkbody,
+            );
 
             let hir_id = this.lower_node_id(closure_id);
             this.maybe_forward_track_caller(body.span, fn_id, hir_id);
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index c14a05bd145..b31325485db 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -370,7 +370,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 ty::Array(ty, _) | ty::Slice(ty) => {
                     self.describe_field_from_ty(ty, field, variant_index, including_tuple_field)
                 }
-                ty::Closure(def_id, _) | ty::Coroutine(def_id, _, _) => {
+                ty::Closure(def_id, _) | ty::Coroutine(def_id, _) => {
                     // We won't be borrowck'ing here if the closure came from another crate,
                     // so it's safe to call `expect_local`.
                     //
@@ -792,8 +792,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
         debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt);
         if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind
-            && let AggregateKind::Closure(def_id, _) | AggregateKind::Coroutine(def_id, _, _) =
-                **kind
+            && let AggregateKind::Closure(def_id, _) | AggregateKind::Coroutine(def_id, _) = **kind
         {
             debug!("move_spans: def_id={:?} places={:?}", def_id, places);
             let def_id = def_id.expect_local();
@@ -928,7 +927,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind {
                 let (&def_id, is_coroutine) = match kind {
                     box AggregateKind::Closure(def_id, _) => (def_id, false),
-                    box AggregateKind::Coroutine(def_id, _, _) => (def_id, true),
+                    box AggregateKind::Coroutine(def_id, _) => (def_id, true),
                     _ => continue,
                 };
                 let def_id = def_id.expect_local();
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index af21847cffd..495b255583c 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -274,11 +274,12 @@ fn do_mir_borrowck<'tcx>(
         // The first argument is the coroutine type passed by value
         if let Some(local) = body.local_decls.raw.get(1)
         // Get the interior types and args which typeck computed
-        && let ty::Coroutine(_, _, hir::Movability::Static) = local.ty.kind()
+        && let ty::Coroutine(def_id, _) = *local.ty.kind()
+        && tcx.coroutine_movability(def_id) == hir::Movability::Movable
     {
-        false
-    } else {
         true
+    } else {
+        false
     };
 
     for (idx, move_data) in promoted_move_data {
@@ -1306,7 +1307,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 // moved into the closure and subsequently used by the closure,
                 // in order to populate our used_mut set.
                 match **aggregate_kind {
-                    AggregateKind::Closure(def_id, _) | AggregateKind::Coroutine(def_id, _, _) => {
+                    AggregateKind::Closure(def_id, _) | AggregateKind::Coroutine(def_id, _) => {
                         let def_id = def_id.expect_local();
                         let BorrowCheckResult { used_mut_upvars, .. } =
                             self.infcx.tcx.mir_borrowck(def_id);
@@ -1612,7 +1613,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     | ty::FnPtr(_)
                     | ty::Dynamic(_, _, _)
                     | ty::Closure(_, _)
-                    | ty::Coroutine(_, _, _)
+                    | ty::Coroutine(_, _)
                     | ty::CoroutineWitness(..)
                     | ty::Never
                     | ty::Tuple(_)
@@ -1636,7 +1637,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             return;
                         }
                     }
-                    ty::Closure(_, _) | ty::Coroutine(_, _, _) | ty::Tuple(_) => (),
+                    ty::Closure(_, _) | ty::Coroutine(_, _) | ty::Tuple(_) => (),
                     ty::Bool
                     | ty::Char
                     | ty::Int(_)
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 8a862953fba..80575e30a8d 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -762,7 +762,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
         let (variant, args) = match base_ty {
             PlaceTy { ty, variant_index: Some(variant_index) } => match *ty.kind() {
                 ty::Adt(adt_def, args) => (adt_def.variant(variant_index), args),
-                ty::Coroutine(def_id, args, _) => {
+                ty::Coroutine(def_id, args) => {
                     let mut variants = args.as_coroutine().state_tys(def_id, tcx);
                     let Some(mut variant) = variants.nth(variant_index.into()) else {
                         bug!(
@@ -790,7 +790,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
                         }),
                     };
                 }
-                ty::Coroutine(_, args, _) => {
+                ty::Coroutine(_, args) => {
                     // Only prefix fields (upvars and current state) are
                     // accessible without a variant index.
                     return match args.as_coroutine().prefix_tys().get(field.index()) {
@@ -1784,7 +1784,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     }),
                 }
             }
-            AggregateKind::Coroutine(_, args, _) => {
+            AggregateKind::Coroutine(_, args) => {
                 // It doesn't make sense to look at a field beyond the prefix;
                 // these require a variant index, and are not initialized in
                 // aggregate rvalues.
@@ -2392,7 +2392,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 AggregateKind::Array(_) => None,
                 AggregateKind::Tuple => None,
                 AggregateKind::Closure(_, _) => None,
-                AggregateKind::Coroutine(_, _, _) => None,
+                AggregateKind::Coroutine(_, _) => None,
             },
         }
     }
@@ -2620,7 +2620,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             // desugaring. A closure gets desugared to a struct, and
             // these extra requirements are basically like where
             // clauses on the struct.
-            AggregateKind::Closure(def_id, args) | AggregateKind::Coroutine(def_id, args, _) => {
+            AggregateKind::Closure(def_id, args) | AggregateKind::Coroutine(def_id, args) => {
                 (def_id, self.prove_closure_bounds(tcx, def_id.expect_local(), args, location))
             }
 
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index 2b83c787139..a02304a2f8b 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -14,7 +14,6 @@
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::Diagnostic;
-use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::BodyOwnerKind;
@@ -94,7 +93,7 @@ pub enum DefiningTy<'tcx> {
     /// The MIR is a coroutine. The signature is that coroutines take
     /// no parameters and return the result of
     /// `ClosureArgs::coroutine_return_ty`.
-    Coroutine(DefId, GenericArgsRef<'tcx>, hir::Movability),
+    Coroutine(DefId, GenericArgsRef<'tcx>),
 
     /// The MIR is a fn item with the given `DefId` and args. The signature
     /// of the function can be bound then with the `fn_sig` query.
@@ -118,7 +117,7 @@ impl<'tcx> DefiningTy<'tcx> {
     pub fn upvar_tys(self) -> &'tcx ty::List<Ty<'tcx>> {
         match self {
             DefiningTy::Closure(_, args) => args.as_closure().upvar_tys(),
-            DefiningTy::Coroutine(_, args, _) => args.as_coroutine().upvar_tys(),
+            DefiningTy::Coroutine(_, args) => args.as_coroutine().upvar_tys(),
             DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => {
                 ty::List::empty()
             }
@@ -354,7 +353,7 @@ impl<'tcx> UniversalRegions<'tcx> {
                     err.note(format!("late-bound region is {:?}", self.to_region_vid(r)));
                 });
             }
-            DefiningTy::Coroutine(def_id, args, _) => {
+            DefiningTy::Coroutine(def_id, args) => {
                 let v = with_no_trimmed_paths!(
                     args[tcx.generics_of(def_id).parent_count..]
                         .iter()
@@ -527,7 +526,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
         debug!("build: local regions  = {}..{}", first_local_index, num_universals);
 
         let yield_ty = match defining_ty {
-            DefiningTy::Coroutine(_, args, _) => Some(args.as_coroutine().yield_ty()),
+            DefiningTy::Coroutine(_, args) => Some(args.as_coroutine().yield_ty()),
             _ => None,
         };
 
@@ -562,9 +561,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
 
                 match *defining_ty.kind() {
                     ty::Closure(def_id, args) => DefiningTy::Closure(def_id, args),
-                    ty::Coroutine(def_id, args, movability) => {
-                        DefiningTy::Coroutine(def_id, args, movability)
-                    }
+                    ty::Coroutine(def_id, args) => DefiningTy::Coroutine(def_id, args),
                     ty::FnDef(def_id, args) => DefiningTy::FnDef(def_id, args),
                     _ => span_bug!(
                         tcx.def_span(self.mir_def),
@@ -620,7 +617,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
         let identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id);
         let fr_args = match defining_ty {
             DefiningTy::Closure(_, args)
-            | DefiningTy::Coroutine(_, args, _)
+            | DefiningTy::Coroutine(_, args)
             | DefiningTy::InlineConst(_, args) => {
                 // In the case of closures, we rely on the fact that
                 // the first N elements in the ClosureArgs are
@@ -685,11 +682,11 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
                 )
             }
 
-            DefiningTy::Coroutine(def_id, args, movability) => {
+            DefiningTy::Coroutine(def_id, args) => {
                 assert_eq!(self.mir_def.to_def_id(), def_id);
                 let resume_ty = args.as_coroutine().resume_ty();
                 let output = args.as_coroutine().return_ty();
-                let coroutine_ty = Ty::new_coroutine(tcx, def_id, args, movability);
+                let coroutine_ty = Ty::new_coroutine(tcx, def_id, args);
                 let inputs_and_output =
                     self.infcx.tcx.mk_type_list(&[coroutine_ty, resume_ty, output]);
                 ty::Binder::dummy(inputs_and_output)
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index 838c73fa213..f016e6950d4 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -974,8 +974,8 @@ pub(crate) fn assert_assignable<'tcx>(
                 }
             }
         }
-        (&ty::Coroutine(def_id_a, args_a, mov_a), &ty::Coroutine(def_id_b, args_b, mov_b))
-            if def_id_a == def_id_b && mov_a == mov_b =>
+        (&ty::Coroutine(def_id_a, args_a), &ty::Coroutine(def_id_b, args_b))
+            if def_id_a == def_id_b =>
         {
             let mut types_a = args_a.types();
             let mut types_b = args_b.types();
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index b8a8c144dc9..42e61b3ccb5 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -1296,7 +1296,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
     }
 
     // Atomic Operations
-    fn atomic_cmpxchg(&mut self, dst: RValue<'gcc>, cmp: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, failure_order: AtomicOrdering, weak: bool) -> RValue<'gcc> {
+    fn atomic_cmpxchg(&mut self, dst: RValue<'gcc>, cmp: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, failure_order: AtomicOrdering, weak: bool) -> (RValue<'gcc>, RValue<'gcc>) {
         let expected = self.current_func().new_local(None, cmp.get_type(), "expected");
         self.llbb().add_assignment(None, expected, cmp);
         // NOTE: gcc doesn't support a failure memory model that is stronger than the success
@@ -1310,20 +1310,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
             };
         let success = self.compare_exchange(dst, expected, src, order, failure_order, weak);
 
-        let pair_type = self.cx.type_struct(&[src.get_type(), self.bool_type], false);
-        let result = self.current_func().new_local(None, pair_type, "atomic_cmpxchg_result");
-        let align = Align::from_bits(64).expect("align"); // TODO(antoyo): use good align.
+        // NOTE: since success contains the call to the intrinsic, it must be added to the basic block before
+        // expected so that we store expected after the call.
+        let success_var = self.current_func().new_local(None, self.bool_type, "success");
+        self.llbb().add_assignment(None, success_var, success);
 
-        let value_type = result.to_rvalue().get_type();
-        if let Some(struct_type) = value_type.is_struct() {
-            self.store(success, result.access_field(None, struct_type.get_field(1)).get_address(None), align);
-            // NOTE: since success contains the call to the intrinsic, it must be stored before
-            // expected so that we store expected after the call.
-            self.store(expected.to_rvalue(), result.access_field(None, struct_type.get_field(0)).get_address(None), align);
-        }
-        // TODO(antoyo): handle when value is not a struct.
-
-        result.to_rvalue()
+        (expected.to_rvalue(), success_var.to_rvalue())
     }
 
     fn atomic_rmw(&mut self, op: AtomicRmwBinOp, dst: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering) -> RValue<'gcc> {
diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs
index 479a814788a..e5c0b2de4ca 100644
--- a/compiler/rustc_codegen_gcc/src/type_of.rs
+++ b/compiler/rustc_codegen_gcc/src/type_of.rs
@@ -98,7 +98,7 @@ fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout
                     write!(&mut name, "::{}", def.variant(index).name).unwrap();
                 }
             }
-            if let (&ty::Coroutine(_, _, _), &Variants::Single { index }) =
+            if let (&ty::Coroutine(_, _), &Variants::Single { index }) =
                 (layout.ty.kind(), &layout.variants)
             {
                 write!(&mut name, "::{}", ty::CoroutineArgs::variant_name(index)).unwrap();
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 8f60175a603..4e5fe290bb1 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -1072,7 +1072,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         order: rustc_codegen_ssa::common::AtomicOrdering,
         failure_order: rustc_codegen_ssa::common::AtomicOrdering,
         weak: bool,
-    ) -> &'ll Value {
+    ) -> (&'ll Value, &'ll Value) {
         let weak = if weak { llvm::True } else { llvm::False };
         unsafe {
             let value = llvm::LLVMBuildAtomicCmpXchg(
@@ -1085,7 +1085,9 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
                 llvm::False, // SingleThreaded
             );
             llvm::LLVMSetWeak(value, weak);
-            value
+            let val = self.extract_value(value, 0);
+            let success = self.extract_value(value, 1);
+            (val, success)
         }
     }
     fn atomic_rmw(
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 59c075a3d3e..76c9ac6614a 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -1066,7 +1066,7 @@ fn build_upvar_field_di_nodes<'ll, 'tcx>(
     closure_or_coroutine_di_node: &'ll DIType,
 ) -> SmallVec<&'ll DIType> {
     let (&def_id, up_var_tys) = match closure_or_coroutine_ty.kind() {
-        ty::Coroutine(def_id, args, _) => (def_id, args.as_coroutine().prefix_tys()),
+        ty::Coroutine(def_id, args) => (def_id, args.as_coroutine().prefix_tys()),
         ty::Closure(def_id, args) => (def_id, args.as_closure().upvar_tys()),
         _ => {
             bug!(
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 4a2861af44c..4792b0798df 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
@@ -679,7 +679,7 @@ fn build_union_fields_for_direct_tag_coroutine<'ll, 'tcx>(
     };
 
     let (coroutine_def_id, coroutine_args) = match coroutine_type_and_layout.ty.kind() {
-        &ty::Coroutine(def_id, args, _) => (def_id, args.as_coroutine()),
+        &ty::Coroutine(def_id, args) => (def_id, args.as_coroutine()),
         _ => unreachable!(),
     };
 
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 eef8dbb33b4..7f671d1d061 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
@@ -336,7 +336,7 @@ pub fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>(
     let variant_layout = coroutine_type_and_layout.for_variant(cx, variant_index);
 
     let coroutine_args = match coroutine_type_and_layout.ty.kind() {
-        ty::Coroutine(_, args, _) => args.as_coroutine(),
+        ty::Coroutine(_, args) => args.as_coroutine(),
         _ => unreachable!(),
     };
 
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 cba4e3811d5..3dbe820b8ff 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs
@@ -135,7 +135,7 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
     unique_type_id: UniqueTypeId<'tcx>,
 ) -> DINodeCreationResult<'ll> {
     let coroutine_type = unique_type_id.expect_ty();
-    let &ty::Coroutine(coroutine_def_id, _, _) = coroutine_type.kind() else {
+    let &ty::Coroutine(coroutine_def_id, _) = coroutine_type.kind() else {
         bug!("build_coroutine_di_node() called with non-coroutine type: `{:?}`", coroutine_type)
     };
 
diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs
index 624ce6d8813..57b46382c96 100644
--- a/compiler/rustc_codegen_llvm/src/type_of.rs
+++ b/compiler/rustc_codegen_llvm/src/type_of.rs
@@ -54,7 +54,7 @@ fn uncached_llvm_type<'a, 'tcx>(
                     write!(&mut name, "::{}", def.variant(index).name).unwrap();
                 }
             }
-            if let (&ty::Coroutine(_, _, _), &Variants::Single { index }) =
+            if let (&ty::Coroutine(_, _), &Variants::Single { index }) =
                 (layout.ty.kind(), &layout.variants)
             {
                 write!(&mut name, "::{}", ty::CoroutineArgs::variant_name(index)).unwrap();
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 533803ea7ff..8530bf9e2b3 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -335,7 +335,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                                 cmp = bx.ptrtoint(cmp, bx.type_isize());
                                 src = bx.ptrtoint(src, bx.type_isize());
                             }
-                            let pair = bx.atomic_cmpxchg(
+                            let (val, success) = bx.atomic_cmpxchg(
                                 dst,
                                 cmp,
                                 src,
@@ -343,8 +343,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                                 parse_ordering(bx, failure),
                                 weak,
                             );
-                            let val = bx.extract_value(pair, 0);
-                            let success = bx.extract_value(pair, 1);
                             let val = bx.from_immediate(val);
                             let success = bx.from_immediate(success);
 
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index aa411f002a0..1c5c78e6ca2 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -296,7 +296,7 @@ pub trait BuilderMethods<'a, 'tcx>:
         order: AtomicOrdering,
         failure_order: AtomicOrdering,
         weak: bool,
-    ) -> Self::Value;
+    ) -> (Self::Value, Self::Value);
     fn atomic_rmw(
         &mut self,
         op: AtomicRmwBinOp,
diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs
index d9f583c1d1f..bb8c17cf779 100644
--- a/compiler/rustc_const_eval/src/interpret/discriminant.rs
+++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs
@@ -171,7 +171,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     ty::Adt(adt, _) => {
                         adt.discriminants(*self.tcx).find(|(_, var)| var.val == discr_bits)
                     }
-                    ty::Coroutine(def_id, args, _) => {
+                    ty::Coroutine(def_id, args) => {
                         let args = args.as_coroutine();
                         args.discriminants(def_id, *self.tcx).find(|(_, var)| var.val == discr_bits)
                     }
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index c29f23b913f..1e9e7d94596 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -85,7 +85,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
             | ty::FnPtr(_)
             | ty::Dynamic(_, _, _)
             | ty::Closure(_, _)
-            | ty::Coroutine(_, _, _)
+            | ty::Coroutine(_, _)
             | ty::CoroutineWitness(..)
             | ty::Never
             | ty::Tuple(_)
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 07500f74477..8b44b87647d 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -217,7 +217,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
         // Now we know we are projecting to a field, so figure out which one.
         match layout.ty.kind() {
             // coroutines and closures.
-            ty::Closure(def_id, _) | ty::Coroutine(def_id, _, _) => {
+            ty::Closure(def_id, _) | ty::Coroutine(def_id, _) => {
                 let mut name = None;
                 // FIXME this should be more descriptive i.e. CapturePlace instead of CapturedVar
                 // https://github.com/rust-lang/project-rfc-2229/issues/46
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 68ded1d324f..b249ffb84b3 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -694,7 +694,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                         };
                         check_equal(self, location, f_ty);
                     }
-                    &ty::Coroutine(def_id, args, _) => {
+                    &ty::Coroutine(def_id, args) => {
                         let f_ty = if let Some(var) = parent_ty.variant_index {
                             let gen_body = if def_id == self.body.source.def_id() {
                                 self.body
diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs
index a82b65b19a8..976e42ad768 100644
--- a/compiler/rustc_const_eval/src/util/type_name.rs
+++ b/compiler/rustc_const_eval/src/util/type_name.rs
@@ -51,7 +51,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
             | ty::FnDef(def_id, args)
             | ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. })
             | ty::Closure(def_id, args)
-            | ty::Coroutine(def_id, args, _) => self.print_def_path(def_id, args),
+            | ty::Coroutine(def_id, args) => self.print_def_path(def_id, args),
             ty::Foreign(def_id) => self.print_def_path(def_id, &[]),
 
             ty::Alias(ty::Weak, _) => bug!("type_name: unexpected weak projection"),
diff --git a/compiler/rustc_data_structures/src/hashes.rs b/compiler/rustc_data_structures/src/hashes.rs
index ad068cdbc98..291ee5bbe26 100644
--- a/compiler/rustc_data_structures/src/hashes.rs
+++ b/compiler/rustc_data_structures/src/hashes.rs
@@ -25,7 +25,7 @@ impl Hash64 {
     pub const ZERO: Hash64 = Hash64 { inner: 0 };
 
     #[inline]
-    pub(crate) fn new(n: u64) -> Self {
+    pub fn new(n: u64) -> Self {
         Self { inner: n }
     }
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0453.md b/compiler/rustc_error_codes/src/error_codes/E0453.md
index 11789db8f36..86ca0d9eca9 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0453.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0453.md
@@ -8,8 +8,8 @@ Example of erroneous code:
 
 #[allow(non_snake_case)]
 fn main() {
-    let MyNumber = 2; // error: allow(non_snake_case) overruled by outer
-                      //        forbid(non_snake_case)
+    // error: allow(non_snake_case) incompatible with previous forbid
+    let MyNumber = 2;
 }
 ```
 
diff --git a/compiler/rustc_hir/src/def_path_hash_map.rs b/compiler/rustc_hir/src/def_path_hash_map.rs
index 8bfb47af26f..9a6dee1e511 100644
--- a/compiler/rustc_hir/src/def_path_hash_map.rs
+++ b/compiler/rustc_hir/src/def_path_hash_map.rs
@@ -1,21 +1,22 @@
-use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_span::def_id::{DefIndex, DefPathHash};
+use rustc_data_structures::stable_hasher::Hash64;
+use rustc_span::def_id::DefIndex;
 
 #[derive(Clone, Default)]
 pub struct Config;
 
 impl odht::Config for Config {
-    type Key = DefPathHash;
+    // This hash-map is single-crate, so we only need to key by the local hash.
+    type Key = Hash64;
     type Value = DefIndex;
 
-    type EncodedKey = [u8; 16];
+    type EncodedKey = [u8; 8];
     type EncodedValue = [u8; 4];
 
     type H = odht::UnHashFn;
 
     #[inline]
-    fn encode_key(k: &DefPathHash) -> [u8; 16] {
-        k.0.to_le_bytes()
+    fn encode_key(k: &Hash64) -> [u8; 8] {
+        k.as_u64().to_le_bytes()
     }
 
     #[inline]
@@ -24,8 +25,8 @@ impl odht::Config for Config {
     }
 
     #[inline]
-    fn decode_key(k: &[u8; 16]) -> DefPathHash {
-        DefPathHash(Fingerprint::from_le_bytes(*k))
+    fn decode_key(k: &[u8; 8]) -> Hash64 {
+        Hash64::new(u64::from_le_bytes(*k))
     }
 
     #[inline]
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index 2ab9a6ef32c..9fb1fc19bf4 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -20,27 +20,42 @@ use std::hash::Hash;
 /// Internally the `DefPathTable` holds a tree of `DefKey`s, where each `DefKey`
 /// stores the `DefIndex` of its parent.
 /// There is one `DefPathTable` for each crate.
-#[derive(Clone, Default, Debug)]
+#[derive(Debug)]
 pub struct DefPathTable {
+    stable_crate_id: StableCrateId,
     index_to_key: IndexVec<DefIndex, DefKey>,
-    def_path_hashes: IndexVec<DefIndex, DefPathHash>,
+    // We do only store the local hash, as all the definitions are from the current crate.
+    def_path_hashes: IndexVec<DefIndex, Hash64>,
     def_path_hash_to_index: DefPathHashMap,
 }
 
 impl DefPathTable {
+    fn new(stable_crate_id: StableCrateId) -> DefPathTable {
+        DefPathTable {
+            stable_crate_id,
+            index_to_key: Default::default(),
+            def_path_hashes: Default::default(),
+            def_path_hash_to_index: Default::default(),
+        }
+    }
+
     fn allocate(&mut self, key: DefKey, def_path_hash: DefPathHash) -> DefIndex {
+        // Assert that all DefPathHashes correctly contain the local crate's StableCrateId.
+        debug_assert_eq!(self.stable_crate_id, def_path_hash.stable_crate_id());
+        let local_hash = def_path_hash.local_hash();
+
         let index = {
             let index = DefIndex::from(self.index_to_key.len());
             debug!("DefPathTable::insert() - {:?} <-> {:?}", key, index);
             self.index_to_key.push(key);
             index
         };
-        self.def_path_hashes.push(def_path_hash);
+        self.def_path_hashes.push(local_hash);
         debug_assert!(self.def_path_hashes.len() == self.index_to_key.len());
 
         // Check for hash collisions of DefPathHashes. These should be
         // exceedingly rare.
-        if let Some(existing) = self.def_path_hash_to_index.insert(&def_path_hash, &index) {
+        if let Some(existing) = self.def_path_hash_to_index.insert(&local_hash, &index) {
             let def_path1 = DefPath::make(LOCAL_CRATE, existing, |idx| self.def_key(idx));
             let def_path2 = DefPath::make(LOCAL_CRATE, index, |idx| self.def_key(idx));
 
@@ -58,13 +73,6 @@ impl DefPathTable {
             );
         }
 
-        // Assert that all DefPathHashes correctly contain the local crate's
-        // StableCrateId
-        #[cfg(debug_assertions)]
-        if let Some(root) = self.def_path_hashes.get(CRATE_DEF_INDEX) {
-            assert!(def_path_hash.stable_crate_id() == root.stable_crate_id());
-        }
-
         index
     }
 
@@ -73,19 +81,19 @@ impl DefPathTable {
         self.index_to_key[index]
     }
 
+    #[instrument(level = "trace", skip(self), ret)]
     #[inline(always)]
     pub fn def_path_hash(&self, index: DefIndex) -> DefPathHash {
         let hash = self.def_path_hashes[index];
-        debug!("def_path_hash({:?}) = {:?}", index, hash);
-        hash
+        DefPathHash::new(self.stable_crate_id, hash)
     }
 
     pub fn enumerated_keys_and_path_hashes(
         &self,
-    ) -> impl Iterator<Item = (DefIndex, &DefKey, &DefPathHash)> + ExactSizeIterator + '_ {
+    ) -> impl Iterator<Item = (DefIndex, &DefKey, DefPathHash)> + ExactSizeIterator + '_ {
         self.index_to_key
             .iter_enumerated()
-            .map(move |(index, key)| (index, key, &self.def_path_hashes[index]))
+            .map(move |(index, key)| (index, key, self.def_path_hash(index)))
     }
 }
 
@@ -96,9 +104,6 @@ impl DefPathTable {
 pub struct Definitions {
     table: DefPathTable,
     next_disambiguator: UnordMap<(LocalDefId, DefPathData), u32>,
-
-    /// The [StableCrateId] of the local crate.
-    stable_crate_id: StableCrateId,
 }
 
 /// A unique identifier that we can use to lookup a definition
@@ -329,11 +334,11 @@ impl Definitions {
         let def_path_hash = key.compute_stable_hash(parent_hash);
 
         // Create the root definition.
-        let mut table = DefPathTable::default();
+        let mut table = DefPathTable::new(stable_crate_id);
         let root = LocalDefId { local_def_index: table.allocate(key, def_path_hash) };
         assert_eq!(root.local_def_index, CRATE_DEF_INDEX);
 
-        Definitions { table, next_disambiguator: Default::default(), stable_crate_id }
+        Definitions { table, next_disambiguator: Default::default() }
     }
 
     /// Adds a definition with a parent definition.
@@ -375,10 +380,10 @@ impl Definitions {
         hash: DefPathHash,
         err: &mut dyn FnMut() -> !,
     ) -> LocalDefId {
-        debug_assert!(hash.stable_crate_id() == self.stable_crate_id);
+        debug_assert!(hash.stable_crate_id() == self.table.stable_crate_id);
         self.table
             .def_path_hash_to_index
-            .get(&hash)
+            .get(&hash.local_hash())
             .map(|local_def_index| LocalDefId { local_def_index })
             .unwrap_or_else(|| err())
     }
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
index 984c2829c81..0ca0f7d2daf 100644
--- a/compiler/rustc_hir_typeck/src/check.rs
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -160,12 +160,7 @@ pub(super) fn check_fn<'a, 'tcx>(
         ));
 
         let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap();
-        Some(CoroutineTypes {
-            resume_ty,
-            yield_ty,
-            interior,
-            movability: coroutine_kind.movability(),
-        })
+        Some(CoroutineTypes { resume_ty, yield_ty, interior })
     } else {
         None
     };
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index c29ef375ce4..bf6fda20df8 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -105,8 +105,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             span: self.tcx.def_span(expr_def_id),
         });
 
-        if let Some(CoroutineTypes { resume_ty, yield_ty, interior, movability }) = coroutine_types
-        {
+        if let Some(CoroutineTypes { resume_ty, yield_ty, interior }) = coroutine_types {
             let coroutine_args = ty::CoroutineArgs::new(
                 self.tcx,
                 ty::CoroutineArgsParts {
@@ -119,12 +118,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 },
             );
 
-            return Ty::new_coroutine(
-                self.tcx,
-                expr_def_id.to_def_id(),
-                coroutine_args.args,
-                movability,
-            );
+            return Ty::new_coroutine(self.tcx, expr_def_id.to_def_id(), coroutine_args.args);
         }
 
         // Tuple up the arguments and insert the resulting function type into
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index d9106439420..da9a2bde783 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -304,9 +304,6 @@ struct CoroutineTypes<'tcx> {
 
     /// Types that are captured (see `CoroutineInterior` for more).
     interior: Ty<'tcx>,
-
-    /// Indicates if the coroutine is movable or static (immovable).
-    movability: hir::Movability,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 6530d828b3b..47fdd64796e 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -3306,6 +3306,7 @@ fn print_disambiguation_help<'tcx>(
     span: Span,
     item: ty::AssocItem,
 ) -> Option<String> {
+    let trait_impl_type = trait_ref.self_ty().peel_refs();
     let trait_ref = if item.fn_has_self_parameter {
         trait_ref.print_only_trait_name().to_string()
     } else {
@@ -3318,27 +3319,34 @@ fn print_disambiguation_help<'tcx>(
         {
             let def_kind_descr = tcx.def_kind_descr(item.kind.as_def_kind(), item.def_id);
             let item_name = item.ident(tcx);
-            let rcvr_ref = tcx
-                .fn_sig(item.def_id)
-                .skip_binder()
-                .skip_binder()
-                .inputs()
-                .get(0)
-                .and_then(|ty| ty.ref_mutability())
-                .map_or("", |mutbl| mutbl.ref_prefix_str());
-            let args = format!(
-                "({}{})",
-                rcvr_ref,
-                std::iter::once(receiver)
-                    .chain(args.iter())
-                    .map(|arg| tcx
-                        .sess
-                        .source_map()
-                        .span_to_snippet(arg.span)
-                        .unwrap_or_else(|_| { "_".to_owned() }))
-                    .collect::<Vec<_>>()
-                    .join(", "),
+            let first_input =
+                tcx.fn_sig(item.def_id).instantiate_identity().skip_binder().inputs().get(0);
+            let (first_arg_type, rcvr_ref) = (
+                first_input.map(|first| first.peel_refs()),
+                first_input
+                    .and_then(|ty| ty.ref_mutability())
+                    .map_or("", |mutbl| mutbl.ref_prefix_str()),
             );
+
+            // If the type of first arg of this assoc function is `Self` or current trait impl type or `arbitrary_self_types`, we need to take the receiver as args. Otherwise, we don't.
+            let args = if let Some(first_arg_type) = first_arg_type
+                && (first_arg_type == tcx.types.self_param
+                    || first_arg_type == trait_impl_type
+                    || item.fn_has_self_parameter)
+            {
+                Some(receiver)
+            } else {
+                None
+            }
+            .into_iter()
+            .chain(args)
+            .map(|arg| {
+                tcx.sess.source_map().span_to_snippet(arg.span).unwrap_or_else(|_| "_".to_owned())
+            })
+            .collect::<Vec<_>>()
+            .join(", ");
+
+            let args = format!("({}{})", rcvr_ref, args);
             err.span_suggestion_verbose(
                 span,
                 format!(
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index fc525a0fd4e..47b9d5f6503 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -172,7 +172,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let ty = self.node_ty(closure_hir_id);
         let (closure_def_id, args) = match *ty.kind() {
             ty::Closure(def_id, args) => (def_id, UpvarArgs::Closure(args)),
-            ty::Coroutine(def_id, args, _) => (def_id, UpvarArgs::Coroutine(args)),
+            ty::Coroutine(def_id, args) => (def_id, UpvarArgs::Coroutine(args)),
             ty::Error(_) => {
                 // #51714: skip analysis when we have already encountered type errors
                 return;
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index 2656fd529cd..11b5b437eff 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -456,7 +456,7 @@ where
                 args.as_closure().sig_as_fn_ptr_ty().visit_with(self);
             }
 
-            ty::Coroutine(_, args, _) => {
+            ty::Coroutine(_, args) => {
                 // Skip lifetime parameters of the enclosing item(s)
                 // Also skip the witness type, because that has no free regions.
 
diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs
index 47038cfd468..fc3d8375873 100644
--- a/compiler/rustc_infer/src/infer/outlives/components.rs
+++ b/compiler/rustc_infer/src/infer/outlives/components.rs
@@ -103,7 +103,7 @@ fn compute_components<'tcx>(
                 compute_components(tcx, tupled_ty, out, visited);
             }
 
-            ty::Coroutine(_, args, _) => {
+            ty::Coroutine(_, args) => {
                 // Same as the closure case
                 let tupled_ty = args.as_coroutine().tupled_upvars_ty();
                 compute_components(tcx, tupled_ty, out, visited);
diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs
index 4d8c691ea3d..27d37fd9369 100644
--- a/compiler/rustc_infer/src/infer/relate/generalize.rs
+++ b/compiler/rustc_infer/src/infer/relate/generalize.rs
@@ -1,6 +1,7 @@
 use std::mem;
 
 use rustc_data_structures::sso::SsoHashMap;
+use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir::def_id::DefId;
 use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
 use rustc_middle::ty::error::TypeError;
@@ -215,7 +216,9 @@ where
         let old_ambient_variance = self.ambient_variance;
         self.ambient_variance = self.ambient_variance.xform(variance);
         debug!(?self.ambient_variance, "new ambient variance");
-        let r = self.relate(a, b)?;
+        // Recursive calls to `relate` can overflow the stack. For example a deeper version of
+        // `ui/associated-consts/issue-93775.rs`.
+        let r = ensure_sufficient_stack(|| self.relate(a, b))?;
         self.ambient_variance = old_ambient_variance;
         Ok(r)
     }
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 40b70ba4e04..39c965e75d6 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -1069,7 +1069,7 @@ impl<'a> EarlyContext<'a> {
     pub(crate) fn new(
         sess: &'a Session,
         features: &'a Features,
-        warn_about_weird_lints: bool,
+        lint_added_lints: bool,
         lint_store: &'a LintStore,
         registered_tools: &'a RegisteredTools,
         buffered: LintBuffer,
@@ -1078,7 +1078,7 @@ impl<'a> EarlyContext<'a> {
             builder: LintLevelsBuilder::new(
                 sess,
                 features,
-                warn_about_weird_lints,
+                lint_added_lints,
                 lint_store,
                 registered_tools,
             ),
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 17c56f1ca58..c229728cb79 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -135,7 +135,7 @@ fn lint_expectations(tcx: TyCtxt<'_>, (): ()) -> Vec<(LintExpectationId, LintExp
             unstable_to_stable_ids: FxHashMap::default(),
             empty: FxHashMap::default(),
         },
-        warn_about_weird_lints: false,
+        lint_added_lints: false,
         store,
         registered_tools: tcx.registered_tools(()),
     };
@@ -164,7 +164,7 @@ fn shallow_lint_levels_on(tcx: TyCtxt<'_>, owner: hir::OwnerId) -> ShallowLintLe
             empty: FxHashMap::default(),
             attrs,
         },
-        warn_about_weird_lints: false,
+        lint_added_lints: false,
         store,
         registered_tools: tcx.registered_tools(()),
     };
@@ -451,7 +451,7 @@ pub struct LintLevelsBuilder<'s, P> {
     sess: &'s Session,
     features: &'s Features,
     provider: P,
-    warn_about_weird_lints: bool,
+    lint_added_lints: bool,
     store: &'s LintStore,
     registered_tools: &'s RegisteredTools,
 }
@@ -464,7 +464,7 @@ impl<'s> LintLevelsBuilder<'s, TopDown> {
     pub(crate) fn new(
         sess: &'s Session,
         features: &'s Features,
-        warn_about_weird_lints: bool,
+        lint_added_lints: bool,
         store: &'s LintStore,
         registered_tools: &'s RegisteredTools,
     ) -> Self {
@@ -472,7 +472,7 @@ impl<'s> LintLevelsBuilder<'s, TopDown> {
             sess,
             features,
             provider: TopDown { sets: LintLevelSets::new(), cur: COMMAND_LINE },
-            warn_about_weird_lints,
+            lint_added_lints,
             store,
             registered_tools,
         };
@@ -642,7 +642,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
         //
         // This means that this only errors if we're truly lowering the lint
         // level from forbid.
-        if level != Level::Forbid {
+        if self.lint_added_lints && level != Level::Forbid {
             if let Level::Forbid = old_level {
                 // Backwards compatibility check:
                 //
@@ -968,7 +968,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
                         continue;
                     }
 
-                    _ if !self.warn_about_weird_lints => {}
+                    _ if !self.lint_added_lints => {}
 
                     CheckLintNameResult::Renamed(ref replace) => {
                         let suggestion =
@@ -1029,7 +1029,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
             }
         }
 
-        if !is_crate_node {
+        if self.lint_added_lints && !is_crate_node {
             for (id, &(level, ref src)) in self.current_specs().iter() {
                 if !id.lint.crate_level_only {
                     continue;
@@ -1054,33 +1054,33 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
     /// Checks if the lint is gated on a feature that is not enabled.
     ///
     /// Returns `true` if the lint's feature is enabled.
-    // FIXME only emit this once for each attribute, instead of repeating it 4 times for
-    // pre-expansion lints, post-expansion lints, `shallow_lint_levels_on` and `lint_expectations`.
     #[track_caller]
     fn check_gated_lint(&self, lint_id: LintId, span: Span, lint_from_cli: bool) -> bool {
         if let Some(feature) = lint_id.lint.feature_gate {
             if !self.features.active(feature) {
-                let lint = builtin::UNKNOWN_LINTS;
-                let (level, src) = self.lint_level(builtin::UNKNOWN_LINTS);
-                struct_lint_level(
-                    self.sess,
-                    lint,
-                    level,
-                    src,
-                    Some(span.into()),
-                    fluent::lint_unknown_gated_lint,
-                    |lint| {
-                        lint.set_arg("name", lint_id.lint.name_lower());
-                        lint.note(fluent::lint_note);
-                        rustc_session::parse::add_feature_diagnostics_for_issue(
-                            lint,
-                            &self.sess.parse_sess,
-                            feature,
-                            GateIssue::Language,
-                            lint_from_cli,
-                        );
-                    },
-                );
+                if self.lint_added_lints {
+                    let lint = builtin::UNKNOWN_LINTS;
+                    let (level, src) = self.lint_level(builtin::UNKNOWN_LINTS);
+                    struct_lint_level(
+                        self.sess,
+                        lint,
+                        level,
+                        src,
+                        Some(span.into()),
+                        fluent::lint_unknown_gated_lint,
+                        |lint| {
+                            lint.set_arg("name", lint_id.lint.name_lower());
+                            lint.note(fluent::lint_note);
+                            rustc_session::parse::add_feature_diagnostics_for_issue(
+                                lint,
+                                &self.sess.parse_sess,
+                                feature,
+                                GateIssue::Language,
+                                lint_from_cli,
+                            );
+                        },
+                    );
+                }
                 return false;
             }
         }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index ae4a0e15fab..2de29db9e5c 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -508,21 +508,19 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for ExpnId {
 impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span {
     fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Span {
         let start = decoder.position();
-        let mode = SpanEncodingMode::decode(decoder);
-        let data = match mode {
-            SpanEncodingMode::Direct => SpanData::decode(decoder),
-            SpanEncodingMode::RelativeOffset(offset) => {
-                decoder.with_position(start - offset, |decoder| {
-                    let mode = SpanEncodingMode::decode(decoder);
-                    debug_assert!(matches!(mode, SpanEncodingMode::Direct));
-                    SpanData::decode(decoder)
-                })
-            }
-            SpanEncodingMode::AbsoluteOffset(addr) => decoder.with_position(addr, |decoder| {
-                let mode = SpanEncodingMode::decode(decoder);
-                debug_assert!(matches!(mode, SpanEncodingMode::Direct));
-                SpanData::decode(decoder)
-            }),
+        let tag = SpanTag(decoder.peek_byte());
+        let data = if tag.kind() == SpanKind::Indirect {
+            // Skip past the tag we just peek'd.
+            decoder.read_u8();
+            let offset_or_position = decoder.read_usize();
+            let position = if tag.is_relative_offset() {
+                start - offset_or_position
+            } else {
+                offset_or_position
+            };
+            decoder.with_position(position, SpanData::decode)
+        } else {
+            SpanData::decode(decoder)
         };
         Span::new(data.lo, data.hi, data.ctxt, data.parent)
     }
@@ -530,17 +528,17 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span {
 
 impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for SpanData {
     fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> SpanData {
-        let ctxt = SyntaxContext::decode(decoder);
-        let tag = u8::decode(decoder);
+        let tag = SpanTag::decode(decoder);
+        let ctxt = tag.context().unwrap_or_else(|| SyntaxContext::decode(decoder));
 
-        if tag == TAG_PARTIAL_SPAN {
+        if tag.kind() == SpanKind::Partial {
             return DUMMY_SP.with_ctxt(ctxt).data();
         }
 
-        debug_assert!(tag == TAG_VALID_SPAN_LOCAL || tag == TAG_VALID_SPAN_FOREIGN);
+        debug_assert!(tag.kind() == SpanKind::Local || tag.kind() == SpanKind::Foreign);
 
         let lo = BytePos::decode(decoder);
-        let len = BytePos::decode(decoder);
+        let len = tag.length().unwrap_or_else(|| BytePos::decode(decoder));
         let hi = lo + len;
 
         let Some(sess) = decoder.sess else {
@@ -581,7 +579,7 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for SpanData {
         // treat the 'local' and 'foreign' cases almost identically during deserialization:
         // we can call `imported_source_file` for the proper crate, and binary search
         // through the returned slice using our span.
-        let source_file = if tag == TAG_VALID_SPAN_LOCAL {
+        let source_file = if tag.kind() == SpanKind::Local {
             decoder.cdata().imported_source_file(metadata_index, sess)
         } else {
             // When we encode a proc-macro crate, all `Span`s should be encoded
diff --git a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
index 4f280bb9d80..9950bc1c31f 100644
--- a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
+++ b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
@@ -19,7 +19,9 @@ impl DefPathHashMapRef<'_> {
     #[inline]
     pub fn def_path_hash_to_def_index(&self, def_path_hash: &DefPathHash) -> DefIndex {
         match *self {
-            DefPathHashMapRef::OwnedFromMetadata(ref map) => map.get(def_path_hash).unwrap(),
+            DefPathHashMapRef::OwnedFromMetadata(ref map) => {
+                map.get(&def_path_hash.local_hash()).unwrap()
+            }
             DefPathHashMapRef::BorrowedFromTcx(_) => {
                 panic!("DefPathHashMap::BorrowedFromTcx variant only exists for serialization")
             }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index f322588e365..aca7a66596e 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -177,15 +177,17 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Span {
                 // previously saved offset must be smaller than the current position.
                 let offset = s.opaque.position() - last_location;
                 if offset < last_location {
-                    SpanEncodingMode::RelativeOffset(offset).encode(s)
+                    SpanTag::indirect(true).encode(s);
+                    offset.encode(s);
                 } else {
-                    SpanEncodingMode::AbsoluteOffset(last_location).encode(s)
+                    SpanTag::indirect(false).encode(s);
+                    last_location.encode(s);
                 }
             }
             Entry::Vacant(v) => {
                 let position = s.opaque.position();
                 v.insert(position);
-                SpanEncodingMode::Direct.encode(s);
+                // Data is encoded with a SpanTag prefix (see below).
                 self.data().encode(s);
             }
         }
@@ -225,14 +227,15 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for SpanData {
         // IMPORTANT: If this is ever changed, be sure to update
         // `rustc_span::hygiene::raw_encode_expn_id` to handle
         // encoding `ExpnData` for proc-macro crates.
-        if s.is_proc_macro {
-            SyntaxContext::root().encode(s);
-        } else {
-            self.ctxt.encode(s);
-        }
+        let ctxt = if s.is_proc_macro { SyntaxContext::root() } else { self.ctxt };
 
         if self.is_dummy() {
-            return TAG_PARTIAL_SPAN.encode(s);
+            let tag = SpanTag::new(SpanKind::Partial, ctxt, 0);
+            tag.encode(s);
+            if tag.context().is_none() {
+                ctxt.encode(s);
+            }
+            return;
         }
 
         // The Span infrastructure should make sure that this invariant holds:
@@ -250,7 +253,12 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for SpanData {
         if !source_file.contains(self.hi) {
             // Unfortunately, macro expansion still sometimes generates Spans
             // that malformed in this way.
-            return TAG_PARTIAL_SPAN.encode(s);
+            let tag = SpanTag::new(SpanKind::Partial, ctxt, 0);
+            tag.encode(s);
+            if tag.context().is_none() {
+                ctxt.encode(s);
+            }
+            return;
         }
 
         // There are two possible cases here:
@@ -269,7 +277,7 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for SpanData {
         // if we're a proc-macro crate.
         // This allows us to avoid loading the dependencies of proc-macro crates: all of
         // the information we need to decode `Span`s is stored in the proc-macro crate.
-        let (tag, metadata_index) = if source_file.is_imported() && !s.is_proc_macro {
+        let (kind, metadata_index) = if source_file.is_imported() && !s.is_proc_macro {
             // To simplify deserialization, we 'rebase' this span onto the crate it originally came
             // from (the crate that 'owns' the file it references. These rebased 'lo' and 'hi'
             // values are relative to the source map information for the 'foreign' crate whose
@@ -287,7 +295,7 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for SpanData {
                 }
             };
 
-            (TAG_VALID_SPAN_FOREIGN, metadata_index)
+            (SpanKind::Foreign, metadata_index)
         } else {
             // Record the fact that we need to encode the data for this `SourceFile`
             let source_files =
@@ -296,7 +304,7 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for SpanData {
             let metadata_index: u32 =
                 metadata_index.try_into().expect("cannot export more than U32_MAX files");
 
-            (TAG_VALID_SPAN_LOCAL, metadata_index)
+            (SpanKind::Local, metadata_index)
         };
 
         // Encode the start position relative to the file start, so we profit more from the
@@ -307,14 +315,20 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for SpanData {
         // from the variable-length integer encoding that we use.
         let len = self.hi - self.lo;
 
+        let tag = SpanTag::new(kind, ctxt, len.0 as usize);
         tag.encode(s);
+        if tag.context().is_none() {
+            ctxt.encode(s);
+        }
         lo.encode(s);
-        len.encode(s);
+        if tag.length().is_none() {
+            len.encode(s);
+        }
 
         // Encode the index of the `SourceFile` for the span, in order to make decoding faster.
         metadata_index.encode(s);
 
-        if tag == TAG_VALID_SPAN_FOREIGN {
+        if kind == SpanKind::Foreign {
             // This needs to be two lines to avoid holding the `s.source_file_cache`
             // while calling `cnum.encode(s)`
             let cnum = s.source_file_cache.0.cnum;
@@ -1444,7 +1458,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             if def_kind == DefKind::Closure
                 && let Some(coroutine_kind) = self.tcx.coroutine_kind(def_id)
             {
-                self.tables.coroutine_kind.set(def_id.index, Some(coroutine_kind));
+                self.tables.coroutine_kind.set(def_id.index, Some(coroutine_kind))
             }
             if let DefKind::Enum | DefKind::Struct | DefKind::Union = def_kind {
                 self.encode_info_for_adt(local_id);
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index bafd3f0b84d..54ee50c2358 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -66,13 +66,6 @@ const METADATA_VERSION: u8 = 9;
 /// unsigned integer, and further followed by the rustc version string.
 pub const METADATA_HEADER: &[u8] = &[b'r', b'u', b's', b't', 0, 0, 0, METADATA_VERSION];
 
-#[derive(Encodable, Decodable)]
-enum SpanEncodingMode {
-    RelativeOffset(usize),
-    AbsoluteOffset(usize),
-    Direct,
-}
-
 /// A value of type T referred to by its absolute position
 /// in the metadata, and which can be decoded lazily.
 ///
@@ -488,10 +481,88 @@ bitflags::bitflags! {
     }
 }
 
-// Tags used for encoding Spans:
-const TAG_VALID_SPAN_LOCAL: u8 = 0;
-const TAG_VALID_SPAN_FOREIGN: u8 = 1;
-const TAG_PARTIAL_SPAN: u8 = 2;
+/// A span tag byte encodes a bunch of data, so that we can cut out a few extra bytes from span
+/// encodings (which are very common, for example, libcore has ~650,000 unique spans and over 1.1
+/// million references to prior-written spans).
+///
+/// The byte format is split into several parts:
+///
+/// [ a a a a a c d d ]
+///
+/// `a` bits represent the span length. We have 5 bits, so we can store lengths up to 30 inline, with
+/// an all-1s pattern representing that the length is stored separately.
+///
+/// `c` represents whether the span context is zero (and then it is not stored as a separate varint)
+/// for direct span encodings, and whether the offset is absolute or relative otherwise (zero for
+/// absolute).
+///
+/// d bits represent the kind of span we are storing (local, foreign, partial, indirect).
+#[derive(Encodable, Decodable, Copy, Clone)]
+struct SpanTag(u8);
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+enum SpanKind {
+    Local = 0b00,
+    Foreign = 0b01,
+    Partial = 0b10,
+    // Indicates the actual span contents are elsewhere.
+    // If this is the kind, then the span context bit represents whether it is a relative or
+    // absolute offset.
+    Indirect = 0b11,
+}
+
+impl SpanTag {
+    fn new(kind: SpanKind, context: rustc_span::SyntaxContext, length: usize) -> SpanTag {
+        let mut data = 0u8;
+        data |= kind as u8;
+        if context.is_root() {
+            data |= 0b100;
+        }
+        let all_1s_len = (0xffu8 << 3) >> 3;
+        // strictly less than - all 1s pattern is a sentinel for storage being out of band.
+        if length < all_1s_len as usize {
+            data |= (length as u8) << 3;
+        } else {
+            data |= all_1s_len << 3;
+        }
+
+        SpanTag(data)
+    }
+
+    fn indirect(relative: bool) -> SpanTag {
+        let mut tag = SpanTag(SpanKind::Indirect as u8);
+        if relative {
+            tag.0 |= 0b100;
+        }
+        tag
+    }
+
+    fn kind(self) -> SpanKind {
+        let masked = self.0 & 0b11;
+        match masked {
+            0b00 => SpanKind::Local,
+            0b01 => SpanKind::Foreign,
+            0b10 => SpanKind::Partial,
+            0b11 => SpanKind::Indirect,
+            _ => unreachable!(),
+        }
+    }
+
+    fn is_relative_offset(self) -> bool {
+        debug_assert_eq!(self.kind(), SpanKind::Indirect);
+        self.0 & 0b100 != 0
+    }
+
+    fn context(self) -> Option<rustc_span::SyntaxContext> {
+        if self.0 & 0b100 != 0 { Some(rustc_span::SyntaxContext::root()) } else { None }
+    }
+
+    fn length(self) -> Option<rustc_span::BytePos> {
+        let all_1s_len = (0xffu8 << 3) >> 3;
+        let len = self.0 >> 3;
+        if len != all_1s_len { Some(rustc_span::BytePos(u32::from(len))) } else { None }
+    }
+}
 
 // Tags for encoding Symbol's
 const SYMBOL_STR: u8 = 0;
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index b995f622388..8e7aaee065f 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -1049,7 +1049,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
                         struct_fmt.finish()
                     }),
 
-                    AggregateKind::Coroutine(def_id, _, _) => ty::tls::with(|tcx| {
+                    AggregateKind::Coroutine(def_id, _) => ty::tls::with(|tcx| {
                         let name = format!("{{coroutine@{:?}}}", tcx.def_span(def_id));
                         let mut struct_fmt = fmt.debug_struct(&name);
 
@@ -1304,11 +1304,11 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
                     self.push(&format!("+ args: {args:#?}"));
                 }
 
-                AggregateKind::Coroutine(def_id, args, movability) => {
+                AggregateKind::Coroutine(def_id, args) => {
                     self.push("coroutine");
                     self.push(&format!("+ def_id: {def_id:?}"));
                     self.push(&format!("+ args: {args:#?}"));
-                    self.push(&format!("+ movability: {movability:?}"));
+                    self.push(&format!("+ kind: {:?}", self.tcx.coroutine_kind(def_id)));
                 }
 
                 AggregateKind::Adt(_, _, _, Some(user_ty), _) => {
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 8cf9e55f0b6..462076d750f 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -14,7 +14,6 @@ use crate::ty::{Region, UserTypeAnnotationIndex};
 
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_hir::def_id::DefId;
-use rustc_hir::{self as hir};
 use rustc_hir::{self, CoroutineKind};
 use rustc_index::IndexVec;
 use rustc_target::abi::{FieldIdx, VariantIdx};
@@ -1344,7 +1343,7 @@ pub enum AggregateKind<'tcx> {
     Adt(DefId, VariantIdx, GenericArgsRef<'tcx>, Option<UserTypeAnnotationIndex>, Option<FieldIdx>),
 
     Closure(DefId, GenericArgsRef<'tcx>),
-    Coroutine(DefId, GenericArgsRef<'tcx>, hir::Movability),
+    Coroutine(DefId, GenericArgsRef<'tcx>),
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index f9b2a6ee8aa..234ccee5546 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -201,9 +201,7 @@ impl<'tcx> Rvalue<'tcx> {
                 }
                 AggregateKind::Adt(did, _, args, _, _) => tcx.type_of(did).instantiate(tcx, args),
                 AggregateKind::Closure(did, args) => Ty::new_closure(tcx, did, args),
-                AggregateKind::Coroutine(did, args, movability) => {
-                    Ty::new_coroutine(tcx, did, args, movability)
-                }
+                AggregateKind::Coroutine(did, args) => Ty::new_coroutine(tcx, did, args),
             },
             Rvalue::ShallowInitBox(_, ty) => Ty::new_box(tcx, ty),
             Rvalue::CopyForDeref(ref place) => place.ty(local_decls, tcx).ty,
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 9059936f495..132ecf91af1 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -736,7 +736,6 @@ macro_rules! make_mir_visitor {
                             AggregateKind::Coroutine(
                                 _,
                                 coroutine_args,
-                                _movability,
                             ) => {
                                 self.visit_args(coroutine_args, location);
                             }
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 17691de630f..6807eacb7f1 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -847,6 +847,12 @@ impl<'tcx> TyCtxt<'tcx> {
         self.coroutine_kind(def_id).is_some()
     }
 
+    /// Returns the movability of the coroutine of `def_id`, or panics
+    /// if given a `def_id` that is not a coroutine.
+    pub fn coroutine_movability(self, def_id: DefId) -> hir::Movability {
+        self.coroutine_kind(def_id).expect("expected a coroutine").movability()
+    }
+
     /// Returns `true` if the node pointed to by `def_id` is a coroutine for an async construct.
     pub fn coroutine_is_async(self, def_id: DefId) -> bool {
         matches!(
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index 38a9cabca97..6ed68f90eb3 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -128,7 +128,7 @@ pub fn simplify_type<'tcx>(
         },
         ty::Ref(_, _, mutbl) => Some(SimplifiedType::Ref(mutbl)),
         ty::FnDef(def_id, _) | ty::Closure(def_id, _) => Some(SimplifiedType::Closure(def_id)),
-        ty::Coroutine(def_id, _, _) => Some(SimplifiedType::Coroutine(def_id)),
+        ty::Coroutine(def_id, _) => Some(SimplifiedType::Coroutine(def_id)),
         ty::CoroutineWitness(def_id, _) => Some(SimplifiedType::CoroutineWitness(def_id)),
         ty::Never => Some(SimplifiedType::Never),
         ty::Tuple(tys) => Some(SimplifiedType::Tuple(tys.len())),
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index f9a2385b100..0c1d1091414 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -96,7 +96,7 @@ impl FlagComputation {
                 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
             }
 
-            ty::Coroutine(_, args, _) => {
+            ty::Coroutine(_, args) => {
                 let args = args.as_coroutine();
                 let should_remove_further_specializable =
                     !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 1c7a7545e2b..1b6d59ab257 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -689,13 +689,13 @@ fn polymorphize<'tcx>(
                         Ty::new_closure(self.tcx, def_id, polymorphized_args)
                     }
                 }
-                ty::Coroutine(def_id, args, movability) => {
+                ty::Coroutine(def_id, args) => {
                     let polymorphized_args =
                         polymorphize(self.tcx, ty::InstanceDef::Item(def_id), args);
                     if args == polymorphized_args {
                         ty
                     } else {
-                        Ty::new_coroutine(self.tcx, def_id, polymorphized_args, movability)
+                        Ty::new_coroutine(self.tcx, def_id, polymorphized_args)
                     }
                 }
                 _ => ty.super_fold_with(self),
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 8a02914b435..5cc0ce87c9b 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -906,7 +906,7 @@ where
                     i,
                 ),
 
-                ty::Coroutine(def_id, args, _) => match this.variants {
+                ty::Coroutine(def_id, args) => match this.variants {
                     Variants::Single { index } => TyMaybeWithLayout::Ty(
                         args.as_coroutine()
                             .state_tys(def_id, tcx)
diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs
index 71fe7d15a6c..fc4d4c9a3d2 100644
--- a/compiler/rustc_middle/src/ty/opaque_types.rs
+++ b/compiler/rustc_middle/src/ty/opaque_types.rs
@@ -153,9 +153,9 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
                 Ty::new_closure(self.tcx, def_id, args)
             }
 
-            ty::Coroutine(def_id, args, movability) => {
+            ty::Coroutine(def_id, args) => {
                 let args = self.fold_closure_args(def_id, args);
-                Ty::new_coroutine(self.tcx, def_id, args, movability)
+                Ty::new_coroutine(self.tcx, def_id, args)
             }
 
             ty::CoroutineWitness(def_id, args) => {
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index 5e09154789a..f32b7b0852a 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -259,7 +259,7 @@ fn characteristic_def_id_of_type_cached<'a>(
 
         ty::FnDef(def_id, _)
         | ty::Closure(def_id, _)
-        | ty::Coroutine(def_id, _, _)
+        | ty::Coroutine(def_id, _)
         | ty::CoroutineWitness(def_id, _)
         | ty::Foreign(def_id) => Some(def_id),
 
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index f7900d883ad..99384e34222 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -783,14 +783,14 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                 }
             }
             ty::Str => p!("str"),
-            ty::Coroutine(did, args, movability) => {
+            ty::Coroutine(did, args) => {
                 p!(write("{{"));
                 let coroutine_kind = self.tcx().coroutine_kind(did).unwrap();
                 let should_print_movability = self.should_print_verbose()
                     || matches!(coroutine_kind, hir::CoroutineKind::Coroutine(_));
 
                 if should_print_movability {
-                    match movability {
+                    match coroutine_kind.movability() {
                         hir::Movability::Movable => {}
                         hir::Movability::Static => p!("static "),
                     }
@@ -1055,7 +1055,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                             && assoc.trait_container(tcx) == tcx.lang_items().coroutine_trait()
                             && assoc.name == rustc_span::sym::Return
                         {
-                            if let ty::Coroutine(_, args, _) = args.type_at(0).kind() {
+                            if let ty::Coroutine(_, args) = args.type_at(0).kind() {
                                 let return_ty = args.as_coroutine().return_ty();
                                 if !return_ty.is_ty_var() {
                                     return_ty.into()
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 9d92f81db0b..8543bd0bbdd 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -455,14 +455,12 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
             Ok(Ty::new_dynamic(tcx, relation.relate(a_obj, b_obj)?, region_bound, a_repr))
         }
 
-        (&ty::Coroutine(a_id, a_args, movability), &ty::Coroutine(b_id, b_args, _))
-            if a_id == b_id =>
-        {
+        (&ty::Coroutine(a_id, a_args), &ty::Coroutine(b_id, b_args)) if a_id == b_id => {
             // All Coroutine types with the same id represent
             // the (anonymous) type of the same coroutine expression. So
             // all of their regions should be equated.
             let args = relate_args_invariantly(relation, a_args, b_args)?;
-            Ok(Ty::new_coroutine(tcx, a_id, args, movability))
+            Ok(Ty::new_coroutine(tcx, a_id, args))
         }
 
         (&ty::CoroutineWitness(a_id, a_args), &ty::CoroutineWitness(b_id, b_args))
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 1c75d73e552..7c869adbd83 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -578,9 +578,7 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for Ty<'tcx> {
             ty::Ref(r, ty, mutbl) => {
                 ty::Ref(r.try_fold_with(folder)?, ty.try_fold_with(folder)?, mutbl)
             }
-            ty::Coroutine(did, args, movability) => {
-                ty::Coroutine(did, args.try_fold_with(folder)?, movability)
-            }
+            ty::Coroutine(did, args) => ty::Coroutine(did, args.try_fold_with(folder)?),
             ty::CoroutineWitness(did, args) => {
                 ty::CoroutineWitness(did, args.try_fold_with(folder)?)
             }
@@ -630,7 +628,7 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for Ty<'tcx> {
                 r.visit_with(visitor)?;
                 ty.visit_with(visitor)
             }
-            ty::Coroutine(_did, ref args, _) => args.visit_with(visitor),
+            ty::Coroutine(_did, ref args) => args.visit_with(visitor),
             ty::CoroutineWitness(_did, ref args) => args.visit_with(visitor),
             ty::Closure(_did, ref args) => args.visit_with(visitor),
             ty::Alias(_, ref data) => data.visit_with(visitor),
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 5b9dff8e3f2..38bf39bff90 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -241,38 +241,36 @@ pub struct ClosureArgs<'tcx> {
 }
 
 /// Struct returned by `split()`.
-pub struct ClosureArgsParts<'tcx, T> {
+pub struct ClosureArgsParts<'tcx> {
     pub parent_args: &'tcx [GenericArg<'tcx>],
-    pub closure_kind_ty: T,
-    pub closure_sig_as_fn_ptr_ty: T,
-    pub tupled_upvars_ty: T,
+    pub closure_kind_ty: Ty<'tcx>,
+    pub closure_sig_as_fn_ptr_ty: Ty<'tcx>,
+    pub tupled_upvars_ty: Ty<'tcx>,
 }
 
 impl<'tcx> ClosureArgs<'tcx> {
     /// Construct `ClosureArgs` from `ClosureArgsParts`, containing `Args`
     /// for the closure parent, alongside additional closure-specific components.
-    pub fn new(tcx: TyCtxt<'tcx>, parts: ClosureArgsParts<'tcx, Ty<'tcx>>) -> ClosureArgs<'tcx> {
+    pub fn new(tcx: TyCtxt<'tcx>, parts: ClosureArgsParts<'tcx>) -> ClosureArgs<'tcx> {
         ClosureArgs {
-            args: tcx.mk_args_from_iter(
-                parts.parent_args.iter().copied().chain(
-                    [parts.closure_kind_ty, parts.closure_sig_as_fn_ptr_ty, parts.tupled_upvars_ty]
-                        .iter()
-                        .map(|&ty| ty.into()),
-                ),
-            ),
+            args: tcx.mk_args_from_iter(parts.parent_args.iter().copied().chain([
+                parts.closure_kind_ty.into(),
+                parts.closure_sig_as_fn_ptr_ty.into(),
+                parts.tupled_upvars_ty.into(),
+            ])),
         }
     }
 
     /// Divides the closure args into their respective components.
     /// The ordering assumed here must match that used by `ClosureArgs::new` above.
-    fn split(self) -> ClosureArgsParts<'tcx, GenericArg<'tcx>> {
+    fn split(self) -> ClosureArgsParts<'tcx> {
         match self.args[..] {
             [ref parent_args @ .., closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty] => {
                 ClosureArgsParts {
                     parent_args,
-                    closure_kind_ty,
-                    closure_sig_as_fn_ptr_ty,
-                    tupled_upvars_ty,
+                    closure_kind_ty: closure_kind_ty.expect_ty(),
+                    closure_sig_as_fn_ptr_ty: closure_sig_as_fn_ptr_ty.expect_ty(),
+                    tupled_upvars_ty: tupled_upvars_ty.expect_ty(),
                 }
             }
             _ => bug!("closure args missing synthetics"),
@@ -285,7 +283,7 @@ impl<'tcx> ClosureArgs<'tcx> {
     /// Used primarily by `ty::print::pretty` to be able to handle closure
     /// types that haven't had their synthetic types substituted in.
     pub fn is_valid(self) -> bool {
-        self.args.len() >= 3 && matches!(self.split().tupled_upvars_ty.expect_ty().kind(), Tuple(_))
+        self.args.len() >= 3 && matches!(self.split().tupled_upvars_ty.kind(), Tuple(_))
     }
 
     /// Returns the substitutions of the closure's parent.
@@ -309,14 +307,14 @@ impl<'tcx> ClosureArgs<'tcx> {
     /// Returns the tuple type representing the upvars for this closure.
     #[inline]
     pub fn tupled_upvars_ty(self) -> Ty<'tcx> {
-        self.split().tupled_upvars_ty.expect_ty()
+        self.split().tupled_upvars_ty
     }
 
     /// Returns the closure kind for this closure; may return a type
     /// variable during inference. To get the closure kind during
     /// inference, use `infcx.closure_kind(args)`.
     pub fn kind_ty(self) -> Ty<'tcx> {
-        self.split().closure_kind_ty.expect_ty()
+        self.split().closure_kind_ty
     }
 
     /// Returns the `fn` pointer type representing the closure signature for this
@@ -325,7 +323,7 @@ impl<'tcx> ClosureArgs<'tcx> {
     // type is known at the time of the creation of `ClosureArgs`,
     // see `rustc_hir_analysis::check::closure`.
     pub fn sig_as_fn_ptr_ty(self) -> Ty<'tcx> {
-        self.split().closure_sig_as_fn_ptr_ty.expect_ty()
+        self.split().closure_sig_as_fn_ptr_ty
     }
 
     /// Returns the closure kind for this closure; only usable outside
@@ -357,51 +355,42 @@ pub struct CoroutineArgs<'tcx> {
     pub args: GenericArgsRef<'tcx>,
 }
 
-pub struct CoroutineArgsParts<'tcx, T> {
+pub struct CoroutineArgsParts<'tcx> {
     pub parent_args: &'tcx [GenericArg<'tcx>],
-    pub resume_ty: T,
-    pub yield_ty: T,
-    pub return_ty: T,
-    pub witness: T,
-    pub tupled_upvars_ty: T,
+    pub resume_ty: Ty<'tcx>,
+    pub yield_ty: Ty<'tcx>,
+    pub return_ty: Ty<'tcx>,
+    pub witness: Ty<'tcx>,
+    pub tupled_upvars_ty: Ty<'tcx>,
 }
 
 impl<'tcx> CoroutineArgs<'tcx> {
     /// Construct `CoroutineArgs` from `CoroutineArgsParts`, containing `Args`
     /// for the coroutine parent, alongside additional coroutine-specific components.
-    pub fn new(
-        tcx: TyCtxt<'tcx>,
-        parts: CoroutineArgsParts<'tcx, Ty<'tcx>>,
-    ) -> CoroutineArgs<'tcx> {
+    pub fn new(tcx: TyCtxt<'tcx>, parts: CoroutineArgsParts<'tcx>) -> CoroutineArgs<'tcx> {
         CoroutineArgs {
-            args: tcx.mk_args_from_iter(
-                parts.parent_args.iter().copied().chain(
-                    [
-                        parts.resume_ty,
-                        parts.yield_ty,
-                        parts.return_ty,
-                        parts.witness,
-                        parts.tupled_upvars_ty,
-                    ]
-                    .iter()
-                    .map(|&ty| ty.into()),
-                ),
-            ),
+            args: tcx.mk_args_from_iter(parts.parent_args.iter().copied().chain([
+                parts.resume_ty.into(),
+                parts.yield_ty.into(),
+                parts.return_ty.into(),
+                parts.witness.into(),
+                parts.tupled_upvars_ty.into(),
+            ])),
         }
     }
 
     /// Divides the coroutine args into their respective components.
     /// The ordering assumed here must match that used by `CoroutineArgs::new` above.
-    fn split(self) -> CoroutineArgsParts<'tcx, GenericArg<'tcx>> {
+    fn split(self) -> CoroutineArgsParts<'tcx> {
         match self.args[..] {
             [ref parent_args @ .., resume_ty, yield_ty, return_ty, witness, tupled_upvars_ty] => {
                 CoroutineArgsParts {
                     parent_args,
-                    resume_ty,
-                    yield_ty,
-                    return_ty,
-                    witness,
-                    tupled_upvars_ty,
+                    resume_ty: resume_ty.expect_ty(),
+                    yield_ty: yield_ty.expect_ty(),
+                    return_ty: return_ty.expect_ty(),
+                    witness: witness.expect_ty(),
+                    tupled_upvars_ty: tupled_upvars_ty.expect_ty(),
                 }
             }
             _ => bug!("coroutine args missing synthetics"),
@@ -414,7 +403,7 @@ impl<'tcx> CoroutineArgs<'tcx> {
     /// Used primarily by `ty::print::pretty` to be able to handle coroutine
     /// types that haven't had their synthetic types substituted in.
     pub fn is_valid(self) -> bool {
-        self.args.len() >= 5 && matches!(self.split().tupled_upvars_ty.expect_ty().kind(), Tuple(_))
+        self.args.len() >= 5 && matches!(self.split().tupled_upvars_ty.kind(), Tuple(_))
     }
 
     /// Returns the substitutions of the coroutine's parent.
@@ -428,7 +417,7 @@ impl<'tcx> CoroutineArgs<'tcx> {
     /// The state transformation MIR pass may only produce layouts which mention types
     /// in this tuple. Upvars are not counted here.
     pub fn witness(self) -> Ty<'tcx> {
-        self.split().witness.expect_ty()
+        self.split().witness
     }
 
     /// Returns an iterator over the list of types of captured paths by the coroutine.
@@ -447,31 +436,32 @@ impl<'tcx> CoroutineArgs<'tcx> {
     /// Returns the tuple type representing the upvars for this coroutine.
     #[inline]
     pub fn tupled_upvars_ty(self) -> Ty<'tcx> {
-        self.split().tupled_upvars_ty.expect_ty()
+        self.split().tupled_upvars_ty
     }
 
     /// Returns the type representing the resume type of the coroutine.
     pub fn resume_ty(self) -> Ty<'tcx> {
-        self.split().resume_ty.expect_ty()
+        self.split().resume_ty
     }
 
     /// Returns the type representing the yield type of the coroutine.
     pub fn yield_ty(self) -> Ty<'tcx> {
-        self.split().yield_ty.expect_ty()
+        self.split().yield_ty
     }
 
     /// Returns the type representing the return type of the coroutine.
     pub fn return_ty(self) -> Ty<'tcx> {
-        self.split().return_ty.expect_ty()
+        self.split().return_ty
     }
 
     /// Returns the "coroutine signature", which consists of its resume, yield
     /// and return types.
     pub fn sig(self) -> GenSig<'tcx> {
+        let parts = self.split();
         ty::GenSig {
-            resume_ty: self.resume_ty(),
-            yield_ty: self.yield_ty(),
-            return_ty: self.return_ty(),
+            resume_ty: parts.resume_ty,
+            yield_ty: parts.yield_ty,
+            return_ty: parts.return_ty,
         }
     }
 }
@@ -2168,14 +2158,13 @@ impl<'tcx> Ty<'tcx> {
         tcx: TyCtxt<'tcx>,
         def_id: DefId,
         coroutine_args: GenericArgsRef<'tcx>,
-        movability: hir::Movability,
     ) -> Ty<'tcx> {
         debug_assert_eq!(
             coroutine_args.len(),
             tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 5,
             "coroutine constructed with incorrect number of substitutions"
         );
-        Ty::new(tcx, Coroutine(def_id, coroutine_args, movability))
+        Ty::new(tcx, Coroutine(def_id, coroutine_args))
     }
 
     #[inline]
@@ -2656,7 +2645,7 @@ impl<'tcx> Ty<'tcx> {
     pub fn variant_range(self, tcx: TyCtxt<'tcx>) -> Option<Range<VariantIdx>> {
         match self.kind() {
             TyKind::Adt(adt, _) => Some(adt.variant_range()),
-            TyKind::Coroutine(def_id, args, _) => {
+            TyKind::Coroutine(def_id, args) => {
                 Some(args.as_coroutine().variant_range(*def_id, tcx))
             }
             _ => None,
@@ -2677,7 +2666,7 @@ impl<'tcx> Ty<'tcx> {
             TyKind::Adt(adt, _) if adt.is_enum() => {
                 Some(adt.discriminant_for_variant(tcx, variant_index))
             }
-            TyKind::Coroutine(def_id, args, _) => {
+            TyKind::Coroutine(def_id, args) => {
                 Some(args.as_coroutine().discriminant_for_variant(*def_id, tcx, variant_index))
             }
             _ => None,
@@ -2688,7 +2677,7 @@ impl<'tcx> Ty<'tcx> {
     pub fn discriminant_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
         match self.kind() {
             ty::Adt(adt, _) if adt.is_enum() => adt.repr().discr_type().to_ty(tcx),
-            ty::Coroutine(_, args, _) => args.as_coroutine().discr_ty(tcx),
+            ty::Coroutine(_, args) => args.as_coroutine().discr_ty(tcx),
 
             ty::Param(_) | ty::Alias(..) | ty::Infer(ty::TyVar(_)) => {
                 let assoc_items = tcx.associated_item_def_ids(
@@ -2983,7 +2972,7 @@ impl<'tcx> Ty<'tcx> {
             | FnPtr(_)
             | Dynamic(_, _, _)
             | Closure(_, _)
-            | Coroutine(_, _, _)
+            | Coroutine(_, _)
             | CoroutineWitness(..)
             | Never
             | Tuple(_) => true,
diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs
index 20bdbcb5b7b..9050716db9d 100644
--- a/compiler/rustc_middle/src/ty/walk.rs
+++ b/compiler/rustc_middle/src/ty/walk.rs
@@ -189,7 +189,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
             }
             ty::Adt(_, args)
             | ty::Closure(_, args)
-            | ty::Coroutine(_, args, _)
+            | ty::Coroutine(_, args)
             | ty::CoroutineWitness(_, args)
             | ty::FnDef(_, args) => {
                 stack.extend(args.iter().rev());
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index 04dcc6854c7..f799be165ec 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -387,8 +387,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 closure_id,
                 args,
                 ref upvars,
-                movability,
                 ref fake_reads,
+                movability: _,
             }) => {
                 // Convert the closure fake reads, if any, from `ExprRef` to mir `Place`
                 // and push the fake reads.
@@ -474,10 +474,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
                 let result = match args {
                     UpvarArgs::Coroutine(args) => {
-                        // We implicitly set the discriminant to 0. See
-                        // librustc_mir/transform/deaggregator.rs for details.
-                        let movability = movability.unwrap();
-                        Box::new(AggregateKind::Coroutine(closure_id.to_def_id(), args, movability))
+                        Box::new(AggregateKind::Coroutine(closure_id.to_def_id(), args))
                     }
                     UpvarArgs::Closure(args) => {
                         Box::new(AggregateKind::Closure(closure_id.to_def_id(), args))
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index a6336ec63b2..e0199fb8767 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -646,7 +646,7 @@ fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) -
         }
         DefKind::Closure if coroutine_kind.is_some() => {
             let coroutine_ty = tcx.type_of(def_id).instantiate_identity();
-            let ty::Coroutine(_, args, _) = coroutine_ty.kind() else {
+            let ty::Coroutine(_, args) = coroutine_ty.kind() else {
                 bug!("expected type of coroutine-like closure to be a coroutine")
             };
             let args = args.as_coroutine();
@@ -813,7 +813,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
         let upvar_args = match closure_ty.kind() {
             ty::Closure(_, args) => ty::UpvarArgs::Closure(args),
-            ty::Coroutine(_, args, _) => ty::UpvarArgs::Coroutine(args),
+            ty::Coroutine(_, args) => ty::UpvarArgs::Coroutine(args),
             _ => return,
         };
 
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 01f4678fa09..8ec70c58c46 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -552,8 +552,8 @@ impl<'tcx> Cx<'tcx> {
                 let closure_ty = self.typeck_results().expr_ty(expr);
                 let (def_id, args, movability) = match *closure_ty.kind() {
                     ty::Closure(def_id, args) => (def_id, UpvarArgs::Closure(args), None),
-                    ty::Coroutine(def_id, args, movability) => {
-                        (def_id, UpvarArgs::Coroutine(args), Some(movability))
+                    ty::Coroutine(def_id, args) => {
+                        (def_id, UpvarArgs::Coroutine(args), Some(tcx.coroutine_movability(def_id)))
                     }
                     _ => {
                         span_bug!(expr.span, "closure expr w/o closure type: {:?}", closure_ty);
diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
index 958fa0d17cd..c9930565186 100644
--- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
@@ -862,7 +862,7 @@ where
             // This should only happen for the self argument on the resume function.
             // It effectively only contains upvars until the coroutine transformation runs.
             // See librustc_body/transform/coroutine.rs for more details.
-            ty::Coroutine(_, args, _) => self.open_drop_for_tuple(args.as_coroutine().upvar_tys()),
+            ty::Coroutine(_, args) => self.open_drop_for_tuple(args.as_coroutine().upvar_tys()),
             ty::Tuple(fields) => self.open_drop_for_tuple(fields),
             ty::Adt(def, args) => self.open_drop_for_adt(*def, args),
             ty::Dynamic(..) => self.complete_drop(self.succ, self.unwind),
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index ccf3dc7941f..cae35765308 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -155,7 +155,7 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> {
                     | ty::FnPtr(_)
                     | ty::Dynamic(_, _, _)
                     | ty::Closure(_, _)
-                    | ty::Coroutine(_, _, _)
+                    | ty::Coroutine(_, _)
                     | ty::CoroutineWitness(..)
                     | ty::Never
                     | ty::Tuple(_)
@@ -177,7 +177,7 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> {
                             union_path.get_or_insert(base);
                         }
                     }
-                    ty::Closure(_, _) | ty::Coroutine(_, _, _) | ty::Tuple(_) => (),
+                    ty::Closure(_, _) | ty::Coroutine(_, _) | ty::Tuple(_) => (),
                     ty::Bool
                     | ty::Char
                     | ty::Int(_)
diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs
index 23726e49f4d..d94d96c1115 100644
--- a/compiler/rustc_mir_transform/src/check_unsafety.rs
+++ b/compiler/rustc_mir_transform/src/check_unsafety.rs
@@ -128,7 +128,7 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
                         ),
                     }
                 }
-                &AggregateKind::Closure(def_id, _) | &AggregateKind::Coroutine(def_id, _, _) => {
+                &AggregateKind::Closure(def_id, _) | &AggregateKind::Coroutine(def_id, _) => {
                     let def_id = def_id.expect_local();
                     let UnsafetyCheckResult { violations, used_unsafe_blocks, .. } =
                         self.tcx.unsafety_check_result(def_id);
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index e66d5e0a9f9..c5824c30770 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -1,29 +1,22 @@
 //! Propagates constants for early reporting of statically known
 //! assertion failures
 
-use either::Right;
-use rustc_const_eval::ReportErrorExt;
+use rustc_const_eval::interpret::{
+    self, compile_time_machine, AllocId, ConstAllocation, FnArg, Frame, ImmTy, InterpCx,
+    InterpResult, OpTy, PlaceTy, Pointer,
+};
 use rustc_data_structures::fx::FxHashSet;
-use rustc_hir::def::DefKind;
 use rustc_index::bit_set::BitSet;
-use rustc_index::{IndexSlice, IndexVec};
-use rustc_middle::mir::visit::{
-    MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor,
-};
+use rustc_index::IndexVec;
+use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::query::TyCtxtAt;
-use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
-use rustc_middle::ty::{self, GenericArgs, Instance, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
-use rustc_span::{def_id::DefId, Span};
-use rustc_target::abi::{self, HasDataLayout, Size, TargetDataLayout};
+use rustc_middle::ty::layout::TyAndLayout;
+use rustc_middle::ty::{self, ParamEnv, TyCtxt};
+use rustc_span::def_id::DefId;
+use rustc_target::abi::Size;
 use rustc_target::spec::abi::Abi as CallAbi;
 
-use crate::dataflow_const_prop::Patch;
-use rustc_const_eval::interpret::{
-    self, compile_time_machine, AllocId, ConstAllocation, FnArg, Frame, ImmTy, Immediate, InterpCx,
-    InterpResult, MemoryKind, OpTy, PlaceTy, Pointer, Scalar, StackPopCleanup,
-};
-
 /// The maximum number of bytes that we'll allocate space for a local or the return value.
 /// Needed for #66397, because otherwise we eval into large places and that can cause OOM or just
 /// Severely regress performance.
@@ -56,62 +49,7 @@ pub(crate) macro throw_machine_stop_str($($tt:tt)*) {{
     throw_machine_stop!(Zst)
 }}
 
-pub struct ConstProp;
-
-impl<'tcx> MirPass<'tcx> for ConstProp {
-    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
-        sess.mir_opt_level() >= 2
-    }
-
-    #[instrument(skip(self, tcx), level = "debug")]
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        // will be evaluated by miri and produce its errors there
-        if body.source.promoted.is_some() {
-            return;
-        }
-
-        let def_id = body.source.def_id().expect_local();
-        let def_kind = tcx.def_kind(def_id);
-        let is_fn_like = def_kind.is_fn_like();
-        let is_assoc_const = def_kind == DefKind::AssocConst;
-
-        // Only run const prop on functions, methods, closures and associated constants
-        if !is_fn_like && !is_assoc_const {
-            // skip anon_const/statics/consts because they'll be evaluated by miri anyway
-            trace!("ConstProp skipped for {:?}", def_id);
-            return;
-        }
-
-        // FIXME(welseywiser) const prop doesn't work on coroutines because of query cycles
-        // computing their layout.
-        if tcx.is_coroutine(def_id.to_def_id()) {
-            trace!("ConstProp skipped for coroutine {:?}", def_id);
-            return;
-        }
-
-        trace!("ConstProp starting for {:?}", def_id);
-
-        // FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold
-        // constants, instead of just checking for const-folding succeeding.
-        // That would require a uniform one-def no-mutation analysis
-        // and RPO (or recursing when needing the value of a local).
-        let mut optimization_finder = ConstPropagator::new(body, tcx);
-
-        // Traverse the body in reverse post-order, to ensure that `FullConstProp` locals are
-        // assigned before being read.
-        for &bb in body.basic_blocks.reverse_postorder() {
-            let data = &body.basic_blocks[bb];
-            optimization_finder.visit_basic_block_data(bb, data);
-        }
-
-        let mut patch = optimization_finder.patch;
-        patch.visit_body_preserves_cfg(body);
-
-        trace!("ConstProp done for {:?}", def_id);
-    }
-}
-
-pub struct ConstPropMachine<'mir, 'tcx> {
+pub(crate) struct ConstPropMachine<'mir, 'tcx> {
     /// The virtual call stack.
     stack: Vec<Frame<'mir, 'tcx>>,
     pub written_only_inside_own_block_locals: FxHashSet<Local>,
@@ -267,297 +205,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
     }
 }
 
-/// Finds optimization opportunities on the MIR.
-struct ConstPropagator<'mir, 'tcx> {
-    ecx: InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>,
-    tcx: TyCtxt<'tcx>,
-    param_env: ParamEnv<'tcx>,
-    local_decls: &'mir IndexSlice<Local, LocalDecl<'tcx>>,
-    patch: Patch<'tcx>,
-}
-
-impl<'tcx> LayoutOfHelpers<'tcx> for ConstPropagator<'_, 'tcx> {
-    type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
-
-    #[inline]
-    fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
-        err
-    }
-}
-
-impl HasDataLayout for ConstPropagator<'_, '_> {
-    #[inline]
-    fn data_layout(&self) -> &TargetDataLayout {
-        &self.tcx.data_layout
-    }
-}
-
-impl<'tcx> ty::layout::HasTyCtxt<'tcx> for ConstPropagator<'_, 'tcx> {
-    #[inline]
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-}
-
-impl<'tcx> ty::layout::HasParamEnv<'tcx> for ConstPropagator<'_, 'tcx> {
-    #[inline]
-    fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        self.param_env
-    }
-}
-
-impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
-    fn new(body: &'mir Body<'tcx>, tcx: TyCtxt<'tcx>) -> ConstPropagator<'mir, 'tcx> {
-        let def_id = body.source.def_id();
-        let args = &GenericArgs::identity_for_item(tcx, def_id);
-        let param_env = tcx.param_env_reveal_all_normalized(def_id);
-
-        let can_const_prop = CanConstProp::check(tcx, param_env, body);
-        let mut ecx = InterpCx::new(
-            tcx,
-            tcx.def_span(def_id),
-            param_env,
-            ConstPropMachine::new(can_const_prop),
-        );
-
-        let ret_layout = ecx
-            .layout_of(body.bound_return_ty().instantiate(tcx, args))
-            .ok()
-            // Don't bother allocating memory for large values.
-            // I don't know how return types can seem to be unsized but this happens in the
-            // `type/type-unsatisfiable.rs` test.
-            .filter(|ret_layout| {
-                ret_layout.is_sized() && ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT)
-            })
-            .unwrap_or_else(|| ecx.layout_of(tcx.types.unit).unwrap());
-
-        let ret = ecx
-            .allocate(ret_layout, MemoryKind::Stack)
-            .expect("couldn't perform small allocation")
-            .into();
-
-        ecx.push_stack_frame(
-            Instance::new(def_id, args),
-            body,
-            &ret,
-            StackPopCleanup::Root { cleanup: false },
-        )
-        .expect("failed to push initial stack frame");
-
-        for local in body.local_decls.indices() {
-            // Mark everything initially live.
-            // This is somewhat dicey since some of them might be unsized and it is incoherent to
-            // mark those as live... We rely on `local_to_place`/`local_to_op` in the interpreter
-            // stopping us before those unsized immediates can cause issues deeper in the
-            // interpreter.
-            ecx.frame_mut().locals[local].make_live_uninit();
-        }
-
-        let patch = Patch::new(tcx);
-        ConstPropagator { ecx, tcx, param_env, local_decls: &body.local_decls, patch }
-    }
-
-    fn get_const(&self, place: Place<'tcx>) -> Option<OpTy<'tcx>> {
-        let op = match self.ecx.eval_place_to_op(place, None) {
-            Ok(op) => {
-                if op
-                    .as_mplace_or_imm()
-                    .right()
-                    .is_some_and(|imm| matches!(*imm, Immediate::Uninit))
-                {
-                    // Make sure nobody accidentally uses this value.
-                    return None;
-                }
-                op
-            }
-            Err(e) => {
-                trace!("get_const failed: {:?}", e.into_kind().debug());
-                return None;
-            }
-        };
-
-        // Try to read the local as an immediate so that if it is representable as a scalar, we can
-        // handle it as such, but otherwise, just return the value as is.
-        Some(match self.ecx.read_immediate_raw(&op) {
-            Ok(Right(imm)) => imm.into(),
-            _ => op,
-        })
-    }
-
-    /// Remove `local` from the pool of `Locals`. Allows writing to them,
-    /// but not reading from them anymore.
-    fn remove_const(ecx: &mut InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, local: Local) {
-        ecx.frame_mut().locals[local].make_live_uninit();
-        ecx.machine.written_only_inside_own_block_locals.remove(&local);
-    }
-
-    fn check_rvalue(&mut self, rvalue: &Rvalue<'tcx>) -> Option<()> {
-        // Perform any special handling for specific Rvalue types.
-        // Generally, checks here fall into one of two categories:
-        //   1. Additional checking to provide useful lints to the user
-        //        - In this case, we will do some validation and then fall through to the
-        //          end of the function which evals the assignment.
-        //   2. Working around bugs in other parts of the compiler
-        //        - In this case, we'll return `None` from this function to stop evaluation.
-        match rvalue {
-            // Do not try creating references (#67862)
-            Rvalue::AddressOf(_, place) | Rvalue::Ref(_, _, place) => {
-                trace!("skipping AddressOf | Ref for {:?}", place);
-
-                // This may be creating mutable references or immutable references to cells.
-                // If that happens, the pointed to value could be mutated via that reference.
-                // Since we aren't tracking references, the const propagator loses track of what
-                // value the local has right now.
-                // Thus, all locals that have their reference taken
-                // must not take part in propagation.
-                Self::remove_const(&mut self.ecx, place.local);
-
-                return None;
-            }
-            Rvalue::ThreadLocalRef(def_id) => {
-                trace!("skipping ThreadLocalRef({:?})", def_id);
-
-                return None;
-            }
-            // There's no other checking to do at this time.
-            Rvalue::Aggregate(..)
-            | Rvalue::Use(..)
-            | Rvalue::CopyForDeref(..)
-            | Rvalue::Repeat(..)
-            | Rvalue::Len(..)
-            | Rvalue::Cast(..)
-            | Rvalue::ShallowInitBox(..)
-            | Rvalue::Discriminant(..)
-            | Rvalue::NullaryOp(..)
-            | Rvalue::UnaryOp(..)
-            | Rvalue::BinaryOp(..)
-            | Rvalue::CheckedBinaryOp(..) => {}
-        }
-
-        // FIXME we need to revisit this for #67176
-        if rvalue.has_param() {
-            trace!("skipping, has param");
-            return None;
-        }
-        if !rvalue
-            .ty(&self.ecx.frame().body.local_decls, *self.ecx.tcx)
-            .is_sized(*self.ecx.tcx, self.param_env)
-        {
-            // the interpreter doesn't support unsized locals (only unsized arguments),
-            // but rustc does (in a kinda broken way), so we have to skip them here
-            return None;
-        }
-
-        Some(())
-    }
-
-    // Attempt to use algebraic identities to eliminate constant expressions
-    fn eval_rvalue_with_identities(
-        &mut self,
-        rvalue: &Rvalue<'tcx>,
-        place: Place<'tcx>,
-    ) -> Option<()> {
-        match rvalue {
-            Rvalue::BinaryOp(op, box (left, right))
-            | Rvalue::CheckedBinaryOp(op, box (left, right)) => {
-                let l = self.ecx.eval_operand(left, None).and_then(|x| self.ecx.read_immediate(&x));
-                let r =
-                    self.ecx.eval_operand(right, None).and_then(|x| self.ecx.read_immediate(&x));
-
-                let const_arg = match (l, r) {
-                    (Ok(x), Err(_)) | (Err(_), Ok(x)) => x, // exactly one side is known
-                    (Err(_), Err(_)) => return None,        // neither side is known
-                    (Ok(_), Ok(_)) => return self.ecx.eval_rvalue_into_place(rvalue, place).ok(), // both sides are known
-                };
-
-                if !matches!(const_arg.layout.abi, abi::Abi::Scalar(..)) {
-                    // We cannot handle Scalar Pair stuff.
-                    // No point in calling `eval_rvalue_into_place`, since only one side is known
-                    return None;
-                }
-
-                let arg_value = const_arg.to_scalar().to_bits(const_arg.layout.size).ok()?;
-                let dest = self.ecx.eval_place(place).ok()?;
-
-                match op {
-                    BinOp::BitAnd if arg_value == 0 => {
-                        self.ecx.write_immediate(*const_arg, &dest).ok()
-                    }
-                    BinOp::BitOr
-                        if arg_value == const_arg.layout.size.truncate(u128::MAX)
-                            || (const_arg.layout.ty.is_bool() && arg_value == 1) =>
-                    {
-                        self.ecx.write_immediate(*const_arg, &dest).ok()
-                    }
-                    BinOp::Mul if const_arg.layout.ty.is_integral() && arg_value == 0 => {
-                        if let Rvalue::CheckedBinaryOp(_, _) = rvalue {
-                            let val = Immediate::ScalarPair(
-                                const_arg.to_scalar(),
-                                Scalar::from_bool(false),
-                            );
-                            self.ecx.write_immediate(val, &dest).ok()
-                        } else {
-                            self.ecx.write_immediate(*const_arg, &dest).ok()
-                        }
-                    }
-                    _ => None,
-                }
-            }
-            _ => self.ecx.eval_rvalue_into_place(rvalue, place).ok(),
-        }
-    }
-
-    fn replace_with_const(&mut self, place: Place<'tcx>) -> Option<Const<'tcx>> {
-        // This will return None if the above `const_prop` invocation only "wrote" a
-        // type whose creation requires no write. E.g. a coroutine whose initial state
-        // consists solely of uninitialized memory (so it doesn't capture any locals).
-        let value = self.get_const(place)?;
-        if !self.tcx.consider_optimizing(|| format!("ConstantPropagation - {value:?}")) {
-            return None;
-        }
-        trace!("replacing {:?} with {:?}", place, value);
-
-        // FIXME: figure out what to do when read_immediate_raw fails
-        let imm = self.ecx.read_immediate_raw(&value).ok()?;
-
-        let Right(imm) = imm else { return None };
-        match *imm {
-            Immediate::Scalar(scalar) if scalar.try_to_int().is_ok() => {
-                Some(Const::from_scalar(self.tcx, scalar, value.layout.ty))
-            }
-            Immediate::ScalarPair(l, r) if l.try_to_int().is_ok() && r.try_to_int().is_ok() => {
-                let alloc_id = self
-                    .ecx
-                    .intern_with_temp_alloc(value.layout, |ecx, dest| {
-                        ecx.write_immediate(*imm, dest)
-                    })
-                    .ok()?;
-
-                Some(Const::Val(
-                    ConstValue::Indirect { alloc_id, offset: Size::ZERO },
-                    value.layout.ty,
-                ))
-            }
-            // Scalars or scalar pairs that contain undef values are assumed to not have
-            // successfully evaluated and are thus not propagated.
-            _ => None,
-        }
-    }
-
-    fn ensure_not_propagated(&self, local: Local) {
-        if cfg!(debug_assertions) {
-            assert!(
-                self.get_const(local.into()).is_none()
-                    || self
-                        .layout_of(self.local_decls[local].ty)
-                        .map_or(true, |layout| layout.is_zst()),
-                "failed to remove values for `{local:?}`, value={:?}",
-                self.get_const(local.into()),
-            )
-        }
-    }
-}
-
 /// The mode that `ConstProp` is allowed to run in for a given `Local`.
 #[derive(Clone, Copy, Debug, PartialEq)]
 pub enum ConstPropMode {
@@ -677,154 +324,3 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
         }
     }
 }
-
-impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
-    fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
-        self.super_operand(operand, location);
-        if let Some(place) = operand.place()
-            && let Some(value) = self.replace_with_const(place)
-        {
-            self.patch.before_effect.insert((location, place), value);
-        }
-    }
-
-    fn visit_projection_elem(
-        &mut self,
-        _: PlaceRef<'tcx>,
-        elem: PlaceElem<'tcx>,
-        _: PlaceContext,
-        location: Location,
-    ) {
-        if let PlaceElem::Index(local) = elem
-            && let Some(value) = self.replace_with_const(local.into())
-        {
-            self.patch.before_effect.insert((location, local.into()), value);
-        }
-    }
-
-    fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
-        self.super_assign(place, rvalue, location);
-
-        let Some(()) = self.check_rvalue(rvalue) else {
-            trace!("rvalue check failed, removing const");
-            Self::remove_const(&mut self.ecx, place.local);
-            return;
-        };
-
-        match self.ecx.machine.can_const_prop[place.local] {
-            // Do nothing if the place is indirect.
-            _ if place.is_indirect() => {}
-            ConstPropMode::NoPropagation => self.ensure_not_propagated(place.local),
-            ConstPropMode::OnlyInsideOwnBlock | ConstPropMode::FullConstProp => {
-                if let Some(()) = self.eval_rvalue_with_identities(rvalue, *place) {
-                    // If this was already an evaluated constant, keep it.
-                    if let Rvalue::Use(Operand::Constant(c)) = rvalue
-                        && let Const::Val(..) = c.const_
-                    {
-                        trace!(
-                            "skipping replace of Rvalue::Use({:?} because it is already a const",
-                            c
-                        );
-                    } else if let Some(operand) = self.replace_with_const(*place) {
-                        self.patch.assignments.insert(location, operand);
-                    }
-                } else {
-                    // Const prop failed, so erase the destination, ensuring that whatever happens
-                    // from here on, does not know about the previous value.
-                    // This is important in case we have
-                    // ```rust
-                    // let mut x = 42;
-                    // x = SOME_MUTABLE_STATIC;
-                    // // x must now be uninit
-                    // ```
-                    // FIXME: we overzealously erase the entire local, because that's easier to
-                    // implement.
-                    trace!(
-                        "propagation into {:?} failed.
-                        Nuking the entire site from orbit, it's the only way to be sure",
-                        place,
-                    );
-                    Self::remove_const(&mut self.ecx, place.local);
-                }
-            }
-        }
-    }
-
-    fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
-        trace!("visit_statement: {:?}", statement);
-
-        // We want to evaluate operands before any change to the assigned-to value,
-        // so we recurse first.
-        self.super_statement(statement, location);
-
-        match statement.kind {
-            StatementKind::SetDiscriminant { ref place, .. } => {
-                match self.ecx.machine.can_const_prop[place.local] {
-                    // Do nothing if the place is indirect.
-                    _ if place.is_indirect() => {}
-                    ConstPropMode::NoPropagation => self.ensure_not_propagated(place.local),
-                    ConstPropMode::FullConstProp | ConstPropMode::OnlyInsideOwnBlock => {
-                        if self.ecx.statement(statement).is_ok() {
-                            trace!("propped discriminant into {:?}", place);
-                        } else {
-                            Self::remove_const(&mut self.ecx, place.local);
-                        }
-                    }
-                }
-            }
-            StatementKind::StorageLive(local) => {
-                Self::remove_const(&mut self.ecx, local);
-            }
-            // We do not need to mark dead locals as such. For `FullConstProp` locals,
-            // this allows to propagate the single assigned value in this case:
-            // ```
-            // let x = SOME_CONST;
-            // if a {
-            //   f(copy x);
-            //   StorageDead(x);
-            // } else {
-            //   g(copy x);
-            //   StorageDead(x);
-            // }
-            // ```
-            //
-            // This may propagate a constant where the local would be uninit or dead.
-            // In both cases, this does not matter, as those reads would be UB anyway.
-            _ => {}
-        }
-    }
-
-    fn visit_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) {
-        self.super_basic_block_data(block, data);
-
-        // We remove all Locals which are restricted in propagation to their containing blocks and
-        // which were modified in the current block.
-        // Take it out of the ecx so we can get a mutable reference to the ecx for `remove_const`.
-        let mut written_only_inside_own_block_locals =
-            std::mem::take(&mut self.ecx.machine.written_only_inside_own_block_locals);
-
-        // This loop can get very hot for some bodies: it check each local in each bb.
-        // To avoid this quadratic behaviour, we only clear the locals that were modified inside
-        // the current block.
-        for local in written_only_inside_own_block_locals.drain() {
-            debug_assert_eq!(
-                self.ecx.machine.can_const_prop[local],
-                ConstPropMode::OnlyInsideOwnBlock
-            );
-            Self::remove_const(&mut self.ecx, local);
-        }
-        self.ecx.machine.written_only_inside_own_block_locals =
-            written_only_inside_own_block_locals;
-
-        if cfg!(debug_assertions) {
-            for (local, &mode) in self.ecx.machine.can_const_prop.iter_enumerated() {
-                match mode {
-                    ConstPropMode::FullConstProp => {}
-                    ConstPropMode::NoPropagation | ConstPropMode::OnlyInsideOwnBlock => {
-                        self.ensure_not_propagated(local);
-                    }
-                }
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index 05d8d842b58..ce1a36cf670 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -1417,20 +1417,18 @@ fn create_coroutine_resume_function<'tcx>(
     cases.insert(0, (UNRESUMED, START_BLOCK));
 
     // Panic when resumed on the returned or poisoned state
-    let coroutine_kind = body.coroutine_kind().unwrap();
-
     if can_unwind {
         cases.insert(
             1,
-            (POISONED, insert_panic_block(tcx, body, ResumedAfterPanic(coroutine_kind))),
+            (POISONED, insert_panic_block(tcx, body, ResumedAfterPanic(transform.coroutine_kind))),
         );
     }
 
     if can_return {
-        let block = match coroutine_kind {
+        let block = match transform.coroutine_kind {
             CoroutineKind::Desugared(CoroutineDesugaring::Async, _)
             | CoroutineKind::Coroutine(_) => {
-                insert_panic_block(tcx, body, ResumedAfterReturn(coroutine_kind))
+                insert_panic_block(tcx, body, ResumedAfterReturn(transform.coroutine_kind))
             }
             CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)
             | CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => {
@@ -1444,7 +1442,7 @@ fn create_coroutine_resume_function<'tcx>(
 
     make_coroutine_state_argument_indirect(tcx, body);
 
-    match coroutine_kind {
+    match transform.coroutine_kind {
         // Iterator::next doesn't accept a pinned argument,
         // unlike for all other coroutine kinds.
         CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => {}
@@ -1565,7 +1563,7 @@ pub(crate) fn mir_coroutine_witnesses<'tcx>(
     let coroutine_ty = body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty;
 
     let movable = match *coroutine_ty.kind() {
-        ty::Coroutine(_, _, movability) => movability == hir::Movability::Movable,
+        ty::Coroutine(def_id, _) => tcx.coroutine_movability(def_id) == hir::Movability::Movable,
         ty::Error(_) => return None,
         _ => span_bug!(body.span, "unexpected coroutine type {}", coroutine_ty),
     };
@@ -1597,12 +1595,13 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
 
         // The first argument is the coroutine type passed by value
         let coroutine_ty = body.local_decls.raw[1].ty;
+        let coroutine_kind = body.coroutine_kind().unwrap();
 
         // Get the discriminant type and args which typeck computed
         let (discr_ty, movable) = match *coroutine_ty.kind() {
-            ty::Coroutine(_, args, movability) => {
+            ty::Coroutine(_, args) => {
                 let args = args.as_coroutine();
-                (args.discr_ty(tcx), movability == hir::Movability::Movable)
+                (args.discr_ty(tcx), coroutine_kind.movability() == hir::Movability::Movable)
             }
             _ => {
                 tcx.dcx().span_delayed_bug(
@@ -1613,19 +1612,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
             }
         };
 
-        let is_async_kind = matches!(
-            body.coroutine_kind(),
-            Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, _))
-        );
-        let is_async_gen_kind = matches!(
-            body.coroutine_kind(),
-            Some(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _))
-        );
-        let is_gen_kind = matches!(
-            body.coroutine_kind(),
-            Some(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _))
-        );
-        let new_ret_ty = match body.coroutine_kind().unwrap() {
+        let new_ret_ty = match coroutine_kind {
             CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => {
                 // Compute Poll<return_ty>
                 let poll_did = tcx.require_lang_item(LangItem::Poll, None);
@@ -1658,7 +1645,10 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
         let old_ret_local = replace_local(RETURN_PLACE, new_ret_ty, body, tcx);
 
         // Replace all occurrences of `ResumeTy` with `&mut Context<'_>` within async bodies.
-        if is_async_kind || is_async_gen_kind {
+        if matches!(
+            coroutine_kind,
+            CoroutineKind::Desugared(CoroutineDesugaring::Async | CoroutineDesugaring::AsyncGen, _)
+        ) {
             transform_async_context(tcx, body);
         }
 
@@ -1667,11 +1657,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
         // case there is no `Assign` to it that the transform can turn into a store to the coroutine
         // state. After the yield the slot in the coroutine state would then be uninitialized.
         let resume_local = Local::new(2);
-        let resume_ty = if is_async_kind {
-            Ty::new_task_context(tcx)
-        } else {
-            body.local_decls[resume_local].ty
-        };
+        let resume_ty = body.local_decls[resume_local].ty;
         let old_resume_local = replace_local(resume_local, resume_ty, body, tcx);
 
         // When first entering the coroutine, move the resume argument into its old local
@@ -1714,11 +1700,11 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
         // Run the transformation which converts Places from Local to coroutine struct
         // accesses for locals in `remap`.
         // It also rewrites `return x` and `yield y` as writing a new coroutine state and returning
-        // either CoroutineState::Complete(x) and CoroutineState::Yielded(y),
-        // or Poll::Ready(x) and Poll::Pending respectively depending on `is_async_kind`.
+        // either `CoroutineState::Complete(x)` and `CoroutineState::Yielded(y)`,
+        // or `Poll::Ready(x)` and `Poll::Pending` respectively depending on the coroutine kind.
         let mut transform = TransformVisitor {
             tcx,
-            coroutine_kind: body.coroutine_kind().unwrap(),
+            coroutine_kind,
             remap,
             storage_liveness,
             always_live_locals,
@@ -1735,7 +1721,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
         body.spread_arg = None;
 
         // Remove the context argument within generator bodies.
-        if is_gen_kind {
+        if matches!(coroutine_kind, CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) {
             transform_gen_context(tcx, body);
         }
 
diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs
index 604589e5b96..d995d562521 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters.rs
@@ -1,4 +1,4 @@
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::graph::WithNumNodes;
 use rustc_index::bit_set::BitSet;
 use rustc_index::IndexVec;
@@ -47,7 +47,10 @@ pub(super) struct CoverageCounters {
     bcb_counters: IndexVec<BasicCoverageBlock, Option<BcbCounter>>,
     /// Coverage counters/expressions that are associated with the control-flow
     /// edge between two BCBs.
-    bcb_edge_counters: FxHashMap<(BasicCoverageBlock, BasicCoverageBlock), BcbCounter>,
+    ///
+    /// The iteration order of this map can affect the precise contents of MIR,
+    /// so we use `FxIndexMap` to avoid query stability hazards.
+    bcb_edge_counters: FxIndexMap<(BasicCoverageBlock, BasicCoverageBlock), BcbCounter>,
     /// Tracks which BCBs have a counter associated with some incoming edge.
     /// Only used by assertions, to verify that BCBs with incoming edge
     /// counters do not have their own physical counters (expressions are allowed).
@@ -64,7 +67,7 @@ impl CoverageCounters {
         Self {
             next_counter_id: CounterId::START,
             bcb_counters: IndexVec::from_elem_n(None, num_bcbs),
-            bcb_edge_counters: FxHashMap::default(),
+            bcb_edge_counters: FxIndexMap::default(),
             bcb_has_incoming_edge_counters: BitSet::new_empty(num_bcbs),
             expressions: IndexVec::new(),
         }
diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
index 474cb205d13..ff6545e9d25 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
@@ -91,7 +91,7 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>(
 fn is_closure(statement: &Statement<'_>) -> bool {
     match statement.kind {
         StatementKind::Assign(box (_, Rvalue::Aggregate(box ref agg_kind, _))) => match agg_kind {
-            AggregateKind::Closure(_, _) | AggregateKind::Coroutine(_, _, _) => true,
+            AggregateKind::Closure(_, _) | AggregateKind::Coroutine(_, _) => true,
             _ => false,
         },
         _ => false,
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 3b8adf7e86b..2551c8aca88 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -109,7 +109,7 @@ pub struct GVN;
 
 impl<'tcx> MirPass<'tcx> for GVN {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
-        sess.mir_opt_level() >= 4
+        sess.mir_opt_level() >= 2
     }
 
     #[instrument(level = "trace", skip(self, tcx, body))]
@@ -850,7 +850,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 assert!(!fields.is_empty());
                 (AggregateTy::Tuple, FIRST_VARIANT)
             }
-            AggregateKind::Closure(did, substs) | AggregateKind::Coroutine(did, substs, _) => {
+            AggregateKind::Closure(did, substs) | AggregateKind::Coroutine(did, substs) => {
                 (AggregateTy::Def(did, substs), FIRST_VARIANT)
             }
             AggregateKind::Adt(did, variant_index, substs, _, None) => {
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 9d03bab4844..5562ae7f3bd 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -588,7 +588,6 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             // destroy the SSA property. It should still happen before const-propagation, so the
             // latter pass will leverage the created opportunities.
             &separate_const_switch::SeparateConstSwitch,
-            &const_prop::ConstProp,
             &gvn::GVN,
             &simplify::SimplifyLocals::AfterGVN,
             &dataflow_const_prop::DataflowConstProp,
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index fba73d5195b..f6b820bfcd0 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -69,7 +69,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
         ty::InstanceDef::DropGlue(def_id, ty) => {
             // FIXME(#91576): Drop shims for coroutines aren't subject to the MIR passes at the end
             // of this function. Is this intentional?
-            if let Some(ty::Coroutine(coroutine_def_id, args, _)) = ty.map(Ty::kind) {
+            if let Some(ty::Coroutine(coroutine_def_id, args)) = ty.map(Ty::kind) {
                 let body = tcx.optimized_mir(*coroutine_def_id).coroutine_drop().unwrap();
                 let mut body = EarlyBinder::bind(body.clone()).instantiate(tcx, args);
                 debug!("make_shim({:?}) = {:?}", instance, body);
@@ -394,7 +394,8 @@ fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -
         _ if is_copy => builder.copy_shim(),
         ty::Closure(_, args) => builder.tuple_like_shim(dest, src, args.as_closure().upvar_tys()),
         ty::Tuple(..) => builder.tuple_like_shim(dest, src, self_ty.tuple_fields()),
-        ty::Coroutine(coroutine_def_id, args, hir::Movability::Movable) => {
+        ty::Coroutine(coroutine_def_id, args) => {
+            assert_eq!(tcx.coroutine_movability(*coroutine_def_id), hir::Movability::Movable);
             builder.coroutine_shim(dest, src, *coroutine_def_id, args.as_coroutine())
         }
         _ => bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty),
diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
index ac2e8960b06..db1aee11903 100644
--- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs
+++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
@@ -333,7 +333,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
             | ty::FnPtr(_)
             | ty::Dynamic(_, _, _)
             | ty::Closure(_, _)
-            | ty::Coroutine(_, _, _)
+            | ty::Coroutine(_, _)
             | ty::CoroutineWitness(..)
             | ty::Never
             | ty::Tuple(_)
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index b4493df57e2..77bca2f138a 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -450,37 +450,39 @@ impl<'a> Parser<'a> {
 
         let mut expected = edible
             .iter()
-            .map(|x| TokenType::Token(x.clone()))
-            .chain(inedible.iter().map(|x| TokenType::Token(x.clone())))
+            .chain(inedible)
+            .cloned()
+            .map(TokenType::Token)
             .chain(self.expected_tokens.iter().cloned())
-            .filter_map(|token| {
-                // filter out suggestions which suggest the same token which was found and deemed incorrect
+            .filter(|token| {
+                // Filter out suggestions that suggest the same token which was found and deemed incorrect.
                 fn is_ident_eq_keyword(found: &TokenKind, expected: &TokenType) -> bool {
-                    if let TokenKind::Ident(current_sym, _) = found {
-                        if let TokenType::Keyword(suggested_sym) = expected {
-                            return current_sym == suggested_sym;
-                        }
+                    if let TokenKind::Ident(current_sym, _) = found
+                        && let TokenType::Keyword(suggested_sym) = expected
+                    {
+                        return current_sym == suggested_sym;
                     }
                     false
                 }
-                if token != parser::TokenType::Token(self.token.kind.clone()) {
+
+                if *token != parser::TokenType::Token(self.token.kind.clone()) {
                     let eq = is_ident_eq_keyword(&self.token.kind, &token);
-                    // if the suggestion is a keyword and the found token is an ident,
+                    // If the suggestion is a keyword and the found token is an ident,
                     // the content of which are equal to the suggestion's content,
-                    // we can remove that suggestion (see the return None statement below)
+                    // we can remove that suggestion (see the `return false` below).
 
-                    // if this isn't the case however, and the suggestion is a token the
-                    // content of which is the same as the found token's, we remove it as well
+                    // If this isn't the case however, and the suggestion is a token the
+                    // content of which is the same as the found token's, we remove it as well.
                     if !eq {
                         if let TokenType::Token(kind) = &token {
                             if kind == &self.token.kind {
-                                return None;
+                                return false;
                             }
                         }
-                        return Some(token);
+                        return true;
                     }
                 }
-                return None;
+                false
             })
             .collect::<Vec<_>>();
         expected.sort_by_cached_key(|x| x.to_string());
@@ -488,10 +490,10 @@ impl<'a> Parser<'a> {
 
         let sm = self.sess.source_map();
 
-        // Special-case "expected `;`" errors
+        // Special-case "expected `;`" errors.
         if expected.contains(&TokenType::Token(token::Semi)) {
             // If the user is trying to write a ternary expression, recover it and
-            // return an Err to prevent a cascade of irrelevant diagnostics
+            // return an Err to prevent a cascade of irrelevant diagnostics.
             if self.prev_token == token::Question
                 && let Err(e) = self.maybe_recover_from_ternary_operator()
             {
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 73bd19f34c1..bf6151b64d3 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -2937,7 +2937,13 @@ impl<'a> Parser<'a> {
             let is_almost_fat_arrow = TokenKind::FatArrow
                 .similar_tokens()
                 .is_some_and(|similar_tokens| similar_tokens.contains(&this.token.kind));
-            let mut result = if !is_fat_arrow && !is_almost_fat_arrow {
+
+            // this avoids the compiler saying that a `,` or `}` was expected even though
+            // the pattern isn't a never pattern (and thus an arm body is required)
+            let armless = (!is_fat_arrow && !is_almost_fat_arrow && pat.could_be_never_pattern())
+                || matches!(this.token.kind, token::Comma | token::CloseDelim(Delimiter::Brace));
+
+            let mut result = if armless {
                 // A pattern without a body, allowed for never patterns.
                 arm_body = None;
                 this.expect_one_of(&[token::Comma], &[token::CloseDelim(Delimiter::Brace)]).map(
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 1598fd19f6d..19226f37abe 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -320,9 +320,15 @@ impl TokenType {
     }
 }
 
+/// Used by [`Parser::expect_any_with_type`].
 #[derive(Copy, Clone, Debug)]
 enum TokenExpectType {
+    /// Unencountered tokens are inserted into [`Parser::expected_tokens`].
+    /// See [`Parser::check`].
     Expect,
+
+    /// Unencountered tokens are not inserted into [`Parser::expected_tokens`].
+    /// See [`Parser::check_noexpect`].
     NoExpect,
 }
 
@@ -504,18 +510,10 @@ impl<'a> Parser<'a> {
     }
 
     fn ident_or_err(&mut self, recover: bool) -> PResult<'a, (Ident, /* is_raw */ bool)> {
-        let result = self.token.ident().ok_or_else(|| self.expected_ident_found(recover));
-
-        let (ident, is_raw) = match result {
-            Ok(ident) => ident,
-            Err(err) => match err {
-                // we recovered!
-                Ok(ident) => ident,
-                Err(err) => return Err(err),
-            },
-        };
-
-        Ok((ident, is_raw))
+        match self.token.ident() {
+            Some(ident) => Ok(ident),
+            None => self.expected_ident_found(recover),
+        }
     }
 
     /// Checks if the next token is `tok`, and returns `true` if so.
@@ -766,13 +764,17 @@ impl<'a> Parser<'a> {
         }
     }
 
+    /// Checks if the next token is contained within `kets`, and returns `true` if so.
     fn expect_any_with_type(&mut self, kets: &[&TokenKind], expect: TokenExpectType) -> bool {
         kets.iter().any(|k| match expect {
             TokenExpectType::Expect => self.check(k),
-            TokenExpectType::NoExpect => self.token == **k,
+            TokenExpectType::NoExpect => self.check_noexpect(k),
         })
     }
 
+    /// Parses a sequence until the specified delimiters. The function
+    /// `f` must consume tokens until reaching the next separator or
+    /// closing bracket.
     fn parse_seq_to_before_tokens<T>(
         &mut self,
         kets: &[&TokenKind],
@@ -791,13 +793,15 @@ impl<'a> Parser<'a> {
             }
             if let Some(t) = &sep.sep {
                 if first {
+                    // no separator for the first element
                     first = false;
                 } else {
+                    // check for separator
                     match self.expect(t) {
-                        Ok(false) => {
+                        Ok(false) /* not recovered */ => {
                             self.current_closure.take();
                         }
-                        Ok(true) => {
+                        Ok(true) /* recovered */ => {
                             self.current_closure.take();
                             recovered = true;
                             break;
@@ -965,7 +969,7 @@ impl<'a> Parser<'a> {
         Ok(())
     }
 
-    /// Parses a sequence, not including the closing delimiter. The function
+    /// Parses a sequence, not including the delimiters. The function
     /// `f` must consume tokens until reaching the next separator or
     /// closing bracket.
     fn parse_seq_to_before_end<T>(
@@ -973,11 +977,11 @@ impl<'a> Parser<'a> {
         ket: &TokenKind,
         sep: SeqSep,
         f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
-    ) -> PResult<'a, (ThinVec<T>, bool, bool)> {
+    ) -> PResult<'a, (ThinVec<T>, bool /* trailing */, bool /* recovered */)> {
         self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f)
     }
 
-    /// Parses a sequence, including the closing delimiter. The function
+    /// Parses a sequence, including only the closing delimiter. The function
     /// `f` must consume tokens until reaching the next separator or
     /// closing bracket.
     fn parse_seq_to_end<T>(
@@ -993,7 +997,7 @@ impl<'a> Parser<'a> {
         Ok((val, trailing))
     }
 
-    /// Parses a sequence, including the closing delimiter. The function
+    /// Parses a sequence, including both delimiters. The function
     /// `f` must consume tokens until reaching the next separator or
     /// closing bracket.
     fn parse_unspanned_seq<T>(
@@ -1002,16 +1006,19 @@ impl<'a> Parser<'a> {
         ket: &TokenKind,
         sep: SeqSep,
         f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
-    ) -> PResult<'a, (ThinVec<T>, bool)> {
+    ) -> PResult<'a, (ThinVec<T>, bool /* trailing */)> {
         self.expect(bra)?;
         self.parse_seq_to_end(ket, sep, f)
     }
 
+    /// Parses a comma-separated sequence, including both delimiters.
+    /// The function `f` must consume tokens until reaching the next separator or
+    /// closing bracket.
     fn parse_delim_comma_seq<T>(
         &mut self,
         delim: Delimiter,
         f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
-    ) -> PResult<'a, (ThinVec<T>, bool)> {
+    ) -> PResult<'a, (ThinVec<T>, bool /* trailing */)> {
         self.parse_unspanned_seq(
             &token::OpenDelim(delim),
             &token::CloseDelim(delim),
@@ -1020,10 +1027,13 @@ impl<'a> Parser<'a> {
         )
     }
 
+    /// Parses a comma-separated sequence delimited by parentheses (e.g. `(x, y)`).
+    /// The function `f` must consume tokens until reaching the next separator or
+    /// closing bracket.
     fn parse_paren_comma_seq<T>(
         &mut self,
         f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
-    ) -> PResult<'a, (ThinVec<T>, bool)> {
+    ) -> PResult<'a, (ThinVec<T>, bool /* trailing */)> {
         self.parse_delim_comma_seq(Delimiter::Parenthesis, f)
     }
 
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 6be01e0d88f..cfe829f170f 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -101,7 +101,6 @@ use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::DUMMY_SP;
 use rustc_span::{BytePos, Span};
 
-use std::collections::VecDeque;
 use std::io;
 use std::io::prelude::*;
 use std::rc::Rc;
@@ -317,35 +316,13 @@ impl<'tcx> IrMaps<'tcx> {
         // For struct patterns, take note of which fields used shorthand
         // (`x` rather than `x: x`).
         let mut shorthand_field_ids = HirIdSet::default();
-        let mut pats = VecDeque::new();
-        pats.push_back(pat);
-
-        while let Some(pat) = pats.pop_front() {
-            use rustc_hir::PatKind::*;
-            match &pat.kind {
-                Binding(.., inner_pat) => {
-                    pats.extend(inner_pat.iter());
-                }
-                Struct(_, fields, _) => {
-                    let (short, not_short): (Vec<hir::PatField<'_>>, _) =
-                        fields.iter().partition(|f| f.is_shorthand);
-                    shorthand_field_ids.extend(short.iter().map(|f| f.pat.hir_id));
-                    pats.extend(not_short.iter().map(|f| f.pat));
-                }
-                Ref(inner_pat, _) | Box(inner_pat) => {
-                    pats.push_back(inner_pat);
-                }
-                TupleStruct(_, inner_pats, _) | Tuple(inner_pats, _) | Or(inner_pats) => {
-                    pats.extend(inner_pats.iter());
-                }
-                Slice(pre_pats, inner_pat, post_pats) => {
-                    pats.extend(pre_pats.iter());
-                    pats.extend(inner_pat.iter());
-                    pats.extend(post_pats.iter());
-                }
-                _ => {}
+
+        pat.walk_always(|pat| {
+            if let hir::PatKind::Struct(_, fields, _) = pat.kind {
+                let short = fields.iter().filter(|f| f.is_shorthand);
+                shorthand_field_ids.extend(short.map(|f| f.pat.hir_id));
             }
-        }
+        });
 
         shorthand_field_ids
     }
@@ -1351,6 +1328,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> {
 
     fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
         self.check_unused_vars_in_pat(arm.pat, None, None, |_, _, _, _| {});
+        if let Some(hir::Guard::IfLet(let_expr)) = arm.guard {
+            self.check_unused_vars_in_pat(let_expr.pat, None, None, |_, _, _, _| {});
+        }
         intravisit::walk_arm(self, arm);
     }
 }
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index 3c1bdfd910e..b09d565f076 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -366,7 +366,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
             | ty::FnPtr(_)
             | ty::Dynamic(_, _, _)
             | ty::Closure(_, _)
-            | ty::Coroutine(_, _, _)
+            | ty::Coroutine(_, _)
             | ty::Alias(_, _)
             | ty::Param(_)
             | ty::Error(_) => ConstructorSet::Unlistable,
diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs
index bbc98af45c0..17162d0de25 100644
--- a/compiler/rustc_smir/src/rustc_internal/internal.rs
+++ b/compiler/rustc_smir/src/rustc_internal/internal.rs
@@ -104,11 +104,9 @@ impl<'tcx> RustcInternal<'tcx> for RigidTy {
             RigidTy::Closure(def, args) => {
                 rustc_ty::TyKind::Closure(def.0.internal(tables), args.internal(tables))
             }
-            RigidTy::Coroutine(def, args, mov) => rustc_ty::TyKind::Coroutine(
-                def.0.internal(tables),
-                args.internal(tables),
-                mov.internal(tables),
-            ),
+            RigidTy::Coroutine(def, args, _mov) => {
+                rustc_ty::TyKind::Coroutine(def.0.internal(tables), args.internal(tables))
+            }
             RigidTy::CoroutineWitness(def, args) => {
                 rustc_ty::TyKind::CoroutineWitness(def.0.internal(tables), args.internal(tables))
             }
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
index 49bf2192f82..c5fb6f7a26f 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
@@ -531,11 +531,11 @@ impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> {
                     generic_arg.stable(tables),
                 )
             }
-            mir::AggregateKind::Coroutine(def_id, generic_arg, movability) => {
+            mir::AggregateKind::Coroutine(def_id, generic_arg) => {
                 stable_mir::mir::AggregateKind::Coroutine(
                     tables.coroutine_def(*def_id),
                     generic_arg.stable(tables),
-                    movability.stable(tables),
+                    tables.tcx.coroutine_movability(*def_id).stable(tables),
                 )
             }
         }
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
index cbdddc30072..f0f1d798d44 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
@@ -386,10 +386,10 @@ impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> {
                 tables.closure_def(*def_id),
                 generic_args.stable(tables),
             )),
-            ty::Coroutine(def_id, generic_args, movability) => TyKind::RigidTy(RigidTy::Coroutine(
+            ty::Coroutine(def_id, generic_args) => TyKind::RigidTy(RigidTy::Coroutine(
                 tables.coroutine_def(*def_id),
                 generic_args.stable(tables),
-                movability.stable(tables),
+                tables.tcx.coroutine_movability(*def_id).stable(tables),
             )),
             ty::Never => TyKind::RigidTy(RigidTy::Never),
             ty::Tuple(fields) => {
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index a273a412146..4a5f58443bc 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -211,7 +211,7 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> {
             ty::FnDef(def_id, args)
             | ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. })
             | ty::Closure(def_id, args)
-            | ty::Coroutine(def_id, args, _) => self.print_def_path(def_id, args),
+            | ty::Coroutine(def_id, args) => self.print_def_path(def_id, args),
 
             // The `pretty_print_type` formatting of array size depends on
             // -Zverbose-internals flag, so we cannot reuse it here.
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 d2962b2968b..0cc82ac7506 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
@@ -895,8 +895,8 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
             ty = Ty::new_closure(tcx, *def_id, transform_args(tcx, args, options));
         }
 
-        ty::Coroutine(def_id, args, movability) => {
-            ty = Ty::new_coroutine(tcx, *def_id, transform_args(tcx, args, options), *movability);
+        ty::Coroutine(def_id, args) => {
+            ty = Ty::new_coroutine(tcx, *def_id, transform_args(tcx, args, options));
         }
 
         ty::Ref(region, ty0, ..) => {
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index e002e345ae6..e89a640767f 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -427,7 +427,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
             | ty::FnDef(def_id, args)
             | ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. })
             | ty::Closure(def_id, args)
-            | ty::Coroutine(def_id, args, _) => {
+            | ty::Coroutine(def_id, args) => {
                 self.print_def_path(def_id, args)?;
             }
             ty::Foreign(def_id) => {
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index 81a766f24b0..caf9470b4c6 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -432,7 +432,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             | ty::FnPtr(_)
             | ty::Dynamic(_, _, _)
             | ty::Closure(_, _)
-            | ty::Coroutine(_, _, _)
+            | ty::Coroutine(_, _)
             | ty::Never
             | ty::Tuple(_) => {
                 let simp =
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
index f442e2a08a8..274a75a125c 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
@@ -57,7 +57,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
 
         ty::Closure(_, args) => Ok(vec![args.as_closure().tupled_upvars_ty()]),
 
-        ty::Coroutine(_, args, _) => {
+        ty::Coroutine(_, args) => {
             let coroutine_args = args.as_coroutine();
             Ok(vec![coroutine_args.tupled_upvars_ty(), coroutine_args.witness()])
         }
@@ -177,7 +177,6 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
         ty::Dynamic(..)
         | ty::Str
         | ty::Slice(_)
-        | ty::Coroutine(_, _, Movability::Static)
         | ty::Foreign(..)
         | ty::Ref(_, _, Mutability::Mut)
         | ty::Adt(_, _)
@@ -194,14 +193,17 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
 
         ty::Closure(_, args) => Ok(vec![args.as_closure().tupled_upvars_ty()]),
 
-        ty::Coroutine(_, args, Movability::Movable) => {
-            if ecx.tcx().features().coroutine_clone {
-                let coroutine = args.as_coroutine();
-                Ok(vec![coroutine.tupled_upvars_ty(), coroutine.witness()])
-            } else {
-                Err(NoSolution)
+        ty::Coroutine(def_id, args) => match ecx.tcx().coroutine_movability(def_id) {
+            Movability::Static => Err(NoSolution),
+            Movability::Movable => {
+                if ecx.tcx().features().coroutine_clone {
+                    let coroutine = args.as_coroutine();
+                    Ok(vec![coroutine.tupled_upvars_ty(), coroutine.witness()])
+                } else {
+                    Err(NoSolution)
+                }
             }
-        }
+        },
 
         ty::CoroutineWitness(def_id, args) => Ok(ecx
             .tcx()
@@ -278,7 +280,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
         | ty::RawPtr(_)
         | ty::Ref(_, _, _)
         | ty::Dynamic(_, _, _)
-        | ty::Coroutine(_, _, _)
+        | ty::Coroutine(_, _)
         | ty::CoroutineWitness(..)
         | ty::Never
         | ty::Tuple(_)
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
index bac08f6588f..ccee6f8eb29 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
@@ -468,7 +468,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
         let self_ty = goal.predicate.self_ty();
-        let ty::Coroutine(def_id, args, _) = *self_ty.kind() else {
+        let ty::Coroutine(def_id, args) = *self_ty.kind() else {
             return Err(NoSolution);
         };
 
@@ -499,7 +499,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
         let self_ty = goal.predicate.self_ty();
-        let ty::Coroutine(def_id, args, _) = *self_ty.kind() else {
+        let ty::Coroutine(def_id, args) = *self_ty.kind() else {
             return Err(NoSolution);
         };
 
@@ -530,7 +530,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
         let self_ty = goal.predicate.self_ty();
-        let ty::Coroutine(def_id, args, _) = *self_ty.kind() else {
+        let ty::Coroutine(def_id, args) = *self_ty.kind() else {
             return Err(NoSolution);
         };
 
@@ -564,7 +564,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
         let self_ty = goal.predicate.self_ty();
-        let ty::Coroutine(def_id, args, _) = *self_ty.kind() else {
+        let ty::Coroutine(def_id, args) = *self_ty.kind() else {
             return Err(NoSolution);
         };
 
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index ac3ffd2d6c2..be079275684 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -337,7 +337,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
             return Err(NoSolution);
         }
 
-        let ty::Coroutine(def_id, _, _) = *goal.predicate.self_ty().kind() else {
+        let ty::Coroutine(def_id, _) = *goal.predicate.self_ty().kind() else {
             return Err(NoSolution);
         };
 
@@ -361,7 +361,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
             return Err(NoSolution);
         }
 
-        let ty::Coroutine(def_id, _, _) = *goal.predicate.self_ty().kind() else {
+        let ty::Coroutine(def_id, _) = *goal.predicate.self_ty().kind() else {
             return Err(NoSolution);
         };
 
@@ -385,7 +385,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
             return Err(NoSolution);
         }
 
-        let ty::Coroutine(def_id, _, _) = *goal.predicate.self_ty().kind() else {
+        let ty::Coroutine(def_id, _) = *goal.predicate.self_ty().kind() else {
             return Err(NoSolution);
         };
 
@@ -410,7 +410,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         }
 
         let self_ty = goal.predicate.self_ty();
-        let ty::Coroutine(def_id, args, _) = *self_ty.kind() else {
+        let ty::Coroutine(def_id, args) = *self_ty.kind() else {
             return Err(NoSolution);
         };
 
@@ -927,10 +927,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             // Coroutines have one special built-in candidate, `Unpin`, which
             // takes precedence over the structural auto trait candidate being
             // assembled.
-            ty::Coroutine(_, _, movability)
+            ty::Coroutine(def_id, _)
                 if Some(goal.predicate.def_id()) == self.tcx().lang_items().unpin_trait() =>
             {
-                match movability {
+                match self.tcx().coroutine_movability(def_id) {
                     Movability::Static => Some(Err(NoSolution)),
                     Movability::Movable => {
                         Some(self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
@@ -959,7 +959,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             | ty::FnDef(_, _)
             | ty::FnPtr(_)
             | ty::Closure(_, _)
-            | ty::Coroutine(_, _, _)
+            | ty::Coroutine(_, _)
             | ty::CoroutineWitness(..)
             | ty::Never
             | ty::Tuple(_)
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 1143b9d3360..f63314081d6 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -3406,7 +3406,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                                 }
                                 err.note(msg.trim_end_matches(", ").to_string())
                             }
-                            ty::Coroutine(def_id, _, _) => {
+                            ty::Coroutine(def_id, _) => {
                                 let sp = self.tcx.def_span(def_id);
 
                                 // Special-case this to say "async block" instead of `[static coroutine]`.
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index d32b4adbefc..dd4e69efe37 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -2083,7 +2083,7 @@ fn confirm_coroutine_candidate<'cx, 'tcx>(
     nested: Vec<PredicateObligation<'tcx>>,
 ) -> Progress<'tcx> {
     let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
-    let ty::Coroutine(_, args, _) = self_ty.kind() else {
+    let ty::Coroutine(_, args) = self_ty.kind() else {
         unreachable!(
             "expected coroutine self type for built-in coroutine candidate, found {self_ty}"
         )
@@ -2138,7 +2138,7 @@ fn confirm_future_candidate<'cx, 'tcx>(
     nested: Vec<PredicateObligation<'tcx>>,
 ) -> Progress<'tcx> {
     let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
-    let ty::Coroutine(_, args, _) = self_ty.kind() else {
+    let ty::Coroutine(_, args) = self_ty.kind() else {
         unreachable!(
             "expected coroutine self type for built-in async future candidate, found {self_ty}"
         )
@@ -2182,7 +2182,7 @@ fn confirm_iterator_candidate<'cx, 'tcx>(
     nested: Vec<PredicateObligation<'tcx>>,
 ) -> Progress<'tcx> {
     let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
-    let ty::Coroutine(_, args, _) = self_ty.kind() else {
+    let ty::Coroutine(_, args) = self_ty.kind() else {
         unreachable!("expected coroutine self type for built-in gen candidate, found {self_ty}")
     };
     let gen_sig = args.as_coroutine().sig();
@@ -2223,8 +2223,7 @@ fn confirm_async_iterator_candidate<'cx, 'tcx>(
     obligation: &ProjectionTyObligation<'tcx>,
     nested: Vec<PredicateObligation<'tcx>>,
 ) -> Progress<'tcx> {
-    let ty::Coroutine(_, args, _) =
-        selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind()
+    let ty::Coroutine(_, args) = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind()
     else {
         unreachable!()
     };
diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
index f9c8f3d14c3..138bc6129f7 100644
--- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
@@ -259,7 +259,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
             })?
         }
 
-        ty::Coroutine(_, args, _movability) => {
+        ty::Coroutine(_, args) => {
             // rust-lang/rust#49918: types can be constructed, stored
             // in the interior, and sit idle when coroutine yields
             // (and is subsequently dropped).
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 3a37bc518ef..54b91ab1d4d 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -263,7 +263,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         candidates: &mut SelectionCandidateSet<'tcx>,
     ) {
         let self_ty = obligation.self_ty().skip_binder();
-        if let ty::Coroutine(did, args, _) = *self_ty.kind() {
+        if let ty::Coroutine(did, args) = *self_ty.kind() {
             // gen constructs get lowered to a special kind of coroutine that
             // should directly `impl AsyncIterator`.
             if self.tcx().coroutine_is_async_gen(did) {
@@ -486,7 +486,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 | ty::RawPtr(_)
                 | ty::Ref(_, _, _)
                 | ty::Closure(_, _)
-                | ty::Coroutine(_, _, _)
+                | ty::Coroutine(_, _)
                 | ty::CoroutineWitness(..)
                 | ty::Never
                 | ty::Tuple(_)
@@ -529,7 +529,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let def_id = obligation.predicate.def_id();
 
         if self.tcx().trait_is_auto(def_id) {
-            match self_ty.kind() {
+            match *self_ty.kind() {
                 ty::Dynamic(..) => {
                     // For object types, we don't know what the closed
                     // over types are. This means we conservatively
@@ -564,10 +564,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     // The auto impl might apply; we don't know.
                     candidates.ambiguous = true;
                 }
-                ty::Coroutine(_, _, movability)
+                ty::Coroutine(coroutine_def_id, _)
                     if self.tcx().lang_items().unpin_trait() == Some(def_id) =>
                 {
-                    match movability {
+                    match self.tcx().coroutine_movability(coroutine_def_id) {
                         hir::Movability::Static => {
                             // Immovable coroutines are never `Unpin`, so
                             // suppress the normal auto-impl candidate for it.
@@ -1023,7 +1023,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             | ty::FnPtr(_)
             | ty::Dynamic(_, _, _)
             | ty::Closure(_, _)
-            | ty::Coroutine(_, _, _)
+            | ty::Coroutine(_, _)
             | ty::CoroutineWitness(..)
             | ty::Never
             | ty::Alias(..)
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index f1da1c046d4..e20bb06d777 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -730,7 +730,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // touch bound regions, they just capture the in-scope
         // type/region parameters.
         let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
-        let ty::Coroutine(coroutine_def_id, args, _) = *self_ty.kind() else {
+        let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else {
             bug!("closure candidate for non-closure {:?}", obligation);
         };
 
@@ -768,7 +768,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // touch bound regions, they just capture the in-scope
         // type/region parameters.
         let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
-        let ty::Coroutine(coroutine_def_id, args, _) = *self_ty.kind() else {
+        let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else {
             bug!("closure candidate for non-closure {:?}", obligation);
         };
 
@@ -797,7 +797,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // touch bound regions, they just capture the in-scope
         // type/region parameters.
         let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
-        let ty::Coroutine(coroutine_def_id, args, _) = *self_ty.kind() else {
+        let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else {
             bug!("closure candidate for non-closure {:?}", obligation);
         };
 
@@ -826,7 +826,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // touch bound regions, they just capture the in-scope
         // type/region parameters.
         let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
-        let ty::Coroutine(coroutine_def_id, args, _) = *self_ty.kind() else {
+        let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else {
             bug!("closure candidate for non-closure {:?}", obligation);
         };
 
@@ -1298,7 +1298,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 ty::Closure(_, args) => {
                     stack.push(args.as_closure().tupled_upvars_ty());
                 }
-                ty::Coroutine(_, args, _) => {
+                ty::Coroutine(_, args) => {
                     let coroutine = args.as_coroutine();
                     stack.extend([coroutine.tupled_upvars_ty(), coroutine.witness()]);
                 }
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 336c0c5299f..c45925295ee 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -2176,7 +2176,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             ty::Dynamic(..)
             | ty::Str
             | ty::Slice(..)
-            | ty::Coroutine(_, _, hir::Movability::Static)
             | ty::Foreign(..)
             | ty::Ref(_, _, hir::Mutability::Mut) => None,
 
@@ -2185,26 +2184,31 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 Where(obligation.predicate.rebind(tys.iter().collect()))
             }
 
-            ty::Coroutine(_, args, hir::Movability::Movable) => {
-                if self.tcx().features().coroutine_clone {
-                    let resolved_upvars =
-                        self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty());
-                    let resolved_witness =
-                        self.infcx.shallow_resolve(args.as_coroutine().witness());
-                    if resolved_upvars.is_ty_var() || resolved_witness.is_ty_var() {
-                        // Not yet resolved.
-                        Ambiguous
-                    } else {
-                        let all = args
-                            .as_coroutine()
-                            .upvar_tys()
-                            .iter()
-                            .chain([args.as_coroutine().witness()])
-                            .collect::<Vec<_>>();
-                        Where(obligation.predicate.rebind(all))
+            ty::Coroutine(coroutine_def_id, args) => {
+                match self.tcx().coroutine_movability(coroutine_def_id) {
+                    hir::Movability::Static => None,
+                    hir::Movability::Movable => {
+                        if self.tcx().features().coroutine_clone {
+                            let resolved_upvars =
+                                self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty());
+                            let resolved_witness =
+                                self.infcx.shallow_resolve(args.as_coroutine().witness());
+                            if resolved_upvars.is_ty_var() || resolved_witness.is_ty_var() {
+                                // Not yet resolved.
+                                Ambiguous
+                            } else {
+                                let all = args
+                                    .as_coroutine()
+                                    .upvar_tys()
+                                    .iter()
+                                    .chain([args.as_coroutine().witness()])
+                                    .collect::<Vec<_>>();
+                                Where(obligation.predicate.rebind(all))
+                            }
+                        } else {
+                            None
+                        }
                     }
-                } else {
-                    None
                 }
             }
 
@@ -2307,7 +2311,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 t.rebind(vec![ty])
             }
 
-            ty::Coroutine(_, args, _) => {
+            ty::Coroutine(_, args) => {
                 let ty = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty());
                 let witness = args.as_coroutine().witness();
                 t.rebind([ty].into_iter().chain(iter::once(witness)).collect())
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index 4756a45a447..2772831e731 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -97,7 +97,7 @@ fn fn_sig_for_fn_abi<'tcx>(
                 bound_vars,
             )
         }
-        ty::Coroutine(did, args, _) => {
+        ty::Coroutine(did, args) => {
             let coroutine_kind = tcx.coroutine_kind(did).unwrap();
             let sig = args.as_coroutine().sig();
 
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 42db43caf9f..81d5304b812 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -246,7 +246,7 @@ fn resolve_associated_item<'tcx>(
                     })
                 }
             } else if Some(trait_ref.def_id) == lang_items.future_trait() {
-                let ty::Coroutine(coroutine_def_id, args, _) = *rcvr_args.type_at(0).kind() else {
+                let ty::Coroutine(coroutine_def_id, args) = *rcvr_args.type_at(0).kind() else {
                     bug!()
                 };
                 if Some(trait_item_id) == tcx.lang_items().future_poll_fn() {
@@ -259,7 +259,7 @@ fn resolve_associated_item<'tcx>(
                     Some(Instance::new(trait_item_id, rcvr_args))
                 }
             } else if Some(trait_ref.def_id) == lang_items.iterator_trait() {
-                let ty::Coroutine(coroutine_def_id, args, _) = *rcvr_args.type_at(0).kind() else {
+                let ty::Coroutine(coroutine_def_id, args) = *rcvr_args.type_at(0).kind() else {
                     bug!()
                 };
                 if Some(trait_item_id) == tcx.lang_items().next_fn() {
@@ -272,7 +272,7 @@ fn resolve_associated_item<'tcx>(
                     Some(Instance::new(trait_item_id, rcvr_args))
                 }
             } else if Some(trait_ref.def_id) == lang_items.async_iterator_trait() {
-                let ty::Coroutine(coroutine_def_id, args, _) = *rcvr_args.type_at(0).kind() else {
+                let ty::Coroutine(coroutine_def_id, args) = *rcvr_args.type_at(0).kind() else {
                     bug!()
                 };
 
@@ -287,7 +287,7 @@ fn resolve_associated_item<'tcx>(
                 // `AsyncIterator::poll_next` is generated by the compiler.
                 Some(Instance { def: ty::InstanceDef::Item(coroutine_def_id), args })
             } else if Some(trait_ref.def_id) == lang_items.coroutine_trait() {
-                let ty::Coroutine(coroutine_def_id, args, _) = *rcvr_args.type_at(0).kind() else {
+                let ty::Coroutine(coroutine_def_id, args) = *rcvr_args.type_at(0).kind() else {
                     bug!()
                 };
                 if cfg!(debug_assertions) && tcx.item_name(trait_item_id) != sym::resume {
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index d39377a1acb..db89fba2a89 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -316,7 +316,7 @@ fn layout_of_uncached<'tcx>(
             tcx.mk_layout(unit)
         }
 
-        ty::Coroutine(def_id, args, _) => coroutine_layout(cx, ty, def_id, args)?,
+        ty::Coroutine(def_id, args) => coroutine_layout(cx, ty, def_id, args)?,
 
         ty::Closure(_, args) => {
             let tys = args.as_closure().upvar_tys();
@@ -961,7 +961,7 @@ fn record_layout_for_printing<'tcx>(cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, layout: T
             record(adt_kind.into(), adt_packed, opt_discr_size, variant_infos);
         }
 
-        ty::Coroutine(def_id, args, _) => {
+        ty::Coroutine(def_id, args) => {
             debug!("print-type-size t: `{:?}` record coroutine", layout.ty);
             // Coroutines always have a begin/poisoned/end state with additional suspend points
             let (variant_infos, opt_discr_size) =
diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs
index 8d118e6dfef..08e5476ae43 100644
--- a/compiler/rustc_ty_utils/src/needs_drop.rs
+++ b/compiler/rustc_ty_utils/src/needs_drop.rs
@@ -145,7 +145,7 @@ where
                     // for the coroutine witness and check whether any of the contained types
                     // need to be dropped, and only require the captured types to be live
                     // if they do.
-                    ty::Coroutine(_, args, _) => {
+                    ty::Coroutine(_, args) => {
                         if self.reveal_coroutine_witnesses {
                             queue_type(self, args.as_coroutine().witness());
                         } else {
diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs
index 70adfbee2ed..859000fb6cb 100644
--- a/compiler/rustc_type_ir/src/ty_kind.rs
+++ b/compiler/rustc_type_ir/src/ty_kind.rs
@@ -207,7 +207,7 @@ pub enum TyKind<I: Interner> {
     ///
     /// For more info about coroutine args, visit the documentation for
     /// `CoroutineArgs`.
-    Coroutine(I::DefId, I::GenericArgs, Movability),
+    Coroutine(I::DefId, I::GenericArgs),
 
     /// A type representing the types stored inside a coroutine.
     /// This should only appear as part of the `CoroutineArgs`.
@@ -317,7 +317,7 @@ const fn tykind_discriminant<I: Interner>(value: &TyKind<I>) -> usize {
         FnPtr(_) => 13,
         Dynamic(..) => 14,
         Closure(_, _) => 15,
-        Coroutine(_, _, _) => 16,
+        Coroutine(_, _) => 16,
         CoroutineWitness(_, _) => 17,
         Never => 18,
         Tuple(_) => 19,
@@ -356,9 +356,7 @@ impl<I: Interner> PartialEq for TyKind<I> {
                 a_p == b_p && a_r == b_r && a_repr == b_repr
             }
             (Closure(a_d, a_s), Closure(b_d, b_s)) => a_d == b_d && a_s == b_s,
-            (Coroutine(a_d, a_s, a_m), Coroutine(b_d, b_s, b_m)) => {
-                a_d == b_d && a_s == b_s && a_m == b_m
-            }
+            (Coroutine(a_d, a_s), Coroutine(b_d, b_s)) => a_d == b_d && a_s == b_s,
             (CoroutineWitness(a_d, a_s), CoroutineWitness(b_d, b_s)) => a_d == b_d && a_s == b_s,
             (Tuple(a_t), Tuple(b_t)) => a_t == b_t,
             (Alias(a_i, a_p), Alias(b_i, b_p)) => a_i == b_i && a_p == b_p,
@@ -432,9 +430,7 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
                 }
             },
             Closure(d, s) => f.debug_tuple("Closure").field(d).field(&this.wrap(s)).finish(),
-            Coroutine(d, s, m) => {
-                f.debug_tuple("Coroutine").field(d).field(&this.wrap(s)).field(m).finish()
-            }
+            Coroutine(d, s) => f.debug_tuple("Coroutine").field(d).field(&this.wrap(s)).finish(),
             CoroutineWitness(d, s) => {
                 f.debug_tuple("CoroutineWitness").field(d).field(&this.wrap(s)).finish()
             }
diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs
index 5871600bece..72227a04bf1 100644
--- a/compiler/stable_mir/src/mir/body.rs
+++ b/compiler/stable_mir/src/mir/body.rs
@@ -662,6 +662,7 @@ pub enum AggregateKind {
     Tuple,
     Adt(AdtDef, VariantIdx, GenericArgs, Option<UserTypeAnnotationIndex>, Option<FieldIdx>),
     Closure(ClosureDef, GenericArgs),
+    // FIXME(stable_mir): Movability here is redundant
     Coroutine(CoroutineDef, GenericArgs, Movability),
 }
 
diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs
index 1d4d7b6d352..9e6ecbe8315 100644
--- a/compiler/stable_mir/src/ty.rs
+++ b/compiler/stable_mir/src/ty.rs
@@ -460,6 +460,7 @@ pub enum RigidTy {
     FnDef(FnDef, GenericArgs),
     FnPtr(PolyFnSig),
     Closure(ClosureDef, GenericArgs),
+    // FIXME(stable_mir): Movability here is redundant
     Coroutine(CoroutineDef, GenericArgs, Movability),
     Dynamic(Vec<Binder<ExistentialPredicate>>, Region, DynKind),
     Never,
diff --git a/config.example.toml b/config.example.toml
index dacc61a3e4c..f1ea6bac3ca 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -661,7 +661,7 @@
 
 # Indicates whether some LLVM tools, like llvm-objdump, will be made available in the
 # sysroot.
-#llvm-tools = false
+#llvm-tools = true
 
 # Whether to deny warnings in crates
 #deny-warnings = true
diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs
index 99ec68f5aa5..74fa30456eb 100644
--- a/library/alloc/src/raw_vec.rs
+++ b/library/alloc/src/raw_vec.rs
@@ -284,7 +284,7 @@ impl<T, A: Allocator> RawVec<T, A> {
     ///
     /// # Panics
     ///
-    /// Panics if the new capacity exceeds `isize::MAX` bytes.
+    /// Panics if the new capacity exceeds `isize::MAX` _bytes_.
     ///
     /// # Aborts
     ///
@@ -342,7 +342,7 @@ impl<T, A: Allocator> RawVec<T, A> {
     ///
     /// # Panics
     ///
-    /// Panics if the new capacity exceeds `isize::MAX` bytes.
+    /// Panics if the new capacity exceeds `isize::MAX` _bytes_.
     ///
     /// # Aborts
     ///
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 85df491636a..1fc6fe631ab 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -2917,20 +2917,17 @@ impl<T: ?Sized, A: Allocator + Clone> Clone for Weak<T, A> {
     /// ```
     #[inline]
     fn clone(&self) -> Weak<T, A> {
-        let inner = if let Some(inner) = self.inner() {
-            inner
-        } else {
-            return Weak { ptr: self.ptr, alloc: self.alloc.clone() };
-        };
-        // See comments in Arc::clone() for why this is relaxed. This can use a
-        // fetch_add (ignoring the lock) because the weak count is only locked
-        // where are *no other* weak pointers in existence. (So we can't be
-        // running this code in that case).
-        let old_size = inner.weak.fetch_add(1, Relaxed);
-
-        // See comments in Arc::clone() for why we do this (for mem::forget).
-        if old_size > MAX_REFCOUNT {
-            abort();
+        if let Some(inner) = self.inner() {
+            // See comments in Arc::clone() for why this is relaxed. This can use a
+            // fetch_add (ignoring the lock) because the weak count is only locked
+            // where are *no other* weak pointers in existence. (So we can't be
+            // running this code in that case).
+            let old_size = inner.weak.fetch_add(1, Relaxed);
+
+            // See comments in Arc::clone() for why we do this (for mem::forget).
+            if old_size > MAX_REFCOUNT {
+                abort();
+            }
         }
 
         Weak { ptr: self.ptr, alloc: self.alloc.clone() }
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index fca85c6123b..e8a096cac86 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -445,7 +445,7 @@ impl<T> Vec<T> {
     ///
     /// # Panics
     ///
-    /// Panics if the new capacity exceeds `isize::MAX` bytes.
+    /// Panics if the new capacity exceeds `isize::MAX` _bytes_.
     ///
     /// # Examples
     ///
@@ -633,7 +633,7 @@ impl<T, A: Allocator> Vec<T, A> {
     ///
     /// # Panics
     ///
-    /// Panics if the new capacity exceeds `isize::MAX` bytes.
+    /// Panics if the new capacity exceeds `isize::MAX` _bytes_.
     ///
     /// # Examples
     ///
@@ -896,7 +896,7 @@ impl<T, A: Allocator> Vec<T, A> {
     ///
     /// # Panics
     ///
-    /// Panics if the new capacity exceeds `isize::MAX` bytes.
+    /// Panics if the new capacity exceeds `isize::MAX` _bytes_.
     ///
     /// # Examples
     ///
@@ -926,7 +926,7 @@ impl<T, A: Allocator> Vec<T, A> {
     ///
     /// # Panics
     ///
-    /// Panics if the new capacity exceeds `isize::MAX` bytes.
+    /// Panics if the new capacity exceeds `isize::MAX` _bytes_.
     ///
     /// # Examples
     ///
@@ -1900,7 +1900,7 @@ impl<T, A: Allocator> Vec<T, A> {
     ///
     /// # Panics
     ///
-    /// Panics if the new capacity exceeds `isize::MAX` bytes.
+    /// Panics if the new capacity exceeds `isize::MAX` _bytes_.
     ///
     /// # Examples
     ///
@@ -2003,7 +2003,7 @@ impl<T, A: Allocator> Vec<T, A> {
     ///
     /// # Panics
     ///
-    /// Panics if the new capacity exceeds `isize::MAX` bytes.
+    /// Panics if the new capacity exceeds `isize::MAX` _bytes_.
     ///
     /// # Examples
     ///
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index 544a42d9ada..d34c19a47e3 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -55,7 +55,6 @@ o("profiler", "build.profiler", "build the profiler runtime")
 o("full-tools", None, "enable all tools")
 o("lld", "rust.lld", "build lld")
 o("clang", "llvm.clang", "build clang")
-o("missing-tools", "dist.missing-tools", "allow failures when building tools")
 o("use-libcxx", "llvm.use-libcxx", "build LLVM with libc++")
 o("control-flow-guard", "rust.control-flow-guard", "Enable Control Flow Guard")
 o("patch-binaries-for-nix", "build.patch-binaries-for-nix", "whether patch binaries for usage with Nix toolchains")
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index df4d1a43dab..dbb64583d56 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -1738,7 +1738,7 @@ impl Step for Assemble {
         if builder.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) {
             let llvm::LlvmResult { llvm_config, .. } =
                 builder.ensure(llvm::Llvm { target: target_compiler.host });
-            if !builder.config.dry_run() {
+            if !builder.config.dry_run() && builder.config.llvm_tools_enabled {
                 let llvm_bin_dir = output(Command::new(llvm_config).arg("--bindir"));
                 let llvm_bin_dir = Path::new(llvm_bin_dir.trim());
 
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index 98e267713da..d87651cb367 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -1110,9 +1110,7 @@ impl Step for Rls {
         let compiler = self.compiler;
         let target = self.target;
 
-        let rls = builder
-            .ensure(tool::Rls { compiler, target, extra_features: Vec::new() })
-            .expect("rls expected to build");
+        let rls = builder.ensure(tool::Rls { compiler, target, extra_features: Vec::new() });
 
         let mut tarball = Tarball::new(builder, "rls", &target.triple);
         tarball.set_overlay(OverlayKind::RLS);
@@ -1154,9 +1152,7 @@ impl Step for RustAnalyzer {
         let compiler = self.compiler;
         let target = self.target;
 
-        let rust_analyzer = builder
-            .ensure(tool::RustAnalyzer { compiler, target })
-            .expect("rust-analyzer always builds");
+        let rust_analyzer = builder.ensure(tool::RustAnalyzer { compiler, target });
 
         let mut tarball = Tarball::new(builder, "rust-analyzer", &target.triple);
         tarball.set_overlay(OverlayKind::RustAnalyzer);
@@ -1201,12 +1197,9 @@ impl Step for Clippy {
         // Prepare the image directory
         // We expect clippy to build, because we've exited this step above if tool
         // state for clippy isn't testing.
-        let clippy = builder
-            .ensure(tool::Clippy { compiler, target, extra_features: Vec::new() })
-            .expect("clippy expected to build - essential tool");
-        let cargoclippy = builder
-            .ensure(tool::CargoClippy { compiler, target, extra_features: Vec::new() })
-            .expect("clippy expected to build - essential tool");
+        let clippy = builder.ensure(tool::Clippy { compiler, target, extra_features: Vec::new() });
+        let cargoclippy =
+            builder.ensure(tool::CargoClippy { compiler, target, extra_features: Vec::new() });
 
         let mut tarball = Tarball::new(builder, "clippy", &target.triple);
         tarball.set_overlay(OverlayKind::Clippy);
@@ -1255,9 +1248,9 @@ impl Step for Miri {
         let compiler = self.compiler;
         let target = self.target;
 
-        let miri = builder.ensure(tool::Miri { compiler, target, extra_features: Vec::new() })?;
+        let miri = builder.ensure(tool::Miri { compiler, target, extra_features: Vec::new() });
         let cargomiri =
-            builder.ensure(tool::CargoMiri { compiler, target, extra_features: Vec::new() })?;
+            builder.ensure(tool::CargoMiri { compiler, target, extra_features: Vec::new() });
 
         let mut tarball = Tarball::new(builder, "miri", &target.triple);
         tarball.set_overlay(OverlayKind::Miri);
@@ -1396,12 +1389,10 @@ impl Step for Rustfmt {
         let compiler = self.compiler;
         let target = self.target;
 
-        let rustfmt = builder
-            .ensure(tool::Rustfmt { compiler, target, extra_features: Vec::new() })
-            .expect("rustfmt expected to build - essential tool");
-        let cargofmt = builder
-            .ensure(tool::Cargofmt { compiler, target, extra_features: Vec::new() })
-            .expect("cargo fmt expected to build - essential tool");
+        let rustfmt =
+            builder.ensure(tool::Rustfmt { compiler, target, extra_features: Vec::new() });
+        let cargofmt =
+            builder.ensure(tool::Cargofmt { compiler, target, extra_features: Vec::new() });
         let mut tarball = Tarball::new(builder, "rustfmt", &target.triple);
         tarball.set_overlay(OverlayKind::Rustfmt);
         tarball.is_preview(true);
@@ -1455,9 +1446,8 @@ impl Step for RustDemangler {
             return None;
         }
 
-        let rust_demangler = builder
-            .ensure(tool::RustDemangler { compiler, target, extra_features: Vec::new() })
-            .expect("rust-demangler expected to build - in-tree tool");
+        let rust_demangler =
+            builder.ensure(tool::RustDemangler { compiler, target, extra_features: Vec::new() });
 
         // Prepare the image directory
         let mut tarball = Tarball::new(builder, "rust-demangler", &target.triple);
@@ -2157,12 +2147,14 @@ impl Step for LlvmTools {
         tarball.set_overlay(OverlayKind::LLVM);
         tarball.is_preview(true);
 
-        // Prepare the image directory
-        let src_bindir = builder.llvm_out(target).join("bin");
-        let dst_bindir = format!("lib/rustlib/{}/bin", target.triple);
-        for tool in LLVM_TOOLS {
-            let exe = src_bindir.join(exe(tool, target));
-            tarball.add_file(&exe, &dst_bindir, 0o755);
+        if builder.config.llvm_tools_enabled {
+            // Prepare the image directory
+            let src_bindir = builder.llvm_out(target).join("bin");
+            let dst_bindir = format!("lib/rustlib/{}/bin", target.triple);
+            for tool in LLVM_TOOLS {
+                let exe = src_bindir.join(exe(tool, target));
+                tarball.add_file(&exe, &dst_bindir, 0o755);
+            }
         }
 
         // Copy libLLVM.so to the target lib dir as well, so the RPATH like
diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs
index d1d6b7e869e..d9e0da14a70 100644
--- a/src/bootstrap/src/core/build_steps/run.rs
+++ b/src/bootstrap/src/core/build_steps/run.rs
@@ -148,9 +148,8 @@ impl Step for Miri {
         let target = self.target;
         let compiler = builder.compiler(stage, host);
 
-        let miri = builder
-            .ensure(tool::Miri { compiler, target: self.host, extra_features: Vec::new() })
-            .expect("in-tree tool");
+        let miri =
+            builder.ensure(tool::Miri { compiler, target: self.host, extra_features: Vec::new() });
         let miri_sysroot = test::Miri::build_miri_sysroot(builder, compiler, &miri, target);
 
         // # Run miri.
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index d0f36f99342..92140b00da8 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -427,9 +427,7 @@ impl Step for Rustfmt {
         let host = self.host;
         let compiler = builder.compiler(stage, host);
 
-        builder
-            .ensure(tool::Rustfmt { compiler, target: self.host, extra_features: Vec::new() })
-            .expect("in-tree tool");
+        builder.ensure(tool::Rustfmt { compiler, target: self.host, extra_features: Vec::new() });
 
         let mut cargo = tool::prepare_tool_cargo(
             builder,
@@ -476,9 +474,11 @@ impl Step for RustDemangler {
         let host = self.host;
         let compiler = builder.compiler(stage, host);
 
-        let rust_demangler = builder
-            .ensure(tool::RustDemangler { compiler, target: self.host, extra_features: Vec::new() })
-            .expect("in-tree tool");
+        let rust_demangler = builder.ensure(tool::RustDemangler {
+            compiler,
+            target: self.host,
+            extra_features: Vec::new(),
+        });
         let mut cargo = tool::prepare_tool_cargo(
             builder,
             compiler,
@@ -609,12 +609,13 @@ impl Step for Miri {
         // Except if we are at stage 2, the bootstrap loop is complete and we can stick with our current stage.
         let compiler_std = builder.compiler(if stage < 2 { stage + 1 } else { stage }, host);
 
-        let miri = builder
-            .ensure(tool::Miri { compiler, target: self.host, extra_features: Vec::new() })
-            .expect("in-tree tool");
-        let _cargo_miri = builder
-            .ensure(tool::CargoMiri { compiler, target: self.host, extra_features: Vec::new() })
-            .expect("in-tree tool");
+        let miri =
+            builder.ensure(tool::Miri { compiler, target: self.host, extra_features: Vec::new() });
+        let _cargo_miri = builder.ensure(tool::CargoMiri {
+            compiler,
+            target: self.host,
+            extra_features: Vec::new(),
+        });
         // The stdlib we need might be at a different stage. And just asking for the
         // sysroot does not seem to populate it, so we do that first.
         builder.ensure(compile::Std::new(compiler_std, host));
@@ -788,9 +789,7 @@ impl Step for Clippy {
         let host = self.host;
         let compiler = builder.compiler(stage, host);
 
-        builder
-            .ensure(tool::Clippy { compiler, target: self.host, extra_features: Vec::new() })
-            .expect("in-tree tool");
+        builder.ensure(tool::Clippy { compiler, target: self.host, extra_features: Vec::new() });
         let mut cargo = tool::prepare_tool_cargo(
             builder,
             compiler,
@@ -1668,13 +1667,11 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
         if mode == "coverage-run" {
             // The demangler doesn't need the current compiler, so we can avoid
             // unnecessary rebuilds by using the bootstrap compiler instead.
-            let rust_demangler = builder
-                .ensure(tool::RustDemangler {
-                    compiler: compiler.with_stage(0),
-                    target: compiler.host,
-                    extra_features: Vec::new(),
-                })
-                .expect("in-tree tool");
+            let rust_demangler = builder.ensure(tool::RustDemangler {
+                compiler: compiler.with_stage(0),
+                target: compiler.host,
+                extra_features: Vec::new(),
+            });
             cmd.arg("--rust-demangler-path").arg(rust_demangler);
         }
 
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index 8e3941dbeda..2cd42dd8081 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -27,7 +27,6 @@ struct ToolBuild {
     tool: &'static str,
     path: &'static str,
     mode: Mode,
-    is_optional_tool: bool,
     source_type: SourceType,
     extra_features: Vec<String>,
     /// Nightly-only features that are allowed (comma-separated list).
@@ -60,7 +59,7 @@ impl Builder<'_> {
 }
 
 impl Step for ToolBuild {
-    type Output = Option<PathBuf>;
+    type Output = PathBuf;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         run.never()
@@ -70,12 +69,11 @@ impl Step for ToolBuild {
     ///
     /// This will build the specified tool with the specified `host` compiler in
     /// `stage` into the normal cargo output directory.
-    fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
+    fn run(self, builder: &Builder<'_>) -> PathBuf {
         let compiler = self.compiler;
         let target = self.target;
         let mut tool = self.tool;
         let path = self.path;
-        let is_optional_tool = self.is_optional_tool;
 
         match self.mode {
             Mode::ToolRustc => {
@@ -109,20 +107,16 @@ impl Step for ToolBuild {
         );
 
         let mut cargo = Command::from(cargo);
-        // we check this in `is_optional_tool` in a second
-        let is_expected = builder.run_cmd(BootstrapCommand::from(&mut cargo).allow_failure());
+        // we check this below
+        let build_success = builder.run_cmd(BootstrapCommand::from(&mut cargo).allow_failure());
 
         builder.save_toolstate(
             tool,
-            if is_expected { ToolState::TestFail } else { ToolState::BuildFail },
+            if build_success { ToolState::TestFail } else { ToolState::BuildFail },
         );
 
-        if !is_expected {
-            if !is_optional_tool {
-                crate::exit!(1);
-            } else {
-                None
-            }
+        if !build_success {
+            crate::exit!(1);
         } else {
             // HACK(#82501): on Windows, the tools directory gets added to PATH when running tests, and
             // compiletest confuses HTML tidy with the in-tree tidy. Name the in-tree tidy something
@@ -133,7 +127,7 @@ impl Step for ToolBuild {
             let cargo_out = builder.cargo_out(compiler, self.mode, target).join(exe(tool, target));
             let bin = builder.tools_dir(compiler).join(exe(tool, target));
             builder.copy(&cargo_out, &bin);
-            Some(bin)
+            bin
         }
     }
 }
@@ -278,7 +272,6 @@ macro_rules! bootstrap_tool {
                         Mode::ToolBootstrap
                     },
                     path: $path,
-                    is_optional_tool: false,
                     source_type: if false $(|| $external)* {
                         SourceType::Submodule
                     } else {
@@ -286,7 +279,7 @@ macro_rules! bootstrap_tool {
                     },
                     extra_features: vec![],
                     allow_features: concat!($($allow_features)*),
-                }).expect("expected to build -- essential tool")
+                })
             }
         }
         )+
@@ -361,19 +354,16 @@ impl Step for ErrorIndex {
     }
 
     fn run(self, builder: &Builder<'_>) -> PathBuf {
-        builder
-            .ensure(ToolBuild {
-                compiler: self.compiler,
-                target: self.compiler.host,
-                tool: "error_index_generator",
-                mode: Mode::ToolRustc,
-                path: "src/tools/error_index_generator",
-                is_optional_tool: false,
-                source_type: SourceType::InTree,
-                extra_features: Vec::new(),
-                allow_features: "",
-            })
-            .expect("expected to build -- essential tool")
+        builder.ensure(ToolBuild {
+            compiler: self.compiler,
+            target: self.compiler.host,
+            tool: "error_index_generator",
+            mode: Mode::ToolRustc,
+            path: "src/tools/error_index_generator",
+            source_type: SourceType::InTree,
+            extra_features: Vec::new(),
+            allow_features: "",
+        })
     }
 }
 
@@ -398,19 +388,16 @@ impl Step for RemoteTestServer {
     }
 
     fn run(self, builder: &Builder<'_>) -> PathBuf {
-        builder
-            .ensure(ToolBuild {
-                compiler: self.compiler,
-                target: self.target,
-                tool: "remote-test-server",
-                mode: Mode::ToolStd,
-                path: "src/tools/remote-test-server",
-                is_optional_tool: false,
-                source_type: SourceType::InTree,
-                extra_features: Vec::new(),
-                allow_features: "",
-            })
-            .expect("expected to build -- essential tool")
+        builder.ensure(ToolBuild {
+            compiler: self.compiler,
+            target: self.target,
+            tool: "remote-test-server",
+            mode: Mode::ToolStd,
+            path: "src/tools/remote-test-server",
+            source_type: SourceType::InTree,
+            extra_features: Vec::new(),
+            allow_features: "",
+        })
     }
 }
 
@@ -557,19 +544,16 @@ impl Step for Cargo {
     }
 
     fn run(self, builder: &Builder<'_>) -> PathBuf {
-        let cargo_bin_path = builder
-            .ensure(ToolBuild {
-                compiler: self.compiler,
-                target: self.target,
-                tool: "cargo",
-                mode: Mode::ToolRustc,
-                path: "src/tools/cargo",
-                is_optional_tool: false,
-                source_type: SourceType::Submodule,
-                extra_features: Vec::new(),
-                allow_features: "",
-            })
-            .expect("expected to build -- essential tool");
+        let cargo_bin_path = builder.ensure(ToolBuild {
+            compiler: self.compiler,
+            target: self.target,
+            tool: "cargo",
+            mode: Mode::ToolRustc,
+            path: "src/tools/cargo",
+            source_type: SourceType::Submodule,
+            extra_features: Vec::new(),
+            allow_features: "",
+        });
         cargo_bin_path
     }
 }
@@ -588,19 +572,16 @@ impl Step for LldWrapper {
     }
 
     fn run(self, builder: &Builder<'_>) -> PathBuf {
-        let src_exe = builder
-            .ensure(ToolBuild {
-                compiler: self.compiler,
-                target: self.target,
-                tool: "lld-wrapper",
-                mode: Mode::ToolStd,
-                path: "src/tools/lld-wrapper",
-                is_optional_tool: false,
-                source_type: SourceType::InTree,
-                extra_features: Vec::new(),
-                allow_features: "",
-            })
-            .expect("expected to build -- essential tool");
+        let src_exe = builder.ensure(ToolBuild {
+            compiler: self.compiler,
+            target: self.target,
+            tool: "lld-wrapper",
+            mode: Mode::ToolStd,
+            path: "src/tools/lld-wrapper",
+            source_type: SourceType::InTree,
+            extra_features: Vec::new(),
+            allow_features: "",
+        });
 
         src_exe
     }
@@ -617,7 +598,7 @@ impl RustAnalyzer {
 }
 
 impl Step for RustAnalyzer {
-    type Output = Option<PathBuf>;
+    type Output = PathBuf;
     const DEFAULT: bool = true;
     const ONLY_HOSTS: bool = true;
 
@@ -640,7 +621,7 @@ impl Step for RustAnalyzer {
         });
     }
 
-    fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
+    fn run(self, builder: &Builder<'_>) -> PathBuf {
         builder.ensure(ToolBuild {
             compiler: self.compiler,
             target: self.target,
@@ -648,7 +629,6 @@ impl Step for RustAnalyzer {
             mode: Mode::ToolRustc,
             path: "src/tools/rust-analyzer",
             extra_features: vec!["rust-analyzer/in-rust-tree".to_owned()],
-            is_optional_tool: false,
             source_type: SourceType::InTree,
             allow_features: RustAnalyzer::ALLOW_FEATURES,
         })
@@ -696,10 +676,9 @@ impl Step for RustAnalyzerProcMacroSrv {
             mode: Mode::ToolStd,
             path: "src/tools/rust-analyzer/crates/proc-macro-srv-cli",
             extra_features: vec!["sysroot-abi".to_owned()],
-            is_optional_tool: false,
             source_type: SourceType::InTree,
             allow_features: RustAnalyzer::ALLOW_FEATURES,
-        })?;
+        });
 
         // Copy `rust-analyzer-proc-macro-srv` to `<sysroot>/libexec/`
         // so that r-a can use it.
@@ -730,7 +709,7 @@ macro_rules! tool_extended {
         }
 
         impl Step for $name {
-            type Output = Option<PathBuf>;
+            type Output = PathBuf;
             const DEFAULT: bool = true; // Overwritten below
             const ONLY_HOSTS: bool = true;
 
@@ -761,7 +740,7 @@ macro_rules! tool_extended {
             }
 
             #[allow(unused_mut)]
-            fn run(mut $sel, $builder: &Builder<'_>) -> Option<PathBuf> {
+            fn run(mut $sel, $builder: &Builder<'_>) -> PathBuf {
                 let tool = $builder.ensure(ToolBuild {
                     compiler: $sel.compiler,
                     target: $sel.target,
@@ -769,10 +748,9 @@ macro_rules! tool_extended {
                     mode: if false $(|| $tool_std)? { Mode::ToolStd } else { Mode::ToolRustc },
                     path: $path,
                     extra_features: $sel.extra_features,
-                    is_optional_tool: true,
                     source_type: SourceType::InTree,
                     allow_features: concat!($($allow_features)*),
-                })?;
+                });
 
                 if (false $(|| !$add_bins_to_sysroot.is_empty())?) && $sel.compiler.stage > 0 {
                     let bindir = $builder.sysroot($sel.compiler).join("bin");
@@ -789,9 +767,9 @@ macro_rules! tool_extended {
                     })?
 
                     let tool = bindir.join(exe($tool_name, $sel.compiler.host));
-                    Some(tool)
+                    tool
                 } else {
-                    Some(tool)
+                    tool
                 }
             }
         }
diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs
index 753b41abaf4..e85753a3512 100644
--- a/src/bootstrap/src/core/builder.rs
+++ b/src/bootstrap/src/core/builder.rs
@@ -1198,7 +1198,7 @@ impl<'a> Builder<'a> {
         let mut dylib_path = helpers::dylib_path();
         dylib_path.insert(0, self.sysroot(run_compiler).join("lib"));
 
-        let mut cmd = Command::new(cargo_clippy.unwrap());
+        let mut cmd = Command::new(cargo_clippy);
         cmd.env(helpers::dylib_path_var(), env::join_paths(&dylib_path).unwrap());
         cmd.env("PATH", path);
         cmd
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index f1e1b89d9ba..c6bf71c8837 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -305,7 +305,7 @@ pub struct Config {
     pub save_toolstates: Option<PathBuf>,
     pub print_step_timings: bool,
     pub print_step_rusage: bool,
-    pub missing_tools: bool,
+    pub missing_tools: bool, // FIXME: Deprecated field. Remove it at 2024.
 
     // Fallback musl-root for all targets
     pub musl_root: Option<PathBuf>,
@@ -1630,7 +1630,7 @@ impl Config {
                 );
             }
 
-            set(&mut config.llvm_tools_enabled, llvm_tools);
+            config.llvm_tools_enabled = llvm_tools.unwrap_or(true);
             config.rustc_parallel =
                 parallel_compiler.unwrap_or(config.channel == "dev" || config.channel == "nightly");
             config.rustc_default_linker = default_linker;
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index 1eadc036b5e..25efa5079c8 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -101,4 +101,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Warning,
         summary: "rust-analyzer-proc-macro-srv is no longer enabled by default. To build it, you must either enable it in the configuration or explicitly invoke it with x.py.",
     },
+    ChangeInfo {
+        change_id: 119373,
+        severity: ChangeSeverity::Info,
+        summary: "The dist.missing-tools config option was deprecated, as it was unused. If you are using it, remove it from your config, it will be removed soon.",
+    },
 ];
diff --git a/src/ci/docker/host-x86_64/dist-powerpc-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-powerpc-linux/Dockerfile
index b546f571f66..7081d9527f0 100644
--- a/src/ci/docker/host-x86_64/dist-powerpc-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-powerpc-linux/Dockerfile
@@ -26,5 +26,5 @@ ENV \
 
 ENV HOSTS=powerpc-unknown-linux-gnu
 
-ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
+ENV RUST_CONFIGURE_ARGS --enable-extended --enable-profiler --disable-docs
 ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/run.sh b/src/ci/run.sh
index 5700172fd3e..e48fac1a087 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -153,10 +153,6 @@ else
   fi
 fi
 
-if [ "$RUST_RELEASE_CHANNEL" = "nightly" ] || [ "$DIST_REQUIRE_ALL_TOOLS" = "" ]; then
-    RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-missing-tools"
-fi
-
 # Unless we're using an older version of LLVM, check that all LLVM components
 # used by tests are available.
 if [ "$IS_NOT_LATEST_LLVM" = "" ]; then
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index e824a1fd4bd..e6263db3283 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -1805,11 +1805,20 @@ function initSearch(rawSearchIndex) {
             return unifyFunctionTypes([row], [elem], whereClause, mgens);
         }
 
-        function checkPath(contains, ty, maxEditDistance) {
+        /**
+         * Compute an "edit distance" that ignores missing path elements.
+         * @param {string[]} contains search query path
+         * @param {Row} ty indexed item
+         * @returns {null|number} edit distance
+         */
+        function checkPath(contains, ty) {
             if (contains.length === 0) {
                 return 0;
             }
-            let ret_dist = maxEditDistance + 1;
+            const maxPathEditDistance = Math.floor(
+                contains.reduce((acc, next) => acc + next.length, 0) / 3
+            );
+            let ret_dist = maxPathEditDistance + 1;
             const path = ty.path.split("::");
 
             if (ty.parent && ty.parent.name) {
@@ -1821,15 +1830,23 @@ function initSearch(rawSearchIndex) {
             pathiter: for (let i = length - clength; i >= 0; i -= 1) {
                 let dist_total = 0;
                 for (let x = 0; x < clength; ++x) {
-                    const dist = editDistance(path[i + x], contains[x], maxEditDistance);
-                    if (dist > maxEditDistance) {
-                        continue pathiter;
+                    const [p, c] = [path[i + x], contains[x]];
+                    if (Math.floor((p.length - c.length) / 3) <= maxPathEditDistance &&
+                        p.indexOf(c) !== -1
+                    ) {
+                        // discount distance on substring match
+                        dist_total += Math.floor((p.length - c.length) / 3);
+                    } else {
+                        const dist = editDistance(p, c, maxPathEditDistance);
+                        if (dist > maxPathEditDistance) {
+                            continue pathiter;
+                        }
+                        dist_total += dist;
                     }
-                    dist_total += dist;
                 }
                 ret_dist = Math.min(ret_dist, Math.round(dist_total / clength));
             }
-            return ret_dist;
+            return ret_dist > maxPathEditDistance ? null : ret_dist;
         }
 
         function typePassesFilter(filter, type) {
@@ -2030,8 +2047,8 @@ function initSearch(rawSearchIndex) {
             }
 
             if (elem.fullPath.length > 1) {
-                path_dist = checkPath(elem.pathWithoutLast, row, maxEditDistance);
-                if (path_dist > maxEditDistance) {
+                path_dist = checkPath(elem.pathWithoutLast, row);
+                if (path_dist === null) {
                     return;
                 }
             }
@@ -2045,7 +2062,7 @@ function initSearch(rawSearchIndex) {
 
             const dist = editDistance(row.normalizedName, elem.normalizedPathLast, maxEditDistance);
 
-            if (index === -1 && dist + path_dist > maxEditDistance) {
+            if (index === -1 && dist > maxEditDistance) {
                 return;
             }
 
@@ -2100,13 +2117,9 @@ function initSearch(rawSearchIndex) {
         }
 
         function innerRunQuery() {
-            let queryLen = 0;
-            for (const elem of parsedQuery.elems) {
-                queryLen += elem.name.length;
-            }
-            for (const elem of parsedQuery.returned) {
-                queryLen += elem.name.length;
-            }
+            const queryLen =
+                parsedQuery.elems.reduce((acc, next) => acc + next.pathLast.length, 0) +
+                parsedQuery.returned.reduce((acc, next) => acc + next.pathLast.length, 0);
             const maxEditDistance = Math.floor(queryLen / 3);
 
             /**
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 70aff7f60e0..f82421a687b 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6,11 +6,68 @@ document.
 
 ## Unreleased / Beta / In Rust Nightly
 
-[7671c283...master](https://github.com/rust-lang/rust-clippy/compare/7671c283...master)
+[09ac14c9...master](https://github.com/rust-lang/rust-clippy/compare/09ac14c9...master)
+
+## Rust 1.75
+
+Current stable, released 2023-12-28
+
+[View all 69 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-09-25T11%3A47%3A47Z..2023-11-02T16%3A41%3A59Z+base%3Amaster)
+
+### New Lints
+
+* [`unused_enumerate_index`]
+  [#10404](https://github.com/rust-lang/rust-clippy/pull/10404)
+* [`unnecessary_fallible_conversions`]
+  [#11669](https://github.com/rust-lang/rust-clippy/pull/11669)
+* [`waker_clone_wake`]
+  [#11698](https://github.com/rust-lang/rust-clippy/pull/11698)
+* [`struct_field_names`]
+  [#11496](https://github.com/rust-lang/rust-clippy/pull/11496)
+* [`into_iter_without_iter`]
+  [#11587](https://github.com/rust-lang/rust-clippy/pull/11587)
+* [`iter_without_into_iter`]
+  [#11527](https://github.com/rust-lang/rust-clippy/pull/11527)
+* [`manual_hash_one`]
+  [#11556](https://github.com/rust-lang/rust-clippy/pull/11556)
+
+
+### Moves and Deprecations
+
+* Moved [`read_zero_byte_vec`] to `nursery` (Now allow-by-default)
+  [#11727](https://github.com/rust-lang/rust-clippy/pull/11727)
+* Moved [`missing_enforced_import_renames`] to `style` (Now warn-by-default)
+  [#11539](https://github.com/rust-lang/rust-clippy/pull/11539)
+* Moved [`needless_raw_string_hashes`] to `pedantic` (Now allow-by-default)
+  [#11415](https://github.com/rust-lang/rust-clippy/pull/11415)
+* Moved [`needless_pass_by_ref_mut`] to `nursery` (Now allow-by-default)
+  [#11596](https://github.com/rust-lang/rust-clippy/pull/11596)
+
+### Enhancements
+
+* [`declare_interior_mutable_const`] and [`borrow_interior_mutable_const`]: Now check the
+  [`ignore-interior-mutability`] config value
+  [#11678](https://github.com/rust-lang/rust-clippy/pull/11678)
+
+### Suggestion Fixes/Improvements
+
+* [`items_after_test_module`]: The suggestion is now machine-applicable
+  [#11611](https://github.com/rust-lang/rust-clippy/pull/11611)
+
+### ICE Fixes
+
+* [`redundant_locals`]: No longer crashes if variables are rebound above macros
+  [#11623](https://github.com/rust-lang/rust-clippy/pull/11623)
+* [`implicit_hasher`]: No longer lints inside macros, which could cause ICEs
+  [#11593](https://github.com/rust-lang/rust-clippy/pull/11593)
+
+### Documentation Improvements
+
+* `cargo clippy --help` now uses colors for readability :tada:
 
 ## Rust 1.74
 
-Current stable, released 2023-11-16
+Released 2023-11-16
 
 [View all 94 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-08-11T15%3A29%3A18Z..2023-09-25T08%3A48%3A22Z+base%3Amaster)
 
@@ -51,7 +108,7 @@ Current stable, released 2023-11-16
 ### Enhancements
 
 * [`undocumented_unsafe_blocks`]: The config values [`accept-comment-above-statement`] and 
-  [`accept-comment-above-attributes`] to `true` by default
+  [`accept-comment-above-attributes`] are now `true` by default
   [#11170](https://github.com/rust-lang/rust-clippy/pull/11170)
 * [`explicit_iter_loop`]: Added [`enforce-iter-loop-reborrow`] to disable reborrow linting by default
   [#11418](https://github.com/rust-lang/rust-clippy/pull/11418)
@@ -5044,6 +5101,7 @@ Released 2018-09-13
 [`duplicate_mod`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_mod
 [`duplicate_underscore_argument`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_underscore_argument
 [`duration_subsec`]: https://rust-lang.github.io/rust-clippy/master/index.html#duration_subsec
+[`eager_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#eager_transmute
 [`else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else
 [`empty_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_drop
 [`empty_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_enum
@@ -5177,6 +5235,8 @@ Released 2018-09-13
 [`items_after_test_module`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_test_module
 [`iter_cloned_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect
 [`iter_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_count
+[`iter_filter_is_ok`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_filter_is_ok
+[`iter_filter_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_filter_is_some
 [`iter_kv_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_kv_map
 [`iter_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop
 [`iter_next_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_slice
@@ -5470,6 +5530,7 @@ Released 2018-09-13
 [`reserve_after_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#reserve_after_initialization
 [`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs
 [`result_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_expect_used
+[`result_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_filter_map
 [`result_large_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err
 [`result_map_or_into_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_or_into_option
 [`result_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unit_fn
@@ -5582,6 +5643,7 @@ Released 2018-09-13
 [`type_id_on_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_id_on_box
 [`type_repetition_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds
 [`unchecked_duration_subtraction`]: https://rust-lang.github.io/rust-clippy/master/index.html#unchecked_duration_subtraction
+[`unconditional_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#unconditional_recursion
 [`undocumented_unsafe_blocks`]: https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks
 [`undropped_manually_drops`]: https://rust-lang.github.io/rust-clippy/master/index.html#undropped_manually_drops
 [`unicode_not_nfc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unicode_not_nfc
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index f6084a46272..eda20531e40 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy"
-version = "0.1.76"
+version = "0.1.77"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index 2bb89321cef..7c9a8eb1bfb 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -212,7 +212,7 @@ default configuration of Clippy. By default, any configuration will replace the
 * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`.
 * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list.
 
-**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]`
+**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "WebGL2", "WebGPU", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]`
 
 ---
 **Affected lints:**
diff --git a/src/tools/clippy/clippy_config/Cargo.toml b/src/tools/clippy/clippy_config/Cargo.toml
index 20f31320127..74b8e5eaa1c 100644
--- a/src/tools/clippy/clippy_config/Cargo.toml
+++ b/src/tools/clippy/clippy_config/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_config"
-version = "0.1.76"
+version = "0.1.77"
 edition = "2021"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs
index 3cf4377002a..a4f368397ce 100644
--- a/src/tools/clippy/clippy_config/src/conf.rs
+++ b/src/tools/clippy/clippy_config/src/conf.rs
@@ -27,7 +27,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[
     "OAuth", "GraphQL",
     "OCaml",
     "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS",
-    "WebGL",
+    "WebGL", "WebGL2", "WebGPU",
     "TensorFlow",
     "TrueType",
     "iOS", "macOS", "FreeBSD",
@@ -640,7 +640,8 @@ impl Conf {
                 }
             },
             Err(error) => {
-                sess.dcx().err(format!("error finding Clippy's configuration file: {error}"));
+                sess.dcx()
+                    .err(format!("error finding Clippy's configuration file: {error}"));
             },
         }
 
diff --git a/src/tools/clippy/clippy_config/src/msrvs.rs b/src/tools/clippy/clippy_config/src/msrvs.rs
index 13e61e5a032..471ad73e207 100644
--- a/src/tools/clippy/clippy_config/src/msrvs.rs
+++ b/src/tools/clippy/clippy_config/src/msrvs.rs
@@ -41,6 +41,7 @@ msrv_aliases! {
     1,35,0 { OPTION_COPIED, RANGE_CONTAINS }
     1,34,0 { TRY_FROM }
     1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES }
+    1,29,0 { ITER_FLATTEN }
     1,28,0 { FROM_BOOL }
     1,27,0 { ITERATOR_TRY_FOLD }
     1,26,0 { RANGE_INCLUSIVE, STRING_RETAIN }
@@ -106,7 +107,8 @@ impl Msrv {
 
         if let Some(msrv_attr) = msrv_attrs.next() {
             if let Some(duplicate) = msrv_attrs.last() {
-                sess.dcx().struct_span_err(duplicate.span, "`clippy::msrv` is defined multiple times")
+                sess.dcx()
+                    .struct_span_err(duplicate.span, "`clippy::msrv` is defined multiple times")
                     .span_note(msrv_attr.span, "first definition found here")
                     .emit();
             }
@@ -116,7 +118,8 @@ impl Msrv {
                     return Some(version);
                 }
 
-                sess.dcx().span_err(msrv_attr.span, format!("`{msrv}` is not a valid Rust version"));
+                sess.dcx()
+                    .span_err(msrv_attr.span, format!("`{msrv}` is not a valid Rust version"));
             } else {
                 sess.dcx().span_err(msrv_attr.span, "bad clippy attribute");
             }
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index ad8b7ded46b..8cba35f3d87 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_lints"
-version = "0.1.76"
+version = "0.1.77"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
index a15ec199a28..1e327f7a6df 100644
--- a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
+++ b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
@@ -1,7 +1,7 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{constant_with_source, Constant, ConstantSource};
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn};
-use rustc_hir::Expr;
+use rustc_hir::{Expr, Item, ItemKind, Node};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
@@ -42,9 +42,18 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants {
         let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn) else {
             return;
         };
-        let Some(Constant::Bool(val)) = constant(cx, cx.typeck_results(), condition) else {
+        let Some((Constant::Bool(val), source)) = constant_with_source(cx, cx.typeck_results(), condition) else {
             return;
         };
+        if let ConstantSource::Constant = source
+            && let Some(node) = cx.tcx.hir().find_parent(e.hir_id)
+            && let Node::Item(Item {
+                kind: ItemKind::Const(..),
+                ..
+            }) = node
+        {
+            return;
+        }
         if val {
             span_lint_and_help(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/async_yields_async.rs b/src/tools/clippy/clippy_lints/src/async_yields_async.rs
index c965341d3fd..bb08ac7508b 100644
--- a/src/tools/clippy/clippy_lints/src/async_yields_async.rs
+++ b/src/tools/clippy/clippy_lints/src/async_yields_async.rs
@@ -2,9 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::implements_trait;
 use rustc_errors::Applicability;
-use rustc_hir::{
-    Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, QPath,
-};
+use rustc_hir::{Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 1220eb89013..eae9dfac064 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -369,6 +369,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::ITERATOR_STEP_BY_ZERO_INFO,
     crate::methods::ITER_CLONED_COLLECT_INFO,
     crate::methods::ITER_COUNT_INFO,
+    crate::methods::ITER_FILTER_IS_OK_INFO,
+    crate::methods::ITER_FILTER_IS_SOME_INFO,
     crate::methods::ITER_KV_MAP_INFO,
     crate::methods::ITER_NEXT_SLICE_INFO,
     crate::methods::ITER_NTH_INFO,
@@ -419,6 +421,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::READ_LINE_WITHOUT_TRIM_INFO,
     crate::methods::REDUNDANT_AS_STR_INFO,
     crate::methods::REPEAT_ONCE_INFO,
+    crate::methods::RESULT_FILTER_MAP_INFO,
     crate::methods::RESULT_MAP_OR_INTO_OPTION_INFO,
     crate::methods::SEARCH_IS_SOME_INFO,
     crate::methods::SEEK_FROM_CURRENT_INFO,
@@ -650,6 +653,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS_INFO,
     crate::trait_bounds::TYPE_REPETITION_IN_BOUNDS_INFO,
     crate::transmute::CROSSPOINTER_TRANSMUTE_INFO,
+    crate::transmute::EAGER_TRANSMUTE_INFO,
     crate::transmute::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS_INFO,
     crate::transmute::TRANSMUTE_BYTES_TO_STR_INFO,
     crate::transmute::TRANSMUTE_FLOAT_TO_INT_INFO,
@@ -676,6 +680,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::types::REDUNDANT_ALLOCATION_INFO,
     crate::types::TYPE_COMPLEXITY_INFO,
     crate::types::VEC_BOX_INFO,
+    crate::unconditional_recursion::UNCONDITIONAL_RECURSION_INFO,
     crate::undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS_INFO,
     crate::undocumented_unsafe_blocks::UNNECESSARY_SAFETY_COMMENT_INFO,
     crate::unicode::INVISIBLE_CHARACTERS_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs
index 9ce5acfbcc2..71e1a25c2bc 100644
--- a/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs
+++ b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs
@@ -42,7 +42,7 @@ declare_clippy_lint! {
     #[clippy::version = "1.71.0"]
     pub DEFAULT_CONSTRUCTED_UNIT_STRUCTS,
     complexity,
-    "unit structs can be contructed without calling `default`"
+    "unit structs can be constructed without calling `default`"
 }
 declare_lint_pass!(DefaultConstructedUnitStructs => [DEFAULT_CONSTRUCTED_UNIT_STRUCTS]);
 
diff --git a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
index 4cbfa97a8a3..26f120cb33f 100644
--- a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
@@ -72,7 +72,7 @@ pub fn check(
             && let body = cx.tcx.hir().body(body_id)
             && let ret_ty = typeck.expr_ty(body.value)
             && implements_trait(cx, ret_ty, future, &[])
-            && let ty::Coroutine(_, subs, _) = ret_ty.kind()
+            && let ty::Coroutine(_, subs) = ret_ty.kind()
             && is_type_diagnostic_item(cx, subs.as_coroutine().return_ty(), sym::Result)
         {
             span_lint(
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 3901dd984f9..2b08437d827 100644
--- a/src/tools/clippy/clippy_lints/src/format_push_string.rs
+++ b/src/tools/clippy/clippy_lints/src/format_push_string.rs
@@ -57,7 +57,7 @@ fn is_format(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
             Some(higher::IfLetOrMatch::Match(_, arms, MatchSource::Normal)) => {
                 arms.iter().any(|arm| is_format(cx, arm.body))
             },
-            Some(higher::IfLetOrMatch::IfLet(_, _, then, r#else)) => {
+            Some(higher::IfLetOrMatch::IfLet(_, _, then, r#else, _)) => {
                 is_format(cx, then) || r#else.is_some_and(|e| is_format(cx, e))
             },
             _ => false,
diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
index 0f5a9ea5d84..fab8ffedb94 100644
--- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
@@ -158,7 +158,7 @@ fn try_resolve_type<'tcx>(
 
 /// This function tries to, for all generic type parameters in a supertrait predicate `trait ...<U>:
 /// GenericTrait<U>`, check if the substituted type in the implied-by bound matches with what's
-/// subtituted in the implied bound.
+/// substituted in the implied bound.
 ///
 /// Consider this example.
 /// ```rust,ignore
diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
index 0ae03d101ab..391db0b0df7 100644
--- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
@@ -170,7 +170,23 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
                         return;
                     }
                     // Index is a constant uint.
-                    if constant(cx, cx.typeck_results(), index).is_some() {
+                    if let Some(constant) = constant(cx, cx.typeck_results(), index) {
+                        // only `usize` index is legal in rust array index
+                        // leave other type to rustc
+                        if let Constant::Int(off) = constant
+                            && let ty::Uint(utype) = cx.typeck_results().expr_ty(index).kind()
+                            && *utype == ty::UintTy::Usize
+                            && let ty::Array(_, s) = ty.kind()
+                            && let Some(size) = s.try_eval_target_usize(cx.tcx, cx.param_env)
+                        {
+                            // get constant offset and check whether it is in bounds
+                            let off = usize::try_from(off).unwrap();
+                            let size = usize::try_from(size).unwrap();
+
+                            if off >= size {
+                                span_lint(cx, OUT_OF_BOUNDS_INDEXING, expr.span, "index is out of bounds");
+                            }
+                        }
                         // Let rustc's `const_err` lint handle constant `usize` indexing on arrays.
                         return;
                     }
diff --git a/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs b/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs
index 955f90d4262..af5b1f95739 100644
--- a/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs
+++ b/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs
@@ -16,7 +16,7 @@ declare_clippy_lint! {
     ///
     /// ### Why is this bad?
     /// `.append(true)` already enables `write(true)`, making this one
-    /// superflous.
+    /// superfluous.
     ///
     /// ### Example
     /// ```no_run
diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
index 3a5756482a1..c9dc48668f2 100644
--- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
@@ -49,7 +49,7 @@ declare_clippy_lint! {
     ///     }
     /// }
     /// ```
-    #[clippy::version = "1.74.0"]
+    #[clippy::version = "1.75.0"]
     pub ITER_WITHOUT_INTO_ITER,
     pedantic,
     "implementing `iter(_mut)` without an associated `IntoIterator for (&|&mut) Type` impl"
@@ -101,7 +101,7 @@ declare_clippy_lint! {
     ///     }
     /// }
     /// ```
-    #[clippy::version = "1.74.0"]
+    #[clippy::version = "1.75.0"]
     pub INTO_ITER_WITHOUT_ITER,
     pedantic,
     "implementing `IntoIterator for (&|&mut) Type` without an inherent `iter(_mut)` method"
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 8c032b17023..c09d3d1862b 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -8,8 +8,8 @@ use rustc_hir::def::Res;
 use rustc_hir::def_id::{DefId, DefIdSet};
 use rustc_hir::{
     AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind,
-    ImplicitSelfKind, Item, ItemKind, Mutability, Node, PatKind, PathSegment, PrimTy, QPath, TraitItemRef,
-    TyKind, TypeBindingKind, OpaqueTyOrigin,
+    ImplicitSelfKind, Item, ItemKind, Mutability, Node, OpaqueTyOrigin, PatKind, PathSegment, PrimTy, QPath,
+    TraitItemRef, TyKind, TypeBindingKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 7758d6a58e6..755a4ff525d 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -22,6 +22,7 @@
 // FIXME: switch to something more ergonomic here, once available.
 // (Currently there is no way to opt into sysroot crates without `extern crate`.)
 extern crate pulldown_cmark;
+extern crate rustc_abi;
 extern crate rustc_arena;
 extern crate rustc_ast;
 extern crate rustc_ast_pretty;
@@ -327,6 +328,7 @@ mod trait_bounds;
 mod transmute;
 mod tuple_array_conversions;
 mod types;
+mod unconditional_recursion;
 mod undocumented_unsafe_blocks;
 mod unicode;
 mod uninhabited_references;
@@ -1078,6 +1080,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(|_| Box::new(repeat_vec_with_capacity::RepeatVecWithCapacity));
     store.register_late_pass(|_| Box::new(uninhabited_references::UninhabitedReferences));
     store.register_late_pass(|_| Box::new(ineffective_open_options::IneffectiveOpenOptions));
+    store.register_late_pass(|_| Box::new(unconditional_recursion::UnconditionalRecursion));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs b/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs
index 9b88dd76e5c..5e099f1e76f 100644
--- a/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs
@@ -49,7 +49,7 @@ pub(super) fn check<'tcx>(
             if let FnRetTy::DefaultReturn(ret_span) = parent_fn_ret {
                 diag.span_suggestion(
                     ret_span,
-                    "if this is intentional, consider specifing `!` as function return",
+                    "if this is intentional, consider specifying `!` as function return",
                     " -> !",
                     Applicability::MaybeIncorrect,
                 );
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
index a726b116956..36de9021f49 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
@@ -20,7 +20,7 @@ pub(super) fn check<'tcx>(
     span: Span,
 ) {
     let inner_expr = peel_blocks_with_stmt(body);
-    if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: None })
+    if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: None, .. })
             = higher::IfLet::hir(cx, inner_expr)
         // Ensure match_expr in `if let` statement is the same as the pat from the for-loop
         && let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind
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 21b9efba54c..d070ee74985 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
@@ -14,7 +14,7 @@ use rustc_span::symbol::sym;
 use rustc_span::Symbol;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-    if let Some(higher::WhileLet { if_then, let_pat, let_expr }) = higher::WhileLet::hir(expr)
+    if let Some(higher::WhileLet { if_then, let_pat, let_expr, .. }) = higher::WhileLet::hir(expr)
         // check for `Some(..)` pattern
         && let PatKind::TupleStruct(ref pat_path, some_pat, _) = let_pat.kind
         && is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome)
diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
index 9ba1d3afcbe..4cd5f3b81e5 100644
--- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
@@ -3,9 +3,9 @@ use clippy_utils::source::{position_before_rarrow, snippet_block, snippet_opt};
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
-    Block, Body, Closure, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, FnDecl, FnRetTy,
-    GenericArg, GenericBound, ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind,
-    TypeBindingKind, ClosureKind,
+    Block, Body, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, FnDecl,
+    FnRetTy, GenericArg, GenericBound, ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind,
+    TypeBindingKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
@@ -172,23 +172,13 @@ fn captures_all_lifetimes(inputs: &[Ty<'_>], output_lifetimes: &[LifetimeName])
             .all(|in_lt| output_lifetimes.iter().any(|out_lt| in_lt == out_lt))
 }
 
-fn desugared_async_block<'tcx>(
-    cx: &LateContext<'tcx>,
-    block: &'tcx Block<'tcx>,
-) -> Option<&'tcx Body<'tcx>> {
+fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> Option<&'tcx Body<'tcx>> {
     if let Some(Expr {
-        kind:
-            ExprKind::Closure(&Closure {
-                kind:
-                    ClosureKind::Coroutine(CoroutineKind::Desugared(
-                        CoroutineDesugaring::Async,
-                        CoroutineSource::Block,
-                    )),
-                body,
-                ..
-            }),
+        kind: ExprKind::Closure(&Closure { kind, body, .. }),
         ..
     }) = block.expr
+        && let ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block)) =
+            kind
     {
         return Some(cx.tcx.hir().body(body));
     }
diff --git a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs
index 252b3a83a18..73687fbbe54 100644
--- a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs
@@ -40,7 +40,7 @@ declare_clippy_lint! {
     ///
     /// let hash = s.hash_one(&value);
     /// ```
-    #[clippy::version = "1.74.0"]
+    #[clippy::version = "1.75.0"]
     pub MANUAL_HASH_ONE,
     complexity,
     "manual implementations of `BuildHasher::hash_one`"
diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
index 92dc4d57ab1..fdf8fa4e277 100644
--- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
@@ -61,7 +61,7 @@ impl<'tcx> QuestionMark {
             && let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init)
         {
             match if_let_or_match {
-                IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else) => {
+                IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else, ..) => {
                     if let Some(ident_map) = expr_simple_identity_map(local.pat, let_pat, if_then)
                         && let Some(if_else) = if_else
                         && is_never_expr(cx, if_else).is_some()
diff --git a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
index 48fc5746b3c..91e6ca7fa8b 100644
--- a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
@@ -41,7 +41,7 @@ fn check_arm<'tcx>(
     let inner_expr = peel_blocks_with_stmt(outer_then_body);
     if let Some(inner) = IfLetOrMatch::parse(cx, inner_expr)
         && let Some((inner_scrutinee, inner_then_pat, inner_else_body)) = match inner {
-            IfLetOrMatch::IfLet(scrutinee, pat, _, els) => Some((scrutinee, pat, els)),
+            IfLetOrMatch::IfLet(scrutinee, pat, _, els, _) => Some((scrutinee, pat, els)),
             IfLetOrMatch::Match(scrutinee, arms, ..) => if arms.len() == 2 && arms.iter().all(|a| a.guard.is_none())
                 // if there are more than two arms, collapsing would be non-trivial
                 // one of the arms must be "wild-like"
@@ -75,7 +75,7 @@ fn check_arm<'tcx>(
         )
         // ...or anywhere in the inner expression
         && match inner {
-            IfLetOrMatch::IfLet(_, _, body, els) => {
+            IfLetOrMatch::IfLet(_, _, body, els, _) => {
                 !is_local_used(cx, body, binding_id) && els.map_or(true, |e| !is_local_used(cx, e, binding_id))
             },
             IfLetOrMatch::Match(_, arms, ..) => !arms.iter().any(|arm| is_local_used(cx, arm, binding_id)),
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
index 0627e458dfe..152aba99ce9 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
@@ -63,9 +63,7 @@ where
         return None;
     }
 
-    let Some(some_expr) = get_some_expr_fn(cx, some_pat, some_expr, expr_ctxt) else {
-        return None;
-    };
+    let some_expr = get_some_expr_fn(cx, some_pat, some_expr, expr_ctxt)?;
 
     // These two lints will go back and forth with each other.
     if cx.typeck_results().expr_ty(some_expr.expr) == cx.tcx.types.unit
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index 4c7568f39b4..50494f4819f 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -469,15 +469,15 @@ declare_clippy_lint! {
 declare_clippy_lint! {
     /// ### What it does
     /// Lint for redundant pattern matching over `Result`, `Option`,
-    /// `std::task::Poll` or `std::net::IpAddr`
+    /// `std::task::Poll`, `std::net::IpAddr` or `bool`s
     ///
     /// ### Why is this bad?
     /// It's more concise and clear to just use the proper
-    /// utility function
+    /// utility function or using the condition directly
     ///
     /// ### Known problems
-    /// This will change the drop order for the matched type. Both `if let` and
-    /// `while let` will drop the value at the end of the block, both `if` and `while` will drop the
+    /// For suggestions involving bindings in patterns, this will change the drop order for the matched type.
+    /// Both `if let` and `while let` will drop the value at the end of the block, both `if` and `while` will drop the
     /// value before entering the block. For most types this change will not matter, but for a few
     /// types this will not be an acceptable change (e.g. locks). See the
     /// [reference](https://doc.rust-lang.org/reference/destructors.html#drop-scopes) for more about
@@ -499,6 +499,10 @@ declare_clippy_lint! {
     ///     Ok(_) => true,
     ///     Err(_) => false,
     /// };
+    ///
+    /// let cond = true;
+    /// if let true = cond {}
+    /// matches!(cond, true);
     /// ```
     ///
     /// The more idiomatic use would be:
@@ -515,6 +519,10 @@ declare_clippy_lint! {
     /// if IpAddr::V4(Ipv4Addr::LOCALHOST).is_ipv4() {}
     /// if IpAddr::V6(Ipv6Addr::LOCALHOST).is_ipv6() {}
     /// Ok::<i32, i32>(42).is_ok();
+    ///
+    /// let cond = true;
+    /// if cond {}
+    /// cond;
     /// ```
     #[clippy::version = "1.31.0"]
     pub REDUNDANT_PATTERN_MATCHING,
@@ -1019,8 +1027,11 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
         let from_expansion = expr.span.from_expansion();
 
         if let ExprKind::Match(ex, arms, source) = expr.kind {
-            if is_direct_expn_of(expr.span, "matches").is_some() {
+            if is_direct_expn_of(expr.span, "matches").is_some()
+                && let [arm, _] = arms
+            {
                 redundant_pattern_match::check_match(cx, expr, ex, arms);
+                redundant_pattern_match::check_matches_true(cx, expr, arm, ex);
             }
 
             if source == MatchSource::Normal && !is_span_match(cx, expr.span) {
@@ -1104,6 +1115,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
                     if_let.let_pat,
                     if_let.let_expr,
                     if_let.if_else.is_some(),
+                    if_let.let_span,
                 );
                 needless_match::check_if_let(cx, expr, &if_let);
             }
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 2582f7edcf6..a4acdfb1db4 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
@@ -1,7 +1,7 @@
 use super::REDUNDANT_PATTERN_MATCHING;
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::{snippet, walk_span_to_context};
-use clippy_utils::sugg::Sugg;
+use clippy_utils::sugg::{make_unop, Sugg};
 use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop};
 use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr};
 use clippy_utils::{higher, is_expn_of, is_trait_method};
@@ -12,13 +12,20 @@ use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady,
 use rustc_hir::{Arm, Expr, ExprKind, Guard, Node, Pat, PatKind, QPath, UnOp};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, GenericArgKind, Ty};
-use rustc_span::{sym, Symbol};
+use rustc_span::{sym, Span, Symbol};
 use std::fmt::Write;
 use std::ops::ControlFlow;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-    if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) {
-        find_sugg_for_if_let(cx, expr, let_pat, let_expr, "while", false);
+    if let Some(higher::WhileLet {
+        let_pat,
+        let_expr,
+        let_span,
+        ..
+    }) = higher::WhileLet::hir(expr)
+    {
+        find_method_sugg_for_if_let(cx, expr, let_pat, let_expr, "while", false);
+        find_if_let_true(cx, let_pat, let_expr, let_span);
     }
 }
 
@@ -28,8 +35,73 @@ pub(super) fn check_if_let<'tcx>(
     pat: &'tcx Pat<'_>,
     scrutinee: &'tcx Expr<'_>,
     has_else: bool,
+    let_span: Span,
+) {
+    find_if_let_true(cx, pat, scrutinee, let_span);
+    find_method_sugg_for_if_let(cx, expr, pat, scrutinee, "if", has_else);
+}
+
+/// Looks for:
+/// * `matches!(expr, true)`
+pub fn check_matches_true<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    arm: &'tcx Arm<'_>,
+    scrutinee: &'tcx Expr<'_>,
+) {
+    find_match_true(
+        cx,
+        arm.pat,
+        scrutinee,
+        expr.span.source_callsite(),
+        "using `matches!` to pattern match a bool",
+    );
+}
+
+/// Looks for any of:
+/// * `if let true = ...`
+/// * `if let false = ...`
+/// * `while let true = ...`
+fn find_if_let_true<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, scrutinee: &'tcx Expr<'_>, let_span: Span) {
+    find_match_true(cx, pat, scrutinee, let_span, "using `if let` to pattern match a bool");
+}
+
+/// Common logic between `find_if_let_true` and `check_matches_true`
+fn find_match_true<'tcx>(
+    cx: &LateContext<'tcx>,
+    pat: &'tcx Pat<'_>,
+    scrutinee: &'tcx Expr<'_>,
+    span: Span,
+    message: &str,
 ) {
-    find_sugg_for_if_let(cx, expr, pat, scrutinee, "if", has_else);
+    if let PatKind::Lit(lit) = pat.kind
+        && let ExprKind::Lit(lit) = lit.kind
+        && let LitKind::Bool(pat_is_true) = lit.node
+    {
+        let mut applicability = Applicability::MachineApplicable;
+
+        let mut sugg = Sugg::hir_with_context(
+            cx,
+            scrutinee,
+            scrutinee.span.source_callsite().ctxt(),
+            "..",
+            &mut applicability,
+        );
+
+        if !pat_is_true {
+            sugg = make_unop("!", sugg);
+        }
+
+        span_lint_and_sugg(
+            cx,
+            REDUNDANT_PATTERN_MATCHING,
+            span,
+            message,
+            "consider using the condition directly",
+            sugg.to_string(),
+            applicability,
+        );
+    }
 }
 
 // Extract the generic arguments out of a type
@@ -56,9 +128,7 @@ fn find_method_and_type<'tcx>(
 
             if is_wildcard || is_rest {
                 let res = cx.typeck_results().qpath_res(qpath, check_pat.hir_id);
-                let Some(id) = res.opt_def_id().map(|ctor_id| cx.tcx.parent(ctor_id)) else {
-                    return None;
-                };
+                let id = res.opt_def_id().map(|ctor_id| cx.tcx.parent(ctor_id))?;
                 let lang_items = cx.tcx.lang_items();
                 if Some(id) == lang_items.result_ok_variant() {
                     Some(("is_ok()", try_get_generic_ty(op_ty, 0).unwrap_or(op_ty)))
@@ -100,7 +170,7 @@ fn find_method_and_type<'tcx>(
     }
 }
 
-fn find_sugg_for_if_let<'tcx>(
+fn find_method_sugg_for_if_let<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'_>,
     let_pat: &Pat<'_>,
@@ -341,31 +411,25 @@ fn get_good_method<'tcx>(
     path_left: &QPath<'_>,
 ) -> Option<(&'static str, Option<&'tcx Guard<'tcx>>)> {
     if let Some(name) = get_ident(path_left) {
-        return match name.as_str() {
-            "Ok" => {
-                find_good_method_for_matches_macro(cx, arms, path_left, Item::Lang(ResultOk), "is_ok()", "is_err()")
-            },
-            "Err" => {
-                find_good_method_for_matches_macro(cx, arms, path_left, Item::Lang(ResultErr), "is_err()", "is_ok()")
-            },
-            "Some" => find_good_method_for_matches_macro(
-                cx,
-                arms,
-                path_left,
-                Item::Lang(OptionSome),
-                "is_some()",
-                "is_none()",
-            ),
-            "None" => find_good_method_for_matches_macro(
-                cx,
-                arms,
-                path_left,
-                Item::Lang(OptionNone),
-                "is_none()",
-                "is_some()",
-            ),
-            _ => None,
+        let (expected_item_left, should_be_left, should_be_right) = match name.as_str() {
+            "Ok" => (Item::Lang(ResultOk), "is_ok()", "is_err()"),
+            "Err" => (Item::Lang(ResultErr), "is_err()", "is_ok()"),
+            "Some" => (Item::Lang(OptionSome), "is_some()", "is_none()"),
+            "None" => (Item::Lang(OptionNone), "is_none()", "is_some()"),
+            "Ready" => (Item::Lang(PollReady), "is_ready()", "is_pending()"),
+            "Pending" => (Item::Lang(PollPending), "is_pending()", "is_ready()"),
+            "V4" => (Item::Diag(sym::IpAddr, sym!(V4)), "is_ipv4()", "is_ipv6()"),
+            "V6" => (Item::Diag(sym::IpAddr, sym!(V6)), "is_ipv6()", "is_ipv4()"),
+            _ => return None,
         };
+        return find_good_method_for_matches_macro(
+            cx,
+            arms,
+            path_left,
+            expected_item_left,
+            should_be_left,
+            should_be_right,
+        );
     }
     None
 }
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 844ab40cab1..7cfd3d346b6 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
@@ -14,7 +14,7 @@ use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::Span;
 use std::borrow::Cow;
 
-use super::{MANUAL_FILTER_MAP, MANUAL_FIND_MAP, OPTION_FILTER_MAP};
+use super::{MANUAL_FILTER_MAP, MANUAL_FIND_MAP, OPTION_FILTER_MAP, RESULT_FILTER_MAP};
 
 fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> bool {
     match &expr.kind {
@@ -22,6 +22,7 @@ fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) ->
         hir::ExprKind::Path(QPath::Resolved(_, segments)) => {
             segments.segments.last().unwrap().ident.name == method_name
         },
+        hir::ExprKind::MethodCall(segment, _, _, _) => segment.ident.name == method_name,
         hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
             let body = cx.tcx.hir().body(body);
             let closure_expr = peel_blocks(body.value);
@@ -46,6 +47,9 @@ fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) ->
 fn is_option_filter_map(cx: &LateContext<'_>, filter_arg: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) -> bool {
     is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_some))
 }
+fn is_ok_filter_map(cx: &LateContext<'_>, filter_arg: &hir::Expr<'_>, map_arg: &hir::Expr<'_>) -> bool {
+    is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_ok))
+}
 
 #[derive(Debug, Copy, Clone)]
 enum OffendingFilterExpr<'tcx> {
@@ -186,7 +190,7 @@ impl<'tcx> OffendingFilterExpr<'tcx> {
                     match higher::IfLetOrMatch::parse(cx, map_body.value) {
                         // For `if let` we want to check that the variant matching arm references the local created by
                         // its pattern
-                        Some(higher::IfLetOrMatch::IfLet(sc, pat, then, Some(else_)))
+                        Some(higher::IfLetOrMatch::IfLet(sc, pat, then, Some(else_), ..))
                             if let Some((ident, span)) = expr_uses_local(pat, then) =>
                         {
                             (sc, else_, ident, span)
@@ -273,6 +277,18 @@ fn is_filter_some_map_unwrap(
     (iterator || option) && is_option_filter_map(cx, filter_arg, map_arg)
 }
 
+/// is `filter(|x| x.is_ok()).map(|x| x.unwrap())`
+fn is_filter_ok_map_unwrap(
+    cx: &LateContext<'_>,
+    expr: &hir::Expr<'_>,
+    filter_arg: &hir::Expr<'_>,
+    map_arg: &hir::Expr<'_>,
+) -> bool {
+    // result has no filter, so we only check for iterators
+    let iterator = is_trait_method(cx, expr, sym::Iterator);
+    iterator && is_ok_filter_map(cx, filter_arg, map_arg)
+}
+
 /// lint use of `filter().map()` or `find().map()` for `Iterators`
 #[allow(clippy::too_many_arguments)]
 pub(super) fn check(
@@ -300,30 +316,21 @@ pub(super) fn check(
         return;
     }
 
-    if is_trait_method(cx, map_recv, sym::Iterator)
-
-        // filter(|x| ...is_some())...
-        && let ExprKind::Closure(&Closure { body: filter_body_id, .. }) = filter_arg.kind
-        && let filter_body = cx.tcx.hir().body(filter_body_id)
-        && let [filter_param] = filter_body.params
-        // optional ref pattern: `filter(|&x| ..)`
-        && let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind {
-            (ref_pat, true)
-        } else {
-            (filter_param.pat, false)
-        }
-
-        && let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind
-        && let Some(mut offending_expr) = OffendingFilterExpr::hir(cx, filter_body.value, filter_param_id)
+    if is_filter_ok_map_unwrap(cx, expr, filter_arg, map_arg) {
+        span_lint_and_sugg(
+            cx,
+            RESULT_FILTER_MAP,
+            filter_span.with_hi(expr.span.hi()),
+            "`filter` for `Ok` followed by `unwrap`",
+            "consider using `flatten` instead",
+            reindent_multiline(Cow::Borrowed("flatten()"), true, indent_of(cx, map_span)).into_owned(),
+            Applicability::MachineApplicable,
+        );
 
-        && let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind
-        && let map_body = cx.tcx.hir().body(map_body_id)
-        && let [map_param] = map_body.params
-        && let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind
+        return;
+    }
 
-        && let Some(check_result) =
-            offending_expr.check_map_call(cx, map_body, map_param_id, filter_param_id, is_filter_param_ref)
-    {
+    if let Some((map_param_ident, check_result)) = is_find_or_filter(cx, map_recv, filter_arg, map_arg) {
         let span = filter_span.with_hi(expr.span.hi());
         let (filter_name, lint) = if is_find {
             ("find", MANUAL_FIND_MAP)
@@ -395,6 +402,40 @@ pub(super) fn check(
     }
 }
 
+fn is_find_or_filter<'a>(
+    cx: &LateContext<'a>,
+    map_recv: &hir::Expr<'_>,
+    filter_arg: &hir::Expr<'_>,
+    map_arg: &hir::Expr<'_>,
+) -> Option<(Ident, CheckResult<'a>)> {
+    if is_trait_method(cx, map_recv, sym::Iterator)
+        // filter(|x| ...is_some())...
+        && let ExprKind::Closure(&Closure { body: filter_body_id, .. }) = filter_arg.kind
+        && let filter_body = cx.tcx.hir().body(filter_body_id)
+        && let [filter_param] = filter_body.params
+        // optional ref pattern: `filter(|&x| ..)`
+        && let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind {
+            (ref_pat, true)
+        } else {
+            (filter_param.pat, false)
+        }
+
+        && let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind
+        && let Some(mut offending_expr) = OffendingFilterExpr::hir(cx, filter_body.value, filter_param_id)
+
+        && let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind
+        && let map_body = cx.tcx.hir().body(map_body_id)
+        && let [map_param] = map_body.params
+        && let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind
+
+        && let Some(check_result) =
+            offending_expr.check_map_call(cx, map_body, map_param_id, filter_param_id, is_filter_param_ref)
+    {
+        return Some((map_param_ident, check_result));
+    }
+    None
+}
+
 fn acceptable_methods(method: &PathSegment<'_>) -> bool {
     let methods: [Symbol; 8] = [
         sym::clone,
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs b/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs
new file mode 100644
index 00000000000..ade8e3155fa
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs
@@ -0,0 +1,87 @@
+use rustc_lint::{LateContext, LintContext};
+
+use super::{ITER_FILTER_IS_OK, ITER_FILTER_IS_SOME};
+
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::{indent_of, reindent_multiline};
+use clippy_utils::{is_trait_method, peel_blocks, span_contains_comment};
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_hir::def::Res;
+use rustc_hir::QPath;
+use rustc_span::symbol::{sym, Symbol};
+use rustc_span::Span;
+use std::borrow::Cow;
+
+fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> bool {
+    match &expr.kind {
+        hir::ExprKind::Path(QPath::TypeRelative(_, mname)) => mname.ident.name == method_name,
+        hir::ExprKind::Path(QPath::Resolved(_, segments)) => {
+            segments.segments.last().unwrap().ident.name == method_name
+        },
+        hir::ExprKind::MethodCall(segment, _, _, _) => segment.ident.name == method_name,
+        hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
+            let body = cx.tcx.hir().body(body);
+            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, .. }, receiver, ..) => {
+                    if ident.name == method_name
+                        && let hir::ExprKind::Path(path) = &receiver.kind
+                        && let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id)
+                    {
+                        return arg_id == *local;
+                    }
+                    false
+                },
+                _ => false,
+            }
+        },
+        _ => false,
+    }
+}
+
+fn parent_is_map(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
+    if let hir::Node::Expr(parent_expr) = cx.tcx.hir().get_parent(expr.hir_id) {
+        is_method(cx, parent_expr, rustc_span::sym::map)
+    } else {
+        false
+    }
+}
+
+#[allow(clippy::too_many_arguments)]
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_arg: &hir::Expr<'_>, filter_span: Span) {
+    let is_iterator = is_trait_method(cx, expr, sym::Iterator);
+    let parent_is_not_map = !parent_is_map(cx, expr);
+
+    if is_iterator
+        && parent_is_not_map
+        && is_method(cx, filter_arg, sym!(is_some))
+        && !span_contains_comment(cx.sess().source_map(), filter_span.with_hi(expr.span.hi()))
+    {
+        span_lint_and_sugg(
+            cx,
+            ITER_FILTER_IS_SOME,
+            filter_span.with_hi(expr.span.hi()),
+            "`filter` for `is_some` on iterator over `Option`",
+            "consider using `flatten` instead",
+            reindent_multiline(Cow::Borrowed("flatten()"), true, indent_of(cx, filter_span)).into_owned(),
+            Applicability::HasPlaceholders,
+        );
+    }
+    if is_iterator
+        && parent_is_not_map
+        && is_method(cx, filter_arg, sym!(is_ok))
+        && !span_contains_comment(cx.sess().source_map(), filter_span.with_hi(expr.span.hi()))
+    {
+        span_lint_and_sugg(
+            cx,
+            ITER_FILTER_IS_OK,
+            filter_span.with_hi(expr.span.hi()),
+            "`filter` for `is_ok` on iterator over `Result`s",
+            "consider using `flatten` instead",
+            reindent_multiline(Cow::Borrowed("flatten()"), true, indent_of(cx, filter_span)).into_owned(),
+            Applicability::HasPlaceholders,
+        );
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index b4f60ffadd7..25b1ea526e2 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -38,6 +38,7 @@ mod into_iter_on_ref;
 mod is_digit_ascii_radix;
 mod iter_cloned_collect;
 mod iter_count;
+mod iter_filter;
 mod iter_kv_map;
 mod iter_next_slice;
 mod iter_nth;
@@ -1175,7 +1176,8 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for indirect collection of populated `Option`
+    /// Checks for iterators of `Option`s using `.filter(Option::is_some).map(Option::unwrap)` that may
+    /// be replaced with a `.flatten()` call.
     ///
     /// ### Why is this bad?
     /// `Option` is like a collection of 0-1 things, so `flatten`
@@ -3752,6 +3754,81 @@ declare_clippy_lint! {
     "using `Option.map_or(Err(_), Ok)`, which is more succinctly expressed as `Option.ok_or(_)`"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for iterators of `Result`s using `.filter(Result::is_ok).map(Result::unwrap)` that may
+    /// be replaced with a `.flatten()` call.
+    ///
+    /// ### Why is this bad?
+    /// `Result` implements `IntoIterator<Item = T>`. This means that `Result` can be flattened
+    /// automatically without suspicious-looking `unwrap` calls.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// let _ = std::iter::empty::<Result<i32, ()>>().filter(Result::is_ok).map(Result::unwrap);
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// let _ = std::iter::empty::<Result<i32, ()>>().flatten();
+    /// ```
+    #[clippy::version = "1.76.0"]
+    pub RESULT_FILTER_MAP,
+    complexity,
+    "filtering `Result` for `Ok` then force-unwrapping, which can be one type-safe operation"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `.filter(Option::is_some)` that may be replaced with a `.flatten()` call.
+    /// This lint will require additional changes to the follow-up calls as it appects the type.
+    ///
+    /// ### Why is this bad?
+    /// This pattern is often followed by manual unwrapping of the `Option`. The simplification
+    /// results in more readable and succint code without the need for manual unwrapping.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// // example code where clippy issues a warning
+    /// vec![Some(1)].into_iter().filter(Option::is_some);
+    ///
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// // example code which does not raise clippy warning
+    /// vec![Some(1)].into_iter().flatten();
+    /// ```
+    #[clippy::version = "1.76.0"]
+    pub ITER_FILTER_IS_SOME,
+    pedantic,
+    "filtering an iterator over `Option`s for `Some` can be achieved with `flatten`"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `.filter(Result::is_ok)` that may be replaced with a `.flatten()` call.
+    /// This lint will require additional changes to the follow-up calls as it appects the type.
+    ///
+    /// ### Why is this bad?
+    /// This pattern is often followed by manual unwrapping of `Result`. The simplification
+    /// results in more readable and succint code without the need for manual unwrapping.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// // example code where clippy issues a warning
+    /// vec![Ok::<i32, String>(1)].into_iter().filter(Result::is_ok);
+    ///
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// // example code which does not raise clippy warning
+    /// vec![Ok::<i32, String>(1)].into_iter().flatten();
+    /// ```
+    #[clippy::version = "1.76.0"]
+    pub ITER_FILTER_IS_OK,
+    pedantic,
+    "filtering an iterator over `Result`s for `Ok` can be achieved with `flatten`"
+}
+
 pub struct Methods {
     avoid_breaking_exported_api: bool,
     msrv: Msrv,
@@ -3903,6 +3980,9 @@ impl_lint_pass!(Methods => [
     UNNECESSARY_FALLIBLE_CONVERSIONS,
     JOIN_ABSOLUTE_PATHS,
     OPTION_MAP_OR_ERR_OK,
+    RESULT_FILTER_MAP,
+    ITER_FILTER_IS_SOME,
+    ITER_FILTER_IS_OK,
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -4232,7 +4312,24 @@ impl Methods {
                     string_extend_chars::check(cx, expr, recv, arg);
                     extend_with_drain::check(cx, expr, recv, arg);
                 },
-                (name @ ("filter" | "find"), [arg]) => {
+                ("filter", [arg]) => {
+                    if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
+                        // if `arg` has side-effect, the semantic will change
+                        iter_overeager_cloned::check(
+                            cx,
+                            expr,
+                            recv,
+                            recv2,
+                            iter_overeager_cloned::Op::FixClosure(name, arg),
+                            false,
+                        );
+                    }
+                    if self.msrv.meets(msrvs::ITER_FLATTEN) {
+                        // use the sourcemap to get the span of the closure
+                        iter_filter::check(cx, expr, arg, span);
+                    }
+                },
+                ("find", [arg]) => {
                     if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
                         // if `arg` has side-effect, the semantic will change
                         iter_overeager_cloned::check(
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 c4775b6bd04..637368e9361 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
@@ -7,6 +7,7 @@ use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, peel_mid
 use clippy_utils::visitors::find_all_ret_expressions;
 use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty};
 use rustc_errors::Applicability;
+use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{BorrowKind, Expr, ExprKind, ItemKind, Node};
 use rustc_hir_typeck::{FnCtxt, Inherited};
@@ -37,6 +38,9 @@ pub fn check<'tcx>(
         if is_cloned_or_copied(cx, method_name, method_def_id) {
             unnecessary_iter_cloned::check(cx, expr, method_name, receiver);
         } else if is_to_owned_like(cx, expr, method_name, method_def_id) {
+            if check_split_call_arg(cx, expr, method_name, receiver) {
+                return;
+            }
             // At this point, we know the call is of a `to_owned`-like function. The functions
             // `check_addr_of_expr` and `check_call_arg` determine whether the call is unnecessary
             // based on its context, that is, whether it is a referent in an `AddrOf` expression, an
@@ -233,6 +237,58 @@ fn check_into_iter_call_arg(
     false
 }
 
+/// Checks whether `expr` is an argument in an `into_iter` call and, if so, determines whether its
+/// call of a `to_owned`-like function is unnecessary.
+fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool {
+    if let Some(parent) = get_parent_expr(cx, expr)
+        && let Some((fn_name, argument_expr)) = get_fn_name_and_arg(cx, parent)
+        && fn_name.as_str() == "split"
+        && let Some(receiver_snippet) = snippet_opt(cx, receiver.span)
+        && let Some(arg_snippet) = snippet_opt(cx, argument_expr.span)
+    {
+        // The next suggestion may be incorrect because the removal of the `to_owned`-like
+        // function could cause the iterator to hold a reference to a resource that is used
+        // mutably. See https://github.com/rust-lang/rust-clippy/issues/8148.
+        span_lint_and_sugg(
+            cx,
+            UNNECESSARY_TO_OWNED,
+            parent.span,
+            &format!("unnecessary use of `{method_name}`"),
+            "use",
+            format!("{receiver_snippet}.split({arg_snippet})"),
+            Applicability::MaybeIncorrect,
+        );
+        return true;
+    }
+    false
+}
+
+fn get_fn_name_and_arg<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<(Symbol, Expr<'tcx>)> {
+    match &expr.kind {
+        ExprKind::MethodCall(path, _, [arg_expr], ..) => Some((path.ident.name, *arg_expr)),
+        ExprKind::Call(
+            Expr {
+                kind: ExprKind::Path(qpath),
+                hir_id: path_hir_id,
+                ..
+            },
+            [arg_expr],
+        ) => {
+            // Only return Fn-like DefIds, not the DefIds of statics/consts/etc that contain or
+            // deref to fn pointers, dyn Fn, impl Fn - #8850
+            if let Res::Def(DefKind::Fn | DefKind::Ctor(..) | DefKind::AssocFn, def_id) =
+                cx.typeck_results().qpath_res(qpath, *path_hir_id)
+                && let Some(fn_name) = cx.tcx.opt_item_name(def_id)
+            {
+                Some((fn_name, *arg_expr))
+            } else {
+                None
+            }
+        },
+        _ => None,
+    }
+}
+
 /// Checks whether `expr` is an argument in a function call and, if so, determines whether its call
 /// of a `to_owned`-like function is unnecessary.
 fn check_other_call_arg<'tcx>(
diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs
index 218ca5e80f3..bf27adb45af 100644
--- a/src/tools/clippy/clippy_lints/src/needless_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs
@@ -340,6 +340,12 @@ fn check_comparison<'a, 'tcx>(
         }
         if l_ty.is_bool() && r_ty.is_bool() {
             let mut applicability = Applicability::MachineApplicable;
+            // Eliminate parentheses in `e` by using the lo pos of lhs and hi pos of rhs,
+            // calling `source_callsite` make sure macros are handled correctly, see issue #9907
+            let binop_span = left_side
+                .span
+                .source_callsite()
+                .with_hi(right_side.span.source_callsite().hi());
 
             if op.node == BinOpKind::Eq {
                 let expression_info = one_side_is_unary_not(left_side, right_side);
@@ -347,13 +353,23 @@ fn check_comparison<'a, 'tcx>(
                     span_lint_and_sugg(
                         cx,
                         BOOL_COMPARISON,
-                        e.span,
+                        binop_span,
                         "this comparison might be written more concisely",
                         "try simplifying it as shown",
                         format!(
                             "{} != {}",
-                            snippet_with_applicability(cx, expression_info.left_span, "..", &mut applicability),
-                            snippet_with_applicability(cx, expression_info.right_span, "..", &mut applicability)
+                            snippet_with_applicability(
+                                cx,
+                                expression_info.left_span.source_callsite(),
+                                "..",
+                                &mut applicability
+                            ),
+                            snippet_with_applicability(
+                                cx,
+                                expression_info.right_span.source_callsite(),
+                                "..",
+                                &mut applicability
+                            )
                         ),
                         applicability,
                     );
@@ -362,16 +378,16 @@ fn check_comparison<'a, 'tcx>(
 
             match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) {
                 (Some(true), None) => left_true.map_or((), |(h, m)| {
-                    suggest_bool_comparison(cx, e, right_side, applicability, m, h);
+                    suggest_bool_comparison(cx, binop_span, right_side, applicability, m, h);
                 }),
                 (None, Some(true)) => right_true.map_or((), |(h, m)| {
-                    suggest_bool_comparison(cx, e, left_side, applicability, m, h);
+                    suggest_bool_comparison(cx, binop_span, left_side, applicability, m, h);
                 }),
                 (Some(false), None) => left_false.map_or((), |(h, m)| {
-                    suggest_bool_comparison(cx, e, right_side, applicability, m, h);
+                    suggest_bool_comparison(cx, binop_span, right_side, applicability, m, h);
                 }),
                 (None, Some(false)) => right_false.map_or((), |(h, m)| {
-                    suggest_bool_comparison(cx, e, left_side, applicability, m, h);
+                    suggest_bool_comparison(cx, binop_span, left_side, applicability, m, h);
                 }),
                 (None, None) => no_literal.map_or((), |(h, m)| {
                     let left_side = Sugg::hir_with_applicability(cx, left_side, "..", &mut applicability);
@@ -379,7 +395,7 @@ fn check_comparison<'a, 'tcx>(
                     span_lint_and_sugg(
                         cx,
                         BOOL_COMPARISON,
-                        e.span,
+                        binop_span,
                         m,
                         "try simplifying it as shown",
                         h(left_side, right_side).to_string(),
@@ -394,17 +410,17 @@ fn check_comparison<'a, 'tcx>(
 
 fn suggest_bool_comparison<'a, 'tcx>(
     cx: &LateContext<'tcx>,
-    e: &'tcx Expr<'_>,
+    span: Span,
     expr: &Expr<'_>,
     mut app: Applicability,
     message: &str,
     conv_hint: impl FnOnce(Sugg<'a>) -> Sugg<'a>,
 ) {
-    let hint = Sugg::hir_with_context(cx, expr, e.span.ctxt(), "..", &mut app);
+    let hint = Sugg::hir_with_context(cx, expr, span.ctxt(), "..", &mut app);
     span_lint_and_sugg(
         cx,
         BOOL_COMPARISON,
-        e.span,
+        span,
         message,
         "try simplifying it as shown",
         conv_hint(hint).to_string(),
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 89e4e3c740d..556c493d36c 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
@@ -238,6 +238,7 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) ->
         let_expr,
         if_then,
         if_else: Some(if_else),
+        ..
     }) = higher::IfLet::hir(cx, expr)
         && !cx.typeck_results().expr_ty(expr).is_unit()
         && !is_else_clause(cx.tcx, expr)
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index fc5835408a9..509d9483e1d 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -8,7 +8,7 @@ use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{
     eq_expr_value, get_parent_node, higher, in_constant, is_else_clause, is_lint_allowed, is_path_lang_item,
     is_res_lang_ctor, pat_and_expr_can_be_question_mark, path_to_local, path_to_local_id, peel_blocks,
-    peel_blocks_with_stmt,
+    peel_blocks_with_stmt, span_contains_comment,
 };
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
@@ -96,6 +96,24 @@ enum IfBlockType<'hir> {
     ),
 }
 
+fn find_let_else_ret_expression<'hir>(block: &'hir Block<'hir>) -> Option<&'hir Expr<'hir>> {
+    if let Block {
+        stmts: &[],
+        expr: Some(els),
+        ..
+    } = block
+    {
+        Some(els)
+    } else if let [stmt] = block.stmts
+        && let StmtKind::Semi(expr) = stmt.kind
+        && let ExprKind::Ret(..) = expr.kind
+    {
+        Some(expr)
+    } else {
+        None
+    }
+}
+
 fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
     if let StmtKind::Local(Local {
         pat,
@@ -103,12 +121,9 @@ fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
         els: Some(els),
         ..
     }) = stmt.kind
-        && let Block {
-            stmts: &[],
-            expr: Some(els),
-            ..
-        } = els
-        && let Some(inner_pat) = pat_and_expr_can_be_question_mark(cx, pat, els)
+        && let Some(ret) = find_let_else_ret_expression(els)
+        && let Some(inner_pat) = pat_and_expr_can_be_question_mark(cx, pat, ret)
+        && !span_contains_comment(cx.tcx.sess.source_map(), els.span)
     {
         let mut applicability = Applicability::MaybeIncorrect;
         let init_expr_str = snippet_with_applicability(cx, init_expr.span, "..", &mut applicability);
@@ -256,6 +271,7 @@ impl QuestionMark {
                 let_expr,
                 if_then,
                 if_else,
+                ..
             }) = higher::IfLet::hir(cx, expr)
             && !is_else_clause(cx.tcx, expr)
             && let PatKind::TupleStruct(ref path1, [field], ddpos) = let_pat.kind
diff --git a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
index b50141f048c..0ed957f1f2f 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
@@ -3,9 +3,12 @@ use std::ops::ControlFlow;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::peel_blocks;
 use clippy_utils::source::{snippet, walk_span_to_context};
+use clippy_utils::ty::implements_trait;
 use clippy_utils::visitors::for_each_expr;
 use rustc_errors::Applicability;
-use rustc_hir::{Closure, ClosureKind, CoroutineKind, CoroutineSource, CoroutineDesugaring, Expr, ExprKind, MatchSource};
+use rustc_hir::{
+    Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, MatchSource,
+};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::UpvarCapture;
@@ -49,6 +52,9 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock {
             let Some(expr) = desugar_await(peel_blocks(body_expr)) &&
             // The await prefix must not come from a macro as its content could change in the future.
             expr.span.eq_ctxt(body_expr.span) &&
+            // The await prefix must implement Future, as implementing IntoFuture is not enough.
+            let Some(future_trait) = cx.tcx.lang_items().future_trait() &&
+            implements_trait(cx, cx.typeck_results().expr_ty(expr), future_trait, &[]) &&
             // An async block does not have immediate side-effects from a `.await` point-of-view.
             (!expr.can_have_side_effects() || desugar_async_block(cx, expr).is_some()) &&
             let Some(shortened_span) = walk_span_to_context(expr.span, span.ctxt())
@@ -71,7 +77,13 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock {
 fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
     if let ExprKind::Closure(Closure { body, def_id, kind, .. }) = expr.kind
         && let body = cx.tcx.hir().body(*body)
-        && matches!(kind, ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block)))
+        && matches!(
+            kind,
+            ClosureKind::Coroutine(CoroutineKind::Desugared(
+                CoroutineDesugaring::Async,
+                CoroutineSource::Block
+            ))
+        )
     {
         cx.typeck_results()
             .closure_min_captures
diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
index 16c929edb92..cde08dfcc74 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
@@ -5,7 +5,7 @@ use clippy_utils::sugg::Sugg;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor};
-use rustc_hir::{intravisit as hir_visit, CoroutineKind, CoroutineSource, CoroutineDesugaring, Node, ClosureKind};
+use rustc_hir::{intravisit as hir_visit, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Node};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::lint::in_external_macro;
@@ -66,7 +66,8 @@ impl<'tcx> Visitor<'tcx> for ReturnVisitor {
 fn is_async_closure(body: &hir::Body<'_>) -> bool {
     if let hir::ExprKind::Closure(innermost_closure_generated_by_desugar) = body.value.kind
         // checks whether it is `async || whatever_expression`
-        && let ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure)) = innermost_closure_generated_by_desugar.kind
+        && let ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure))
+            = innermost_closure_generated_by_desugar.kind
     {
         true
     } else {
diff --git a/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs
new file mode 100644
index 00000000000..01a23c515f5
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs
@@ -0,0 +1,74 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::ty::is_normalizable;
+use clippy_utils::{path_to_local, path_to_local_id};
+use rustc_abi::WrappingRange;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, Node};
+use rustc_lint::LateContext;
+use rustc_middle::ty::Ty;
+
+use super::EAGER_TRANSMUTE;
+
+fn peel_parent_unsafe_blocks<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
+    for (_, parent) in cx.tcx.hir().parent_iter(expr.hir_id) {
+        match parent {
+            Node::Block(_) => {},
+            Node::Expr(e) if let ExprKind::Block(..) = e.kind => {},
+            Node::Expr(e) => return Some(e),
+            _ => break,
+        }
+    }
+    None
+}
+
+fn range_fully_contained(from: WrappingRange, to: WrappingRange) -> bool {
+    to.contains(from.start) && to.contains(from.end)
+}
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+    transmutable: &'tcx Expr<'tcx>,
+    from_ty: Ty<'tcx>,
+    to_ty: Ty<'tcx>,
+) -> bool {
+    if let Some(then_some_call) = peel_parent_unsafe_blocks(cx, expr)
+        && let ExprKind::MethodCall(path, receiver, [arg], _) = then_some_call.kind
+        && cx.typeck_results().expr_ty(receiver).is_bool()
+        && path.ident.name == sym!(then_some)
+        && let ExprKind::Binary(_, lhs, rhs) = receiver.kind
+        && let Some(local_id) = path_to_local(transmutable)
+        && (path_to_local_id(lhs, local_id) || path_to_local_id(rhs, local_id))
+        && is_normalizable(cx, cx.param_env, from_ty)
+        && is_normalizable(cx, cx.param_env, to_ty)
+        // we only want to lint if the target type has a niche that is larger than the one of the source type
+        // e.g. `u8` to `NonZeroU8` should lint, but `NonZeroU8` to `u8` should not
+        && let Ok(from_layout) = cx.tcx.layout_of(cx.param_env.and(from_ty))
+        && let Ok(to_layout) = cx.tcx.layout_of(cx.param_env.and(to_ty))
+        && match (from_layout.largest_niche, to_layout.largest_niche) {
+            (Some(from_niche), Some(to_niche)) => !range_fully_contained(from_niche.valid_range, to_niche.valid_range),
+            (None, Some(_)) => true,
+            (_, None) => false,
+        }
+    {
+        span_lint_and_then(
+            cx,
+            EAGER_TRANSMUTE,
+            expr.span,
+            "this transmute is always evaluated eagerly, even if the condition is false",
+            |diag| {
+                diag.multipart_suggestion(
+                    "consider using `bool::then` to only transmute if the condition holds",
+                    vec![
+                        (path.ident.span, "then".into()),
+                        (arg.span.shrink_to_lo(), "|| ".into()),
+                    ],
+                    Applicability::MaybeIncorrect,
+                );
+            },
+        );
+        true
+    } else {
+        false
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
index 95a92afea66..06de7a11031 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
@@ -1,4 +1,5 @@
 mod crosspointer_transmute;
+mod eager_transmute;
 mod transmute_float_to_int;
 mod transmute_int_to_bool;
 mod transmute_int_to_char;
@@ -463,6 +464,62 @@ declare_clippy_lint! {
     "transmute results in a null function pointer, which is undefined behavior"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for integer validity checks, followed by a transmute that is (incorrectly) evaluated
+    /// eagerly (e.g. using `bool::then_some`).
+    ///
+    /// ### Why is this bad?
+    /// Eager evaluation means that the `transmute` call is executed regardless of whether the condition is true or false.
+    /// This can introduce unsoundness and other subtle bugs.
+    ///
+    /// ### Example
+    /// Consider the following function which is meant to convert an unsigned integer to its enum equivalent via transmute.
+    ///
+    /// ```no_run
+    /// #[repr(u8)]
+    /// enum Opcode {
+    ///     Add = 0,
+    ///     Sub = 1,
+    ///     Mul = 2,
+    ///     Div = 3
+    /// }
+    ///
+    /// fn int_to_opcode(op: u8) -> Option<Opcode> {
+    ///     (op < 4).then_some(unsafe { std::mem::transmute(op) })
+    /// }
+    /// ```
+    /// This may appear fine at first given that it checks that the `u8` is within the validity range of the enum,
+    /// *however* the transmute is evaluated eagerly, meaning that it executes even if `op >= 4`!
+    ///
+    /// This makes the function unsound, because it is possible for the caller to cause undefined behavior
+    /// (creating an enum with an invalid bitpattern) entirely in safe code only by passing an incorrect value,
+    /// which is normally only a bug that is possible in unsafe code.
+    ///
+    /// One possible way in which this can go wrong practically is that the compiler sees it as:
+    /// ```rust,ignore (illustrative)
+    /// let temp: Foo = unsafe { std::mem::transmute(op) };
+    /// (0 < 4).then_some(temp)
+    /// ```
+    /// and optimizes away the `(0 < 4)` check based on the assumption that since a `Foo` was created from `op` with the validity range `0..3`,
+    /// it is **impossible** for this condition to be false.
+    ///
+    /// In short, it is possible for this function to be optimized in a way that makes it [never return `None`](https://godbolt.org/z/ocrcenevq),
+    /// even if passed the value `4`.
+    ///
+    /// This can be avoided by instead using lazy evaluation. For the example above, this should be written:
+    /// ```rust,ignore (illustrative)
+    /// fn int_to_opcode(op: u8) -> Option<Opcode> {
+    ///     (op < 4).then(|| unsafe { std::mem::transmute(op) })
+    ///              ^^^^ ^^ `bool::then` only executes the closure if the condition is true!
+    /// }
+    /// ```
+    #[clippy::version = "1.76.0"]
+    pub EAGER_TRANSMUTE,
+    correctness,
+    "eager evaluation of `transmute`"
+}
+
 pub struct Transmute {
     msrv: Msrv,
 }
@@ -484,6 +541,7 @@ impl_lint_pass!(Transmute => [
     TRANSMUTE_UNDEFINED_REPR,
     TRANSMUTING_NULL,
     TRANSMUTE_NULL_TO_FN,
+    EAGER_TRANSMUTE,
 ]);
 impl Transmute {
     #[must_use]
@@ -530,7 +588,8 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
                 | transmute_float_to_int::check(cx, e, from_ty, to_ty, arg, const_context)
                 | transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg, const_context)
                 | (unsound_collection_transmute::check(cx, e, from_ty, to_ty)
-                    || transmute_undefined_repr::check(cx, e, from_ty, to_ty));
+                    || transmute_undefined_repr::check(cx, e, from_ty, to_ty))
+                | (eager_transmute::check(cx, e, arg, from_ty, to_ty));
 
             if !linted {
                 transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, from_ty_adjusted, to_ty, arg);
diff --git a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
new file mode 100644
index 00000000000..b1fa30aa068
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
@@ -0,0 +1,134 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::{get_trait_def_id, path_res};
+use rustc_ast::BinOpKind;
+use rustc_hir::def::Res;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::intravisit::FnKind;
+use rustc_hir::{Body, Expr, ExprKind, FnDecl, Item, ItemKind, Node};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::{self, Ty};
+use rustc_session::declare_lint_pass;
+use rustc_span::{sym, Span};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks that there isn't an infinite recursion in `PartialEq` trait
+    /// implementation.
+    ///
+    /// ### Why is this bad?
+    /// This is a hard to find infinite recursion which will crashing any code
+    /// using it.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// enum Foo {
+    ///     A,
+    ///     B,
+    /// }
+    ///
+    /// impl PartialEq for Foo {
+    ///     fn eq(&self, other: &Self) -> bool {
+    ///         self == other // bad!
+    ///     }
+    /// }
+    /// ```
+    /// Use instead:
+    ///
+    /// In such cases, either use `#[derive(PartialEq)]` or don't implement it.
+    #[clippy::version = "1.76.0"]
+    pub UNCONDITIONAL_RECURSION,
+    suspicious,
+    "detect unconditional recursion in some traits implementation"
+}
+
+declare_lint_pass!(UnconditionalRecursion => [UNCONDITIONAL_RECURSION]);
+
+fn get_ty_def_id(ty: Ty<'_>) -> Option<DefId> {
+    match ty.peel_refs().kind() {
+        ty::Adt(adt, _) => Some(adt.did()),
+        ty::Foreign(def_id) => Some(*def_id),
+        _ => None,
+    }
+}
+
+fn is_local(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    matches!(path_res(cx, expr), Res::Local(_))
+}
+
+impl<'tcx> LateLintPass<'tcx> for UnconditionalRecursion {
+    #[allow(clippy::unnecessary_def_path)]
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        kind: FnKind<'tcx>,
+        _decl: &'tcx FnDecl<'tcx>,
+        body: &'tcx Body<'tcx>,
+        method_span: Span,
+        def_id: LocalDefId,
+    ) {
+        // If the function is a method...
+        if let FnKind::Method(name, _) = kind
+            // That has two arguments.
+            && let [self_arg, other_arg] = cx
+                .tcx
+                .instantiate_bound_regions_with_erased(cx.tcx.fn_sig(def_id).skip_binder())
+                .inputs()
+            && let Some(self_arg) = get_ty_def_id(*self_arg)
+            && let Some(other_arg) = get_ty_def_id(*other_arg)
+            // The two arguments are of the same type.
+            && self_arg == other_arg
+            && let hir_id = cx.tcx.local_def_id_to_hir_id(def_id)
+            && let Some((
+                _,
+                Node::Item(Item {
+                    kind: ItemKind::Impl(impl_),
+                    owner_id,
+                    ..
+                }),
+            )) = cx.tcx.hir().parent_iter(hir_id).next()
+            // We exclude `impl` blocks generated from rustc's proc macros.
+            && !cx.tcx.has_attr(*owner_id, sym::automatically_derived)
+            // It is a implementation of a trait.
+            && let Some(trait_) = impl_.of_trait
+            && let Some(trait_def_id) = trait_.trait_def_id()
+            // The trait is `PartialEq`.
+            && Some(trait_def_id) == get_trait_def_id(cx, &["core", "cmp", "PartialEq"])
+        {
+            let to_check_op = if name.name == sym::eq {
+                BinOpKind::Eq
+            } else {
+                BinOpKind::Ne
+            };
+            let expr = body.value.peel_blocks();
+            let is_bad = match expr.kind {
+                ExprKind::Binary(op, left, right) if op.node == to_check_op => {
+                    is_local(cx, left) && is_local(cx, right)
+                },
+                ExprKind::MethodCall(segment, receiver, &[arg], _) if segment.ident.name == name.name => {
+                    if is_local(cx, receiver)
+                        && is_local(cx, &arg)
+                        && let Some(fn_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                        && let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
+                        && trait_id == trait_def_id
+                    {
+                        true
+                    } else {
+                        false
+                    }
+                },
+                _ => false,
+            };
+            if is_bad {
+                span_lint_and_then(
+                    cx,
+                    UNCONDITIONAL_RECURSION,
+                    method_span,
+                    "function cannot return without recursing",
+                    |diag| {
+                        diag.span_note(expr.span, "recursive call site");
+                    },
+                );
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
index 7a6549a7c54..e5bc3b5a25f 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -680,9 +680,7 @@ fn text_has_safety_comment(src: &str, line_starts: &[RelativeBytePos], start_pos
         })
         .filter(|(_, text)| !text.is_empty());
 
-    let Some((line_start, line)) = lines.next() else {
-        return None;
-    };
+    let (line_start, line) = lines.next()?;
     // Check for a sequence of line comments.
     if line.starts_with("//") {
         let (mut line, mut line_start) = (line, line_start);
diff --git a/src/tools/clippy/clippy_lints/src/uninhabited_references.rs b/src/tools/clippy/clippy_lints/src/uninhabited_references.rs
index d41576cadad..903593ecfd7 100644
--- a/src/tools/clippy/clippy_lints/src/uninhabited_references.rs
+++ b/src/tools/clippy/clippy_lints/src/uninhabited_references.rs
@@ -32,7 +32,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.76.0"]
     pub UNINHABITED_REFERENCES,
-    suspicious,
+    nursery,
     "reference to uninhabited type"
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index df715b12dea..8817e46b3c8 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -351,6 +351,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
             let_pat,
             let_expr,
             if_then,
+            ..
         }) = higher::WhileLet::hir(expr.value)
         {
             bind!(self, let_pat, let_expr, if_then);
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index 5d23326cec8..b8869eedf52 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_utils"
-version = "0.1.76"
+version = "0.1.77"
 edition = "2021"
 publish = false
 
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index 7fe76b946a4..adc35bd82ae 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -134,6 +134,7 @@ pub fn eq_struct_rest(l: &StructRest, r: &StructRest) -> bool {
     }
 }
 
+#[allow(clippy::too_many_lines)] // Just a big match statement
 pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
     use ExprKind::*;
     if !over(&l.attrs, &r.attrs, eq_attr) {
diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs
index 46c96fad884..db80e07ca1c 100644
--- a/src/tools/clippy/clippy_utils/src/attrs.rs
+++ b/src/tools/clippy/clippy_utils/src/attrs.rs
@@ -76,12 +76,14 @@ pub fn get_attr<'a>(
                 })
                 .map_or_else(
                     || {
-                        sess.dcx().span_err(attr_segments[1].ident.span, "usage of unknown attribute");
+                        sess.dcx()
+                            .span_err(attr_segments[1].ident.span, "usage of unknown attribute");
                         false
                     },
                     |deprecation_status| {
-                        let mut diag =
-                            sess.dcx().struct_span_err(attr_segments[1].ident.span, "usage of deprecated attribute");
+                        let mut diag = sess
+                            .dcx()
+                            .struct_span_err(attr_segments[1].ident.span, "usage of deprecated attribute");
                         match *deprecation_status {
                             DeprecationStatus::Deprecated => {
                                 diag.emit();
@@ -132,7 +134,8 @@ pub fn get_unique_attr<'a>(
     let mut unique_attr: Option<&ast::Attribute> = None;
     for attr in get_attr(sess, attrs, name) {
         if let Some(duplicate) = unique_attr {
-            sess.dcx().struct_span_err(attr.span, format!("`{name}` is defined multiple times"))
+            sess.dcx()
+                .struct_span_err(attr.span, format!("`{name}` is defined multiple times"))
                 .span_note(duplicate.span, "first definition found here")
                 .emit();
         } else {
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index 3135a033648..ba682813dad 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -91,6 +91,9 @@ pub struct IfLet<'hir> {
     pub if_then: &'hir Expr<'hir>,
     /// `if let` else expression
     pub if_else: Option<&'hir Expr<'hir>>,
+    /// `if let PAT = EXPR`
+    ///     ^^^^^^^^^^^^^^
+    pub let_span: Span,
 }
 
 impl<'hir> IfLet<'hir> {
@@ -99,9 +102,10 @@ impl<'hir> IfLet<'hir> {
         if let ExprKind::If(
             Expr {
                 kind:
-                    ExprKind::Let(hir::Let {
+                    ExprKind::Let(&hir::Let {
                         pat: let_pat,
                         init: let_expr,
+                        span: let_span,
                         ..
                     }),
                 ..
@@ -129,6 +133,7 @@ impl<'hir> IfLet<'hir> {
                 let_expr,
                 if_then,
                 if_else,
+                let_span,
             });
         }
         None
@@ -146,6 +151,9 @@ pub enum IfLetOrMatch<'hir> {
         &'hir Pat<'hir>,
         &'hir Expr<'hir>,
         Option<&'hir Expr<'hir>>,
+        /// `if let PAT = EXPR`
+        ///     ^^^^^^^^^^^^^^
+        Span,
     ),
 }
 
@@ -160,7 +168,8 @@ impl<'hir> IfLetOrMatch<'hir> {
                      let_pat,
                      if_then,
                      if_else,
-                 }| { Self::IfLet(let_expr, let_pat, if_then, if_else) },
+                     let_span,
+                 }| { Self::IfLet(let_expr, let_pat, if_then, if_else, let_span) },
             ),
         }
     }
@@ -353,6 +362,9 @@ pub struct WhileLet<'hir> {
     pub let_expr: &'hir Expr<'hir>,
     /// `while let` loop body
     pub if_then: &'hir Expr<'hir>,
+    /// `while let PAT = EXPR`
+    ///        ^^^^^^^^^^^^^^
+    pub let_span: Span,
 }
 
 impl<'hir> WhileLet<'hir> {
@@ -367,9 +379,10 @@ impl<'hir> WhileLet<'hir> {
                             ExprKind::If(
                                 Expr {
                                     kind:
-                                        ExprKind::Let(hir::Let {
+                                        ExprKind::Let(&hir::Let {
                                             pat: let_pat,
                                             init: let_expr,
+                                            span: let_span,
                                             ..
                                         }),
                                     ..
@@ -390,6 +403,7 @@ impl<'hir> WhileLet<'hir> {
                 let_pat,
                 let_expr,
                 if_then,
+                let_span,
             });
         }
         None
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index d752fe7d97e..ebc38e531fe 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -316,10 +316,7 @@ pub fn is_const_evaluatable<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) ->
         is_const: bool,
     }
     impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
-        type NestedFilter = nested_filter::OnlyBodies;
-        fn nested_visit_map(&mut self) -> Self::Map {
-            self.cx.tcx.hir()
-        }
+        type NestedFilter = rustc_hir::intravisit::nested_filter::None;
 
         fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
             if !self.is_const {
diff --git a/src/tools/clippy/declare_clippy_lint/Cargo.toml b/src/tools/clippy/declare_clippy_lint/Cargo.toml
index af123e107d5..5aaafb41721 100644
--- a/src/tools/clippy/declare_clippy_lint/Cargo.toml
+++ b/src/tools/clippy/declare_clippy_lint/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "declare_clippy_lint"
-version = "0.1.76"
+version = "0.1.77"
 edition = "2021"
 publish = false
 
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index d575da6dece..5a2526fd267 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2023-12-16"
+channel = "nightly-2023-12-28"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/tests/ui-internal/disallow_struct_span_lint.rs b/src/tools/clippy/tests/ui-internal/disallow_struct_span_lint.rs
index 3155c0235ff..c81d54918cb 100644
--- a/src/tools/clippy/tests/ui-internal/disallow_struct_span_lint.rs
+++ b/src/tools/clippy/tests/ui-internal/disallow_struct_span_lint.rs
@@ -11,7 +11,7 @@ use rustc_lint::{Lint, LintContext};
 use rustc_middle::ty::TyCtxt;
 
 pub fn a(cx: impl LintContext, lint: &'static Lint, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
-    cx.struct_span_lint(lint, span, msg, |b| b);
+    cx.struct_span_lint(lint, span, msg, |_| {});
 }
 
 pub fn b(
@@ -21,7 +21,7 @@ pub fn b(
     span: impl Into<MultiSpan>,
     msg: impl Into<DiagnosticMessage>,
 ) {
-    tcx.struct_span_lint_hir(lint, hir_id, span, msg, |b| b);
+    tcx.struct_span_lint_hir(lint, hir_id, span, msg, |_| {});
 }
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui-internal/disallow_struct_span_lint.stderr b/src/tools/clippy/tests/ui-internal/disallow_struct_span_lint.stderr
index 76c487fb135..7d424124f2b 100644
--- a/src/tools/clippy/tests/ui-internal/disallow_struct_span_lint.stderr
+++ b/src/tools/clippy/tests/ui-internal/disallow_struct_span_lint.stderr
@@ -1,8 +1,8 @@
 error: use of a disallowed method `rustc_lint::context::LintContext::struct_span_lint`
   --> $DIR/disallow_struct_span_lint.rs:14:5
    |
-LL |     cx.struct_span_lint(lint, span, msg, |b| b);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     cx.struct_span_lint(lint, span, msg, |_| {});
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::disallowed-methods` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]`
@@ -10,8 +10,8 @@ LL |     cx.struct_span_lint(lint, span, msg, |b| b);
 error: use of a disallowed method `rustc_middle::ty::context::TyCtxt::struct_span_lint_hir`
   --> $DIR/disallow_struct_span_lint.rs:24:5
    |
-LL |     tcx.struct_span_lint_hir(lint, hir_id, span, msg, |b| b);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     tcx.struct_span_lint_hir(lint, hir_id, span, msg, |_| {});
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs
index 17c1b03d88c..3edb3a10b76 100644
--- a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs
+++ b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs
@@ -7,7 +7,8 @@
     unconditional_panic,
     clippy::no_effect,
     clippy::unnecessary_operation,
-    clippy::useless_vec
+    clippy::useless_vec,
+    clippy::out_of_bounds_indexing
 )]
 
 const ARR: [i32; 2] = [1, 2];
diff --git a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr
index f8ace799593..84e7eff4557 100644
--- a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr
+++ b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr
@@ -1,17 +1,17 @@
 error[E0080]: evaluation of `main::{constant#3}` failed
-  --> $DIR/test.rs:37:14
+  --> $DIR/test.rs:38:14
    |
 LL |     const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
    |              ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
 
 note: erroneous constant encountered
-  --> $DIR/test.rs:37:5
+  --> $DIR/test.rs:38:5
    |
 LL |     const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: indexing may panic
-  --> $DIR/test.rs:28:5
+  --> $DIR/test.rs:29:5
    |
 LL |     x[index];
    |     ^^^^^^^^
@@ -21,7 +21,7 @@ LL |     x[index];
    = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]`
 
 error: indexing may panic
-  --> $DIR/test.rs:46:5
+  --> $DIR/test.rs:47:5
    |
 LL |     v[0];
    |     ^^^^
@@ -29,7 +29,7 @@ LL |     v[0];
    = help: consider using `.get(n)` or `.get_mut(n)` instead
 
 error: indexing may panic
-  --> $DIR/test.rs:47:5
+  --> $DIR/test.rs:48:5
    |
 LL |     v[10];
    |     ^^^^^
@@ -37,7 +37,7 @@ LL |     v[10];
    = help: consider using `.get(n)` or `.get_mut(n)` instead
 
 error: indexing may panic
-  --> $DIR/test.rs:48:5
+  --> $DIR/test.rs:49:5
    |
 LL |     v[1 << 3];
    |     ^^^^^^^^^
@@ -45,7 +45,7 @@ LL |     v[1 << 3];
    = help: consider using `.get(n)` or `.get_mut(n)` instead
 
 error: indexing may panic
-  --> $DIR/test.rs:54:5
+  --> $DIR/test.rs:55:5
    |
 LL |     v[N];
    |     ^^^^
@@ -53,7 +53,7 @@ LL |     v[N];
    = help: consider using `.get(n)` or `.get_mut(n)` instead
 
 error: indexing may panic
-  --> $DIR/test.rs:55:5
+  --> $DIR/test.rs:56:5
    |
 LL |     v[M];
    |     ^^^^
@@ -61,7 +61,7 @@ LL |     v[M];
    = help: consider using `.get(n)` or `.get_mut(n)` instead
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/test.rs:15:24
+  --> $DIR/test.rs:16:24
    |
 LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
    |                        ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
diff --git a/src/tools/clippy/tests/ui/assertions_on_constants.rs b/src/tools/clippy/tests/ui/assertions_on_constants.rs
index 10809a6d247..1309ae45d0a 100644
--- a/src/tools/clippy/tests/ui/assertions_on_constants.rs
+++ b/src/tools/clippy/tests/ui/assertions_on_constants.rs
@@ -45,4 +45,11 @@ fn main() {
 
     const CFG_FLAG: &bool = &cfg!(feature = "hey");
     assert!(!CFG_FLAG);
+
+    const _: () = assert!(true);
+    //~^ ERROR: `assert!(true)` will be optimized out by the compiler
+
+    // Don't lint if the value is dependent on a defined constant:
+    const N: usize = 1024;
+    const _: () = assert!(N.is_power_of_two());
 }
diff --git a/src/tools/clippy/tests/ui/assertions_on_constants.stderr b/src/tools/clippy/tests/ui/assertions_on_constants.stderr
index 780d1fe1c8a..099be4ed355 100644
--- a/src/tools/clippy/tests/ui/assertions_on_constants.stderr
+++ b/src/tools/clippy/tests/ui/assertions_on_constants.stderr
@@ -72,5 +72,13 @@ LL |     debug_assert!(true);
    |
    = help: remove it
 
-error: aborting due to 9 previous errors
+error: `assert!(true)` will be optimized out by the compiler
+  --> $DIR/assertions_on_constants.rs:49:19
+   |
+LL |     const _: () = assert!(true);
+   |                   ^^^^^^^^^^^^^
+   |
+   = help: remove it
+
+error: aborting due to 10 previous errors
 
diff --git a/src/tools/clippy/tests/ui/author/loop.rs b/src/tools/clippy/tests/ui/author/loop.rs
index d6de21631e2..ff5b6100117 100644
--- a/src/tools/clippy/tests/ui/author/loop.rs
+++ b/src/tools/clippy/tests/ui/author/loop.rs
@@ -1,5 +1,9 @@
 #![feature(stmt_expr_attributes)]
-#![allow(clippy::never_loop, clippy::while_immutable_condition)]
+#![allow(
+    clippy::never_loop,
+    clippy::while_immutable_condition,
+    clippy::redundant_pattern_matching
+)]
 
 fn main() {
     #[clippy::author]
diff --git a/src/tools/clippy/tests/ui/bool_comparison.fixed b/src/tools/clippy/tests/ui/bool_comparison.fixed
index e3f2ca72d1c..02f1d09b833 100644
--- a/src/tools/clippy/tests/ui/bool_comparison.fixed
+++ b/src/tools/clippy/tests/ui/bool_comparison.fixed
@@ -165,3 +165,12 @@ fn issue3973() {
     if is_debug == m!(func) {}
     if m!(func) == is_debug {}
 }
+
+#[allow(clippy::unnecessary_cast)]
+fn issue9907() {
+    let _ = (1 >= 2) as usize;
+    let _ = (!m!(func)) as usize;
+    // This is not part of the issue, but an unexpected found when fixing the issue,
+    // the provided span was inside of macro rather than the macro callsite.
+    let _ = ((1 < 2) != m!(func)) as usize;
+}
diff --git a/src/tools/clippy/tests/ui/bool_comparison.rs b/src/tools/clippy/tests/ui/bool_comparison.rs
index d1bc20d6831..5ef696d855e 100644
--- a/src/tools/clippy/tests/ui/bool_comparison.rs
+++ b/src/tools/clippy/tests/ui/bool_comparison.rs
@@ -165,3 +165,12 @@ fn issue3973() {
     if is_debug == m!(func) {}
     if m!(func) == is_debug {}
 }
+
+#[allow(clippy::unnecessary_cast)]
+fn issue9907() {
+    let _ = ((1 < 2) == false) as usize;
+    let _ = (false == m!(func)) as usize;
+    // This is not part of the issue, but an unexpected found when fixing the issue,
+    // the provided span was inside of macro rather than the macro callsite.
+    let _ = ((1 < 2) == !m!(func)) as usize;
+}
diff --git a/src/tools/clippy/tests/ui/bool_comparison.stderr b/src/tools/clippy/tests/ui/bool_comparison.stderr
index 4560df6d4cd..6907dc0523f 100644
--- a/src/tools/clippy/tests/ui/bool_comparison.stderr
+++ b/src/tools/clippy/tests/ui/bool_comparison.stderr
@@ -133,5 +133,23 @@ error: equality checks against true are unnecessary
 LL |     if m!(func) == true {}
    |        ^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `m!(func)`
 
-error: aborting due to 22 previous errors
+error: equality checks against false can be replaced by a negation
+  --> $DIR/bool_comparison.rs:171:14
+   |
+LL |     let _ = ((1 < 2) == false) as usize;
+   |              ^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `1 >= 2`
+
+error: equality checks against false can be replaced by a negation
+  --> $DIR/bool_comparison.rs:172:14
+   |
+LL |     let _ = (false == m!(func)) as usize;
+   |              ^^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `!m!(func)`
+
+error: this comparison might be written more concisely
+  --> $DIR/bool_comparison.rs:175:14
+   |
+LL |     let _ = ((1 < 2) == !m!(func)) as usize;
+   |              ^^^^^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `(1 < 2) != m!(func)`
+
+error: aborting due to 25 previous errors
 
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs
index d102efa7a58..549908b8770 100644
--- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs
@@ -1,6 +1,10 @@
 #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)]
-#![allow(dead_code)]
-#![allow(clippy::equatable_if_let, clippy::uninlined_format_args)]
+#![allow(
+    clippy::equatable_if_let,
+    clippy::uninlined_format_args,
+    clippy::redundant_pattern_matching,
+    dead_code
+)]
 //@no-rustfix
 // This tests the branches_sharing_code lint at the end of blocks
 
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr
index d00717befc1..8223df0fe7b 100644
--- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr
@@ -1,5 +1,5 @@
 error: all if blocks contain the same code at the end
-  --> $DIR/shared_at_bottom.rs:31:5
+  --> $DIR/shared_at_bottom.rs:35:5
    |
 LL | /         let result = false;
 LL | |
@@ -26,7 +26,7 @@ LL ~     result;
    |
 
 error: all if blocks contain the same code at the end
-  --> $DIR/shared_at_bottom.rs:51:5
+  --> $DIR/shared_at_bottom.rs:55:5
    |
 LL | /         println!("Same end of block");
 LL | |
@@ -40,7 +40,7 @@ LL +     println!("Same end of block");
    |
 
 error: all if blocks contain the same code at the end
-  --> $DIR/shared_at_bottom.rs:69:5
+  --> $DIR/shared_at_bottom.rs:73:5
    |
 LL | /         println!(
 LL | |
@@ -61,7 +61,7 @@ LL +     );
    |
 
 error: all if blocks contain the same code at the end
-  --> $DIR/shared_at_bottom.rs:82:9
+  --> $DIR/shared_at_bottom.rs:86:9
    |
 LL | /             println!("Hello World");
 LL | |
@@ -75,7 +75,7 @@ LL +         println!("Hello World");
    |
 
 error: all if blocks contain the same code at the end
-  --> $DIR/shared_at_bottom.rs:99:5
+  --> $DIR/shared_at_bottom.rs:103:5
    |
 LL | /         let later_used_value = "A string value";
 LL | |
@@ -94,7 +94,7 @@ LL +     println!("{}", later_used_value);
    |
 
 error: all if blocks contain the same code at the end
-  --> $DIR/shared_at_bottom.rs:113:5
+  --> $DIR/shared_at_bottom.rs:117:5
    |
 LL | /         let simple_examples = "I now identify as a &str :)";
 LL | |
@@ -112,7 +112,7 @@ LL +     println!("This is the new simple_example: {}", simple_examples);
    |
 
 error: all if blocks contain the same code at the end
-  --> $DIR/shared_at_bottom.rs:179:5
+  --> $DIR/shared_at_bottom.rs:183:5
    |
 LL | /         x << 2
 LL | |
@@ -128,7 +128,7 @@ LL ~     x << 2;
    |
 
 error: all if blocks contain the same code at the end
-  --> $DIR/shared_at_bottom.rs:188:5
+  --> $DIR/shared_at_bottom.rs:192:5
    |
 LL | /         x * 4
 LL | |
@@ -144,7 +144,7 @@ LL +     x * 4
    |
 
 error: all if blocks contain the same code at the end
-  --> $DIR/shared_at_bottom.rs:202:44
+  --> $DIR/shared_at_bottom.rs:206:44
    |
 LL |     if x == 17 { b = 1; a = 0x99; } else { a = 0x99; }
    |                                            ^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/collapsible_if.fixed b/src/tools/clippy/tests/ui/collapsible_if.fixed
index fff6bfcc753..44b0b6e7391 100644
--- a/src/tools/clippy/tests/ui/collapsible_if.fixed
+++ b/src/tools/clippy/tests/ui/collapsible_if.fixed
@@ -3,7 +3,8 @@
     clippy::equatable_if_let,
     clippy::needless_if,
     clippy::nonminimal_bool,
-    clippy::eq_op
+    clippy::eq_op,
+    clippy::redundant_pattern_matching
 )]
 
 #[rustfmt::skip]
diff --git a/src/tools/clippy/tests/ui/collapsible_if.rs b/src/tools/clippy/tests/ui/collapsible_if.rs
index 70bfea231ae..563a273dcdd 100644
--- a/src/tools/clippy/tests/ui/collapsible_if.rs
+++ b/src/tools/clippy/tests/ui/collapsible_if.rs
@@ -3,7 +3,8 @@
     clippy::equatable_if_let,
     clippy::needless_if,
     clippy::nonminimal_bool,
-    clippy::eq_op
+    clippy::eq_op,
+    clippy::redundant_pattern_matching
 )]
 
 #[rustfmt::skip]
diff --git a/src/tools/clippy/tests/ui/collapsible_if.stderr b/src/tools/clippy/tests/ui/collapsible_if.stderr
index e8a36bf48f1..16df3e433db 100644
--- a/src/tools/clippy/tests/ui/collapsible_if.stderr
+++ b/src/tools/clippy/tests/ui/collapsible_if.stderr
@@ -1,5 +1,5 @@
 error: this `if` statement can be collapsed
-  --> $DIR/collapsible_if.rs:14:5
+  --> $DIR/collapsible_if.rs:15:5
    |
 LL | /     if x == "hello" {
 LL | |         if y == "world" {
@@ -18,7 +18,7 @@ LL +     }
    |
 
 error: this `if` statement can be collapsed
-  --> $DIR/collapsible_if.rs:20:5
+  --> $DIR/collapsible_if.rs:21:5
    |
 LL | /     if x == "hello" || x == "world" {
 LL | |         if y == "world" || y == "hello" {
@@ -35,7 +35,7 @@ LL +     }
    |
 
 error: this `if` statement can be collapsed
-  --> $DIR/collapsible_if.rs:26:5
+  --> $DIR/collapsible_if.rs:27:5
    |
 LL | /     if x == "hello" && x == "world" {
 LL | |         if y == "world" || y == "hello" {
@@ -52,7 +52,7 @@ LL +     }
    |
 
 error: this `if` statement can be collapsed
-  --> $DIR/collapsible_if.rs:32:5
+  --> $DIR/collapsible_if.rs:33:5
    |
 LL | /     if x == "hello" || x == "world" {
 LL | |         if y == "world" && y == "hello" {
@@ -69,7 +69,7 @@ LL +     }
    |
 
 error: this `if` statement can be collapsed
-  --> $DIR/collapsible_if.rs:38:5
+  --> $DIR/collapsible_if.rs:39:5
    |
 LL | /     if x == "hello" && x == "world" {
 LL | |         if y == "world" && y == "hello" {
@@ -86,7 +86,7 @@ LL +     }
    |
 
 error: this `if` statement can be collapsed
-  --> $DIR/collapsible_if.rs:44:5
+  --> $DIR/collapsible_if.rs:45:5
    |
 LL | /     if 42 == 1337 {
 LL | |         if 'a' != 'A' {
@@ -103,7 +103,7 @@ LL +     }
    |
 
 error: this `if` statement can be collapsed
-  --> $DIR/collapsible_if.rs:100:5
+  --> $DIR/collapsible_if.rs:101:5
    |
 LL | /     if x == "hello" {
 LL | |         if y == "world" { // Collapsible
@@ -120,7 +120,7 @@ LL +     }
    |
 
 error: this `if` statement can be collapsed
-  --> $DIR/collapsible_if.rs:159:5
+  --> $DIR/collapsible_if.rs:160:5
    |
 LL | /     if matches!(true, true) {
 LL | |         if matches!(true, true) {}
@@ -128,7 +128,7 @@ LL | |     }
    | |_____^ help: collapse nested if block: `if matches!(true, true) && matches!(true, true) {}`
 
 error: this `if` statement can be collapsed
-  --> $DIR/collapsible_if.rs:164:5
+  --> $DIR/collapsible_if.rs:165:5
    |
 LL | /     if matches!(true, true) && truth() {
 LL | |         if matches!(true, true) {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-11939.rs b/src/tools/clippy/tests/ui/crashes/ice-11939.rs
new file mode 100644
index 00000000000..5e7193b6826
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-11939.rs
@@ -0,0 +1,14 @@
+#![allow(clippy::unit_arg, clippy::no_effect)]
+
+const fn v(_: ()) {}
+
+fn main() {
+    if true {
+        v({
+            [0; 1 + 1];
+        });
+        Some(())
+    } else {
+        None
+    };
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-5497.rs b/src/tools/clippy/tests/ui/crashes/ice-5497.rs
index f77f691c192..fe8d640c470 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-5497.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-5497.rs
@@ -1,4 +1,6 @@
 // reduced from rustc issue-69020-assoc-const-arith-overflow.rs
+#![allow(clippy::out_of_bounds_indexing)]
+
 pub fn main() {}
 
 pub trait Foo {
diff --git a/src/tools/clippy/tests/ui/crashes/ice-5497.stderr b/src/tools/clippy/tests/ui/crashes/ice-5497.stderr
index ee69f3379b6..3efaf05827e 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-5497.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-5497.stderr
@@ -1,5 +1,5 @@
 error: this operation will panic at runtime
-  --> $DIR/ice-5497.rs:9:22
+  --> $DIR/ice-5497.rs:11:22
    |
 LL |     const OOB: i32 = [1][1] + T::OOB;
    |                      ^^^^^^ index out of bounds: the length is 1 but the index is 1
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
index 708ac666675..bff46e55722 100644
--- a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
+++ b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
@@ -65,7 +65,7 @@ fn test_units() {
 /// OAuth GraphQL
 /// OCaml
 /// OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenDNS
-/// WebGL
+/// WebGL WebGL2 WebGPU
 /// TensorFlow
 /// TrueType
 /// iOS macOS FreeBSD
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.rs b/src/tools/clippy/tests/ui/doc/doc-fixable.rs
index 040d6352c52..4e162a97dee 100644
--- a/src/tools/clippy/tests/ui/doc/doc-fixable.rs
+++ b/src/tools/clippy/tests/ui/doc/doc-fixable.rs
@@ -65,7 +65,7 @@ fn test_units() {
 /// OAuth GraphQL
 /// OCaml
 /// OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenDNS
-/// WebGL
+/// WebGL WebGL2 WebGPU
 /// TensorFlow
 /// TrueType
 /// iOS macOS FreeBSD
diff --git a/src/tools/clippy/tests/ui/eager_transmute.fixed b/src/tools/clippy/tests/ui/eager_transmute.fixed
new file mode 100644
index 00000000000..e06aa2cc9fd
--- /dev/null
+++ b/src/tools/clippy/tests/ui/eager_transmute.fixed
@@ -0,0 +1,72 @@
+#![feature(rustc_attrs)]
+#![warn(clippy::eager_transmute)]
+#![allow(clippy::transmute_int_to_non_zero)]
+
+use std::num::NonZeroU8;
+
+#[repr(u8)]
+enum Opcode {
+    Add = 0,
+    Sub = 1,
+    Mul = 2,
+    Div = 3,
+}
+
+fn int_to_opcode(op: u8) -> Option<Opcode> {
+    (op < 4).then(|| unsafe { std::mem::transmute(op) })
+}
+
+fn f(op: u8, unrelated: u8) {
+    true.then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
+    (unrelated < 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
+    (op < 4).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) });
+    (op > 4).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) });
+    (op == 0).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) });
+}
+
+unsafe fn f2(op: u8) {
+    (op < 4).then(|| std::mem::transmute::<_, Opcode>(op));
+}
+
+#[rustc_layout_scalar_valid_range_end(254)]
+struct NonMaxU8(u8);
+#[rustc_layout_scalar_valid_range_end(254)]
+#[rustc_layout_scalar_valid_range_start(1)]
+struct NonZeroNonMaxU8(u8);
+
+macro_rules! impls {
+    ($($t:ty),*) => {
+        $(
+            impl PartialEq<u8> for $t {
+                fn eq(&self, other: &u8) -> bool {
+                    self.0 == *other
+                }
+            }
+            impl PartialOrd<u8> for $t {
+                fn partial_cmp(&self, other: &u8) -> Option<std::cmp::Ordering> {
+                    self.0.partial_cmp(other)
+                }
+            }
+        )*
+    };
+}
+impls!(NonMaxU8, NonZeroNonMaxU8);
+
+fn niche_tests(v1: u8, v2: NonZeroU8, v3: NonZeroNonMaxU8) {
+    // u8 -> NonZeroU8, do lint
+    let _: Option<NonZeroU8> = (v1 > 0).then(|| unsafe { std::mem::transmute(v1) });
+
+    // NonZeroU8 -> u8, don't lint, target type has no niche and therefore a higher validity range
+    let _: Option<u8> = (v2 > NonZeroU8::new(1).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
+
+    // NonZeroU8 -> NonMaxU8, do lint, different niche
+    let _: Option<NonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then(|| unsafe { std::mem::transmute(v2) });
+
+    // NonZeroNonMaxU8 -> NonMaxU8, don't lint, target type has more validity
+    let _: Option<NonMaxU8> = (v3 < 255).then_some(unsafe { std::mem::transmute(v2) });
+
+    // NonZeroU8 -> NonZeroNonMaxU8, do lint, target type has less validity
+    let _: Option<NonZeroNonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then(|| unsafe { std::mem::transmute(v2) });
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/eager_transmute.rs b/src/tools/clippy/tests/ui/eager_transmute.rs
new file mode 100644
index 00000000000..89ccdf583f3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/eager_transmute.rs
@@ -0,0 +1,72 @@
+#![feature(rustc_attrs)]
+#![warn(clippy::eager_transmute)]
+#![allow(clippy::transmute_int_to_non_zero)]
+
+use std::num::NonZeroU8;
+
+#[repr(u8)]
+enum Opcode {
+    Add = 0,
+    Sub = 1,
+    Mul = 2,
+    Div = 3,
+}
+
+fn int_to_opcode(op: u8) -> Option<Opcode> {
+    (op < 4).then_some(unsafe { std::mem::transmute(op) })
+}
+
+fn f(op: u8, unrelated: u8) {
+    true.then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
+    (unrelated < 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
+    (op < 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
+    (op > 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
+    (op == 0).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
+}
+
+unsafe fn f2(op: u8) {
+    (op < 4).then_some(std::mem::transmute::<_, Opcode>(op));
+}
+
+#[rustc_layout_scalar_valid_range_end(254)]
+struct NonMaxU8(u8);
+#[rustc_layout_scalar_valid_range_end(254)]
+#[rustc_layout_scalar_valid_range_start(1)]
+struct NonZeroNonMaxU8(u8);
+
+macro_rules! impls {
+    ($($t:ty),*) => {
+        $(
+            impl PartialEq<u8> for $t {
+                fn eq(&self, other: &u8) -> bool {
+                    self.0 == *other
+                }
+            }
+            impl PartialOrd<u8> for $t {
+                fn partial_cmp(&self, other: &u8) -> Option<std::cmp::Ordering> {
+                    self.0.partial_cmp(other)
+                }
+            }
+        )*
+    };
+}
+impls!(NonMaxU8, NonZeroNonMaxU8);
+
+fn niche_tests(v1: u8, v2: NonZeroU8, v3: NonZeroNonMaxU8) {
+    // u8 -> NonZeroU8, do lint
+    let _: Option<NonZeroU8> = (v1 > 0).then_some(unsafe { std::mem::transmute(v1) });
+
+    // NonZeroU8 -> u8, don't lint, target type has no niche and therefore a higher validity range
+    let _: Option<u8> = (v2 > NonZeroU8::new(1).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
+
+    // NonZeroU8 -> NonMaxU8, do lint, different niche
+    let _: Option<NonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
+
+    // NonZeroNonMaxU8 -> NonMaxU8, don't lint, target type has more validity
+    let _: Option<NonMaxU8> = (v3 < 255).then_some(unsafe { std::mem::transmute(v2) });
+
+    // NonZeroU8 -> NonZeroNonMaxU8, do lint, target type has less validity
+    let _: Option<NonZeroNonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/eager_transmute.stderr b/src/tools/clippy/tests/ui/eager_transmute.stderr
new file mode 100644
index 00000000000..5eb163c5fcb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/eager_transmute.stderr
@@ -0,0 +1,92 @@
+error: this transmute is always evaluated eagerly, even if the condition is false
+  --> $DIR/eager_transmute.rs:16:33
+   |
+LL |     (op < 4).then_some(unsafe { std::mem::transmute(op) })
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::eager-transmute` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::eager_transmute)]`
+help: consider using `bool::then` to only transmute if the condition holds
+   |
+LL |     (op < 4).then(|| unsafe { std::mem::transmute(op) })
+   |              ~~~~ ++
+
+error: this transmute is always evaluated eagerly, even if the condition is false
+  --> $DIR/eager_transmute.rs:22:33
+   |
+LL |     (op < 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using `bool::then` to only transmute if the condition holds
+   |
+LL |     (op < 4).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) });
+   |              ~~~~ ++
+
+error: this transmute is always evaluated eagerly, even if the condition is false
+  --> $DIR/eager_transmute.rs:23:33
+   |
+LL |     (op > 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using `bool::then` to only transmute if the condition holds
+   |
+LL |     (op > 4).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) });
+   |              ~~~~ ++
+
+error: this transmute is always evaluated eagerly, even if the condition is false
+  --> $DIR/eager_transmute.rs:24:34
+   |
+LL |     (op == 0).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using `bool::then` to only transmute if the condition holds
+   |
+LL |     (op == 0).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) });
+   |               ~~~~ ++
+
+error: this transmute is always evaluated eagerly, even if the condition is false
+  --> $DIR/eager_transmute.rs:28:24
+   |
+LL |     (op < 4).then_some(std::mem::transmute::<_, Opcode>(op));
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using `bool::then` to only transmute if the condition holds
+   |
+LL |     (op < 4).then(|| std::mem::transmute::<_, Opcode>(op));
+   |              ~~~~ ++
+
+error: this transmute is always evaluated eagerly, even if the condition is false
+  --> $DIR/eager_transmute.rs:57:60
+   |
+LL |     let _: Option<NonZeroU8> = (v1 > 0).then_some(unsafe { std::mem::transmute(v1) });
+   |                                                            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using `bool::then` to only transmute if the condition holds
+   |
+LL |     let _: Option<NonZeroU8> = (v1 > 0).then(|| unsafe { std::mem::transmute(v1) });
+   |                                         ~~~~ ++
+
+error: this transmute is always evaluated eagerly, even if the condition is false
+  --> $DIR/eager_transmute.rs:63:86
+   |
+LL |     let _: Option<NonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
+   |                                                                                      ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using `bool::then` to only transmute if the condition holds
+   |
+LL |     let _: Option<NonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then(|| unsafe { std::mem::transmute(v2) });
+   |                                                                   ~~~~ ++
+
+error: this transmute is always evaluated eagerly, even if the condition is false
+  --> $DIR/eager_transmute.rs:69:93
+   |
+LL |     let _: Option<NonZeroNonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
+   |                                                                                             ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using `bool::then` to only transmute if the condition holds
+   |
+LL |     let _: Option<NonZeroNonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then(|| unsafe { std::mem::transmute(v2) });
+   |                                                                          ~~~~ ++
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/get_unwrap.fixed b/src/tools/clippy/tests/ui/get_unwrap.fixed
index d5a4309db59..62beb195939 100644
--- a/src/tools/clippy/tests/ui/get_unwrap.fixed
+++ b/src/tools/clippy/tests/ui/get_unwrap.fixed
@@ -2,7 +2,8 @@
     unused_mut,
     clippy::from_iter_instead_of_collect,
     clippy::get_first,
-    clippy::useless_vec
+    clippy::useless_vec,
+    clippy::out_of_bounds_indexing
 )]
 #![warn(clippy::unwrap_used)]
 #![deny(clippy::get_unwrap)]
diff --git a/src/tools/clippy/tests/ui/get_unwrap.rs b/src/tools/clippy/tests/ui/get_unwrap.rs
index 5a9ad204f70..1e09ff5c67e 100644
--- a/src/tools/clippy/tests/ui/get_unwrap.rs
+++ b/src/tools/clippy/tests/ui/get_unwrap.rs
@@ -2,7 +2,8 @@
     unused_mut,
     clippy::from_iter_instead_of_collect,
     clippy::get_first,
-    clippy::useless_vec
+    clippy::useless_vec,
+    clippy::out_of_bounds_indexing
 )]
 #![warn(clippy::unwrap_used)]
 #![deny(clippy::get_unwrap)]
diff --git a/src/tools/clippy/tests/ui/get_unwrap.stderr b/src/tools/clippy/tests/ui/get_unwrap.stderr
index 384860ea116..700f3cfec4e 100644
--- a/src/tools/clippy/tests/ui/get_unwrap.stderr
+++ b/src/tools/clippy/tests/ui/get_unwrap.stderr
@@ -1,17 +1,17 @@
 error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:36:17
+  --> $DIR/get_unwrap.rs:37:17
    |
 LL |         let _ = boxed_slice.get(1).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&boxed_slice[1]`
    |
 note: the lint level is defined here
-  --> $DIR/get_unwrap.rs:8:9
+  --> $DIR/get_unwrap.rs:9:9
    |
 LL | #![deny(clippy::get_unwrap)]
    |         ^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap()` on an `Option` value
-  --> $DIR/get_unwrap.rs:36:17
+  --> $DIR/get_unwrap.rs:37:17
    |
 LL |         let _ = boxed_slice.get(1).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -22,13 +22,13 @@ LL |         let _ = boxed_slice.get(1).unwrap();
    = help: to override `-D warnings` add `#[allow(clippy::unwrap_used)]`
 
 error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:37:17
+  --> $DIR/get_unwrap.rs:38:17
    |
 LL |         let _ = some_slice.get(0).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_slice[0]`
 
 error: used `unwrap()` on an `Option` value
-  --> $DIR/get_unwrap.rs:37:17
+  --> $DIR/get_unwrap.rs:38:17
    |
 LL |         let _ = some_slice.get(0).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -37,13 +37,13 @@ LL |         let _ = some_slice.get(0).unwrap();
    = help: consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:38:17
+  --> $DIR/get_unwrap.rs:39:17
    |
 LL |         let _ = some_vec.get(0).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vec[0]`
 
 error: used `unwrap()` on an `Option` value
-  --> $DIR/get_unwrap.rs:38:17
+  --> $DIR/get_unwrap.rs:39:17
    |
 LL |         let _ = some_vec.get(0).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -52,13 +52,13 @@ LL |         let _ = some_vec.get(0).unwrap();
    = help: consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:39:17
+  --> $DIR/get_unwrap.rs:40:17
    |
 LL |         let _ = some_vecdeque.get(0).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vecdeque[0]`
 
 error: used `unwrap()` on an `Option` value
-  --> $DIR/get_unwrap.rs:39:17
+  --> $DIR/get_unwrap.rs:40:17
    |
 LL |         let _ = some_vecdeque.get(0).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -67,13 +67,13 @@ LL |         let _ = some_vecdeque.get(0).unwrap();
    = help: consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:40:17
+  --> $DIR/get_unwrap.rs:41:17
    |
 LL |         let _ = some_hashmap.get(&1).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_hashmap[&1]`
 
 error: used `unwrap()` on an `Option` value
-  --> $DIR/get_unwrap.rs:40:17
+  --> $DIR/get_unwrap.rs:41:17
    |
 LL |         let _ = some_hashmap.get(&1).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -82,13 +82,13 @@ LL |         let _ = some_hashmap.get(&1).unwrap();
    = help: consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:41:17
+  --> $DIR/get_unwrap.rs:42:17
    |
 LL |         let _ = some_btreemap.get(&1).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_btreemap[&1]`
 
 error: used `unwrap()` on an `Option` value
-  --> $DIR/get_unwrap.rs:41:17
+  --> $DIR/get_unwrap.rs:42:17
    |
 LL |         let _ = some_btreemap.get(&1).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -97,13 +97,13 @@ LL |         let _ = some_btreemap.get(&1).unwrap();
    = help: consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:45:21
+  --> $DIR/get_unwrap.rs:46:21
    |
 LL |         let _: u8 = *boxed_slice.get(1).unwrap();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[1]`
 
 error: used `unwrap()` on an `Option` value
-  --> $DIR/get_unwrap.rs:45:22
+  --> $DIR/get_unwrap.rs:46:22
    |
 LL |         let _: u8 = *boxed_slice.get(1).unwrap();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -112,13 +112,13 @@ LL |         let _: u8 = *boxed_slice.get(1).unwrap();
    = help: consider using `expect()` to provide a better panic message
 
 error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:50:9
+  --> $DIR/get_unwrap.rs:51:9
    |
 LL |         *boxed_slice.get_mut(0).unwrap() = 1;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[0]`
 
 error: used `unwrap()` on an `Option` value
-  --> $DIR/get_unwrap.rs:50:10
+  --> $DIR/get_unwrap.rs:51:10
    |
 LL |         *boxed_slice.get_mut(0).unwrap() = 1;
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -127,13 +127,13 @@ LL |         *boxed_slice.get_mut(0).unwrap() = 1;
    = help: consider using `expect()` to provide a better panic message
 
 error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:51:9
+  --> $DIR/get_unwrap.rs:52:9
    |
 LL |         *some_slice.get_mut(0).unwrap() = 1;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_slice[0]`
 
 error: used `unwrap()` on an `Option` value
-  --> $DIR/get_unwrap.rs:51:10
+  --> $DIR/get_unwrap.rs:52:10
    |
 LL |         *some_slice.get_mut(0).unwrap() = 1;
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -142,13 +142,13 @@ LL |         *some_slice.get_mut(0).unwrap() = 1;
    = help: consider using `expect()` to provide a better panic message
 
 error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:52:9
+  --> $DIR/get_unwrap.rs:53:9
    |
 LL |         *some_vec.get_mut(0).unwrap() = 1;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0]`
 
 error: used `unwrap()` on an `Option` value
-  --> $DIR/get_unwrap.rs:52:10
+  --> $DIR/get_unwrap.rs:53:10
    |
 LL |         *some_vec.get_mut(0).unwrap() = 1;
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -157,13 +157,13 @@ LL |         *some_vec.get_mut(0).unwrap() = 1;
    = help: consider using `expect()` to provide a better panic message
 
 error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:53:9
+  --> $DIR/get_unwrap.rs:54:9
    |
 LL |         *some_vecdeque.get_mut(0).unwrap() = 1;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vecdeque[0]`
 
 error: used `unwrap()` on an `Option` value
-  --> $DIR/get_unwrap.rs:53:10
+  --> $DIR/get_unwrap.rs:54:10
    |
 LL |         *some_vecdeque.get_mut(0).unwrap() = 1;
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -172,13 +172,13 @@ LL |         *some_vecdeque.get_mut(0).unwrap() = 1;
    = help: consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:65:17
+  --> $DIR/get_unwrap.rs:66:17
    |
 LL |         let _ = some_vec.get(0..1).unwrap().to_vec();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]`
 
 error: used `unwrap()` on an `Option` value
-  --> $DIR/get_unwrap.rs:65:17
+  --> $DIR/get_unwrap.rs:66:17
    |
 LL |         let _ = some_vec.get(0..1).unwrap().to_vec();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -187,13 +187,13 @@ LL |         let _ = some_vec.get(0..1).unwrap().to_vec();
    = help: consider using `expect()` to provide a better panic message
 
 error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:66:17
+  --> $DIR/get_unwrap.rs:67:17
    |
 LL |         let _ = some_vec.get_mut(0..1).unwrap().to_vec();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]`
 
 error: used `unwrap()` on an `Option` value
-  --> $DIR/get_unwrap.rs:66:17
+  --> $DIR/get_unwrap.rs:67:17
    |
 LL |         let _ = some_vec.get_mut(0..1).unwrap().to_vec();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -202,25 +202,25 @@ LL |         let _ = some_vec.get_mut(0..1).unwrap().to_vec();
    = help: consider using `expect()` to provide a better panic message
 
 error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:76:24
+  --> $DIR/get_unwrap.rs:77:24
    |
 LL |         let _x: &i32 = f.get(1 + 2).unwrap();
    |                        ^^^^^^^^^^^^^^^^^^^^^ help: try: `&f[1 + 2]`
 
 error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:79:18
+  --> $DIR/get_unwrap.rs:80:18
    |
 LL |         let _x = f.get(1 + 2).unwrap().to_string();
    |                  ^^^^^^^^^^^^^^^^^^^^^ help: try: `f[1 + 2]`
 
 error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:82:18
+  --> $DIR/get_unwrap.rs:83:18
    |
 LL |         let _x = f.get(1 + 2).unwrap().abs();
    |                  ^^^^^^^^^^^^^^^^^^^^^ help: try: `f[1 + 2]`
 
 error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:99:33
+  --> $DIR/get_unwrap.rs:100:33
    |
 LL |                         let b = rest.get_mut(linidx(j, k) - linidx(i, k) - 1).unwrap();
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut rest[linidx(j, k) - linidx(i, k) - 1]`
diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.rs b/src/tools/clippy/tests/ui/if_then_some_else_none.rs
index 77abd663e0a..abc92459148 100644
--- a/src/tools/clippy/tests/ui/if_then_some_else_none.rs
+++ b/src/tools/clippy/tests/ui/if_then_some_else_none.rs
@@ -1,4 +1,5 @@
 #![warn(clippy::if_then_some_else_none)]
+#![allow(clippy::redundant_pattern_matching)]
 
 fn main() {
     // Should issue an error.
diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.stderr b/src/tools/clippy/tests/ui/if_then_some_else_none.stderr
index 5c97b06da15..9b3d65cc803 100644
--- a/src/tools/clippy/tests/ui/if_then_some_else_none.stderr
+++ b/src/tools/clippy/tests/ui/if_then_some_else_none.stderr
@@ -1,5 +1,5 @@
 error: this could be simplified with `bool::then`
-  --> $DIR/if_then_some_else_none.rs:5:13
+  --> $DIR/if_then_some_else_none.rs:6:13
    |
 LL |       let _ = if foo() {
    |  _____________^
@@ -16,7 +16,7 @@ LL | |     };
    = help: to override `-D warnings` add `#[allow(clippy::if_then_some_else_none)]`
 
 error: this could be simplified with `bool::then`
-  --> $DIR/if_then_some_else_none.rs:14:13
+  --> $DIR/if_then_some_else_none.rs:15:13
    |
 LL |       let _ = if matches!(true, true) {
    |  _____________^
@@ -31,7 +31,7 @@ LL | |     };
    = help: consider using `bool::then` like: `matches!(true, true).then(|| { /* snippet */ matches!(true, false) })`
 
 error: this could be simplified with `bool::then_some`
-  --> $DIR/if_then_some_else_none.rs:24:28
+  --> $DIR/if_then_some_else_none.rs:25:28
    |
 LL |     let _ = x.and_then(|o| if o < 32 { Some(o) } else { None });
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -39,7 +39,7 @@ LL |     let _ = x.and_then(|o| if o < 32 { Some(o) } else { None });
    = help: consider using `bool::then_some` like: `(o < 32).then_some(o)`
 
 error: this could be simplified with `bool::then_some`
-  --> $DIR/if_then_some_else_none.rs:29:13
+  --> $DIR/if_then_some_else_none.rs:30:13
    |
 LL |     let _ = if !x { Some(0) } else { None };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -47,7 +47,7 @@ LL |     let _ = if !x { Some(0) } else { None };
    = help: consider using `bool::then_some` like: `(!x).then_some(0)`
 
 error: this could be simplified with `bool::then`
-  --> $DIR/if_then_some_else_none.rs:85:13
+  --> $DIR/if_then_some_else_none.rs:86:13
    |
 LL |       let _ = if foo() {
    |  _____________^
diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.rs b/src/tools/clippy/tests/ui/indexing_slicing_index.rs
index f0da5dfc60b..1ac0bb11014 100644
--- a/src/tools/clippy/tests/ui/indexing_slicing_index.rs
+++ b/src/tools/clippy/tests/ui/indexing_slicing_index.rs
@@ -74,4 +74,7 @@ fn main() {
     //~^ ERROR: indexing may panic
     v[M];
     //~^ ERROR: indexing may panic
+
+    let slice = &x;
+    let _ = x[4];
 }
diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr
index 1c34875d2b8..6d64fa1e6cf 100644
--- a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr
+++ b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr
@@ -38,6 +38,21 @@ LL |     x[index];
    |
    = help: consider using `.get(n)` or `.get_mut(n)` instead
 
+error: index is out of bounds
+  --> $DIR/indexing_slicing_index.rs:32:5
+   |
+LL |     x[4];
+   |     ^^^^
+   |
+   = note: `-D clippy::out-of-bounds-indexing` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::out_of_bounds_indexing)]`
+
+error: index is out of bounds
+  --> $DIR/indexing_slicing_index.rs:34:5
+   |
+LL |     x[1 << 3];
+   |     ^^^^^^^^^
+
 error: indexing may panic
   --> $DIR/indexing_slicing_index.rs:45:14
    |
@@ -56,6 +71,12 @@ LL |     const { &ARR[idx4()] };
    = help: consider using `.get(n)` or `.get_mut(n)` instead
    = note: the suggestion might not be applicable in constant blocks
 
+error: index is out of bounds
+  --> $DIR/indexing_slicing_index.rs:55:5
+   |
+LL |     y[4];
+   |     ^^^^
+
 error: indexing may panic
   --> $DIR/indexing_slicing_index.rs:58:5
    |
@@ -80,6 +101,12 @@ LL |     v[1 << 3];
    |
    = help: consider using `.get(n)` or `.get_mut(n)` instead
 
+error: index is out of bounds
+  --> $DIR/indexing_slicing_index.rs:70:5
+   |
+LL |     x[N];
+   |     ^^^^
+
 error: indexing may panic
   --> $DIR/indexing_slicing_index.rs:73:5
    |
@@ -96,12 +123,18 @@ LL |     v[M];
    |
    = help: consider using `.get(n)` or `.get_mut(n)` instead
 
+error: index is out of bounds
+  --> $DIR/indexing_slicing_index.rs:79:13
+   |
+LL |     let _ = x[4];
+   |             ^^^^
+
 error[E0080]: evaluation of constant value failed
   --> $DIR/indexing_slicing_index.rs:16:24
    |
 LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
    |                        ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
 
-error: aborting due to 12 previous errors
+error: aborting due to 17 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/src/tools/clippy/tests/ui/infinite_loops.stderr b/src/tools/clippy/tests/ui/infinite_loops.stderr
index f58b3cebbc3..771fbfa44ee 100644
--- a/src/tools/clippy/tests/ui/infinite_loops.stderr
+++ b/src/tools/clippy/tests/ui/infinite_loops.stderr
@@ -9,7 +9,7 @@ LL | |     }
    |
    = note: `-D clippy::infinite-loop` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::infinite_loop)]`
-help: if this is intentional, consider specifing `!` as function return
+help: if this is intentional, consider specifying `!` as function return
    |
 LL | fn no_break() -> ! {
    |               ++++
@@ -26,7 +26,7 @@ LL | |         do_something();
 LL | |     }
    | |_____^
    |
-help: if this is intentional, consider specifing `!` as function return
+help: if this is intentional, consider specifying `!` as function return
    |
 LL | fn all_inf() -> ! {
    |              ++++
@@ -43,7 +43,7 @@ LL | |             }
 LL | |         }
    | |_________^
    |
-help: if this is intentional, consider specifing `!` as function return
+help: if this is intentional, consider specifying `!` as function return
    |
 LL | fn all_inf() -> ! {
    |              ++++
@@ -57,7 +57,7 @@ LL | |                 do_something();
 LL | |             }
    | |_____________^
    |
-help: if this is intentional, consider specifing `!` as function return
+help: if this is intentional, consider specifying `!` as function return
    |
 LL | fn all_inf() -> ! {
    |              ++++
@@ -84,7 +84,7 @@ LL | |         do_something();
 LL | |     }
    | |_____^
    |
-help: if this is intentional, consider specifing `!` as function return
+help: if this is intentional, consider specifying `!` as function return
    |
 LL | fn no_break_never_ret_noise() -> ! {
    |                               ++++
@@ -101,7 +101,7 @@ LL | |         }
 LL | |     }
    | |_____^
    |
-help: if this is intentional, consider specifing `!` as function return
+help: if this is intentional, consider specifying `!` as function return
    |
 LL | fn break_inner_but_not_outer_1(cond: bool) -> ! {
    |                                            ++++
@@ -118,7 +118,7 @@ LL | |         }
 LL | |     }
    | |_____^
    |
-help: if this is intentional, consider specifing `!` as function return
+help: if this is intentional, consider specifying `!` as function return
    |
 LL | fn break_inner_but_not_outer_2(cond: bool) -> ! {
    |                                            ++++
@@ -132,7 +132,7 @@ LL | |             do_something();
 LL | |         }
    | |_________^
    |
-help: if this is intentional, consider specifing `!` as function return
+help: if this is intentional, consider specifying `!` as function return
    |
 LL | fn break_outer_but_not_inner() -> ! {
    |                                ++++
@@ -149,7 +149,7 @@ LL | |             }
 LL | |         }
    | |_________^
    |
-help: if this is intentional, consider specifing `!` as function return
+help: if this is intentional, consider specifying `!` as function return
    |
 LL | fn break_wrong_loop(cond: bool) -> ! {
    |                                 ++++
@@ -166,7 +166,7 @@ LL | |         }
 LL | |     }
    | |_____^
    |
-help: if this is intentional, consider specifing `!` as function return
+help: if this is intentional, consider specifying `!` as function return
    |
 LL | fn match_like() -> ! {
    |                 ++++
@@ -180,7 +180,7 @@ LL | |         let _x = matches!(result, Ok(v) if v != 0).then_some(0);
 LL | |     }
    | |_____^
    |
-help: if this is intentional, consider specifing `!` as function return
+help: if this is intentional, consider specifying `!` as function return
    |
 LL | fn match_like() -> ! {
    |                 ++++
@@ -197,7 +197,7 @@ LL | |         });
 LL | |     }
    | |_____^
    |
-help: if this is intentional, consider specifing `!` as function return
+help: if this is intentional, consider specifying `!` as function return
    |
 LL | fn match_like() -> ! {
    |                 ++++
@@ -211,7 +211,7 @@ LL | |             do_something();
 LL | |         }
    | |_________^
    |
-help: if this is intentional, consider specifing `!` as function return
+help: if this is intentional, consider specifying `!` as function return
    |
 LL |     fn problematic_trait_method() -> ! {
    |                                   ++++
@@ -225,7 +225,7 @@ LL | |             do_something();
 LL | |         }
    | |_________^
    |
-help: if this is intentional, consider specifing `!` as function return
+help: if this is intentional, consider specifying `!` as function return
    |
 LL |     fn could_be_problematic() -> ! {
    |                               ++++
@@ -239,7 +239,7 @@ LL | |             do_something();
 LL | |         }
    | |_________^
    |
-help: if this is intentional, consider specifing `!` as function return
+help: if this is intentional, consider specifying `!` as function return
    |
 LL |     let _loop_forever = || -> ! {
    |                            ++++
diff --git a/src/tools/clippy/tests/ui/iter_filter_is_ok.fixed b/src/tools/clippy/tests/ui/iter_filter_is_ok.fixed
new file mode 100644
index 00000000000..a5ca41528af
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_filter_is_ok.fixed
@@ -0,0 +1,26 @@
+#![warn(clippy::iter_filter_is_ok)]
+
+fn main() {
+    let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten();
+    //~^ HELP: consider using `flatten` instead
+    let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten();
+    //~^ HELP: consider using `flatten` instead
+
+    #[rustfmt::skip]
+    let _ = vec![Ok(1), Err(2)].into_iter().flatten();
+    //~^ HELP: consider using `flatten` instead
+
+    // Don't lint below
+    let mut counter = 0;
+    let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| {
+        counter += 1;
+        o.is_ok()
+    });
+    let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| {
+        // Roses are red,
+        // Violets are blue,
+        // `Err` is not an `Option`,
+        // and this doesn't ryme
+        o.is_ok()
+    });
+}
diff --git a/src/tools/clippy/tests/ui/iter_filter_is_ok.rs b/src/tools/clippy/tests/ui/iter_filter_is_ok.rs
new file mode 100644
index 00000000000..e4e73f5ada1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_filter_is_ok.rs
@@ -0,0 +1,26 @@
+#![warn(clippy::iter_filter_is_ok)]
+
+fn main() {
+    let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(Result::is_ok);
+    //~^ HELP: consider using `flatten` instead
+    let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|a| a.is_ok());
+    //~^ HELP: consider using `flatten` instead
+
+    #[rustfmt::skip]
+    let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| { o.is_ok() });
+    //~^ HELP: consider using `flatten` instead
+
+    // Don't lint below
+    let mut counter = 0;
+    let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| {
+        counter += 1;
+        o.is_ok()
+    });
+    let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| {
+        // Roses are red,
+        // Violets are blue,
+        // `Err` is not an `Option`,
+        // and this doesn't ryme
+        o.is_ok()
+    });
+}
diff --git a/src/tools/clippy/tests/ui/iter_filter_is_ok.stderr b/src/tools/clippy/tests/ui/iter_filter_is_ok.stderr
new file mode 100644
index 00000000000..f3acbe38d8a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_filter_is_ok.stderr
@@ -0,0 +1,23 @@
+error: `filter` for `is_ok` on iterator over `Result`s
+  --> $DIR/iter_filter_is_ok.rs:4:52
+   |
+LL |     let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(Result::is_ok);
+   |                                                    ^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+   |
+   = note: `-D clippy::iter-filter-is-ok` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::iter_filter_is_ok)]`
+
+error: `filter` for `is_ok` on iterator over `Result`s
+  --> $DIR/iter_filter_is_ok.rs:6:52
+   |
+LL |     let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|a| a.is_ok());
+   |                                                    ^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+
+error: `filter` for `is_ok` on iterator over `Result`s
+  --> $DIR/iter_filter_is_ok.rs:10:45
+   |
+LL |     let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| { o.is_ok() });
+   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/iter_filter_is_some.fixed b/src/tools/clippy/tests/ui/iter_filter_is_some.fixed
new file mode 100644
index 00000000000..c3fa93f0ab2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_filter_is_some.fixed
@@ -0,0 +1,27 @@
+#![warn(clippy::iter_filter_is_some)]
+
+fn main() {
+    let _ = vec![Some(1)].into_iter().flatten();
+    //~^ HELP: consider using `flatten` instead
+    let _ = vec![Some(1)].into_iter().flatten();
+    //~^ HELP: consider using `flatten` instead
+
+    #[rustfmt::skip]
+    let _ = vec![Some(1)].into_iter().flatten();
+    //~^ HELP: consider using `flatten` instead
+
+    // Don't lint below
+    let mut counter = 0;
+    let _ = vec![Some(1)].into_iter().filter(|o| {
+        counter += 1;
+        o.is_some()
+    });
+
+    let _ = vec![Some(1)].into_iter().filter(|o| {
+        // Roses are red,
+        // Violets are blue,
+        // `Err` is not an `Option`,
+        // and this doesn't ryme
+        o.is_some()
+    });
+}
diff --git a/src/tools/clippy/tests/ui/iter_filter_is_some.rs b/src/tools/clippy/tests/ui/iter_filter_is_some.rs
new file mode 100644
index 00000000000..b023776abe4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_filter_is_some.rs
@@ -0,0 +1,27 @@
+#![warn(clippy::iter_filter_is_some)]
+
+fn main() {
+    let _ = vec![Some(1)].into_iter().filter(Option::is_some);
+    //~^ HELP: consider using `flatten` instead
+    let _ = vec![Some(1)].into_iter().filter(|o| o.is_some());
+    //~^ HELP: consider using `flatten` instead
+
+    #[rustfmt::skip]
+    let _ = vec![Some(1)].into_iter().filter(|o| { o.is_some() });
+    //~^ HELP: consider using `flatten` instead
+
+    // Don't lint below
+    let mut counter = 0;
+    let _ = vec![Some(1)].into_iter().filter(|o| {
+        counter += 1;
+        o.is_some()
+    });
+
+    let _ = vec![Some(1)].into_iter().filter(|o| {
+        // Roses are red,
+        // Violets are blue,
+        // `Err` is not an `Option`,
+        // and this doesn't ryme
+        o.is_some()
+    });
+}
diff --git a/src/tools/clippy/tests/ui/iter_filter_is_some.stderr b/src/tools/clippy/tests/ui/iter_filter_is_some.stderr
new file mode 100644
index 00000000000..1f2b10036fe
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_filter_is_some.stderr
@@ -0,0 +1,23 @@
+error: `filter` for `is_some` on iterator over `Option`
+  --> $DIR/iter_filter_is_some.rs:4:39
+   |
+LL |     let _ = vec![Some(1)].into_iter().filter(Option::is_some);
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+   |
+   = note: `-D clippy::iter-filter-is-some` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::iter_filter_is_some)]`
+
+error: `filter` for `is_some` on iterator over `Option`
+  --> $DIR/iter_filter_is_some.rs:6:39
+   |
+LL |     let _ = vec![Some(1)].into_iter().filter(|o| o.is_some());
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+
+error: `filter` for `is_some` on iterator over `Option`
+  --> $DIR/iter_filter_is_some.rs:10:39
+   |
+LL |     let _ = vec![Some(1)].into_iter().filter(|o| { o.is_some() });
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/manual_let_else_question_mark.fixed b/src/tools/clippy/tests/ui/manual_let_else_question_mark.fixed
index b555186cc22..6b29ce75985 100644
--- a/src/tools/clippy/tests/ui/manual_let_else_question_mark.fixed
+++ b/src/tools/clippy/tests/ui/manual_let_else_question_mark.fixed
@@ -60,3 +60,24 @@ fn foo() -> Option<()> {
 
     Some(())
 }
+
+// lint not just `return None`, but also `return None;` (note the semicolon)
+fn issue11993(y: Option<i32>) -> Option<i32> {
+    let x = y?;
+
+    // don't lint: more than one statement in the else body
+    let Some(x) = y else {
+        todo!();
+        return None;
+    };
+
+    let Some(x) = y else {
+        // Roses are red,
+        // violets are blue,
+        // please keep this comment,
+        // it's art, you know?
+        return None;
+    };
+
+    None
+}
diff --git a/src/tools/clippy/tests/ui/manual_let_else_question_mark.rs b/src/tools/clippy/tests/ui/manual_let_else_question_mark.rs
index 5852c7094a4..e92c4c1375e 100644
--- a/src/tools/clippy/tests/ui/manual_let_else_question_mark.rs
+++ b/src/tools/clippy/tests/ui/manual_let_else_question_mark.rs
@@ -65,3 +65,26 @@ fn foo() -> Option<()> {
 
     Some(())
 }
+
+// lint not just `return None`, but also `return None;` (note the semicolon)
+fn issue11993(y: Option<i32>) -> Option<i32> {
+    let Some(x) = y else {
+        return None;
+    };
+
+    // don't lint: more than one statement in the else body
+    let Some(x) = y else {
+        todo!();
+        return None;
+    };
+
+    let Some(x) = y else {
+        // Roses are red,
+        // violets are blue,
+        // please keep this comment,
+        // it's art, you know?
+        return None;
+    };
+
+    None
+}
diff --git a/src/tools/clippy/tests/ui/manual_let_else_question_mark.stderr b/src/tools/clippy/tests/ui/manual_let_else_question_mark.stderr
index bf0b1bbf0dd..dec6947697a 100644
--- a/src/tools/clippy/tests/ui/manual_let_else_question_mark.stderr
+++ b/src/tools/clippy/tests/ui/manual_let_else_question_mark.stderr
@@ -53,5 +53,13 @@ error: this could be rewritten as `let...else`
 LL |         let v = if let Some(v_some) = g() { v_some } else { return None };
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { return None };`
 
-error: aborting due to 6 previous errors
+error: this `let...else` may be rewritten with the `?` operator
+  --> $DIR/manual_let_else_question_mark.rs:71:5
+   |
+LL | /     let Some(x) = y else {
+LL | |         return None;
+LL | |     };
+   | |______^ help: replace it with: `let x = y?;`
+
+error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_if.fixed b/src/tools/clippy/tests/ui/needless_if.fixed
index 1086ae2c984..79e33a7218b 100644
--- a/src/tools/clippy/tests/ui/needless_if.fixed
+++ b/src/tools/clippy/tests/ui/needless_if.fixed
@@ -10,6 +10,7 @@
     clippy::nonminimal_bool,
     clippy::short_circuit_statement,
     clippy::unnecessary_operation,
+    clippy::redundant_pattern_matching,
     unused
 )]
 #![warn(clippy::needless_if)]
diff --git a/src/tools/clippy/tests/ui/needless_if.rs b/src/tools/clippy/tests/ui/needless_if.rs
index 131cceaf712..2c135fb22bf 100644
--- a/src/tools/clippy/tests/ui/needless_if.rs
+++ b/src/tools/clippy/tests/ui/needless_if.rs
@@ -10,6 +10,7 @@
     clippy::nonminimal_bool,
     clippy::short_circuit_statement,
     clippy::unnecessary_operation,
+    clippy::redundant_pattern_matching,
     unused
 )]
 #![warn(clippy::needless_if)]
diff --git a/src/tools/clippy/tests/ui/needless_if.stderr b/src/tools/clippy/tests/ui/needless_if.stderr
index c3e83c0f1f5..9a911b4dbac 100644
--- a/src/tools/clippy/tests/ui/needless_if.stderr
+++ b/src/tools/clippy/tests/ui/needless_if.stderr
@@ -1,5 +1,5 @@
 error: this `if` branch is empty
-  --> $DIR/needless_if.rs:26:5
+  --> $DIR/needless_if.rs:27:5
    |
 LL |     if (true) {}
    |     ^^^^^^^^^^^^ help: you can remove it
@@ -8,13 +8,13 @@ LL |     if (true) {}
    = help: to override `-D warnings` add `#[allow(clippy::needless_if)]`
 
 error: this `if` branch is empty
-  --> $DIR/needless_if.rs:28:5
+  --> $DIR/needless_if.rs:29:5
    |
 LL |     if maybe_side_effect() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `maybe_side_effect();`
 
 error: this `if` branch is empty
-  --> $DIR/needless_if.rs:33:5
+  --> $DIR/needless_if.rs:34:5
    |
 LL | /     if {
 LL | |         return;
@@ -29,7 +29,7 @@ LL +     });
    |
 
 error: this `if` branch is empty
-  --> $DIR/needless_if.rs:49:5
+  --> $DIR/needless_if.rs:50:5
    |
 LL | /     if {
 LL | |         if let true = true
@@ -54,19 +54,19 @@ LL +     } && true);
    |
 
 error: this `if` branch is empty
-  --> $DIR/needless_if.rs:93:5
+  --> $DIR/needless_if.rs:94:5
    |
 LL |     if { maybe_side_effect() } {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() });`
 
 error: this `if` branch is empty
-  --> $DIR/needless_if.rs:95:5
+  --> $DIR/needless_if.rs:96:5
    |
 LL |     if { maybe_side_effect() } && true {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() } && true);`
 
 error: this `if` branch is empty
-  --> $DIR/needless_if.rs:99:5
+  --> $DIR/needless_if.rs:100:5
    |
 LL |     if true {}
    |     ^^^^^^^^^^ help: you can remove it: `true;`
diff --git a/src/tools/clippy/tests/ui/nonminimal_bool.rs b/src/tools/clippy/tests/ui/nonminimal_bool.rs
index da7876e772e..4d48ef14d31 100644
--- a/src/tools/clippy/tests/ui/nonminimal_bool.rs
+++ b/src/tools/clippy/tests/ui/nonminimal_bool.rs
@@ -1,6 +1,11 @@
 //@no-rustfix: overlapping suggestions
 #![feature(lint_reasons)]
-#![allow(unused, clippy::diverging_sub_expression, clippy::needless_if)]
+#![allow(
+    unused,
+    clippy::diverging_sub_expression,
+    clippy::needless_if,
+    clippy::redundant_pattern_matching
+)]
 #![warn(clippy::nonminimal_bool)]
 #![allow(clippy::useless_vec)]
 
diff --git a/src/tools/clippy/tests/ui/nonminimal_bool.stderr b/src/tools/clippy/tests/ui/nonminimal_bool.stderr
index deae389dbef..fd1568d94e3 100644
--- a/src/tools/clippy/tests/ui/nonminimal_bool.stderr
+++ b/src/tools/clippy/tests/ui/nonminimal_bool.stderr
@@ -1,5 +1,5 @@
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool.rs:13:13
+  --> $DIR/nonminimal_bool.rs:18:13
    |
 LL |     let _ = !true;
    |             ^^^^^ help: try: `false`
@@ -8,43 +8,43 @@ LL |     let _ = !true;
    = help: to override `-D warnings` add `#[allow(clippy::nonminimal_bool)]`
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool.rs:16:13
+  --> $DIR/nonminimal_bool.rs:21:13
    |
 LL |     let _ = !false;
    |             ^^^^^^ help: try: `true`
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool.rs:18:13
+  --> $DIR/nonminimal_bool.rs:23:13
    |
 LL |     let _ = !!a;
    |             ^^^ help: try: `a`
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool.rs:20:13
+  --> $DIR/nonminimal_bool.rs:25:13
    |
 LL |     let _ = false || a;
    |             ^^^^^^^^^^ help: try: `a`
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool.rs:25:13
+  --> $DIR/nonminimal_bool.rs:30:13
    |
 LL |     let _ = !(!a && b);
    |             ^^^^^^^^^^ help: try: `a || !b`
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool.rs:27:13
+  --> $DIR/nonminimal_bool.rs:32:13
    |
 LL |     let _ = !(!a || b);
    |             ^^^^^^^^^^ help: try: `a && !b`
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool.rs:29:13
+  --> $DIR/nonminimal_bool.rs:34:13
    |
 LL |     let _ = !a && !(b && c);
    |             ^^^^^^^^^^^^^^^ help: try: `!(a || b && c)`
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool.rs:38:13
+  --> $DIR/nonminimal_bool.rs:43:13
    |
 LL |     let _ = a == b && c == 5 && a == b;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -57,7 +57,7 @@ LL |     let _ = a == b && c == 5;
    |             ~~~~~~~~~~~~~~~~
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool.rs:40:13
+  --> $DIR/nonminimal_bool.rs:45:13
    |
 LL |     let _ = a == b || c == 5 || a == b;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -70,7 +70,7 @@ LL |     let _ = a == b || c == 5;
    |             ~~~~~~~~~~~~~~~~
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool.rs:42:13
+  --> $DIR/nonminimal_bool.rs:47:13
    |
 LL |     let _ = a == b && c == 5 && b == a;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -83,7 +83,7 @@ LL |     let _ = a == b && c == 5;
    |             ~~~~~~~~~~~~~~~~
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool.rs:44:13
+  --> $DIR/nonminimal_bool.rs:49:13
    |
 LL |     let _ = a != b || !(a != b || c == d);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -96,7 +96,7 @@ LL |     let _ = a != b || c != d;
    |             ~~~~~~~~~~~~~~~~
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool.rs:46:13
+  --> $DIR/nonminimal_bool.rs:51:13
    |
 LL |     let _ = a != b && !(a != b && c == d);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -109,7 +109,7 @@ LL |     let _ = a != b && c != d;
    |             ~~~~~~~~~~~~~~~~
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool.rs:77:8
+  --> $DIR/nonminimal_bool.rs:82:8
    |
 LL |     if matches!(true, true) && true {
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(true, true)`
diff --git a/src/tools/clippy/tests/ui/option_filter_map.fixed b/src/tools/clippy/tests/ui/option_filter_map.fixed
index ee004c0e194..b1c3cfa48a4 100644
--- a/src/tools/clippy/tests/ui/option_filter_map.fixed
+++ b/src/tools/clippy/tests/ui/option_filter_map.fixed
@@ -3,12 +3,18 @@
 
 fn main() {
     let _ = Some(Some(1)).flatten();
+    //~^ ERROR: `filter` for `Some` followed by `unwrap`
     let _ = Some(Some(1)).flatten();
+    //~^ ERROR: `filter` for `Some` followed by `unwrap`
     let _ = Some(1).map(odds_out).flatten();
+    //~^ ERROR: `filter` for `Some` followed by `unwrap`
     let _ = Some(1).map(odds_out).flatten();
+    //~^ ERROR: `filter` for `Some` followed by `unwrap`
 
     let _ = vec![Some(1)].into_iter().flatten();
+    //~^ ERROR: `filter` for `Some` followed by `unwrap`
     let _ = vec![Some(1)].into_iter().flatten();
+    //~^ ERROR: `filter` for `Some` followed by `unwrap`
     let _ = vec![1]
         .into_iter()
         .map(odds_out)
diff --git a/src/tools/clippy/tests/ui/option_filter_map.rs b/src/tools/clippy/tests/ui/option_filter_map.rs
index eae2fa176a8..2550b9cd2b3 100644
--- a/src/tools/clippy/tests/ui/option_filter_map.rs
+++ b/src/tools/clippy/tests/ui/option_filter_map.rs
@@ -3,21 +3,29 @@
 
 fn main() {
     let _ = Some(Some(1)).filter(Option::is_some).map(Option::unwrap);
+    //~^ ERROR: `filter` for `Some` followed by `unwrap`
     let _ = Some(Some(1)).filter(|o| o.is_some()).map(|o| o.unwrap());
+    //~^ ERROR: `filter` for `Some` followed by `unwrap`
     let _ = Some(1).map(odds_out).filter(Option::is_some).map(Option::unwrap);
+    //~^ ERROR: `filter` for `Some` followed by `unwrap`
     let _ = Some(1).map(odds_out).filter(|o| o.is_some()).map(|o| o.unwrap());
+    //~^ ERROR: `filter` for `Some` followed by `unwrap`
 
     let _ = vec![Some(1)].into_iter().filter(Option::is_some).map(Option::unwrap);
+    //~^ ERROR: `filter` for `Some` followed by `unwrap`
     let _ = vec![Some(1)].into_iter().filter(|o| o.is_some()).map(|o| o.unwrap());
+    //~^ ERROR: `filter` for `Some` followed by `unwrap`
     let _ = vec![1]
         .into_iter()
         .map(odds_out)
         .filter(Option::is_some)
+        //~^ ERROR: `filter` for `Some` followed by `unwrap`
         .map(Option::unwrap);
     let _ = vec![1]
         .into_iter()
         .map(odds_out)
         .filter(|o| o.is_some())
+        //~^ ERROR: `filter` for `Some` followed by `unwrap`
         .map(|o| o.unwrap());
 }
 
diff --git a/src/tools/clippy/tests/ui/option_filter_map.stderr b/src/tools/clippy/tests/ui/option_filter_map.stderr
index 148f9d02f5e..6a0fc10822b 100644
--- a/src/tools/clippy/tests/ui/option_filter_map.stderr
+++ b/src/tools/clippy/tests/ui/option_filter_map.stderr
@@ -8,48 +8,50 @@ LL |     let _ = Some(Some(1)).filter(Option::is_some).map(Option::unwrap);
    = help: to override `-D warnings` add `#[allow(clippy::option_filter_map)]`
 
 error: `filter` for `Some` followed by `unwrap`
-  --> $DIR/option_filter_map.rs:6:27
+  --> $DIR/option_filter_map.rs:7:27
    |
 LL |     let _ = Some(Some(1)).filter(|o| o.is_some()).map(|o| o.unwrap());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
 
 error: `filter` for `Some` followed by `unwrap`
-  --> $DIR/option_filter_map.rs:7:35
+  --> $DIR/option_filter_map.rs:9:35
    |
 LL |     let _ = Some(1).map(odds_out).filter(Option::is_some).map(Option::unwrap);
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
 
 error: `filter` for `Some` followed by `unwrap`
-  --> $DIR/option_filter_map.rs:8:35
+  --> $DIR/option_filter_map.rs:11:35
    |
 LL |     let _ = Some(1).map(odds_out).filter(|o| o.is_some()).map(|o| o.unwrap());
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
 
 error: `filter` for `Some` followed by `unwrap`
-  --> $DIR/option_filter_map.rs:10:39
+  --> $DIR/option_filter_map.rs:14:39
    |
 LL |     let _ = vec![Some(1)].into_iter().filter(Option::is_some).map(Option::unwrap);
    |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
 
 error: `filter` for `Some` followed by `unwrap`
-  --> $DIR/option_filter_map.rs:11:39
+  --> $DIR/option_filter_map.rs:16:39
    |
 LL |     let _ = vec![Some(1)].into_iter().filter(|o| o.is_some()).map(|o| o.unwrap());
    |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
 
 error: `filter` for `Some` followed by `unwrap`
-  --> $DIR/option_filter_map.rs:15:10
+  --> $DIR/option_filter_map.rs:21:10
    |
 LL |           .filter(Option::is_some)
    |  __________^
+LL | |
 LL | |         .map(Option::unwrap);
    | |____________________________^ help: consider using `flatten` instead: `flatten()`
 
 error: `filter` for `Some` followed by `unwrap`
-  --> $DIR/option_filter_map.rs:20:10
+  --> $DIR/option_filter_map.rs:27:10
    |
 LL |           .filter(|o| o.is_some())
    |  __________^
+LL | |
 LL | |         .map(|o| o.unwrap());
    | |____________________________^ help: consider using `flatten` instead: `flatten()`
 
diff --git a/src/tools/clippy/tests/ui/redundant_async_block.fixed b/src/tools/clippy/tests/ui/redundant_async_block.fixed
index d492ea1be75..a1875c1c06e 100644
--- a/src/tools/clippy/tests/ui/redundant_async_block.fixed
+++ b/src/tools/clippy/tests/ui/redundant_async_block.fixed
@@ -1,7 +1,7 @@
 #![allow(unused, clippy::manual_async_fn)]
 #![warn(clippy::redundant_async_block)]
 
-use std::future::Future;
+use std::future::{Future, IntoFuture};
 
 async fn func1(n: usize) -> usize {
     n + 1
@@ -189,3 +189,9 @@ fn await_from_macro_deep() -> impl Future<Output = u32> {
     // or return different things depending on its argument
     async { mac!(async { 42 }) }
 }
+
+// Issue 11959
+fn from_into_future(a: impl IntoFuture<Output = u32>) -> impl Future<Output = u32> {
+    // Do not lint: `a` is not equivalent to this expression
+    async { a.await }
+}
diff --git a/src/tools/clippy/tests/ui/redundant_async_block.rs b/src/tools/clippy/tests/ui/redundant_async_block.rs
index dd96e141006..bb43403a043 100644
--- a/src/tools/clippy/tests/ui/redundant_async_block.rs
+++ b/src/tools/clippy/tests/ui/redundant_async_block.rs
@@ -1,7 +1,7 @@
 #![allow(unused, clippy::manual_async_fn)]
 #![warn(clippy::redundant_async_block)]
 
-use std::future::Future;
+use std::future::{Future, IntoFuture};
 
 async fn func1(n: usize) -> usize {
     n + 1
@@ -189,3 +189,9 @@ fn await_from_macro_deep() -> impl Future<Output = u32> {
     // or return different things depending on its argument
     async { mac!(async { 42 }) }
 }
+
+// Issue 11959
+fn from_into_future(a: impl IntoFuture<Output = u32>) -> impl Future<Output = u32> {
+    // Do not lint: `a` is not equivalent to this expression
+    async { a.await }
+}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_if_let_true.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_if_let_true.fixed
new file mode 100644
index 00000000000..6d910678934
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_if_let_true.fixed
@@ -0,0 +1,38 @@
+#![warn(clippy::redundant_pattern_matching)]
+#![allow(clippy::needless_if, clippy::no_effect, clippy::nonminimal_bool)]
+
+macro_rules! condition {
+    () => {
+        true
+    };
+}
+
+macro_rules! lettrue {
+    (if) => {
+        if let true = true {}
+    };
+    (while) => {
+        while let true = true {}
+    };
+}
+
+fn main() {
+    let mut k = 5;
+
+    if k > 1 {}
+    if !(k > 5) {}
+    if k > 1 {}
+    if let (true, true) = (k > 1, k > 2) {}
+    while k > 1 {
+        k += 1;
+    }
+    while condition!() {
+        k += 1;
+    }
+
+    k > 5;
+    !(k > 5);
+    // Whole loop is from a macro expansion, don't lint:
+    lettrue!(if);
+    lettrue!(while);
+}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_if_let_true.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_if_let_true.rs
new file mode 100644
index 00000000000..a82e673982a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_if_let_true.rs
@@ -0,0 +1,38 @@
+#![warn(clippy::redundant_pattern_matching)]
+#![allow(clippy::needless_if, clippy::no_effect, clippy::nonminimal_bool)]
+
+macro_rules! condition {
+    () => {
+        true
+    };
+}
+
+macro_rules! lettrue {
+    (if) => {
+        if let true = true {}
+    };
+    (while) => {
+        while let true = true {}
+    };
+}
+
+fn main() {
+    let mut k = 5;
+
+    if let true = k > 1 {}
+    if let false = k > 5 {}
+    if let (true) = k > 1 {}
+    if let (true, true) = (k > 1, k > 2) {}
+    while let true = k > 1 {
+        k += 1;
+    }
+    while let true = condition!() {
+        k += 1;
+    }
+
+    matches!(k > 5, true);
+    matches!(k > 5, false);
+    // Whole loop is from a macro expansion, don't lint:
+    lettrue!(if);
+    lettrue!(while);
+}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_if_let_true.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_if_let_true.stderr
new file mode 100644
index 00000000000..211a332d79a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_if_let_true.stderr
@@ -0,0 +1,47 @@
+error: using `if let` to pattern match a bool
+  --> $DIR/redundant_pattern_matching_if_let_true.rs:22:8
+   |
+LL |     if let true = k > 1 {}
+   |        ^^^^^^^^^^^^^^^^ help: consider using the condition directly: `k > 1`
+   |
+   = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]`
+
+error: using `if let` to pattern match a bool
+  --> $DIR/redundant_pattern_matching_if_let_true.rs:23:8
+   |
+LL |     if let false = k > 5 {}
+   |        ^^^^^^^^^^^^^^^^^ help: consider using the condition directly: `!(k > 5)`
+
+error: using `if let` to pattern match a bool
+  --> $DIR/redundant_pattern_matching_if_let_true.rs:24:8
+   |
+LL |     if let (true) = k > 1 {}
+   |        ^^^^^^^^^^^^^^^^^^ help: consider using the condition directly: `k > 1`
+
+error: using `if let` to pattern match a bool
+  --> $DIR/redundant_pattern_matching_if_let_true.rs:26:11
+   |
+LL |     while let true = k > 1 {
+   |           ^^^^^^^^^^^^^^^^ help: consider using the condition directly: `k > 1`
+
+error: using `if let` to pattern match a bool
+  --> $DIR/redundant_pattern_matching_if_let_true.rs:29:11
+   |
+LL |     while let true = condition!() {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using the condition directly: `condition!()`
+
+error: using `matches!` to pattern match a bool
+  --> $DIR/redundant_pattern_matching_if_let_true.rs:33:5
+   |
+LL |     matches!(k > 5, true);
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: consider using the condition directly: `k > 5`
+
+error: using `matches!` to pattern match a bool
+  --> $DIR/redundant_pattern_matching_if_let_true.rs:34:5
+   |
+LL |     matches!(k > 5, false);
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: consider using the condition directly: `!(k > 5)`
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.fixed
index 70dd9fc250f..429d33118a5 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.fixed
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.fixed
@@ -18,6 +18,12 @@ fn main() {
 
     if V6(Ipv6Addr::LOCALHOST).is_ipv6() {}
 
+    // Issue 6459
+    if V4(Ipv4Addr::LOCALHOST).is_ipv4() {}
+
+    // Issue 6459
+    if V6(Ipv6Addr::LOCALHOST).is_ipv6() {}
+
     while V4(Ipv4Addr::LOCALHOST).is_ipv4() {}
 
     while V6(Ipv6Addr::LOCALHOST).is_ipv6() {}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.rs
index 6e2a2f7b6d2..e7136b72c20 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.rs
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.rs
@@ -18,6 +18,12 @@ fn main() {
 
     if let V6(_) = V6(Ipv6Addr::LOCALHOST) {}
 
+    // Issue 6459
+    if matches!(V4(Ipv4Addr::LOCALHOST), V4(_)) {}
+
+    // Issue 6459
+    if matches!(V6(Ipv6Addr::LOCALHOST), V6(_)) {}
+
     while let V4(_) = V4(Ipv4Addr::LOCALHOST) {}
 
     while let V6(_) = V6(Ipv6Addr::LOCALHOST) {}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.stderr
index d36129a2bee..54cefa5e82b 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.stderr
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.stderr
@@ -20,19 +20,31 @@ LL |     if let V6(_) = V6(Ipv6Addr::LOCALHOST) {}
    |     -------^^^^^-------------------------- help: try: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()`
 
 error: redundant pattern matching, consider using `is_ipv4()`
-  --> $DIR/redundant_pattern_matching_ipaddr.rs:21:15
+  --> $DIR/redundant_pattern_matching_ipaddr.rs:22:8
+   |
+LL |     if matches!(V4(Ipv4Addr::LOCALHOST), V4(_)) {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv4()`
+
+error: redundant pattern matching, consider using `is_ipv6()`
+  --> $DIR/redundant_pattern_matching_ipaddr.rs:25:8
+   |
+LL |     if matches!(V6(Ipv6Addr::LOCALHOST), V6(_)) {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `V6(Ipv6Addr::LOCALHOST).is_ipv6()`
+
+error: redundant pattern matching, consider using `is_ipv4()`
+  --> $DIR/redundant_pattern_matching_ipaddr.rs:27:15
    |
 LL |     while let V4(_) = V4(Ipv4Addr::LOCALHOST) {}
    |     ----------^^^^^-------------------------- help: try: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()`
 
 error: redundant pattern matching, consider using `is_ipv6()`
-  --> $DIR/redundant_pattern_matching_ipaddr.rs:23:15
+  --> $DIR/redundant_pattern_matching_ipaddr.rs:29:15
    |
 LL |     while let V6(_) = V6(Ipv6Addr::LOCALHOST) {}
    |     ----------^^^^^-------------------------- help: try: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()`
 
 error: redundant pattern matching, consider using `is_ipv4()`
-  --> $DIR/redundant_pattern_matching_ipaddr.rs:33:5
+  --> $DIR/redundant_pattern_matching_ipaddr.rs:39:5
    |
 LL | /     match V4(Ipv4Addr::LOCALHOST) {
 LL | |         V4(_) => true,
@@ -41,7 +53,7 @@ LL | |     };
    | |_____^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv4()`
 
 error: redundant pattern matching, consider using `is_ipv6()`
-  --> $DIR/redundant_pattern_matching_ipaddr.rs:38:5
+  --> $DIR/redundant_pattern_matching_ipaddr.rs:44:5
    |
 LL | /     match V4(Ipv4Addr::LOCALHOST) {
 LL | |         V4(_) => false,
@@ -50,7 +62,7 @@ LL | |     };
    | |_____^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv6()`
 
 error: redundant pattern matching, consider using `is_ipv6()`
-  --> $DIR/redundant_pattern_matching_ipaddr.rs:43:5
+  --> $DIR/redundant_pattern_matching_ipaddr.rs:49:5
    |
 LL | /     match V6(Ipv6Addr::LOCALHOST) {
 LL | |         V4(_) => false,
@@ -59,7 +71,7 @@ LL | |     };
    | |_____^ help: try: `V6(Ipv6Addr::LOCALHOST).is_ipv6()`
 
 error: redundant pattern matching, consider using `is_ipv4()`
-  --> $DIR/redundant_pattern_matching_ipaddr.rs:48:5
+  --> $DIR/redundant_pattern_matching_ipaddr.rs:54:5
    |
 LL | /     match V6(Ipv6Addr::LOCALHOST) {
 LL | |         V4(_) => true,
@@ -68,49 +80,49 @@ LL | |     };
    | |_____^ help: try: `V6(Ipv6Addr::LOCALHOST).is_ipv4()`
 
 error: redundant pattern matching, consider using `is_ipv4()`
-  --> $DIR/redundant_pattern_matching_ipaddr.rs:53:20
+  --> $DIR/redundant_pattern_matching_ipaddr.rs:59:20
    |
 LL |     let _ = if let V4(_) = V4(Ipv4Addr::LOCALHOST) {
    |             -------^^^^^-------------------------- help: try: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()`
 
 error: redundant pattern matching, consider using `is_ipv4()`
-  --> $DIR/redundant_pattern_matching_ipaddr.rs:61:20
+  --> $DIR/redundant_pattern_matching_ipaddr.rs:67:20
    |
 LL |     let _ = if let V4(_) = gen_ipaddr() {
    |             -------^^^^^--------------- help: try: `if gen_ipaddr().is_ipv4()`
 
 error: redundant pattern matching, consider using `is_ipv6()`
-  --> $DIR/redundant_pattern_matching_ipaddr.rs:63:19
+  --> $DIR/redundant_pattern_matching_ipaddr.rs:69:19
    |
 LL |     } else if let V6(_) = gen_ipaddr() {
    |            -------^^^^^--------------- help: try: `if gen_ipaddr().is_ipv6()`
 
 error: redundant pattern matching, consider using `is_ipv4()`
-  --> $DIR/redundant_pattern_matching_ipaddr.rs:75:12
+  --> $DIR/redundant_pattern_matching_ipaddr.rs:81:12
    |
 LL |     if let V4(_) = V4(Ipv4Addr::LOCALHOST) {}
    |     -------^^^^^-------------------------- help: try: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()`
 
 error: redundant pattern matching, consider using `is_ipv6()`
-  --> $DIR/redundant_pattern_matching_ipaddr.rs:77:12
+  --> $DIR/redundant_pattern_matching_ipaddr.rs:83:12
    |
 LL |     if let V6(_) = V6(Ipv6Addr::LOCALHOST) {}
    |     -------^^^^^-------------------------- help: try: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()`
 
 error: redundant pattern matching, consider using `is_ipv4()`
-  --> $DIR/redundant_pattern_matching_ipaddr.rs:79:15
+  --> $DIR/redundant_pattern_matching_ipaddr.rs:85:15
    |
 LL |     while let V4(_) = V4(Ipv4Addr::LOCALHOST) {}
    |     ----------^^^^^-------------------------- help: try: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()`
 
 error: redundant pattern matching, consider using `is_ipv6()`
-  --> $DIR/redundant_pattern_matching_ipaddr.rs:81:15
+  --> $DIR/redundant_pattern_matching_ipaddr.rs:87:15
    |
 LL |     while let V6(_) = V6(Ipv6Addr::LOCALHOST) {}
    |     ----------^^^^^-------------------------- help: try: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()`
 
 error: redundant pattern matching, consider using `is_ipv4()`
-  --> $DIR/redundant_pattern_matching_ipaddr.rs:83:5
+  --> $DIR/redundant_pattern_matching_ipaddr.rs:89:5
    |
 LL | /     match V4(Ipv4Addr::LOCALHOST) {
 LL | |         V4(_) => true,
@@ -119,7 +131,7 @@ LL | |     };
    | |_____^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv4()`
 
 error: redundant pattern matching, consider using `is_ipv6()`
-  --> $DIR/redundant_pattern_matching_ipaddr.rs:88:5
+  --> $DIR/redundant_pattern_matching_ipaddr.rs:94:5
    |
 LL | /     match V6(Ipv6Addr::LOCALHOST) {
 LL | |         V4(_) => false,
@@ -127,5 +139,5 @@ LL | |         V6(_) => true,
 LL | |     };
    | |_____^ help: try: `V6(Ipv6Addr::LOCALHOST).is_ipv6()`
 
-error: aborting due to 18 previous errors
+error: aborting due to 20 previous errors
 
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.fixed
index 718c2f8ea3d..08d83f87e4c 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.fixed
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.fixed
@@ -22,6 +22,12 @@ fn main() {
         bar();
     }
 
+    // Issue 6459
+    if Ready(42).is_ready() {}
+
+    // Issue 6459
+    if Pending::<()>.is_pending() {}
+
     while Ready(42).is_ready() {}
 
     while Ready(42).is_pending() {}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.rs
index daa4761aff5..7bc2b3be4d3 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.rs
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.rs
@@ -22,6 +22,12 @@ fn main() {
         bar();
     }
 
+    // Issue 6459
+    if matches!(Ready(42), Ready(_)) {}
+
+    // Issue 6459
+    if matches!(Pending::<()>, Pending) {}
+
     while let Ready(_) = Ready(42) {}
 
     while let Pending = Ready(42) {}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.stderr
index c010c3c4437..de64331b4e8 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.stderr
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.stderr
@@ -20,25 +20,37 @@ LL |     if let Ready(_) = Ready(42) {
    |     -------^^^^^^^^------------ help: try: `if Ready(42).is_ready()`
 
 error: redundant pattern matching, consider using `is_ready()`
-  --> $DIR/redundant_pattern_matching_poll.rs:25:15
+  --> $DIR/redundant_pattern_matching_poll.rs:26:8
+   |
+LL |     if matches!(Ready(42), Ready(_)) {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ready(42).is_ready()`
+
+error: redundant pattern matching, consider using `is_pending()`
+  --> $DIR/redundant_pattern_matching_poll.rs:29:8
+   |
+LL |     if matches!(Pending::<()>, Pending) {}
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Pending::<()>.is_pending()`
+
+error: redundant pattern matching, consider using `is_ready()`
+  --> $DIR/redundant_pattern_matching_poll.rs:31:15
    |
 LL |     while let Ready(_) = Ready(42) {}
    |     ----------^^^^^^^^------------ help: try: `while Ready(42).is_ready()`
 
 error: redundant pattern matching, consider using `is_pending()`
-  --> $DIR/redundant_pattern_matching_poll.rs:27:15
+  --> $DIR/redundant_pattern_matching_poll.rs:33:15
    |
 LL |     while let Pending = Ready(42) {}
    |     ----------^^^^^^^------------ help: try: `while Ready(42).is_pending()`
 
 error: redundant pattern matching, consider using `is_pending()`
-  --> $DIR/redundant_pattern_matching_poll.rs:29:15
+  --> $DIR/redundant_pattern_matching_poll.rs:35:15
    |
 LL |     while let Pending = Pending::<()> {}
    |     ----------^^^^^^^---------------- help: try: `while Pending::<()>.is_pending()`
 
 error: redundant pattern matching, consider using `is_ready()`
-  --> $DIR/redundant_pattern_matching_poll.rs:35:5
+  --> $DIR/redundant_pattern_matching_poll.rs:41:5
    |
 LL | /     match Ready(42) {
 LL | |         Ready(_) => true,
@@ -47,7 +59,7 @@ LL | |     };
    | |_____^ help: try: `Ready(42).is_ready()`
 
 error: redundant pattern matching, consider using `is_pending()`
-  --> $DIR/redundant_pattern_matching_poll.rs:40:5
+  --> $DIR/redundant_pattern_matching_poll.rs:46:5
    |
 LL | /     match Pending::<()> {
 LL | |         Ready(_) => false,
@@ -56,7 +68,7 @@ LL | |     };
    | |_____^ help: try: `Pending::<()>.is_pending()`
 
 error: redundant pattern matching, consider using `is_pending()`
-  --> $DIR/redundant_pattern_matching_poll.rs:45:13
+  --> $DIR/redundant_pattern_matching_poll.rs:51:13
    |
 LL |       let _ = match Pending::<()> {
    |  _____________^
@@ -66,49 +78,49 @@ LL | |     };
    | |_____^ help: try: `Pending::<()>.is_pending()`
 
 error: redundant pattern matching, consider using `is_ready()`
-  --> $DIR/redundant_pattern_matching_poll.rs:51:20
+  --> $DIR/redundant_pattern_matching_poll.rs:57:20
    |
 LL |     let _ = if let Ready(_) = poll { true } else { false };
    |             -------^^^^^^^^------- help: try: `if poll.is_ready()`
 
 error: redundant pattern matching, consider using `is_ready()`
-  --> $DIR/redundant_pattern_matching_poll.rs:55:20
+  --> $DIR/redundant_pattern_matching_poll.rs:61:20
    |
 LL |     let _ = if let Ready(_) = gen_poll() {
    |             -------^^^^^^^^------------- help: try: `if gen_poll().is_ready()`
 
 error: redundant pattern matching, consider using `is_pending()`
-  --> $DIR/redundant_pattern_matching_poll.rs:57:19
+  --> $DIR/redundant_pattern_matching_poll.rs:63:19
    |
 LL |     } else if let Pending = gen_poll() {
    |            -------^^^^^^^------------- help: try: `if gen_poll().is_pending()`
 
 error: redundant pattern matching, consider using `is_ready()`
-  --> $DIR/redundant_pattern_matching_poll.rs:73:12
+  --> $DIR/redundant_pattern_matching_poll.rs:79:12
    |
 LL |     if let Ready(_) = Ready(42) {}
    |     -------^^^^^^^^------------ help: try: `if Ready(42).is_ready()`
 
 error: redundant pattern matching, consider using `is_pending()`
-  --> $DIR/redundant_pattern_matching_poll.rs:75:12
+  --> $DIR/redundant_pattern_matching_poll.rs:81:12
    |
 LL |     if let Pending = Pending::<()> {}
    |     -------^^^^^^^---------------- help: try: `if Pending::<()>.is_pending()`
 
 error: redundant pattern matching, consider using `is_ready()`
-  --> $DIR/redundant_pattern_matching_poll.rs:77:15
+  --> $DIR/redundant_pattern_matching_poll.rs:83:15
    |
 LL |     while let Ready(_) = Ready(42) {}
    |     ----------^^^^^^^^------------ help: try: `while Ready(42).is_ready()`
 
 error: redundant pattern matching, consider using `is_pending()`
-  --> $DIR/redundant_pattern_matching_poll.rs:79:15
+  --> $DIR/redundant_pattern_matching_poll.rs:85:15
    |
 LL |     while let Pending = Pending::<()> {}
    |     ----------^^^^^^^---------------- help: try: `while Pending::<()>.is_pending()`
 
 error: redundant pattern matching, consider using `is_ready()`
-  --> $DIR/redundant_pattern_matching_poll.rs:81:5
+  --> $DIR/redundant_pattern_matching_poll.rs:87:5
    |
 LL | /     match Ready(42) {
 LL | |         Ready(_) => true,
@@ -117,7 +129,7 @@ LL | |     };
    | |_____^ help: try: `Ready(42).is_ready()`
 
 error: redundant pattern matching, consider using `is_pending()`
-  --> $DIR/redundant_pattern_matching_poll.rs:86:5
+  --> $DIR/redundant_pattern_matching_poll.rs:92:5
    |
 LL | /     match Pending::<()> {
 LL | |         Ready(_) => false,
@@ -125,5 +137,5 @@ LL | |         Pending => true,
 LL | |     };
    | |_____^ help: try: `Pending::<()>.is_pending()`
 
-error: aborting due to 18 previous errors
+error: aborting due to 20 previous errors
 
diff --git a/src/tools/clippy/tests/ui/result_filter_map.fixed b/src/tools/clippy/tests/ui/result_filter_map.fixed
new file mode 100644
index 00000000000..e8943dbc72d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/result_filter_map.fixed
@@ -0,0 +1,27 @@
+#![warn(clippy::result_filter_map)]
+#![allow(clippy::map_flatten, clippy::unnecessary_map_on_constructor)]
+
+fn odds_out(x: i32) -> Result<i32, ()> {
+    if x % 2 == 0 { Ok(x) } else { Err(()) }
+}
+
+fn main() {
+    // Unlike the Option version, Result does not have a filter operation => we will check for iterators
+    // only
+    let _ = vec![Ok(1) as Result<i32, ()>]
+        .into_iter()
+        .flatten();
+
+    let _ = vec![Ok(1) as Result<i32, ()>]
+        .into_iter()
+        .flatten();
+
+    let _ = vec![1]
+        .into_iter()
+        .map(odds_out)
+        .flatten();
+    let _ = vec![1]
+        .into_iter()
+        .map(odds_out)
+        .flatten();
+}
diff --git a/src/tools/clippy/tests/ui/result_filter_map.rs b/src/tools/clippy/tests/ui/result_filter_map.rs
new file mode 100644
index 00000000000..bfe47ffcf38
--- /dev/null
+++ b/src/tools/clippy/tests/ui/result_filter_map.rs
@@ -0,0 +1,35 @@
+#![warn(clippy::result_filter_map)]
+#![allow(clippy::map_flatten, clippy::unnecessary_map_on_constructor)]
+
+fn odds_out(x: i32) -> Result<i32, ()> {
+    if x % 2 == 0 { Ok(x) } else { Err(()) }
+}
+
+fn main() {
+    // Unlike the Option version, Result does not have a filter operation => we will check for iterators
+    // only
+    let _ = vec![Ok(1) as Result<i32, ()>]
+        .into_iter()
+        .filter(Result::is_ok)
+        //~^ ERROR: `filter` for `Ok` followed by `unwrap`
+        .map(Result::unwrap);
+
+    let _ = vec![Ok(1) as Result<i32, ()>]
+        .into_iter()
+        .filter(|o| o.is_ok())
+        //~^ ERROR: `filter` for `Ok` followed by `unwrap`
+        .map(|o| o.unwrap());
+
+    let _ = vec![1]
+        .into_iter()
+        .map(odds_out)
+        .filter(Result::is_ok)
+        //~^ ERROR: `filter` for `Ok` followed by `unwrap`
+        .map(Result::unwrap);
+    let _ = vec![1]
+        .into_iter()
+        .map(odds_out)
+        .filter(|o| o.is_ok())
+        //~^ ERROR: `filter` for `Ok` followed by `unwrap`
+        .map(|o| o.unwrap());
+}
diff --git a/src/tools/clippy/tests/ui/result_filter_map.stderr b/src/tools/clippy/tests/ui/result_filter_map.stderr
new file mode 100644
index 00000000000..4687794949d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/result_filter_map.stderr
@@ -0,0 +1,41 @@
+error: `filter` for `Ok` followed by `unwrap`
+  --> $DIR/result_filter_map.rs:13:10
+   |
+LL |           .filter(Result::is_ok)
+   |  __________^
+LL | |
+LL | |         .map(Result::unwrap);
+   | |____________________________^ help: consider using `flatten` instead: `flatten()`
+   |
+   = note: `-D clippy::result-filter-map` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::result_filter_map)]`
+
+error: `filter` for `Ok` followed by `unwrap`
+  --> $DIR/result_filter_map.rs:19:10
+   |
+LL |           .filter(|o| o.is_ok())
+   |  __________^
+LL | |
+LL | |         .map(|o| o.unwrap());
+   | |____________________________^ help: consider using `flatten` instead: `flatten()`
+
+error: `filter` for `Ok` followed by `unwrap`
+  --> $DIR/result_filter_map.rs:26:10
+   |
+LL |           .filter(Result::is_ok)
+   |  __________^
+LL | |
+LL | |         .map(Result::unwrap);
+   | |____________________________^ help: consider using `flatten` instead: `flatten()`
+
+error: `filter` for `Ok` followed by `unwrap`
+  --> $DIR/result_filter_map.rs:32:10
+   |
+LL |           .filter(|o| o.is_ok())
+   |  __________^
+LL | |
+LL | |         .map(|o| o.unwrap());
+   | |____________________________^ help: consider using `flatten` instead: `flatten()`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unconditional_recursion.rs b/src/tools/clippy/tests/ui/unconditional_recursion.rs
new file mode 100644
index 00000000000..1169118de83
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unconditional_recursion.rs
@@ -0,0 +1,163 @@
+//@no-rustfix
+
+#![warn(clippy::unconditional_recursion)]
+#![allow(clippy::partialeq_ne_impl)]
+
+enum Foo {
+    A,
+    B,
+}
+
+impl PartialEq for Foo {
+    fn ne(&self, other: &Self) -> bool {
+        //~^ ERROR: function cannot return without recursing
+        self != other
+    }
+    fn eq(&self, other: &Self) -> bool {
+        //~^ ERROR: function cannot return without recursing
+        self == other
+    }
+}
+
+enum Foo2 {
+    A,
+    B,
+}
+
+impl PartialEq for Foo2 {
+    fn ne(&self, other: &Self) -> bool {
+        self != &Foo2::B // no error here
+    }
+    fn eq(&self, other: &Self) -> bool {
+        self == &Foo2::B // no error here
+    }
+}
+
+enum Foo3 {
+    A,
+    B,
+}
+
+impl PartialEq for Foo3 {
+    fn ne(&self, other: &Self) -> bool {
+        //~^ ERROR: function cannot return without recursing
+        self.ne(other)
+    }
+    fn eq(&self, other: &Self) -> bool {
+        //~^ ERROR: function cannot return without recursing
+        self.eq(other)
+    }
+}
+
+enum Foo4 {
+    A,
+    B,
+}
+
+impl PartialEq for Foo4 {
+    fn ne(&self, other: &Self) -> bool {
+        self.eq(other) // no error
+    }
+    fn eq(&self, other: &Self) -> bool {
+        self.ne(other) // no error
+    }
+}
+
+enum Foo5 {
+    A,
+    B,
+}
+
+impl Foo5 {
+    fn a(&self) -> bool {
+        true
+    }
+}
+
+impl PartialEq for Foo5 {
+    fn ne(&self, other: &Self) -> bool {
+        self.a() // no error
+    }
+    fn eq(&self, other: &Self) -> bool {
+        self.a() // no error
+    }
+}
+
+struct S;
+
+// Check the order doesn't matter.
+impl PartialEq for S {
+    fn ne(&self, other: &Self) -> bool {
+        //~^ ERROR: function cannot return without recursing
+        other != self
+    }
+    fn eq(&self, other: &Self) -> bool {
+        //~^ ERROR: function cannot return without recursing
+        other == self
+    }
+}
+
+struct S2;
+
+// Check that if the same element is compared, it's also triggering the lint.
+impl PartialEq for S2 {
+    fn ne(&self, other: &Self) -> bool {
+        //~^ ERROR: function cannot return without recursing
+        other != other
+    }
+    fn eq(&self, other: &Self) -> bool {
+        //~^ ERROR: function cannot return without recursing
+        other == other
+    }
+}
+
+struct S3;
+
+impl PartialEq for S3 {
+    fn ne(&self, _other: &Self) -> bool {
+        //~^ ERROR: function cannot return without recursing
+        self != self
+    }
+    fn eq(&self, _other: &Self) -> bool {
+        //~^ ERROR: function cannot return without recursing
+        self == self
+    }
+}
+
+// There should be no warning here!
+#[derive(PartialEq)]
+enum E {
+    A,
+    B,
+}
+
+#[derive(PartialEq)]
+struct Bar<T: PartialEq>(T);
+
+struct S4;
+
+impl PartialEq for S4 {
+    fn eq(&self, other: &Self) -> bool {
+        // No warning here.
+        Bar(self) == Bar(other)
+    }
+}
+
+macro_rules! impl_partial_eq {
+    ($ty:ident) => {
+        impl PartialEq for $ty {
+            fn eq(&self, other: &Self) -> bool {
+                self == other
+            }
+        }
+    };
+}
+
+struct S5;
+
+impl_partial_eq!(S5);
+//~^ ERROR: function cannot return without recursing
+
+fn main() {
+    // test code goes here
+}
diff --git a/src/tools/clippy/tests/ui/unconditional_recursion.stderr b/src/tools/clippy/tests/ui/unconditional_recursion.stderr
new file mode 100644
index 00000000000..1fb01c00f19
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unconditional_recursion.stderr
@@ -0,0 +1,251 @@
+error: function cannot return without recursing
+  --> $DIR/unconditional_recursion.rs:42:5
+   |
+LL |     fn ne(&self, other: &Self) -> bool {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL |
+LL |         self.ne(other)
+   |         -------------- recursive call site
+   |
+   = help: a `loop` may express intention better if this is on purpose
+   = note: `-D unconditional-recursion` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(unconditional_recursion)]`
+
+error: function cannot return without recursing
+  --> $DIR/unconditional_recursion.rs:46:5
+   |
+LL |     fn eq(&self, other: &Self) -> bool {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL |
+LL |         self.eq(other)
+   |         -------------- recursive call site
+   |
+   = help: a `loop` may express intention better if this is on purpose
+
+error: function cannot return without recursing
+  --> $DIR/unconditional_recursion.rs:12:5
+   |
+LL | /     fn ne(&self, other: &Self) -> bool {
+LL | |
+LL | |         self != other
+LL | |     }
+   | |_____^
+   |
+note: recursive call site
+  --> $DIR/unconditional_recursion.rs:14:9
+   |
+LL |         self != other
+   |         ^^^^^^^^^^^^^
+   = note: `-D clippy::unconditional-recursion` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::unconditional_recursion)]`
+
+error: function cannot return without recursing
+  --> $DIR/unconditional_recursion.rs:16:5
+   |
+LL | /     fn eq(&self, other: &Self) -> bool {
+LL | |
+LL | |         self == other
+LL | |     }
+   | |_____^
+   |
+note: recursive call site
+  --> $DIR/unconditional_recursion.rs:18:9
+   |
+LL |         self == other
+   |         ^^^^^^^^^^^^^
+
+error: function cannot return without recursing
+  --> $DIR/unconditional_recursion.rs:42:5
+   |
+LL | /     fn ne(&self, other: &Self) -> bool {
+LL | |
+LL | |         self.ne(other)
+LL | |     }
+   | |_____^
+   |
+note: recursive call site
+  --> $DIR/unconditional_recursion.rs:44:9
+   |
+LL |         self.ne(other)
+   |         ^^^^^^^^^^^^^^
+
+error: parameter is only used in recursion
+  --> $DIR/unconditional_recursion.rs:42:18
+   |
+LL |     fn ne(&self, other: &Self) -> bool {
+   |                  ^^^^^ help: if this is intentional, prefix it with an underscore: `_other`
+   |
+note: parameter used here
+  --> $DIR/unconditional_recursion.rs:44:17
+   |
+LL |         self.ne(other)
+   |                 ^^^^^
+   = note: `-D clippy::only-used-in-recursion` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::only_used_in_recursion)]`
+
+error: function cannot return without recursing
+  --> $DIR/unconditional_recursion.rs:46:5
+   |
+LL | /     fn eq(&self, other: &Self) -> bool {
+LL | |
+LL | |         self.eq(other)
+LL | |     }
+   | |_____^
+   |
+note: recursive call site
+  --> $DIR/unconditional_recursion.rs:48:9
+   |
+LL |         self.eq(other)
+   |         ^^^^^^^^^^^^^^
+
+error: parameter is only used in recursion
+  --> $DIR/unconditional_recursion.rs:46:18
+   |
+LL |     fn eq(&self, other: &Self) -> bool {
+   |                  ^^^^^ help: if this is intentional, prefix it with an underscore: `_other`
+   |
+note: parameter used here
+  --> $DIR/unconditional_recursion.rs:48:17
+   |
+LL |         self.eq(other)
+   |                 ^^^^^
+
+error: function cannot return without recursing
+  --> $DIR/unconditional_recursion.rs:90:5
+   |
+LL | /     fn ne(&self, other: &Self) -> bool {
+LL | |
+LL | |         other != self
+LL | |     }
+   | |_____^
+   |
+note: recursive call site
+  --> $DIR/unconditional_recursion.rs:92:9
+   |
+LL |         other != self
+   |         ^^^^^^^^^^^^^
+
+error: function cannot return without recursing
+  --> $DIR/unconditional_recursion.rs:94:5
+   |
+LL | /     fn eq(&self, other: &Self) -> bool {
+LL | |
+LL | |         other == self
+LL | |     }
+   | |_____^
+   |
+note: recursive call site
+  --> $DIR/unconditional_recursion.rs:96:9
+   |
+LL |         other == self
+   |         ^^^^^^^^^^^^^
+
+error: function cannot return without recursing
+  --> $DIR/unconditional_recursion.rs:104:5
+   |
+LL | /     fn ne(&self, other: &Self) -> bool {
+LL | |
+LL | |         other != other
+LL | |     }
+   | |_____^
+   |
+note: recursive call site
+  --> $DIR/unconditional_recursion.rs:106:9
+   |
+LL |         other != other
+   |         ^^^^^^^^^^^^^^
+
+error: equal expressions as operands to `!=`
+  --> $DIR/unconditional_recursion.rs:106:9
+   |
+LL |         other != other
+   |         ^^^^^^^^^^^^^^
+   |
+   = note: `#[deny(clippy::eq_op)]` on by default
+
+error: function cannot return without recursing
+  --> $DIR/unconditional_recursion.rs:108:5
+   |
+LL | /     fn eq(&self, other: &Self) -> bool {
+LL | |
+LL | |         other == other
+LL | |     }
+   | |_____^
+   |
+note: recursive call site
+  --> $DIR/unconditional_recursion.rs:110:9
+   |
+LL |         other == other
+   |         ^^^^^^^^^^^^^^
+
+error: equal expressions as operands to `==`
+  --> $DIR/unconditional_recursion.rs:110:9
+   |
+LL |         other == other
+   |         ^^^^^^^^^^^^^^
+
+error: function cannot return without recursing
+  --> $DIR/unconditional_recursion.rs:117:5
+   |
+LL | /     fn ne(&self, _other: &Self) -> bool {
+LL | |
+LL | |         self != self
+LL | |     }
+   | |_____^
+   |
+note: recursive call site
+  --> $DIR/unconditional_recursion.rs:119:9
+   |
+LL |         self != self
+   |         ^^^^^^^^^^^^
+
+error: equal expressions as operands to `!=`
+  --> $DIR/unconditional_recursion.rs:119:9
+   |
+LL |         self != self
+   |         ^^^^^^^^^^^^
+
+error: function cannot return without recursing
+  --> $DIR/unconditional_recursion.rs:121:5
+   |
+LL | /     fn eq(&self, _other: &Self) -> bool {
+LL | |
+LL | |         self == self
+LL | |     }
+   | |_____^
+   |
+note: recursive call site
+  --> $DIR/unconditional_recursion.rs:123:9
+   |
+LL |         self == self
+   |         ^^^^^^^^^^^^
+
+error: equal expressions as operands to `==`
+  --> $DIR/unconditional_recursion.rs:123:9
+   |
+LL |         self == self
+   |         ^^^^^^^^^^^^
+
+error: function cannot return without recursing
+  --> $DIR/unconditional_recursion.rs:149:13
+   |
+LL | /             fn eq(&self, other: &Self) -> bool {
+LL | |                 self == other
+LL | |             }
+   | |_____________^
+...
+LL |   impl_partial_eq!(S5);
+   |   -------------------- in this macro invocation
+   |
+note: recursive call site
+  --> $DIR/unconditional_recursion.rs:150:17
+   |
+LL |                 self == other
+   |                 ^^^^^^^^^^^^^
+...
+LL | impl_partial_eq!(S5);
+   | -------------------- in this macro invocation
+   = note: this error originates in the macro `impl_partial_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 19 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.fixed b/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.fixed
new file mode 100644
index 00000000000..53dc3c43e2f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.fixed
@@ -0,0 +1,21 @@
+#[allow(clippy::single_char_pattern)]
+
+fn main() {
+    let _ = "a".split('a').next().unwrap();
+    //~^ ERROR: unnecessary use of `to_string`
+    let _ = "a".split("a").next().unwrap();
+    //~^ ERROR: unnecessary use of `to_string`
+    let _ = "a".split('a').next().unwrap();
+    //~^ ERROR: unnecessary use of `to_owned`
+    let _ = "a".split("a").next().unwrap();
+    //~^ ERROR: unnecessary use of `to_owned`
+
+    let _ = [1].split(|x| *x == 2).next().unwrap();
+    //~^ ERROR: unnecessary use of `to_vec`
+    let _ = [1].split(|x| *x == 2).next().unwrap();
+    //~^ ERROR: unnecessary use of `to_vec`
+    let _ = [1].split(|x| *x == 2).next().unwrap();
+    //~^ ERROR: unnecessary use of `to_owned`
+    let _ = [1].split(|x| *x == 2).next().unwrap();
+    //~^ ERROR: unnecessary use of `to_owned`
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.rs b/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.rs
new file mode 100644
index 00000000000..62400e7eee1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.rs
@@ -0,0 +1,21 @@
+#[allow(clippy::single_char_pattern)]
+
+fn main() {
+    let _ = "a".to_string().split('a').next().unwrap();
+    //~^ ERROR: unnecessary use of `to_string`
+    let _ = "a".to_string().split("a").next().unwrap();
+    //~^ ERROR: unnecessary use of `to_string`
+    let _ = "a".to_owned().split('a').next().unwrap();
+    //~^ ERROR: unnecessary use of `to_owned`
+    let _ = "a".to_owned().split("a").next().unwrap();
+    //~^ ERROR: unnecessary use of `to_owned`
+
+    let _ = [1].to_vec().split(|x| *x == 2).next().unwrap();
+    //~^ ERROR: unnecessary use of `to_vec`
+    let _ = [1].to_vec().split(|x| *x == 2).next().unwrap();
+    //~^ ERROR: unnecessary use of `to_vec`
+    let _ = [1].to_owned().split(|x| *x == 2).next().unwrap();
+    //~^ ERROR: unnecessary use of `to_owned`
+    let _ = [1].to_owned().split(|x| *x == 2).next().unwrap();
+    //~^ ERROR: unnecessary use of `to_owned`
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.stderr b/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.stderr
new file mode 100644
index 00000000000..cfb3766d15e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.stderr
@@ -0,0 +1,53 @@
+error: unnecessary use of `to_string`
+  --> $DIR/unnecessary_to_owned_on_split.rs:4:13
+   |
+LL |     let _ = "a".to_string().split('a').next().unwrap();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `"a".split('a')`
+   |
+   = note: `-D clippy::unnecessary-to-owned` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::unnecessary_to_owned)]`
+
+error: unnecessary use of `to_string`
+  --> $DIR/unnecessary_to_owned_on_split.rs:6:13
+   |
+LL |     let _ = "a".to_string().split("a").next().unwrap();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `"a".split("a")`
+
+error: unnecessary use of `to_owned`
+  --> $DIR/unnecessary_to_owned_on_split.rs:8:13
+   |
+LL |     let _ = "a".to_owned().split('a').next().unwrap();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `"a".split('a')`
+
+error: unnecessary use of `to_owned`
+  --> $DIR/unnecessary_to_owned_on_split.rs:10:13
+   |
+LL |     let _ = "a".to_owned().split("a").next().unwrap();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `"a".split("a")`
+
+error: unnecessary use of `to_vec`
+  --> $DIR/unnecessary_to_owned_on_split.rs:13:13
+   |
+LL |     let _ = [1].to_vec().split(|x| *x == 2).next().unwrap();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[1].split(|x| *x == 2)`
+
+error: unnecessary use of `to_vec`
+  --> $DIR/unnecessary_to_owned_on_split.rs:15:13
+   |
+LL |     let _ = [1].to_vec().split(|x| *x == 2).next().unwrap();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[1].split(|x| *x == 2)`
+
+error: unnecessary use of `to_owned`
+  --> $DIR/unnecessary_to_owned_on_split.rs:17:13
+   |
+LL |     let _ = [1].to_owned().split(|x| *x == 2).next().unwrap();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[1].split(|x| *x == 2)`
+
+error: unnecessary use of `to_owned`
+  --> $DIR/unnecessary_to_owned_on_split.rs:19:13
+   |
+LL |     let _ = [1].to_owned().split(|x| *x == 2).next().unwrap();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[1].split(|x| *x == 2)`
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/util/gh-pages/index.html b/src/tools/clippy/util/gh-pages/index.html
index 99e211654d1..a5274eeb349 100644
--- a/src/tools/clippy/util/gh-pages/index.html
+++ b/src/tools/clippy/util/gh-pages/index.html
@@ -566,8 +566,74 @@ Otherwise, have a great day =^.^=
         </div>
     </div>
 
-    <a href="https://github.com/rust-lang/rust-clippy">
-        <img style="position: absolute; top: 0; right: 0; border: 0; clip-path: polygon(0% 0%, 100% 0%, 100% 100%);" src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on GitHub"/>
+    <a
+        aria-label="View source on GitHub"
+        class="github-corner"
+        href="https://github.com/rust-lang/rust-clippy"
+        rel="noopener noreferrer"
+        target="_blank"
+    >
+        <svg
+            width="80"
+            height="80"
+            viewBox="0 0 250 250"
+            style="position: absolute; top: 0; border: 0; right: 0"
+            aria-hidden="true"
+        >
+            <path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z" fill="var(--theme-color)"></path>
+            <path
+                d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2"
+                fill="currentColor"
+                style="transform-origin: 130px 106px"
+                class="octo-arm"
+            ></path>
+            <path
+                d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
+                fill="currentColor"
+                class="octo-body"
+            ></path>
+        </svg>
+        <style>
+            :root {
+                --theme-background-color: black;
+                --theme-foreground-color: white;
+            }
+            @media (prefers-color-scheme: dark) {
+                :root {
+                    --theme-background-color: white;
+                    --theme-foreground-color: black;
+                }
+            }
+            .github-corner svg {
+                fill: var(--theme-background-color);
+                color: var(--theme-foreground-color);
+            }
+            .github-corner:hover .octo-arm {
+                animation: octocat-wave 560ms ease-in-out;
+            }
+            @keyframes octocat-wave {
+                0%,
+                100% {
+                    transform: rotate(0);
+                }
+                20%,
+                60% {
+                    transform: rotate(-25deg);
+                }
+                40%,
+                80% {
+                    transform: rotate(10deg);
+                }
+            }
+            @media (max-width: 500px) {
+                .github-corner:hover .octo-arm {
+                    animation: none;
+                }
+                .github-corner .octo-arm {
+                    animation: octocat-wave 560ms ease-in-out;
+                }
+            }
+        </style>
     </a>
 
     <script src="https://cdnjs.cloudflare.com/ajax/libs/markdown-it/12.3.2/markdown-it.min.js"></script>
diff --git a/tests/codegen/inherit_overflow.rs b/tests/codegen/inherit_overflow.rs
index 39909d7abfd..fa9ee0ae12a 100644
--- a/tests/codegen/inherit_overflow.rs
+++ b/tests/codegen/inherit_overflow.rs
@@ -1,4 +1,4 @@
-// compile-flags: -Zmir-enable-passes=+Inline,+ConstProp --crate-type lib
+// compile-flags: -Zmir-enable-passes=+Inline,+GVN --crate-type lib
 // revisions: ASSERT NOASSERT
 //[ASSERT] compile-flags: -Coverflow-checks=on
 //[NOASSERT] compile-flags: -Coverflow-checks=off
diff --git a/tests/coverage/async2.cov-map b/tests/coverage/async2.cov-map
index b120e28c464..28f319bfb80 100644
--- a/tests/coverage/async2.cov-map
+++ b/tests/coverage/async2.cov-map
@@ -7,19 +7,17 @@ Number of file 0 mappings: 1
 - Code(Counter(0)) at (prev + 13, 1) to (start + 0, 23)
 
 Function name: async2::async_func::{closure#0}
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 0d, 17, 03, 09, 05, 03, 0a, 02, 06, 02, 02, 06, 00, 07, 07, 01, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 05, 00, 04, 01, 0d, 17, 03, 09, 05, 03, 0a, 02, 06, 00, 02, 06, 00, 07, 03, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
-- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+Number of expressions: 1
+- expression 0 operands: lhs = Counter(1), rhs = Zero
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 13, 23) to (start + 3, 9)
 - Code(Counter(1)) at (prev + 3, 10) to (start + 2, 6)
-- Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
-    = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Zero) at (prev + 2, 6) to (start + 0, 7)
+- Code(Expression(0, Add)) at (prev + 1, 1) to (start + 0, 2)
+    = (c1 + Zero)
 
 Function name: async2::async_func_just_println
 Raw bytes (9): 0x[01, 01, 00, 01, 01, 15, 01, 00, 24]
diff --git a/tests/coverage/partial_eq.cov-map b/tests/coverage/partial_eq.cov-map
index 3549116db7a..3a803e3c18f 100644
--- a/tests/coverage/partial_eq.cov-map
+++ b/tests/coverage/partial_eq.cov-map
@@ -25,18 +25,18 @@ Number of file 0 mappings: 2
 - Code(Zero) at (prev + 0, 32) to (start + 0, 33)
 
 Function name: <partial_eq::Version as core::cmp::PartialOrd>::partial_cmp
-Raw bytes (22): 0x[01, 01, 04, 07, 0b, 05, 09, 0f, 15, 0d, 11, 02, 01, 04, 27, 00, 28, 03, 00, 30, 00, 31]
+Raw bytes (22): 0x[01, 01, 04, 07, 0b, 00, 09, 0f, 15, 00, 11, 02, 01, 04, 27, 00, 28, 03, 00, 30, 00, 31]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 4
 - expression 0 operands: lhs = Expression(1, Add), rhs = Expression(2, Add)
-- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 1 operands: lhs = Zero, rhs = Counter(2)
 - expression 2 operands: lhs = Expression(3, Add), rhs = Counter(5)
-- expression 3 operands: lhs = Counter(3), rhs = Counter(4)
+- expression 3 operands: lhs = Zero, rhs = Counter(4)
 Number of file 0 mappings: 2
 - Code(Counter(0)) at (prev + 4, 39) to (start + 0, 40)
 - Code(Expression(0, Add)) at (prev + 0, 48) to (start + 0, 49)
-    = ((c1 + c2) + ((c3 + c4) + c5))
+    = ((Zero + c2) + ((Zero + c4) + c5))
 
 Function name: <partial_eq::Version as core::fmt::Debug>::fmt
 Raw bytes (9): 0x[01, 01, 00, 01, 01, 04, 11, 00, 16]
diff --git a/tests/incremental/hashes/for_loops.rs b/tests/incremental/hashes/for_loops.rs
index 98c762e4097..84a04ff913b 100644
--- a/tests/incremental/hashes/for_loops.rs
+++ b/tests/incremental/hashes/for_loops.rs
@@ -103,9 +103,9 @@ pub fn change_iterable() {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, promoted_mir")]
+#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, promoted_mir, optimized_mir")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, promoted_mir")]
+#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, promoted_mir, optimized_mir")]
 #[rustc_clean(cfg="cfail6")]
 pub fn change_iterable() {
     let mut _x = 0;
diff --git a/tests/incremental/string_constant.rs b/tests/incremental/string_constant.rs
index e15a8d18f85..47cd100b136 100644
--- a/tests/incremental/string_constant.rs
+++ b/tests/incremental/string_constant.rs
@@ -1,5 +1,5 @@
 // revisions: cfail1 cfail2
-// compile-flags: -Z query-dep-graph
+// compile-flags: -Z query-dep-graph -Copt-level=0
 // build-pass (FIXME(62277): could be check-pass?)
 
 #![allow(warnings)]
diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir
index 59e27512464..3a9c80caa1e 100644
--- a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir
+++ b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir
@@ -11,7 +11,6 @@
                 CoroutineWitness(DefId(0:4 ~ async_await[ccf8]::a::{closure#0}), []),
                 (),
                 ],
-                Static,
             ),
             source_info: SourceInfo {
                 span: $DIR/async_await.rs:16:5: 16:14 (#9),
@@ -29,7 +28,6 @@
                 CoroutineWitness(DefId(0:4 ~ async_await[ccf8]::a::{closure#0}), []),
                 (),
                 ],
-                Static,
             ),
             source_info: SourceInfo {
                 span: $DIR/async_await.rs:17:5: 17:14 (#11),
diff --git a/tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir b/tests/mir-opt/const_allocation.main.GVN.after.32bit.mir
index 9cc4c7c4d76..f089c6741fe 100644
--- a/tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir
+++ b/tests/mir-opt/const_allocation.main.GVN.after.32bit.mir
@@ -1,4 +1,4 @@
-// MIR for `main` after ConstProp
+// MIR for `main` after GVN
 
 fn main() -> () {
     let mut _0: ();
@@ -7,10 +7,10 @@ fn main() -> () {
 
     bb0: {
         StorageLive(_1);
-        StorageLive(_2);
+        nop;
         _2 = const {ALLOC9: &&[(Option<i32>, &[&str])]};
         _1 = (*_2);
-        StorageDead(_2);
+        nop;
         StorageDead(_1);
         _0 = const ();
         return;
diff --git a/tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir b/tests/mir-opt/const_allocation.main.GVN.after.64bit.mir
index faa9d20f2d5..9cbbaf302be 100644
--- a/tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir
+++ b/tests/mir-opt/const_allocation.main.GVN.after.64bit.mir
@@ -1,4 +1,4 @@
-// MIR for `main` after ConstProp
+// MIR for `main` after GVN
 
 fn main() -> () {
     let mut _0: ();
@@ -7,10 +7,10 @@ fn main() -> () {
 
     bb0: {
         StorageLive(_1);
-        StorageLive(_2);
+        nop;
         _2 = const {ALLOC9: &&[(Option<i32>, &[&str])]};
         _1 = (*_2);
-        StorageDead(_2);
+        nop;
         StorageDead(_1);
         _0 = const ();
         return;
diff --git a/tests/mir-opt/const_allocation.rs b/tests/mir-opt/const_allocation.rs
index 577c61aeb7d..5b5fb524fdb 100644
--- a/tests/mir-opt/const_allocation.rs
+++ b/tests/mir-opt/const_allocation.rs
@@ -1,11 +1,11 @@
 // skip-filecheck
-// unit-test: ConstProp
+// unit-test: GVN
 // ignore-endian-big
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 static FOO: &[(Option<i32>, &[&str])] =
     &[(None, &[]), (None, &["foo", "bar"]), (Some(42), &["meh", "mop", "möp"])];
 
-// EMIT_MIR const_allocation.main.ConstProp.after.mir
+// EMIT_MIR const_allocation.main.GVN.after.mir
 fn main() {
     FOO;
 }
diff --git a/tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir b/tests/mir-opt/const_allocation2.main.GVN.after.32bit.mir
index 898835b46e4..dfa2d808128 100644
--- a/tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir
+++ b/tests/mir-opt/const_allocation2.main.GVN.after.32bit.mir
@@ -1,4 +1,4 @@
-// MIR for `main` after ConstProp
+// MIR for `main` after GVN
 
 fn main() -> () {
     let mut _0: ();
@@ -7,10 +7,10 @@ fn main() -> () {
 
     bb0: {
         StorageLive(_1);
-        StorageLive(_2);
+        nop;
         _2 = const {ALLOC9: &&[(Option<i32>, &[&u8])]};
         _1 = (*_2);
-        StorageDead(_2);
+        nop;
         StorageDead(_1);
         _0 = const ();
         return;
diff --git a/tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir b/tests/mir-opt/const_allocation2.main.GVN.after.64bit.mir
index f5352c2aebb..02b66987169 100644
--- a/tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir
+++ b/tests/mir-opt/const_allocation2.main.GVN.after.64bit.mir
@@ -1,4 +1,4 @@
-// MIR for `main` after ConstProp
+// MIR for `main` after GVN
 
 fn main() -> () {
     let mut _0: ();
@@ -7,10 +7,10 @@ fn main() -> () {
 
     bb0: {
         StorageLive(_1);
-        StorageLive(_2);
+        nop;
         _2 = const {ALLOC9: &&[(Option<i32>, &[&u8])]};
         _1 = (*_2);
-        StorageDead(_2);
+        nop;
         StorageDead(_1);
         _0 = const ();
         return;
diff --git a/tests/mir-opt/const_allocation2.rs b/tests/mir-opt/const_allocation2.rs
index 0fcfaad842c..171592889d5 100644
--- a/tests/mir-opt/const_allocation2.rs
+++ b/tests/mir-opt/const_allocation2.rs
@@ -1,8 +1,8 @@
 // skip-filecheck
-// unit-test: ConstProp
+// unit-test: GVN
 // ignore-endian-big
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
-// EMIT_MIR const_allocation2.main.ConstProp.after.mir
+// EMIT_MIR const_allocation2.main.GVN.after.mir
 fn main() {
     FOO;
 }
diff --git a/tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir b/tests/mir-opt/const_allocation3.main.GVN.after.32bit.mir
index 624047f5b6f..386a55ee6fa 100644
--- a/tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir
+++ b/tests/mir-opt/const_allocation3.main.GVN.after.32bit.mir
@@ -1,4 +1,4 @@
-// MIR for `main` after ConstProp
+// MIR for `main` after GVN
 
 fn main() -> () {
     let mut _0: ();
@@ -7,10 +7,10 @@ fn main() -> () {
 
     bb0: {
         StorageLive(_1);
-        StorageLive(_2);
+        nop;
         _2 = const {ALLOC4: &&Packed};
         _1 = (*_2);
-        StorageDead(_2);
+        nop;
         StorageDead(_1);
         _0 = const ();
         return;
diff --git a/tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir b/tests/mir-opt/const_allocation3.main.GVN.after.64bit.mir
index cdd4758e153..b9e98f8cd4c 100644
--- a/tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir
+++ b/tests/mir-opt/const_allocation3.main.GVN.after.64bit.mir
@@ -1,4 +1,4 @@
-// MIR for `main` after ConstProp
+// MIR for `main` after GVN
 
 fn main() -> () {
     let mut _0: ();
@@ -7,10 +7,10 @@ fn main() -> () {
 
     bb0: {
         StorageLive(_1);
-        StorageLive(_2);
+        nop;
         _2 = const {ALLOC2: &&Packed};
         _1 = (*_2);
-        StorageDead(_2);
+        nop;
         StorageDead(_1);
         _0 = const ();
         return;
diff --git a/tests/mir-opt/const_allocation3.rs b/tests/mir-opt/const_allocation3.rs
index b8c9f50977e..91a30f0587b 100644
--- a/tests/mir-opt/const_allocation3.rs
+++ b/tests/mir-opt/const_allocation3.rs
@@ -1,8 +1,8 @@
 // skip-filecheck
-// unit-test: ConstProp
+// unit-test: GVN
 // ignore-endian-big
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
-// EMIT_MIR const_allocation3.main.ConstProp.after.mir
+// EMIT_MIR const_allocation3.main.GVN.after.mir
 fn main() {
     FOO;
 }
diff --git a/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff b/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff
index 87c07279552..c1529dbee13 100644
--- a/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff
+++ b/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff
@@ -34,7 +34,8 @@
                               debug f => _10;
                               let _11: std::option::Option<u16>;
                               scope 7 {
-                                  debug o => _11;
+-                                 debug o => _11;
++                                 debug o => const Option::<u16>::Some(99_u16);
                                   let _12: Point;
                                   scope 8 {
 -                                     debug p => _12;
@@ -54,11 +55,11 @@
       }
   
       bb0: {
-          StorageLive(_1);
+          nop;
           _1 = const 1_u8;
-          StorageLive(_2);
+          nop;
           _2 = const 2_u8;
-          StorageLive(_3);
+          nop;
           _3 = const 3_u8;
           StorageLive(_4);
           StorageLive(_5);
@@ -79,17 +80,17 @@
           StorageLive(_10);
           _10 = (const true, const false, const 123_u32);
           StorageLive(_11);
-          _11 = Option::<u16>::Some(const 99_u16);
+          _11 = const Option::<u16>::Some(99_u16);
           StorageLive(_12);
           _12 = const Point {{ x: 32_u32, y: 32_u32 }};
           StorageLive(_13);
-          StorageLive(_14);
+          nop;
           _14 = const 32_u32;
           StorageLive(_15);
           _15 = const 32_u32;
           _13 = const 64_u32;
           StorageDead(_15);
-          StorageDead(_14);
+          nop;
           _0 = const ();
           StorageDead(_13);
           StorageDead(_12);
@@ -97,9 +98,9 @@
           StorageDead(_10);
           StorageDead(_9);
           StorageDead(_4);
-          StorageDead(_3);
-          StorageDead(_2);
-          StorageDead(_1);
+          nop;
+          nop;
+          nop;
           return;
       }
   }
@@ -108,3 +109,7 @@
       20 00 00 00 20 00 00 00                         │  ... ...
   }
   
+  ALLOC1 (size: 4, align: 2) {
+      01 00 63 00                                     │ ..c.
+  }
+  
diff --git a/tests/mir-opt/const_debuginfo.rs b/tests/mir-opt/const_debuginfo.rs
index 0e5ac4b8bd6..db0c5dbb28f 100644
--- a/tests/mir-opt/const_debuginfo.rs
+++ b/tests/mir-opt/const_debuginfo.rs
@@ -1,5 +1,5 @@
 // unit-test: ConstDebugInfo
-// compile-flags: -C overflow-checks=no -Zmir-enable-passes=+ConstProp
+// compile-flags: -C overflow-checks=no -Zmir-enable-passes=+GVN
 
 struct Point {
     x: u32,
@@ -15,7 +15,7 @@ fn main() {
     // CHECK: debug sum => const 6_u8;
     // CHECK: debug s => const "hello, world!";
     // CHECK: debug f => {{_.*}};
-    // CHECK: debug o => {{_.*}};
+    // CHECK: debug o => const Option::<u16>::Some(99_u16);
     // CHECK: debug p => const Point
     // CHECK: debug a => const 64_u32;
     let x = 1u8;
diff --git a/tests/mir-opt/const_prop/address_of_pair.fn0.ConstProp.diff b/tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff
index 6b96c24d460..2285962fad1 100644
--- a/tests/mir-opt/const_prop/address_of_pair.fn0.ConstProp.diff
+++ b/tests/mir-opt/const_prop/address_of_pair.fn0.GVN.diff
@@ -1,5 +1,5 @@
-- // MIR for `fn0` before ConstProp
-+ // MIR for `fn0` after ConstProp
+- // MIR for `fn0` before GVN
++ // MIR for `fn0` after GVN
   
   fn fn0() -> bool {
       let mut _0: bool;
@@ -23,24 +23,34 @@
   
       bb0: {
           StorageLive(_2);
-          _2 = (const 1_i32, const false);
-          StorageLive(_3);
+-         _2 = (const 1_i32, const false);
+-         StorageLive(_3);
++         _2 = const (1_i32, false);
++         nop;
           _3 = &raw mut (_2.1: bool);
-          _2 = (const 1_i32, const false);
+-         _2 = (const 1_i32, const false);
++         _2 = const (1_i32, false);
           StorageLive(_4);
           (*_3) = const true;
           _4 = const ();
           StorageDead(_4);
-          StorageLive(_5);
+-         StorageLive(_5);
++         nop;
           StorageLive(_6);
           _6 = (_2.1: bool);
           _5 = Not(move _6);
           StorageDead(_6);
           _0 = _5;
-          StorageDead(_5);
-          StorageDead(_3);
+-         StorageDead(_5);
+-         StorageDead(_3);
++         nop;
++         nop;
           StorageDead(_2);
           return;
       }
++ }
++ 
++ ALLOC0 (size: 8, align: 4) {
++     01 00 00 00 00 __ __ __                         │ .....░░░
   }
   
diff --git a/tests/mir-opt/const_prop/address_of_pair.rs b/tests/mir-opt/const_prop/address_of_pair.rs
index 730ebe2ca63..1ab8a602823 100644
--- a/tests/mir-opt/const_prop/address_of_pair.rs
+++ b/tests/mir-opt/const_prop/address_of_pair.rs
@@ -1,6 +1,6 @@
-// unit-test: ConstProp
+// unit-test: GVN
 
-// EMIT_MIR address_of_pair.fn0.ConstProp.diff
+// EMIT_MIR address_of_pair.fn0.GVN.diff
 pub fn fn0() -> bool {
     // CHECK-LABEL: fn fn0(
     // CHECK: debug pair => [[pair:_.*]];
diff --git a/tests/mir-opt/const_prop/aggregate.foo.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/aggregate.foo.GVN.panic-abort.diff
index 5e2db148de8..4f0f7fa8fa2 100644
--- a/tests/mir-opt/const_prop/aggregate.foo.ConstProp.panic-abort.diff
+++ b/tests/mir-opt/const_prop/aggregate.foo.GVN.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `foo` before ConstProp
-+ // MIR for `foo` after ConstProp
+- // MIR for `foo` before GVN
++ // MIR for `foo` after GVN
   
   fn foo(_1: u8) -> () {
       debug x => _1;
@@ -25,7 +25,8 @@
           StorageLive(_4);
           StorageLive(_5);
           _5 = _1;
-          _4 = (const 0_i32, move _5);
+-         _4 = (const 0_i32, move _5);
++         _4 = (const 0_i32, _1);
           StorageDead(_5);
 -         _3 = (_4.0: i32);
 -         _2 = Add(move _3, const 1_i32);
@@ -38,7 +39,8 @@
           StorageLive(_8);
           StorageLive(_9);
           _9 = _1;
-          _8 = (move _9, const 1_i32);
+-         _8 = (move _9, const 1_i32);
++         _8 = (_1, const 1_i32);
           StorageDead(_9);
 -         _7 = (_8.1: i32);
 -         _6 = Add(move _7, const 2_i32);
diff --git a/tests/mir-opt/const_prop/aggregate.foo.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/aggregate.foo.GVN.panic-unwind.diff
index 5e2db148de8..4f0f7fa8fa2 100644
--- a/tests/mir-opt/const_prop/aggregate.foo.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/aggregate.foo.GVN.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `foo` before ConstProp
-+ // MIR for `foo` after ConstProp
+- // MIR for `foo` before GVN
++ // MIR for `foo` after GVN
   
   fn foo(_1: u8) -> () {
       debug x => _1;
@@ -25,7 +25,8 @@
           StorageLive(_4);
           StorageLive(_5);
           _5 = _1;
-          _4 = (const 0_i32, move _5);
+-         _4 = (const 0_i32, move _5);
++         _4 = (const 0_i32, _1);
           StorageDead(_5);
 -         _3 = (_4.0: i32);
 -         _2 = Add(move _3, const 1_i32);
@@ -38,7 +39,8 @@
           StorageLive(_8);
           StorageLive(_9);
           _9 = _1;
-          _8 = (move _9, const 1_i32);
+-         _8 = (move _9, const 1_i32);
++         _8 = (_1, const 1_i32);
           StorageDead(_9);
 -         _7 = (_8.1: i32);
 -         _6 = Add(move _7, const 2_i32);
diff --git a/tests/mir-opt/const_prop/aggregate.main.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/aggregate.main.GVN.panic-abort.diff
index a4911a6d48a..854e27445af 100644
--- a/tests/mir-opt/const_prop/aggregate.main.ConstProp.panic-abort.diff
+++ b/tests/mir-opt/const_prop/aggregate.main.GVN.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -13,7 +13,8 @@
       }
   
       bb0: {
-          StorageLive(_1);
+-         StorageLive(_1);
++         nop;
           StorageLive(_2);
           StorageLive(_3);
           _3 = (const 0_i32, const 1_u8, const 2_i32);
@@ -35,7 +36,8 @@
           StorageDead(_5);
           StorageDead(_4);
           _0 = const ();
-          StorageDead(_1);
+-         StorageDead(_1);
++         nop;
           return;
       }
   }
diff --git a/tests/mir-opt/const_prop/aggregate.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/aggregate.main.GVN.panic-unwind.diff
index b8b9fa5cc1c..f6c4b2c9240 100644
--- a/tests/mir-opt/const_prop/aggregate.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/aggregate.main.GVN.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -13,7 +13,8 @@
       }
   
       bb0: {
-          StorageLive(_1);
+-         StorageLive(_1);
++         nop;
           StorageLive(_2);
           StorageLive(_3);
           _3 = (const 0_i32, const 1_u8, const 2_i32);
@@ -35,7 +36,8 @@
           StorageDead(_5);
           StorageDead(_4);
           _0 = const ();
-          StorageDead(_1);
+-         StorageDead(_1);
++         nop;
           return;
       }
   }
diff --git a/tests/mir-opt/const_prop/aggregate.rs b/tests/mir-opt/const_prop/aggregate.rs
index fa716b0843d..3dd37b5910e 100644
--- a/tests/mir-opt/const_prop/aggregate.rs
+++ b/tests/mir-opt/const_prop/aggregate.rs
@@ -1,8 +1,8 @@
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
-// unit-test: ConstProp
+// unit-test: GVN
 // compile-flags: -O
 
-// EMIT_MIR aggregate.main.ConstProp.diff
+// EMIT_MIR aggregate.main.GVN.diff
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: debug x => [[x:_.*]];
@@ -15,7 +15,7 @@ fn main() {
 }
 
 // Verify that we still propagate if part of the aggregate is not known.
-// EMIT_MIR aggregate.foo.ConstProp.diff
+// EMIT_MIR aggregate.foo.GVN.diff
 fn foo(x: u8) {
     // CHECK-LABEL: fn foo(
     // CHECK: debug first => [[first:_.*]];
diff --git a/tests/mir-opt/const_prop/array_index.main.ConstProp.64bit.panic-abort.diff b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff
index b2f58f8f771..f9537661e8c 100644
--- a/tests/mir-opt/const_prop/array_index.main.ConstProp.64bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -18,12 +18,11 @@
           _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
           StorageLive(_3);
           _3 = const 2_usize;
--         _4 = Len(_2);
+          _4 = Len(_2);
 -         _5 = Lt(_3, _4);
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
-+         _4 = const 4_usize;
-+         _5 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable];
++         _5 = Lt(const 2_usize, _4);
++         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/array_index.main.ConstProp.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff
index f9e3f8f171a..07886779fea 100644
--- a/tests/mir-opt/const_prop/array_index.main.ConstProp.32bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -18,12 +18,11 @@
           _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
           StorageLive(_3);
           _3 = const 2_usize;
--         _4 = Len(_2);
+          _4 = Len(_2);
 -         _5 = Lt(_3, _4);
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
-+         _4 = const 4_usize;
-+         _5 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue];
++         _5 = Lt(const 2_usize, _4);
++         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/array_index.main.ConstProp.32bit.panic-abort.diff b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff
index b2f58f8f771..f9537661e8c 100644
--- a/tests/mir-opt/const_prop/array_index.main.ConstProp.32bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -18,12 +18,11 @@
           _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
           StorageLive(_3);
           _3 = const 2_usize;
--         _4 = Len(_2);
+          _4 = Len(_2);
 -         _5 = Lt(_3, _4);
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
-+         _4 = const 4_usize;
-+         _5 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable];
++         _5 = Lt(const 2_usize, _4);
++         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/array_index.main.ConstProp.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff
index f9e3f8f171a..07886779fea 100644
--- a/tests/mir-opt/const_prop/array_index.main.ConstProp.64bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -18,12 +18,11 @@
           _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32];
           StorageLive(_3);
           _3 = const 2_usize;
--         _4 = Len(_2);
+          _4 = Len(_2);
 -         _5 = Lt(_3, _4);
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
-+         _4 = const 4_usize;
-+         _5 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue];
++         _5 = Lt(const 2_usize, _4);
++         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/array_index.rs b/tests/mir-opt/const_prop/array_index.rs
index c4c46d78f75..2ae5087751f 100644
--- a/tests/mir-opt/const_prop/array_index.rs
+++ b/tests/mir-opt/const_prop/array_index.rs
@@ -1,8 +1,8 @@
-// unit-test: ConstProp
+// unit-test: GVN
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 
-// EMIT_MIR array_index.main.ConstProp.diff
+// EMIT_MIR array_index.main.GVN.diff
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: debug x => [[x:_.*]];
diff --git a/tests/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/bad_op_div_by_zero.main.GVN.panic-abort.diff
index cead70110dc..4838efba6f9 100644
--- a/tests/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.panic-abort.diff
+++ b/tests/mir-opt/const_prop/bad_op_div_by_zero.main.GVN.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -18,7 +18,8 @@
       }
   
       bb0: {
-          StorageLive(_1);
+-         StorageLive(_1);
++         nop;
           _1 = const 0_i32;
           StorageLive(_2);
           StorageLive(_3);
@@ -47,7 +48,8 @@
           StorageDead(_3);
           _0 = const ();
           StorageDead(_2);
-          StorageDead(_1);
+-         StorageDead(_1);
++         nop;
           return;
       }
   }
diff --git a/tests/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/bad_op_div_by_zero.main.GVN.panic-unwind.diff
index c9c4ba8548c..7f403d6efc1 100644
--- a/tests/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/bad_op_div_by_zero.main.GVN.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -18,7 +18,8 @@
       }
   
       bb0: {
-          StorageLive(_1);
+-         StorageLive(_1);
++         nop;
           _1 = const 0_i32;
           StorageLive(_2);
           StorageLive(_3);
@@ -47,7 +48,8 @@
           StorageDead(_3);
           _0 = const ();
           StorageDead(_2);
-          StorageDead(_1);
+-         StorageDead(_1);
++         nop;
           return;
       }
   }
diff --git a/tests/mir-opt/const_prop/bad_op_div_by_zero.rs b/tests/mir-opt/const_prop/bad_op_div_by_zero.rs
index 0e8765a0771..2ba53a80c43 100644
--- a/tests/mir-opt/const_prop/bad_op_div_by_zero.rs
+++ b/tests/mir-opt/const_prop/bad_op_div_by_zero.rs
@@ -1,7 +1,7 @@
-// unit-test: ConstProp
+// unit-test: GVN
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
-// EMIT_MIR bad_op_div_by_zero.main.ConstProp.diff
+// EMIT_MIR bad_op_div_by_zero.main.GVN.diff
 #[allow(unconditional_panic)]
 fn main() {
     // CHECK-LABEL: fn main(
diff --git a/tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/bad_op_mod_by_zero.main.GVN.panic-abort.diff
index 2666fd9eb91..59f2eb86f50 100644
--- a/tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.panic-abort.diff
+++ b/tests/mir-opt/const_prop/bad_op_mod_by_zero.main.GVN.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -18,7 +18,8 @@
       }
   
       bb0: {
-          StorageLive(_1);
+-         StorageLive(_1);
++         nop;
           _1 = const 0_i32;
           StorageLive(_2);
           StorageLive(_3);
@@ -47,7 +48,8 @@
           StorageDead(_3);
           _0 = const ();
           StorageDead(_2);
-          StorageDead(_1);
+-         StorageDead(_1);
++         nop;
           return;
       }
   }
diff --git a/tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/bad_op_mod_by_zero.main.GVN.panic-unwind.diff
index 679df90f16f..9b866082788 100644
--- a/tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/bad_op_mod_by_zero.main.GVN.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -18,7 +18,8 @@
       }
   
       bb0: {
-          StorageLive(_1);
+-         StorageLive(_1);
++         nop;
           _1 = const 0_i32;
           StorageLive(_2);
           StorageLive(_3);
@@ -47,7 +48,8 @@
           StorageDead(_3);
           _0 = const ();
           StorageDead(_2);
-          StorageDead(_1);
+-         StorageDead(_1);
++         nop;
           return;
       }
   }
diff --git a/tests/mir-opt/const_prop/bad_op_mod_by_zero.rs b/tests/mir-opt/const_prop/bad_op_mod_by_zero.rs
index d895d9e2155..9ab57750de0 100644
--- a/tests/mir-opt/const_prop/bad_op_mod_by_zero.rs
+++ b/tests/mir-opt/const_prop/bad_op_mod_by_zero.rs
@@ -1,7 +1,7 @@
-// unit-test: ConstProp
+// unit-test: GVN
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
-// EMIT_MIR bad_op_mod_by_zero.main.ConstProp.diff
+// EMIT_MIR bad_op_mod_by_zero.main.GVN.diff
 #[allow(unconditional_panic)]
 fn main() {
     // CHECK-LABEL: fn main(
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-abort.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff
index e443c8991f9..a42f9291324 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -22,15 +22,18 @@
       }
   
       bb0: {
-          StorageLive(_1);
+-         StorageLive(_1);
++         nop;
           StorageLive(_2);
-          StorageLive(_3);
+-         StorageLive(_3);
++         nop;
           _9 = const _;
           _3 = &(*_9);
           _2 = &raw const (*_3);
           _1 = move _2 as *const [i32] (PointerCoercion(Unsize));
           StorageDead(_2);
-          StorageDead(_3);
+-         StorageDead(_3);
++         nop;
           StorageLive(_5);
           StorageLive(_6);
           _6 = const 3_usize;
@@ -47,7 +50,8 @@
           StorageDead(_6);
           _0 = const ();
           StorageDead(_5);
-          StorageDead(_1);
+-         StorageDead(_1);
++         nop;
           return;
       }
   }
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff
index 592f43f4739..f2d6de6621b 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -22,15 +22,18 @@
       }
   
       bb0: {
-          StorageLive(_1);
+-         StorageLive(_1);
++         nop;
           StorageLive(_2);
-          StorageLive(_3);
+-         StorageLive(_3);
++         nop;
           _9 = const _;
           _3 = &(*_9);
           _2 = &raw const (*_3);
           _1 = move _2 as *const [i32] (PointerCoercion(Unsize));
           StorageDead(_2);
-          StorageDead(_3);
+-         StorageDead(_3);
++         nop;
           StorageLive(_5);
           StorageLive(_6);
           _6 = const 3_usize;
@@ -47,7 +50,8 @@
           StorageDead(_6);
           _0 = const ();
           StorageDead(_5);
-          StorageDead(_1);
+-         StorageDead(_1);
++         nop;
           return;
       }
   }
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-abort.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff
index e443c8991f9..a42f9291324 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -22,15 +22,18 @@
       }
   
       bb0: {
-          StorageLive(_1);
+-         StorageLive(_1);
++         nop;
           StorageLive(_2);
-          StorageLive(_3);
+-         StorageLive(_3);
++         nop;
           _9 = const _;
           _3 = &(*_9);
           _2 = &raw const (*_3);
           _1 = move _2 as *const [i32] (PointerCoercion(Unsize));
           StorageDead(_2);
-          StorageDead(_3);
+-         StorageDead(_3);
++         nop;
           StorageLive(_5);
           StorageLive(_6);
           _6 = const 3_usize;
@@ -47,7 +50,8 @@
           StorageDead(_6);
           _0 = const ();
           StorageDead(_5);
-          StorageDead(_1);
+-         StorageDead(_1);
++         nop;
           return;
       }
   }
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff
index 592f43f4739..f2d6de6621b 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -22,15 +22,18 @@
       }
   
       bb0: {
-          StorageLive(_1);
+-         StorageLive(_1);
++         nop;
           StorageLive(_2);
-          StorageLive(_3);
+-         StorageLive(_3);
++         nop;
           _9 = const _;
           _3 = &(*_9);
           _2 = &raw const (*_3);
           _1 = move _2 as *const [i32] (PointerCoercion(Unsize));
           StorageDead(_2);
-          StorageDead(_3);
+-         StorageDead(_3);
++         nop;
           StorageLive(_5);
           StorageLive(_6);
           _6 = const 3_usize;
@@ -47,7 +50,8 @@
           StorageDead(_6);
           _0 = const ();
           StorageDead(_5);
-          StorageDead(_1);
+-         StorageDead(_1);
++         nop;
           return;
       }
   }
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs
index 266105c11f2..c6d63f0bf18 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs
@@ -1,8 +1,8 @@
-// unit-test: ConstProp
+// unit-test: GVN
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 
-// EMIT_MIR bad_op_unsafe_oob_for_slices.main.ConstProp.diff
+// EMIT_MIR bad_op_unsafe_oob_for_slices.main.GVN.diff
 #[allow(unconditional_panic)]
 fn main() {
     // CHECK-LABEL: fn main(
diff --git a/tests/mir-opt/const_prop/boolean_identities.rs b/tests/mir-opt/const_prop/boolean_identities.rs
index 2aa038034d8..f6575ac8e54 100644
--- a/tests/mir-opt/const_prop/boolean_identities.rs
+++ b/tests/mir-opt/const_prop/boolean_identities.rs
@@ -1,13 +1,14 @@
-// unit-test: ConstProp
+// unit-test: GVN
 
-// EMIT_MIR boolean_identities.test.ConstProp.diff
+// EMIT_MIR boolean_identities.test.GVN.diff
 pub fn test(x: bool, y: bool) -> bool {
     // CHECK-LABEL: fn test(
     // CHECK: debug a => [[a:_.*]];
     // CHECK: debug b => [[b:_.*]];
-    // CHECK: [[a]] = const true;
-    // CHECK: [[b]] = const false;
-    // CHECK: _0 = const false;
+    // FIXME(cjgillot) simplify algebraic identity
+    // CHECK-NOT: [[a]] = const true;
+    // CHECK-NOT: [[b]] = const false;
+    // CHECK-NOT: _0 = const false;
     let a = (y | true);
     let b = (x & false);
     a & b
diff --git a/tests/mir-opt/const_prop/boolean_identities.test.ConstProp.diff b/tests/mir-opt/const_prop/boolean_identities.test.GVN.diff
index 41e1acdff59..eca87af7527 100644
--- a/tests/mir-opt/const_prop/boolean_identities.test.ConstProp.diff
+++ b/tests/mir-opt/const_prop/boolean_identities.test.GVN.diff
@@ -1,5 +1,5 @@
-- // MIR for `test` before ConstProp
-+ // MIR for `test` after ConstProp
+- // MIR for `test` before GVN
++ // MIR for `test` after GVN
   
   fn test(_1: bool, _2: bool) -> bool {
       debug x => _1;
@@ -19,30 +19,32 @@
       }
   
       bb0: {
-          StorageLive(_3);
+-         StorageLive(_3);
++         nop;
           StorageLive(_4);
           _4 = _2;
 -         _3 = BitOr(move _4, const true);
-+         _3 = const true;
++         _3 = BitOr(_2, const true);
           StorageDead(_4);
-          StorageLive(_5);
+-         StorageLive(_5);
++         nop;
           StorageLive(_6);
           _6 = _1;
 -         _5 = BitAnd(move _6, const false);
-+         _5 = const false;
++         _5 = BitAnd(_1, const false);
           StorageDead(_6);
           StorageLive(_7);
--         _7 = _3;
-+         _7 = const true;
+          _7 = _3;
           StorageLive(_8);
--         _8 = _5;
+          _8 = _5;
 -         _0 = BitAnd(move _7, move _8);
-+         _8 = const false;
-+         _0 = const false;
++         _0 = BitAnd(_3, _5);
           StorageDead(_8);
           StorageDead(_7);
-          StorageDead(_5);
-          StorageDead(_3);
+-         StorageDead(_5);
+-         StorageDead(_3);
++         nop;
++         nop;
           return;
       }
   }
diff --git a/tests/mir-opt/const_prop/boxes.main.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff
index c9670a5ee43..b3fdaa5ee82 100644
--- a/tests/mir-opt/const_prop/boxes.main.ConstProp.panic-abort.diff
+++ b/tests/mir-opt/const_prop/boxes.main.GVN.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/const_prop/boxes.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff
index 64fe72be5c8..d0350c97253 100644
--- a/tests/mir-opt/const_prop/boxes.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/boxes.main.GVN.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/const_prop/boxes.rs b/tests/mir-opt/const_prop/boxes.rs
index 90a8e33e823..5227d7b8b8b 100644
--- a/tests/mir-opt/const_prop/boxes.rs
+++ b/tests/mir-opt/const_prop/boxes.rs
@@ -1,4 +1,4 @@
-// unit-test: ConstProp
+// unit-test: GVN
 // compile-flags: -O
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
@@ -6,7 +6,7 @@
 
 // Note: this test verifies that we, in fact, do not const prop `#[rustc_box]`
 
-// EMIT_MIR boxes.main.ConstProp.diff
+// EMIT_MIR boxes.main.GVN.diff
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: debug x => [[x:_.*]];
diff --git a/tests/mir-opt/const_prop/cast.main.ConstProp.diff b/tests/mir-opt/const_prop/cast.main.GVN.diff
index c63adcf1191..bc442c4e446 100644
--- a/tests/mir-opt/const_prop/cast.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/cast.main.GVN.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/const_prop/cast.rs b/tests/mir-opt/const_prop/cast.rs
index b81c2740a73..00a8bcd1adb 100644
--- a/tests/mir-opt/const_prop/cast.rs
+++ b/tests/mir-opt/const_prop/cast.rs
@@ -1,5 +1,5 @@
-// unit-test: ConstProp
-// EMIT_MIR cast.main.ConstProp.diff
+// unit-test: GVN
+// EMIT_MIR cast.main.GVN.diff
 
 fn main() {
     // CHECK-LABEL: fn main(
diff --git a/tests/mir-opt/const_prop/checked_add.main.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/checked_add.main.GVN.panic-abort.diff
index 5a958cc7a47..d5117b2f638 100644
--- a/tests/mir-opt/const_prop/checked_add.main.ConstProp.panic-abort.diff
+++ b/tests/mir-opt/const_prop/checked_add.main.GVN.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/const_prop/checked_add.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/checked_add.main.GVN.panic-unwind.diff
index ab48186aed9..2118d37672c 100644
--- a/tests/mir-opt/const_prop/checked_add.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/checked_add.main.GVN.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/const_prop/checked_add.rs b/tests/mir-opt/const_prop/checked_add.rs
index 571a5cc4e4d..0abcb5dd3d4 100644
--- a/tests/mir-opt/const_prop/checked_add.rs
+++ b/tests/mir-opt/const_prop/checked_add.rs
@@ -1,8 +1,8 @@
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
-// unit-test: ConstProp
+// unit-test: GVN
 // compile-flags: -C overflow-checks=on
 
-// EMIT_MIR checked_add.main.ConstProp.diff
+// EMIT_MIR checked_add.main.GVN.diff
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: debug x => [[x:_.*]];
diff --git a/tests/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-abort.diff
index ba2e89f0a74..803e1d711de 100644
--- a/tests/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.panic-abort.diff
+++ b/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `hello` before ConstProp
-+ // MIR for `hello` after ConstProp
+- // MIR for `hello` before GVN
++ // MIR for `hello` after GVN
   
   fn hello() -> () {
       let mut _0: ();
@@ -8,9 +8,8 @@
   
       bb0: {
           StorageLive(_1);
--         _1 = const _;
+          _1 = const _;
 -         switchInt(move _1) -> [0: bb2, otherwise: bb1];
-+         _1 = const false;
 +         switchInt(const false) -> [0: bb2, otherwise: bb1];
       }
   
diff --git a/tests/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-unwind.diff
index e0a610f60a7..f40eb38c634 100644
--- a/tests/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `hello` before ConstProp
-+ // MIR for `hello` after ConstProp
+- // MIR for `hello` before GVN
++ // MIR for `hello` after GVN
   
   fn hello() -> () {
       let mut _0: ();
@@ -8,9 +8,8 @@
   
       bb0: {
           StorageLive(_1);
--         _1 = const _;
+          _1 = const _;
 -         switchInt(move _1) -> [0: bb2, otherwise: bb1];
-+         _1 = const false;
 +         switchInt(const false) -> [0: bb2, otherwise: bb1];
       }
   
diff --git a/tests/mir-opt/const_prop/control_flow_simplification.rs b/tests/mir-opt/const_prop/control_flow_simplification.rs
index 5fc13e20275..3cb9a4911a9 100644
--- a/tests/mir-opt/const_prop/control_flow_simplification.rs
+++ b/tests/mir-opt/const_prop/control_flow_simplification.rs
@@ -1,6 +1,6 @@
 // skip-filecheck
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
-// unit-test: ConstProp
+// unit-test: GVN
 // compile-flags: -Zmir-opt-level=1
 
 trait NeedsDrop: Sized {
@@ -9,7 +9,7 @@ trait NeedsDrop: Sized {
 
 impl<This> NeedsDrop for This {}
 
-// EMIT_MIR control_flow_simplification.hello.ConstProp.diff
+// EMIT_MIR control_flow_simplification.hello.GVN.diff
 // EMIT_MIR control_flow_simplification.hello.PreCodegen.before.mir
 fn hello<T>(){
     if <bool>::NEEDS {
diff --git a/tests/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff b/tests/mir-opt/const_prop/discriminant.main.GVN.32bit.diff
index e02e7f320b8..70c3c3fe7e4 100644
--- a/tests/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff
+++ b/tests/mir-opt/const_prop/discriminant.main.GVN.32bit.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff b/tests/mir-opt/const_prop/discriminant.main.GVN.64bit.diff
index e02e7f320b8..70c3c3fe7e4 100644
--- a/tests/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff
+++ b/tests/mir-opt/const_prop/discriminant.main.GVN.64bit.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/const_prop/discriminant.rs b/tests/mir-opt/const_prop/discriminant.rs
index 0ed683d629c..53874e9528e 100644
--- a/tests/mir-opt/const_prop/discriminant.rs
+++ b/tests/mir-opt/const_prop/discriminant.rs
@@ -1,4 +1,4 @@
-// unit-test: ConstProp
+// unit-test: GVN
 
 // FIXME(wesleywiser): Ideally, we could const-prop away all of this and just be left with
 // `let x = 42` but that doesn't work because const-prop doesn't support `Operand::Indirect`
@@ -6,7 +6,7 @@
 // Fixing either of those will allow us to const-prop this away.
 
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
-// EMIT_MIR discriminant.main.ConstProp.diff
+// EMIT_MIR discriminant.main.GVN.diff
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: bb0: {
diff --git a/tests/mir-opt/const_prop/indirect.main.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/indirect.main.GVN.panic-abort.diff
index 530cfc6539a..8301a4c1aa8 100644
--- a/tests/mir-opt/const_prop/indirect.main.ConstProp.panic-abort.diff
+++ b/tests/mir-opt/const_prop/indirect.main.GVN.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/const_prop/indirect.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/indirect.main.GVN.panic-unwind.diff
index 08cf72e47a9..8dcbfd2c2c1 100644
--- a/tests/mir-opt/const_prop/indirect.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/indirect.main.GVN.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/const_prop/indirect.rs b/tests/mir-opt/const_prop/indirect.rs
index d3c42e3eb0b..d089418e898 100644
--- a/tests/mir-opt/const_prop/indirect.rs
+++ b/tests/mir-opt/const_prop/indirect.rs
@@ -1,8 +1,8 @@
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
-// unit-test: ConstProp
+// unit-test: GVN
 // compile-flags: -C overflow-checks=on
 
-// EMIT_MIR indirect.main.ConstProp.diff
+// EMIT_MIR indirect.main.GVN.diff
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: debug x => [[x:_.*]];
diff --git a/tests/mir-opt/const_prop/indirect_mutation.bar.ConstProp.diff b/tests/mir-opt/const_prop/indirect_mutation.bar.GVN.diff
index 4eafb8d0917..7dd80d64360 100644
--- a/tests/mir-opt/const_prop/indirect_mutation.bar.ConstProp.diff
+++ b/tests/mir-opt/const_prop/indirect_mutation.bar.GVN.diff
@@ -1,5 +1,5 @@
-- // MIR for `bar` before ConstProp
-+ // MIR for `bar` after ConstProp
+- // MIR for `bar` before GVN
++ // MIR for `bar` after GVN
   
   fn bar() -> () {
       let mut _0: ();
@@ -19,12 +19,15 @@
   
       bb0: {
           StorageLive(_1);
-          _1 = (const 1_i32,);
+-         _1 = (const 1_i32,);
++         _1 = const (1_i32,);
           StorageLive(_2);
-          StorageLive(_3);
+-         StorageLive(_3);
++         nop;
           _3 = &raw mut (_1.0: i32);
           (*_3) = const 5_i32;
-          StorageDead(_3);
+-         StorageDead(_3);
++         nop;
           _2 = const ();
           StorageDead(_2);
           StorageLive(_4);
diff --git a/tests/mir-opt/const_prop/indirect_mutation.foo.ConstProp.diff b/tests/mir-opt/const_prop/indirect_mutation.foo.GVN.diff
index 445d9895d6a..c4b647d9d2d 100644
--- a/tests/mir-opt/const_prop/indirect_mutation.foo.ConstProp.diff
+++ b/tests/mir-opt/const_prop/indirect_mutation.foo.GVN.diff
@@ -1,5 +1,5 @@
-- // MIR for `foo` before ConstProp
-+ // MIR for `foo` after ConstProp
+- // MIR for `foo` before GVN
++ // MIR for `foo` after GVN
   
   fn foo() -> () {
       let mut _0: ();
@@ -16,11 +16,14 @@
   
       bb0: {
           StorageLive(_1);
-          _1 = (const 1_i32,);
-          StorageLive(_2);
+-         _1 = (const 1_i32,);
+-         StorageLive(_2);
++         _1 = const (1_i32,);
++         nop;
           _2 = &mut (_1.0: i32);
           (*_2) = const 5_i32;
-          StorageDead(_2);
+-         StorageDead(_2);
++         nop;
           StorageLive(_3);
           StorageLive(_4);
           _4 = (_1.0: i32);
diff --git a/tests/mir-opt/const_prop/indirect_mutation.rs b/tests/mir-opt/const_prop/indirect_mutation.rs
index ec9da6e8e5c..a4236060c81 100644
--- a/tests/mir-opt/const_prop/indirect_mutation.rs
+++ b/tests/mir-opt/const_prop/indirect_mutation.rs
@@ -1,13 +1,13 @@
-// unit-test: ConstProp
+// unit-test: GVN
 // Check that we do not propagate past an indirect mutation.
 #![feature(raw_ref_op)]
 
-// EMIT_MIR indirect_mutation.foo.ConstProp.diff
+// EMIT_MIR indirect_mutation.foo.GVN.diff
 fn foo() {
     // CHECK-LABEL: fn foo(
     // CHECK: debug u => _1;
     // CHECK: debug y => _3;
-    // CHECK: _1 = (const 1_i32,);
+    // CHECK: _1 = const (1_i32,);
     // CHECK: _2 = &mut (_1.0: i32);
     // CHECK: (*_2) = const 5_i32;
     // CHECK: _4 = (_1.0: i32);
@@ -18,7 +18,7 @@ fn foo() {
     let y = { u.0 } == 5;
 }
 
-// EMIT_MIR indirect_mutation.bar.ConstProp.diff
+// EMIT_MIR indirect_mutation.bar.GVN.diff
 fn bar() {
     // CHECK-LABEL: fn bar(
     // CHECK: debug v => _1;
diff --git a/tests/mir-opt/const_prop/inherit_overflow.main.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/inherit_overflow.main.GVN.panic-abort.diff
index 11cdf9e09db..4c2df228eb8 100644
--- a/tests/mir-opt/const_prop/inherit_overflow.main.ConstProp.panic-abort.diff
+++ b/tests/mir-opt/const_prop/inherit_overflow.main.GVN.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/const_prop/inherit_overflow.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/inherit_overflow.main.GVN.panic-unwind.diff
index 181a2f287d6..c4e666b489e 100644
--- a/tests/mir-opt/const_prop/inherit_overflow.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/inherit_overflow.main.GVN.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/const_prop/inherit_overflow.rs b/tests/mir-opt/const_prop/inherit_overflow.rs
index 5b561ae14ad..c5b1dbe37a9 100644
--- a/tests/mir-opt/const_prop/inherit_overflow.rs
+++ b/tests/mir-opt/const_prop/inherit_overflow.rs
@@ -1,10 +1,10 @@
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
-// unit-test: ConstProp
+// unit-test: GVN
 // compile-flags: -Zmir-enable-passes=+Inline
 
 // After inlining, this will contain a `CheckedBinaryOp`.
 // Propagating the overflow is ok as codegen will just skip emitting the panic.
-// EMIT_MIR inherit_overflow.main.ConstProp.diff
+// EMIT_MIR inherit_overflow.main.GVN.diff
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: {{_.*}} = const (0_u8, true);
diff --git a/tests/mir-opt/const_prop/invalid_constant.main.ConstProp.diff b/tests/mir-opt/const_prop/invalid_constant.main.GVN.diff
index 10e978a683a..da5bf1cf42c 100644
--- a/tests/mir-opt/const_prop/invalid_constant.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/invalid_constant.main.GVN.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -35,17 +35,14 @@
           StorageLive(_1);
           StorageLive(_2);
           _2 = InvalidChar { int: const 1114113_u32 };
--         _1 = (_2.1: char);
-+         _1 = const {transmute(0x00110001): char};
+          _1 = (_2.1: char);
           StorageDead(_2);
           StorageLive(_3);
           StorageLive(_4);
           StorageLive(_5);
           _5 = InvalidTag { int: const 4_u32 };
--         _4 = (_5.1: E);
--         _3 = [move _4];
-+         _4 = const Scalar(0x00000004): E;
-+         _3 = [const Scalar(0x00000004): E];
+          _4 = (_5.1: E);
+          _3 = [move _4];
           StorageDead(_4);
           StorageDead(_5);
           nop;
diff --git a/tests/mir-opt/const_prop/invalid_constant.rs b/tests/mir-opt/const_prop/invalid_constant.rs
index ff6b31a1ee2..142f148d064 100644
--- a/tests/mir-opt/const_prop/invalid_constant.rs
+++ b/tests/mir-opt/const_prop/invalid_constant.rs
@@ -1,5 +1,5 @@
 // skip-filecheck
-// unit-test: ConstProp
+// unit-test: GVN
 // compile-flags: -Zmir-enable-passes=+RemoveZsts
 // Verify that we can pretty print invalid constants.
 
@@ -15,7 +15,7 @@ enum E { A, B, C }
 enum Empty {}
 
 // EMIT_MIR invalid_constant.main.RemoveZsts.diff
-// EMIT_MIR invalid_constant.main.ConstProp.diff
+// EMIT_MIR invalid_constant.main.GVN.diff
 fn main() {
     // An invalid char.
     union InvalidChar {
diff --git a/tests/mir-opt/const_prop/issue_66971.main.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/issue_66971.main.GVN.panic-abort.diff
index ff93c85e586..30e8916e2d0 100644
--- a/tests/mir-opt/const_prop/issue_66971.main.ConstProp.panic-abort.diff
+++ b/tests/mir-opt/const_prop/issue_66971.main.GVN.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -11,8 +11,9 @@
           StorageLive(_1);
           StorageLive(_2);
           StorageLive(_3);
-          _3 = ();
+-         _3 = ();
 -         _2 = (move _3, const 0_u8, const 0_u8);
++         _3 = const ();
 +         _2 = const ((), 0_u8, 0_u8);
           StorageDead(_3);
 -         _1 = encode(move _2) -> [return: bb1, unwind unreachable];
@@ -29,9 +30,5 @@
 + 
 + ALLOC0 (size: 2, align: 1) {
 +     00 00                                           │ ..
-+ }
-+ 
-+ ALLOC1 (size: 2, align: 1) {
-+     00 00                                           │ ..
   }
   
diff --git a/tests/mir-opt/const_prop/issue_66971.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/issue_66971.main.GVN.panic-unwind.diff
index 8790aad4559..4eb29b174a9 100644
--- a/tests/mir-opt/const_prop/issue_66971.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/issue_66971.main.GVN.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -11,8 +11,9 @@
           StorageLive(_1);
           StorageLive(_2);
           StorageLive(_3);
-          _3 = ();
+-         _3 = ();
 -         _2 = (move _3, const 0_u8, const 0_u8);
++         _3 = const ();
 +         _2 = const ((), 0_u8, 0_u8);
           StorageDead(_3);
 -         _1 = encode(move _2) -> [return: bb1, unwind continue];
@@ -29,9 +30,5 @@
 + 
 + ALLOC0 (size: 2, align: 1) {
 +     00 00                                           │ ..
-+ }
-+ 
-+ ALLOC1 (size: 2, align: 1) {
-+     00 00                                           │ ..
   }
   
diff --git a/tests/mir-opt/const_prop/issue_66971.rs b/tests/mir-opt/const_prop/issue_66971.rs
index 49d598ff230..30f8ea1606a 100644
--- a/tests/mir-opt/const_prop/issue_66971.rs
+++ b/tests/mir-opt/const_prop/issue_66971.rs
@@ -1,8 +1,8 @@
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
-// unit-test: ConstProp
+// unit-test: GVN
 
 // Due to a bug in propagating scalar pairs the assertion below used to fail. In the expected
-// outputs below, after ConstProp this is how _2 would look like with the bug:
+// outputs below, after GVN this is how _2 would look like with the bug:
 //
 //     _2 = (const Scalar(0x00) : (), const 0u8);
 //
@@ -12,7 +12,7 @@ fn encode(this: ((), u8, u8)) {
     assert!(this.2 == 0);
 }
 
-// EMIT_MIR issue_66971.main.ConstProp.diff
+// EMIT_MIR issue_66971.main.GVN.diff
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: = encode(const ((), 0_u8, 0_u8))
diff --git a/tests/mir-opt/const_prop/issue_67019.main.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/issue_67019.main.GVN.panic-abort.diff
index 3de9cdd79bc..fc0c8afd4cf 100644
--- a/tests/mir-opt/const_prop/issue_67019.main.ConstProp.panic-abort.diff
+++ b/tests/mir-opt/const_prop/issue_67019.main.GVN.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/const_prop/issue_67019.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/issue_67019.main.GVN.panic-unwind.diff
index 72cf48b5cba..cf4089598e7 100644
--- a/tests/mir-opt/const_prop/issue_67019.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/issue_67019.main.GVN.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/const_prop/issue_67019.rs b/tests/mir-opt/const_prop/issue_67019.rs
index f0a09e6e852..e589ed4edcc 100644
--- a/tests/mir-opt/const_prop/issue_67019.rs
+++ b/tests/mir-opt/const_prop/issue_67019.rs
@@ -1,5 +1,5 @@
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
-// unit-test: ConstProp
+// unit-test: GVN
 
 // This used to ICE in const-prop
 
@@ -7,7 +7,7 @@ fn test(this: ((u8, u8),)) {
     assert!((this.0).0 == 1);
 }
 
-// EMIT_MIR issue_67019.main.ConstProp.diff
+// EMIT_MIR issue_67019.main.GVN.diff
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: = test(const ((1_u8, 2_u8),))
diff --git a/tests/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.panic-abort.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff
index 20e2ee32698..cf36109fdcb 100644
--- a/tests/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -18,17 +18,16 @@
           _2 = [const 0_u8; 5000];
           StorageLive(_3);
           _3 = const 2_usize;
--         _4 = Len(_2);
+          _4 = Len(_2);
 -         _5 = Lt(_3, _4);
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
-+         _4 = const 5000_usize;
-+         _5 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable];
++         _5 = Lt(const 2_usize, _4);
++         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
 -         _1 = _2[_3];
-+         _1 = _2[2 of 3];
++         _1 = const 0_u8;
           StorageDead(_3);
           StorageDead(_2);
           _0 = const ();
diff --git a/tests/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff
index 1bdbbbf7863..40ed9697180 100644
--- a/tests/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -18,17 +18,16 @@
           _2 = [const 0_u8; 5000];
           StorageLive(_3);
           _3 = const 2_usize;
--         _4 = Len(_2);
+          _4 = Len(_2);
 -         _5 = Lt(_3, _4);
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
-+         _4 = const 5000_usize;
-+         _5 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue];
++         _5 = Lt(const 2_usize, _4);
++         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind continue];
       }
   
       bb1: {
 -         _1 = _2[_3];
-+         _1 = _2[2 of 3];
++         _1 = const 0_u8;
           StorageDead(_3);
           StorageDead(_2);
           _0 = const ();
diff --git a/tests/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.panic-abort.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff
index 20e2ee32698..cf36109fdcb 100644
--- a/tests/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -18,17 +18,16 @@
           _2 = [const 0_u8; 5000];
           StorageLive(_3);
           _3 = const 2_usize;
--         _4 = Len(_2);
+          _4 = Len(_2);
 -         _5 = Lt(_3, _4);
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind unreachable];
-+         _4 = const 5000_usize;
-+         _5 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable];
++         _5 = Lt(const 2_usize, _4);
++         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
 -         _1 = _2[_3];
-+         _1 = _2[2 of 3];
++         _1 = const 0_u8;
           StorageDead(_3);
           StorageDead(_2);
           _0 = const ();
diff --git a/tests/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff
index 1bdbbbf7863..40ed9697180 100644
--- a/tests/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -18,17 +18,16 @@
           _2 = [const 0_u8; 5000];
           StorageLive(_3);
           _3 = const 2_usize;
--         _4 = Len(_2);
+          _4 = Len(_2);
 -         _5 = Lt(_3, _4);
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
-+         _4 = const 5000_usize;
-+         _5 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue];
++         _5 = Lt(const 2_usize, _4);
++         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, const 2_usize) -> [success: bb1, unwind continue];
       }
   
       bb1: {
 -         _1 = _2[_3];
-+         _1 = _2[2 of 3];
++         _1 = const 0_u8;
           StorageDead(_3);
           StorageDead(_2);
           _0 = const ();
diff --git a/tests/mir-opt/const_prop/large_array_index.rs b/tests/mir-opt/const_prop/large_array_index.rs
index d98d166ff7c..12507b9434f 100644
--- a/tests/mir-opt/const_prop/large_array_index.rs
+++ b/tests/mir-opt/const_prop/large_array_index.rs
@@ -1,9 +1,9 @@
 // skip-filecheck
-// unit-test: ConstProp
+// unit-test: GVN
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 
-// EMIT_MIR large_array_index.main.ConstProp.diff
+// EMIT_MIR large_array_index.main.GVN.diff
 fn main() {
     // check that we don't propagate this, because it's too large
     let x: u8 = [0_u8; 5000][2];
diff --git a/tests/mir-opt/const_prop/mult_by_zero.rs b/tests/mir-opt/const_prop/mult_by_zero.rs
index 2e9c63a1ca1..2fdb75c3100 100644
--- a/tests/mir-opt/const_prop/mult_by_zero.rs
+++ b/tests/mir-opt/const_prop/mult_by_zero.rs
@@ -1,9 +1,10 @@
-// unit-test: ConstProp
+// unit-test: GVN
 
-// EMIT_MIR mult_by_zero.test.ConstProp.diff
+// EMIT_MIR mult_by_zero.test.GVN.diff
 fn test(x: i32) -> i32 {
     // CHECK: fn test(
-    // CHECK: _0 = const 0_i32;
+    // FIXME(cjgillot) simplify algebraic identity
+    // CHECK-NOT: _0 = const 0_i32;
     x * 0
 }
 
diff --git a/tests/mir-opt/const_prop/mult_by_zero.test.ConstProp.diff b/tests/mir-opt/const_prop/mult_by_zero.test.GVN.diff
index 73b1da06423..e9fb34749c1 100644
--- a/tests/mir-opt/const_prop/mult_by_zero.test.ConstProp.diff
+++ b/tests/mir-opt/const_prop/mult_by_zero.test.GVN.diff
@@ -1,5 +1,5 @@
-- // MIR for `test` before ConstProp
-+ // MIR for `test` after ConstProp
+- // MIR for `test` before GVN
++ // MIR for `test` after GVN
   
   fn test(_1: i32) -> i32 {
       debug x => _1;
@@ -10,7 +10,7 @@
           StorageLive(_2);
           _2 = _1;
 -         _0 = Mul(move _2, const 0_i32);
-+         _0 = const 0_i32;
++         _0 = Mul(_1, const 0_i32);
           StorageDead(_2);
           return;
       }
diff --git a/tests/mir-opt/const_prop/mutable_variable.main.ConstProp.diff b/tests/mir-opt/const_prop/mutable_variable.main.GVN.diff
index ad8d9ddb074..11464e32400 100644
--- a/tests/mir-opt/const_prop/mutable_variable.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/mutable_variable.main.GVN.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -17,8 +17,7 @@
           _1 = const 42_i32;
           _1 = const 99_i32;
           StorageLive(_2);
--         _2 = _1;
-+         _2 = const 99_i32;
+          _2 = _1;
           _0 = const ();
           StorageDead(_2);
           StorageDead(_1);
diff --git a/tests/mir-opt/const_prop/mutable_variable.rs b/tests/mir-opt/const_prop/mutable_variable.rs
index 6c74ea5b9f4..194f39f826e 100644
--- a/tests/mir-opt/const_prop/mutable_variable.rs
+++ b/tests/mir-opt/const_prop/mutable_variable.rs
@@ -1,13 +1,13 @@
-// unit-test: ConstProp
+// unit-test: GVN
 
-// EMIT_MIR mutable_variable.main.ConstProp.diff
+// EMIT_MIR mutable_variable.main.GVN.diff
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: debug x => [[x:_.*]];
     // CHECK: debug y => [[y:_.*]];
     // CHECK: [[x]] = const 42_i32;
     // CHECK: [[x]] = const 99_i32;
-    // CHECK: [[y]] = const 99_i32;
+    // CHECK: [[y]] = [[x]];
     let mut x = 42;
     x = 99;
     let y = x;
diff --git a/tests/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff b/tests/mir-opt/const_prop/mutable_variable_aggregate.main.GVN.diff
index c3ace9687e6..b6ff7b0fc23 100644
--- a/tests/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/mutable_variable_aggregate.main.GVN.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -18,8 +18,7 @@
 +         _1 = const (42_i32, 43_i32);
           (_1.1: i32) = const 99_i32;
           StorageLive(_2);
--         _2 = _1;
-+         _2 = const (42_i32, 99_i32);
+          _2 = _1;
           _0 = const ();
           StorageDead(_2);
           StorageDead(_1);
@@ -28,10 +27,6 @@
 + }
 + 
 + ALLOC0 (size: 8, align: 4) {
-+     2a 00 00 00 63 00 00 00                         │ *...c...
-+ }
-+ 
-+ ALLOC1 (size: 8, align: 4) {
 +     2a 00 00 00 2b 00 00 00                         │ *...+...
   }
   
diff --git a/tests/mir-opt/const_prop/mutable_variable_aggregate.rs b/tests/mir-opt/const_prop/mutable_variable_aggregate.rs
index a3829650290..b59132007aa 100644
--- a/tests/mir-opt/const_prop/mutable_variable_aggregate.rs
+++ b/tests/mir-opt/const_prop/mutable_variable_aggregate.rs
@@ -1,13 +1,13 @@
-// unit-test: ConstProp
+// unit-test: GVN
 
-// EMIT_MIR mutable_variable_aggregate.main.ConstProp.diff
+// EMIT_MIR mutable_variable_aggregate.main.GVN.diff
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: debug x => [[x:_.*]];
     // CHECK: debug y => [[y:_.*]];
     // CHECK: [[x]] = const (42_i32, 43_i32);
     // CHECK: ([[x]].1: i32) = const 99_i32;
-    // CHECK: [[y]] = const (42_i32, 99_i32);
+    // CHECK: [[y]] = [[x]];
     let mut x = (42, 43);
     x.1 = 99;
     let y = x;
diff --git a/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff b/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.GVN.diff
index 106e27f8f27..bc60546cd19 100644
--- a/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.GVN.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -18,17 +18,24 @@
   
       bb0: {
           StorageLive(_1);
-          _1 = (const 42_i32, const 43_i32);
-          StorageLive(_2);
+-         _1 = (const 42_i32, const 43_i32);
+-         StorageLive(_2);
++         _1 = const (42_i32, 43_i32);
++         nop;
           _2 = &mut _1;
           ((*_2).1: i32) = const 99_i32;
           StorageLive(_3);
           _3 = _1;
           _0 = const ();
           StorageDead(_3);
-          StorageDead(_2);
+-         StorageDead(_2);
++         nop;
           StorageDead(_1);
           return;
       }
++ }
++ 
++ ALLOC0 (size: 8, align: 4) {
++     2a 00 00 00 2b 00 00 00                         │ *...+...
   }
   
diff --git a/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs b/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs
index 60f414ae286..1867f7300bd 100644
--- a/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs
+++ b/tests/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.rs
@@ -1,12 +1,12 @@
-// unit-test: ConstProp
+// unit-test: GVN
 
-// EMIT_MIR mutable_variable_aggregate_mut_ref.main.ConstProp.diff
+// EMIT_MIR mutable_variable_aggregate_mut_ref.main.GVN.diff
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: debug x => [[x:_.*]];
     // CHECK: debug z => [[z:_.*]];
     // CHECK: debug y => [[y:_.*]];
-    // CHECK: [[x]] = (const 42_i32, const 43_i32);
+    // CHECK: [[x]] = const (42_i32, 43_i32);
     // CHECK: [[z]] = &mut [[x]];
     // CHECK: ((*[[z]]).1: i32) = const 99_i32;
     // CHECK: [[y]] = [[x]];
diff --git a/tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.GVN.panic-abort.diff
index 34288c62fee..6480e480f8c 100644
--- a/tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.panic-abort.diff
+++ b/tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.GVN.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -21,8 +21,7 @@
           (_1.1: i32) = const 99_i32;
           (_1.0: i32) = const 42_i32;
           StorageLive(_2);
--         _2 = (_1.1: i32);
-+         _2 = const 99_i32;
+          _2 = (_1.1: i32);
           _0 = const ();
           StorageDead(_2);
           StorageDead(_1);
diff --git a/tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.GVN.panic-unwind.diff
index 7ba2b483dc3..fb757801082 100644
--- a/tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.GVN.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -21,8 +21,7 @@
           (_1.1: i32) = const 99_i32;
           (_1.0: i32) = const 42_i32;
           StorageLive(_2);
--         _2 = (_1.1: i32);
-+         _2 = const 99_i32;
+          _2 = (_1.1: i32);
           _0 = const ();
           StorageDead(_2);
           StorageDead(_1);
diff --git a/tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.rs b/tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.rs
index 888fcde2de6..d0a44d8f4a0 100644
--- a/tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.rs
+++ b/tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.rs
@@ -1,7 +1,7 @@
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
-// unit-test: ConstProp
+// unit-test: GVN
 
-// EMIT_MIR mutable_variable_aggregate_partial_read.main.ConstProp.diff
+// EMIT_MIR mutable_variable_aggregate_partial_read.main.GVN.diff
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: debug x => [[x:_.*]];
@@ -9,7 +9,7 @@ fn main() {
     // CHECK: [[x]] = foo()
     // CHECK: ([[x]].1: i32) = const 99_i32;
     // CHECK: ([[x]].0: i32) = const 42_i32;
-    // CHECK: [[y]] = const 99_i32;
+    // CHECK: [[y]] = ([[x]].1: i32);
     let mut x: (i32, i32) = foo();
     x.1 = 99;
     x.0 = 42;
diff --git a/tests/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff b/tests/mir-opt/const_prop/mutable_variable_no_prop.main.GVN.diff
index 1f74bdcfd03..d02c392f6bd 100644
--- a/tests/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/mutable_variable_no_prop.main.GVN.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -22,12 +22,14 @@
           _1 = const 42_u32;
           StorageLive(_2);
           StorageLive(_3);
-          StorageLive(_4);
+-         StorageLive(_4);
++         nop;
           _4 = const {ALLOC0: *mut u32};
           _3 = (*_4);
           _1 = move _3;
           StorageDead(_3);
-          StorageDead(_4);
+-         StorageDead(_4);
++         nop;
           _2 = const ();
           StorageDead(_2);
           StorageLive(_5);
diff --git a/tests/mir-opt/const_prop/mutable_variable_no_prop.rs b/tests/mir-opt/const_prop/mutable_variable_no_prop.rs
index 49e9a701581..180e194928e 100644
--- a/tests/mir-opt/const_prop/mutable_variable_no_prop.rs
+++ b/tests/mir-opt/const_prop/mutable_variable_no_prop.rs
@@ -1,9 +1,9 @@
-// unit-test: ConstProp
+// unit-test: GVN
 
 // Verify that we do not propagate the contents of this mutable static.
 static mut STATIC: u32 = 0x42424242;
 
-// EMIT_MIR mutable_variable_no_prop.main.ConstProp.diff
+// EMIT_MIR mutable_variable_no_prop.main.GVN.diff
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: debug x => [[x:_.*]];
diff --git a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-abort.diff
index 85bd2b6e722..d1d23675bfd 100644
--- a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.panic-abort.diff
+++ b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -22,7 +22,8 @@
       }
   
       bb0: {
-          StorageLive(_1);
+-         StorageLive(_1);
++         nop;
           _1 = foo() -> [return: bb1, unwind unreachable];
       }
   
@@ -32,18 +33,19 @@
 +         _2 = const (1_i32, 2_i32);
           StorageLive(_3);
           _3 = _1;
-          (_2.1: i32) = move _3;
+-         (_2.1: i32) = move _3;
++         (_2.1: i32) = _1;
           StorageDead(_3);
           StorageLive(_4);
           _4 = (_2.1: i32);
           StorageLive(_5);
--         _5 = (_2.0: i32);
-+         _5 = const 1_i32;
+          _5 = (_2.0: i32);
           _0 = const ();
           StorageDead(_5);
           StorageDead(_4);
           StorageDead(_2);
-          StorageDead(_1);
+-         StorageDead(_1);
++         nop;
           return;
       }
 + }
diff --git a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-unwind.diff
index 06e96e57a62..4d69c9ce2ef 100644
--- a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.GVN.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -22,7 +22,8 @@
       }
   
       bb0: {
-          StorageLive(_1);
+-         StorageLive(_1);
++         nop;
           _1 = foo() -> [return: bb1, unwind continue];
       }
   
@@ -32,18 +33,19 @@
 +         _2 = const (1_i32, 2_i32);
           StorageLive(_3);
           _3 = _1;
-          (_2.1: i32) = move _3;
+-         (_2.1: i32) = move _3;
++         (_2.1: i32) = _1;
           StorageDead(_3);
           StorageLive(_4);
           _4 = (_2.1: i32);
           StorageLive(_5);
--         _5 = (_2.0: i32);
-+         _5 = const 1_i32;
+          _5 = (_2.0: i32);
           _0 = const ();
           StorageDead(_5);
           StorageDead(_4);
           StorageDead(_2);
-          StorageDead(_1);
+-         StorageDead(_1);
++         nop;
           return;
       }
 + }
diff --git a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.rs b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.rs
index 04e347fc03d..585363572a5 100644
--- a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.rs
+++ b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.rs
@@ -1,7 +1,7 @@
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
-// unit-test: ConstProp
+// unit-test: GVN
 
-// EMIT_MIR mutable_variable_unprop_assign.main.ConstProp.diff
+// EMIT_MIR mutable_variable_unprop_assign.main.GVN.diff
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: debug a => [[a:_.*]];
@@ -10,10 +10,9 @@ fn main() {
     // CHECK: debug z => [[z:_.*]];
     // CHECK: [[a]] = foo()
     // CHECK: [[x]] = const (1_i32, 2_i32);
-    // CHECK: [[tmp:_.*]] = [[a]];
-    // CHECK: ([[x]].1: i32) = move [[tmp]];
+    // CHECK: ([[x]].1: i32) = [[a]];
     // CHECK: [[y]] = ([[x]].1: i32);
-    // CHECK: [[z]] = const 1_i32;
+    // CHECK: [[z]] = ([[x]].0: i32);
     let a = foo();
     let mut x: (i32, i32) = (1, 2);
     x.1 = a;
diff --git a/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/offset_of.concrete.GVN.panic-abort.diff
index 711db3d21dd..5d94797905d 100644
--- a/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-abort.diff
+++ b/tests/mir-opt/const_prop/offset_of.concrete.GVN.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `concrete` before ConstProp
-+ // MIR for `concrete` after ConstProp
+- // MIR for `concrete` before GVN
++ // MIR for `concrete` after GVN
   
   fn concrete() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/offset_of.concrete.GVN.panic-unwind.diff
index 49458145415..4d890742ee9 100644
--- a/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/offset_of.concrete.GVN.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `concrete` before ConstProp
-+ // MIR for `concrete` after ConstProp
+- // MIR for `concrete` before GVN
++ // MIR for `concrete` after GVN
   
   fn concrete() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/offset_of.generic.GVN.panic-abort.diff
index 768970a7250..025241dd1bf 100644
--- a/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-abort.diff
+++ b/tests/mir-opt/const_prop/offset_of.generic.GVN.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `generic` before ConstProp
-+ // MIR for `generic` after ConstProp
+- // MIR for `generic` before GVN
++ // MIR for `generic` after GVN
   
   fn generic() -> () {
       let mut _0: ();
@@ -58,16 +58,20 @@
           StorageDead(_4);
           StorageLive(_5);
           StorageLive(_6);
-          _6 = OffsetOf(Delta<T>, [(0, 1)]);
-          _5 = must_use::<usize>(move _6) -> [return: bb3, unwind unreachable];
+-         _6 = OffsetOf(Delta<T>, [(0, 1)]);
+-         _5 = must_use::<usize>(move _6) -> [return: bb3, unwind unreachable];
++         _6 = const 0_usize;
++         _5 = must_use::<usize>(const 0_usize) -> [return: bb3, unwind unreachable];
       }
   
       bb3: {
           StorageDead(_6);
           StorageLive(_7);
           StorageLive(_8);
-          _8 = OffsetOf(Delta<T>, [(0, 2)]);
-          _7 = must_use::<usize>(move _8) -> [return: bb4, unwind unreachable];
+-         _8 = OffsetOf(Delta<T>, [(0, 2)]);
+-         _7 = must_use::<usize>(move _8) -> [return: bb4, unwind unreachable];
++         _8 = const 2_usize;
++         _7 = must_use::<usize>(const 2_usize) -> [return: bb4, unwind unreachable];
       }
   
       bb4: {
diff --git a/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/offset_of.generic.GVN.panic-unwind.diff
index 04ccd2b36e0..27f2b2f7355 100644
--- a/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/offset_of.generic.GVN.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `generic` before ConstProp
-+ // MIR for `generic` after ConstProp
+- // MIR for `generic` before GVN
++ // MIR for `generic` after GVN
   
   fn generic() -> () {
       let mut _0: ();
@@ -58,16 +58,20 @@
           StorageDead(_4);
           StorageLive(_5);
           StorageLive(_6);
-          _6 = OffsetOf(Delta<T>, [(0, 1)]);
-          _5 = must_use::<usize>(move _6) -> [return: bb3, unwind continue];
+-         _6 = OffsetOf(Delta<T>, [(0, 1)]);
+-         _5 = must_use::<usize>(move _6) -> [return: bb3, unwind continue];
++         _6 = const 0_usize;
++         _5 = must_use::<usize>(const 0_usize) -> [return: bb3, unwind continue];
       }
   
       bb3: {
           StorageDead(_6);
           StorageLive(_7);
           StorageLive(_8);
-          _8 = OffsetOf(Delta<T>, [(0, 2)]);
-          _7 = must_use::<usize>(move _8) -> [return: bb4, unwind continue];
+-         _8 = OffsetOf(Delta<T>, [(0, 2)]);
+-         _7 = must_use::<usize>(move _8) -> [return: bb4, unwind continue];
++         _8 = const 2_usize;
++         _7 = must_use::<usize>(const 2_usize) -> [return: bb4, unwind continue];
       }
   
       bb4: {
diff --git a/tests/mir-opt/const_prop/offset_of.rs b/tests/mir-opt/const_prop/offset_of.rs
index 2571c3856f4..43ecbbed186 100644
--- a/tests/mir-opt/const_prop/offset_of.rs
+++ b/tests/mir-opt/const_prop/offset_of.rs
@@ -1,5 +1,5 @@
 // skip-filecheck
-// unit-test: ConstProp
+// unit-test: GVN
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
 #![feature(offset_of, offset_of_enum)]
@@ -39,7 +39,7 @@ enum Zeta<T> {
     B(char),
 }
 
-// EMIT_MIR offset_of.concrete.ConstProp.diff
+// EMIT_MIR offset_of.concrete.GVN.diff
 fn concrete() {
     let x = offset_of!(Alpha, x);
     let y = offset_of!(Alpha, y);
@@ -50,7 +50,7 @@ fn concrete() {
     let eC = offset_of!(Epsilon, C.c);
 }
 
-// EMIT_MIR offset_of.generic.ConstProp.diff
+// EMIT_MIR offset_of.generic.GVN.diff
 fn generic<T>() {
     let gx = offset_of!(Gamma<T>, x);
     let gy = offset_of!(Gamma<T>, y);
diff --git a/tests/mir-opt/const_prop/overwrite_with_const_with_params.rs b/tests/mir-opt/const_prop/overwrite_with_const_with_params.rs
index 4cf6d7c1396..2a3499bf2fe 100644
--- a/tests/mir-opt/const_prop/overwrite_with_const_with_params.rs
+++ b/tests/mir-opt/const_prop/overwrite_with_const_with_params.rs
@@ -1,4 +1,4 @@
-// unit-test: ConstProp
+// unit-test: GVN
 // compile-flags: -O
 
 // Regression test for https://github.com/rust-lang/rust/issues/118328
@@ -10,7 +10,7 @@ impl<T> SizeOfConst<T> {
     const SIZE: usize = std::mem::size_of::<T>();
 }
 
-// EMIT_MIR overwrite_with_const_with_params.size_of.ConstProp.diff
+// EMIT_MIR overwrite_with_const_with_params.size_of.GVN.diff
 fn size_of<T>() -> usize {
     // CHECK-LABEL: fn size_of(
     // CHECK: _1 = const 0_usize;
diff --git a/tests/mir-opt/const_prop/overwrite_with_const_with_params.size_of.ConstProp.diff b/tests/mir-opt/const_prop/overwrite_with_const_with_params.size_of.GVN.diff
index ad8318832d6..caa78b7316e 100644
--- a/tests/mir-opt/const_prop/overwrite_with_const_with_params.size_of.ConstProp.diff
+++ b/tests/mir-opt/const_prop/overwrite_with_const_with_params.size_of.GVN.diff
@@ -1,5 +1,5 @@
-- // MIR for `size_of` before ConstProp
-+ // MIR for `size_of` after ConstProp
+- // MIR for `size_of` before GVN
++ // MIR for `size_of` after GVN
   
   fn size_of() -> usize {
       let mut _0: usize;
diff --git a/tests/mir-opt/const_prop/pointer_expose_address.main.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-abort.diff
index bd1de7476a2..425bc3ff6c1 100644
--- a/tests/mir-opt/const_prop/pointer_expose_address.main.ConstProp.panic-abort.diff
+++ b/tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -13,25 +13,30 @@
       }
   
       bb0: {
-          StorageLive(_1);
+-         StorageLive(_1);
++         nop;
           StorageLive(_2);
-          StorageLive(_3);
+-         StorageLive(_3);
++         nop;
           _3 = const _;
           _2 = &raw const (*_3);
           _1 = move _2 as usize (PointerExposeAddress);
           StorageDead(_2);
-          StorageDead(_3);
+-         StorageDead(_3);
++         nop;
           StorageLive(_4);
           StorageLive(_5);
           _5 = _1;
-          _4 = read(move _5) -> [return: bb1, unwind unreachable];
+-         _4 = read(move _5) -> [return: bb1, unwind unreachable];
++         _4 = read(_1) -> [return: bb1, unwind unreachable];
       }
   
       bb1: {
           StorageDead(_5);
           StorageDead(_4);
           _0 = const ();
-          StorageDead(_1);
+-         StorageDead(_1);
++         nop;
           return;
       }
   }
diff --git a/tests/mir-opt/const_prop/pointer_expose_address.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-unwind.diff
index 850b743feb1..e9360ab8d62 100644
--- a/tests/mir-opt/const_prop/pointer_expose_address.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -13,25 +13,30 @@
       }
   
       bb0: {
-          StorageLive(_1);
+-         StorageLive(_1);
++         nop;
           StorageLive(_2);
-          StorageLive(_3);
+-         StorageLive(_3);
++         nop;
           _3 = const _;
           _2 = &raw const (*_3);
           _1 = move _2 as usize (PointerExposeAddress);
           StorageDead(_2);
-          StorageDead(_3);
+-         StorageDead(_3);
++         nop;
           StorageLive(_4);
           StorageLive(_5);
           _5 = _1;
-          _4 = read(move _5) -> [return: bb1, unwind continue];
+-         _4 = read(move _5) -> [return: bb1, unwind continue];
++         _4 = read(_1) -> [return: bb1, unwind continue];
       }
   
       bb1: {
           StorageDead(_5);
           StorageDead(_4);
           _0 = const ();
-          StorageDead(_1);
+-         StorageDead(_1);
++         nop;
           return;
       }
   }
diff --git a/tests/mir-opt/const_prop/pointer_expose_address.rs b/tests/mir-opt/const_prop/pointer_expose_address.rs
index 631aac901b9..8944232f71e 100644
--- a/tests/mir-opt/const_prop/pointer_expose_address.rs
+++ b/tests/mir-opt/const_prop/pointer_expose_address.rs
@@ -1,17 +1,16 @@
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
-// unit-test: ConstProp
+// unit-test: GVN
 
 #[inline(never)]
 fn read(_: usize) { }
 
-// EMIT_MIR pointer_expose_address.main.ConstProp.diff
+// EMIT_MIR pointer_expose_address.main.GVN.diff
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: [[ptr:_.*]] = const _;
     // CHECK: [[ref:_.*]] = &raw const (*[[ptr]]);
     // CHECK: [[x:_.*]] = move [[ref]] as usize (PointerExposeAddress);
-    // CHECK: [[arg:_.*]] = [[x]];
-    // CHECK: = read(move [[arg]])
+    // CHECK: = read([[x]])
     const FOO: &i32 = &1;
     let x = FOO as *const i32 as usize;
     read(x);
diff --git a/tests/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff b/tests/mir-opt/const_prop/read_immutable_static.main.GVN.diff
index e193c82d2c0..38f23505230 100644
--- a/tests/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/read_immutable_static.main.GVN.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -14,8 +14,10 @@
   
       bb0: {
           StorageLive(_1);
-          StorageLive(_2);
-          StorageLive(_3);
+-         StorageLive(_2);
+-         StorageLive(_3);
++         nop;
++         nop;
           _3 = const {ALLOC0: &u8};
 -         _2 = (*_3);
 +         _2 = const 2_u8;
@@ -27,9 +29,11 @@
 +         _4 = const 2_u8;
 +         _1 = const 4_u8;
           StorageDead(_4);
-          StorageDead(_2);
+-         StorageDead(_2);
++         nop;
           StorageDead(_5);
-          StorageDead(_3);
+-         StorageDead(_3);
++         nop;
           _0 = const ();
           StorageDead(_1);
           return;
diff --git a/tests/mir-opt/const_prop/read_immutable_static.rs b/tests/mir-opt/const_prop/read_immutable_static.rs
index 0fa18dd101a..a3d8fee65d7 100644
--- a/tests/mir-opt/const_prop/read_immutable_static.rs
+++ b/tests/mir-opt/const_prop/read_immutable_static.rs
@@ -1,8 +1,8 @@
-// unit-test: ConstProp
+// unit-test: GVN
 
 static FOO: u8 = 2;
 
-// EMIT_MIR read_immutable_static.main.ConstProp.diff
+// EMIT_MIR read_immutable_static.main.GVN.diff
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: debug x => [[x:_.*]];
diff --git a/tests/mir-opt/const_prop/ref_deref.main.ConstProp.diff b/tests/mir-opt/const_prop/ref_deref.main.GVN.diff
index a54ae8d2fdd..8f9aa20524d 100644
--- a/tests/mir-opt/const_prop/ref_deref.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/ref_deref.main.GVN.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -13,11 +13,14 @@
   
       bb0: {
           StorageLive(_1);
-          StorageLive(_2);
+-         StorageLive(_2);
++         nop;
           _4 = const _;
           _2 = &(*_4);
-          _1 = (*_2);
-          StorageDead(_2);
+-         _1 = (*_2);
+-         StorageDead(_2);
++         _1 = const 4_i32;
++         nop;
           _0 = const ();
           StorageDead(_1);
           return;
diff --git a/tests/mir-opt/const_prop/ref_deref.rs b/tests/mir-opt/const_prop/ref_deref.rs
index 5bceae749ff..67de110d8bb 100644
--- a/tests/mir-opt/const_prop/ref_deref.rs
+++ b/tests/mir-opt/const_prop/ref_deref.rs
@@ -1,9 +1,9 @@
-// unit-test: ConstProp
+// unit-test: GVN
 
-// EMIT_MIR ref_deref.main.ConstProp.diff
+// EMIT_MIR ref_deref.main.GVN.diff
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: debug a => [[a:_.*]];
-    // CHECK: [[a]] = (*{{_.*}});
+    // CHECK: [[a]] = const 4_i32;
     let a = *(&4);
 }
diff --git a/tests/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff b/tests/mir-opt/const_prop/ref_deref_project.main.GVN.diff
index 05a4e17742d..8d38888b7d6 100644
--- a/tests/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/ref_deref_project.main.GVN.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -13,11 +13,14 @@
   
       bb0: {
           StorageLive(_1);
-          StorageLive(_2);
+-         StorageLive(_2);
++         nop;
           _4 = const _;
           _2 = &((*_4).1: i32);
-          _1 = (*_2);
-          StorageDead(_2);
+-         _1 = (*_2);
+-         StorageDead(_2);
++         _1 = const 5_i32;
++         nop;
           _0 = const ();
           StorageDead(_1);
           return;
diff --git a/tests/mir-opt/const_prop/ref_deref_project.rs b/tests/mir-opt/const_prop/ref_deref_project.rs
index 4b5c6730316..0f706b91b38 100644
--- a/tests/mir-opt/const_prop/ref_deref_project.rs
+++ b/tests/mir-opt/const_prop/ref_deref_project.rs
@@ -1,10 +1,10 @@
 // This does not currently propagate (#67862)
-// unit-test: ConstProp
+// unit-test: GVN
 
-// EMIT_MIR ref_deref_project.main.ConstProp.diff
+// EMIT_MIR ref_deref_project.main.GVN.diff
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: debug a => [[a:_.*]];
-    // CHECK: [[a]] = (*{{_.*}});
+    // CHECK: [[a]] = const 5_i32;
     let a = *(&(4, 5).1);
 }
diff --git a/tests/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff b/tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff
index e7aa015d078..cde0cb32f75 100644
--- a/tests/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/const_prop/reify_fn_ptr.rs b/tests/mir-opt/const_prop/reify_fn_ptr.rs
index 33fdd4142c1..96077d5b773 100644
--- a/tests/mir-opt/const_prop/reify_fn_ptr.rs
+++ b/tests/mir-opt/const_prop/reify_fn_ptr.rs
@@ -1,5 +1,5 @@
-// unit-test: ConstProp
-// EMIT_MIR reify_fn_ptr.main.ConstProp.diff
+// unit-test: GVN
+// EMIT_MIR reify_fn_ptr.main.GVN.diff
 
 fn main() {
     // CHECK-LABEL: fn main(
diff --git a/tests/mir-opt/const_prop/repeat.main.ConstProp.64bit.panic-abort.diff b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff
index a55bd029e99..a52e6e35483 100644
--- a/tests/mir-opt/const_prop/repeat.main.ConstProp.64bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -20,12 +20,11 @@
           _3 = [const 42_u32; 8];
           StorageLive(_4);
           _4 = const 2_usize;
--         _5 = Len(_3);
+          _5 = Len(_3);
 -         _6 = Lt(_4, _5);
 -         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind unreachable];
-+         _5 = const 8_usize;
-+         _6 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable];
++         _6 = Lt(const 2_usize, _5);
++         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/repeat.main.ConstProp.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff
index d49ef2e0179..fe0acee71eb 100644
--- a/tests/mir-opt/const_prop/repeat.main.ConstProp.64bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -20,12 +20,11 @@
           _3 = [const 42_u32; 8];
           StorageLive(_4);
           _4 = const 2_usize;
--         _5 = Len(_3);
+          _5 = Len(_3);
 -         _6 = Lt(_4, _5);
 -         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind continue];
-+         _5 = const 8_usize;
-+         _6 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue];
++         _6 = Lt(const 2_usize, _5);
++         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, const 2_usize) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/repeat.main.ConstProp.32bit.panic-abort.diff b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff
index a55bd029e99..a52e6e35483 100644
--- a/tests/mir-opt/const_prop/repeat.main.ConstProp.32bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -20,12 +20,11 @@
           _3 = [const 42_u32; 8];
           StorageLive(_4);
           _4 = const 2_usize;
--         _5 = Len(_3);
+          _5 = Len(_3);
 -         _6 = Lt(_4, _5);
 -         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind unreachable];
-+         _5 = const 8_usize;
-+         _6 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable];
++         _6 = Lt(const 2_usize, _5);
++         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, const 2_usize) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/repeat.main.ConstProp.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff
index d49ef2e0179..fe0acee71eb 100644
--- a/tests/mir-opt/const_prop/repeat.main.ConstProp.32bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -20,12 +20,11 @@
           _3 = [const 42_u32; 8];
           StorageLive(_4);
           _4 = const 2_usize;
--         _5 = Len(_3);
+          _5 = Len(_3);
 -         _6 = Lt(_4, _5);
 -         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind continue];
-+         _5 = const 8_usize;
-+         _6 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue];
++         _6 = Lt(const 2_usize, _5);
++         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, const 2_usize) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/repeat.rs b/tests/mir-opt/const_prop/repeat.rs
index 9f688bbb53e..2c8717d25bb 100644
--- a/tests/mir-opt/const_prop/repeat.rs
+++ b/tests/mir-opt/const_prop/repeat.rs
@@ -1,8 +1,8 @@
-// unit-test: ConstProp
+// unit-test: GVN
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 
-// EMIT_MIR repeat.main.ConstProp.diff
+// EMIT_MIR repeat.main.GVN.diff
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: debug x => [[x:_.*]];
diff --git a/tests/mir-opt/const_prop/return_place.add.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/return_place.add.GVN.panic-abort.diff
index 974a42e5078..51f8227c36b 100644
--- a/tests/mir-opt/const_prop/return_place.add.ConstProp.panic-abort.diff
+++ b/tests/mir-opt/const_prop/return_place.add.GVN.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `add` before ConstProp
-+ // MIR for `add` after ConstProp
+- // MIR for `add` before GVN
++ // MIR for `add` after GVN
   
   fn add() -> u32 {
       let mut _0: u32;
diff --git a/tests/mir-opt/const_prop/return_place.add.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/return_place.add.GVN.panic-unwind.diff
index 55dbc700285..8174b4edea6 100644
--- a/tests/mir-opt/const_prop/return_place.add.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/return_place.add.GVN.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `add` before ConstProp
-+ // MIR for `add` after ConstProp
+- // MIR for `add` before GVN
++ // MIR for `add` after GVN
   
   fn add() -> u32 {
       let mut _0: u32;
diff --git a/tests/mir-opt/const_prop/return_place.rs b/tests/mir-opt/const_prop/return_place.rs
index 286543abb99..c207bcbdd62 100644
--- a/tests/mir-opt/const_prop/return_place.rs
+++ b/tests/mir-opt/const_prop/return_place.rs
@@ -1,8 +1,8 @@
-// unit-test: ConstProp
+// unit-test: GVN
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 // compile-flags: -C overflow-checks=on
 
-// EMIT_MIR return_place.add.ConstProp.diff
+// EMIT_MIR return_place.add.GVN.diff
 // EMIT_MIR return_place.add.PreCodegen.before.mir
 fn add() -> u32 {
     // CHECK-LABEL: fn add(
diff --git a/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/scalar_literal_propagation.main.GVN.panic-abort.diff
index c5c09c8edd7..0a20fb0e59e 100644
--- a/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.panic-abort.diff
+++ b/tests/mir-opt/const_prop/scalar_literal_propagation.main.GVN.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -11,7 +11,8 @@
       }
   
       bb0: {
-          StorageLive(_1);
+-         StorageLive(_1);
++         nop;
           _1 = const 1_u32;
           StorageLive(_2);
           StorageLive(_3);
@@ -25,7 +26,8 @@
           StorageDead(_3);
           StorageDead(_2);
           _0 = const ();
-          StorageDead(_1);
+-         StorageDead(_1);
++         nop;
           return;
       }
   }
diff --git a/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/scalar_literal_propagation.main.GVN.panic-unwind.diff
index b256c56765e..8b9519d3adc 100644
--- a/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/scalar_literal_propagation.main.GVN.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -11,7 +11,8 @@
       }
   
       bb0: {
-          StorageLive(_1);
+-         StorageLive(_1);
++         nop;
           _1 = const 1_u32;
           StorageLive(_2);
           StorageLive(_3);
@@ -25,7 +26,8 @@
           StorageDead(_3);
           StorageDead(_2);
           _0 = const ();
-          StorageDead(_1);
+-         StorageDead(_1);
++         nop;
           return;
       }
   }
diff --git a/tests/mir-opt/const_prop/scalar_literal_propagation.rs b/tests/mir-opt/const_prop/scalar_literal_propagation.rs
index 782cd35d422..70d0eb53591 100644
--- a/tests/mir-opt/const_prop/scalar_literal_propagation.rs
+++ b/tests/mir-opt/const_prop/scalar_literal_propagation.rs
@@ -1,7 +1,7 @@
-// unit-test: ConstProp
+// unit-test: GVN
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
-// EMIT_MIR scalar_literal_propagation.main.ConstProp.diff
+// EMIT_MIR scalar_literal_propagation.main.GVN.diff
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: = consume(const 1_u32)
diff --git a/tests/mir-opt/const_prop/slice_len.main.ConstProp.64bit.panic-abort.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff
index 7d5d036f460..8b2411e50ab 100644
--- a/tests/mir-opt/const_prop/slice_len.main.ConstProp.64bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -18,33 +18,41 @@
   
       bb0: {
           StorageLive(_1);
-          StorageLive(_2);
+-         StorageLive(_2);
++         nop;
           StorageLive(_3);
           StorageLive(_4);
           _9 = const _;
-          _4 = _9;
-          _3 = _4;
-          _2 = move _3 as &[u32] (PointerCoercion(Unsize));
+-         _4 = _9;
+-         _3 = _4;
+-         _2 = move _3 as &[u32] (PointerCoercion(Unsize));
++         _4 = const {ALLOC0<imm>: &[u32; 3]};
++         _3 = const {ALLOC0<imm>: &[u32; 3]};
++         _2 = const {ALLOC0<imm>: &[u32; 3]} as &[u32] (PointerCoercion(Unsize));
           StorageDead(_3);
           StorageLive(_6);
           _6 = const 1_usize;
--         _7 = Len((*_2));
+          _7 = Len((*_2));
 -         _8 = Lt(_6, _7);
 -         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind unreachable];
-+         _7 = const 3_usize;
-+         _8 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind unreachable];
++         _8 = Lt(const 1_usize, _7);
++         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 1_usize) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
 -         _1 = (*_2)[_6];
-+         _1 = const 2_u32;
++         _1 = (*_2)[1 of 2];
           StorageDead(_6);
           StorageDead(_4);
-          StorageDead(_2);
+-         StorageDead(_2);
++         nop;
           _0 = const ();
           StorageDead(_1);
           return;
       }
++ }
++ 
++ ALLOC0 (size: 12, align: 4) {
++     01 00 00 00 02 00 00 00 03 00 00 00             │ ............
   }
   
diff --git a/tests/mir-opt/const_prop/slice_len.main.ConstProp.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff
index fa4c5a71be5..9b20d243f87 100644
--- a/tests/mir-opt/const_prop/slice_len.main.ConstProp.32bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -18,33 +18,41 @@
   
       bb0: {
           StorageLive(_1);
-          StorageLive(_2);
+-         StorageLive(_2);
++         nop;
           StorageLive(_3);
           StorageLive(_4);
           _9 = const _;
-          _4 = _9;
-          _3 = _4;
-          _2 = move _3 as &[u32] (PointerCoercion(Unsize));
+-         _4 = _9;
+-         _3 = _4;
+-         _2 = move _3 as &[u32] (PointerCoercion(Unsize));
++         _4 = const {ALLOC0<imm>: &[u32; 3]};
++         _3 = const {ALLOC0<imm>: &[u32; 3]};
++         _2 = const {ALLOC0<imm>: &[u32; 3]} as &[u32] (PointerCoercion(Unsize));
           StorageDead(_3);
           StorageLive(_6);
           _6 = const 1_usize;
--         _7 = Len((*_2));
+          _7 = Len((*_2));
 -         _8 = Lt(_6, _7);
 -         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind continue];
-+         _7 = const 3_usize;
-+         _8 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind continue];
++         _8 = Lt(const 1_usize, _7);
++         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 1_usize) -> [success: bb1, unwind continue];
       }
   
       bb1: {
 -         _1 = (*_2)[_6];
-+         _1 = const 2_u32;
++         _1 = (*_2)[1 of 2];
           StorageDead(_6);
           StorageDead(_4);
-          StorageDead(_2);
+-         StorageDead(_2);
++         nop;
           _0 = const ();
           StorageDead(_1);
           return;
       }
++ }
++ 
++ ALLOC0 (size: 12, align: 4) {
++     01 00 00 00 02 00 00 00 03 00 00 00             │ ............
   }
   
diff --git a/tests/mir-opt/const_prop/slice_len.main.ConstProp.32bit.panic-abort.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff
index 7d5d036f460..8b2411e50ab 100644
--- a/tests/mir-opt/const_prop/slice_len.main.ConstProp.32bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -18,33 +18,41 @@
   
       bb0: {
           StorageLive(_1);
-          StorageLive(_2);
+-         StorageLive(_2);
++         nop;
           StorageLive(_3);
           StorageLive(_4);
           _9 = const _;
-          _4 = _9;
-          _3 = _4;
-          _2 = move _3 as &[u32] (PointerCoercion(Unsize));
+-         _4 = _9;
+-         _3 = _4;
+-         _2 = move _3 as &[u32] (PointerCoercion(Unsize));
++         _4 = const {ALLOC0<imm>: &[u32; 3]};
++         _3 = const {ALLOC0<imm>: &[u32; 3]};
++         _2 = const {ALLOC0<imm>: &[u32; 3]} as &[u32] (PointerCoercion(Unsize));
           StorageDead(_3);
           StorageLive(_6);
           _6 = const 1_usize;
--         _7 = Len((*_2));
+          _7 = Len((*_2));
 -         _8 = Lt(_6, _7);
 -         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind unreachable];
-+         _7 = const 3_usize;
-+         _8 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind unreachable];
++         _8 = Lt(const 1_usize, _7);
++         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 1_usize) -> [success: bb1, unwind unreachable];
       }
   
       bb1: {
 -         _1 = (*_2)[_6];
-+         _1 = const 2_u32;
++         _1 = (*_2)[1 of 2];
           StorageDead(_6);
           StorageDead(_4);
-          StorageDead(_2);
+-         StorageDead(_2);
++         nop;
           _0 = const ();
           StorageDead(_1);
           return;
       }
++ }
++ 
++ ALLOC0 (size: 12, align: 4) {
++     01 00 00 00 02 00 00 00 03 00 00 00             │ ............
   }
   
diff --git a/tests/mir-opt/const_prop/slice_len.main.ConstProp.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff
index fa4c5a71be5..9b20d243f87 100644
--- a/tests/mir-opt/const_prop/slice_len.main.ConstProp.64bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -18,33 +18,41 @@
   
       bb0: {
           StorageLive(_1);
-          StorageLive(_2);
+-         StorageLive(_2);
++         nop;
           StorageLive(_3);
           StorageLive(_4);
           _9 = const _;
-          _4 = _9;
-          _3 = _4;
-          _2 = move _3 as &[u32] (PointerCoercion(Unsize));
+-         _4 = _9;
+-         _3 = _4;
+-         _2 = move _3 as &[u32] (PointerCoercion(Unsize));
++         _4 = const {ALLOC0<imm>: &[u32; 3]};
++         _3 = const {ALLOC0<imm>: &[u32; 3]};
++         _2 = const {ALLOC0<imm>: &[u32; 3]} as &[u32] (PointerCoercion(Unsize));
           StorageDead(_3);
           StorageLive(_6);
           _6 = const 1_usize;
--         _7 = Len((*_2));
+          _7 = Len((*_2));
 -         _8 = Lt(_6, _7);
 -         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind continue];
-+         _7 = const 3_usize;
-+         _8 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind continue];
++         _8 = Lt(const 1_usize, _7);
++         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 1_usize) -> [success: bb1, unwind continue];
       }
   
       bb1: {
 -         _1 = (*_2)[_6];
-+         _1 = const 2_u32;
++         _1 = (*_2)[1 of 2];
           StorageDead(_6);
           StorageDead(_4);
-          StorageDead(_2);
+-         StorageDead(_2);
++         nop;
           _0 = const ();
           StorageDead(_1);
           return;
       }
++ }
++ 
++ ALLOC0 (size: 12, align: 4) {
++     01 00 00 00 02 00 00 00 03 00 00 00             │ ............
   }
   
diff --git a/tests/mir-opt/const_prop/slice_len.rs b/tests/mir-opt/const_prop/slice_len.rs
index 0bf44272698..79cd926df21 100644
--- a/tests/mir-opt/const_prop/slice_len.rs
+++ b/tests/mir-opt/const_prop/slice_len.rs
@@ -1,13 +1,16 @@
-// unit-test: ConstProp
+// unit-test: GVN
 // compile-flags: -Zmir-enable-passes=+InstSimplify
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 
-// EMIT_MIR slice_len.main.ConstProp.diff
+// EMIT_MIR slice_len.main.GVN.diff
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: debug a => [[a:_.*]];
-    // CHECK: assert(const true,
-    // CHECK: [[a]] = const 2_u32;
+    // CHECK: [[slice:_.*]] = const {{.*}} as &[u32] (PointerCoercion(Unsize));
+    // FIXME(cjgillot) simplify Len and projection into unsized slice.
+    // CHECK-NOT: assert(const true,
+    // CHECK: [[a]] = (*[[slice]])[1 of 2];
+    // CHECK-NOT: [[a]] = const 2_u32;
     let a = (&[1u32, 2, 3] as &[u32])[1];
 }
diff --git a/tests/mir-opt/const_prop/switch_int.main.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/switch_int.main.GVN.panic-abort.diff
index 508cc15732c..ee9f2d5c7f5 100644
--- a/tests/mir-opt/const_prop/switch_int.main.ConstProp.panic-abort.diff
+++ b/tests/mir-opt/const_prop/switch_int.main.GVN.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/const_prop/switch_int.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/switch_int.main.GVN.panic-unwind.diff
index 1ce28e979a5..143d04ac984 100644
--- a/tests/mir-opt/const_prop/switch_int.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/switch_int.main.GVN.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/const_prop/switch_int.rs b/tests/mir-opt/const_prop/switch_int.rs
index d1cbaae49aa..c81b574d150 100644
--- a/tests/mir-opt/const_prop/switch_int.rs
+++ b/tests/mir-opt/const_prop/switch_int.rs
@@ -1,11 +1,11 @@
-// unit-test: ConstProp
+// unit-test: GVN
 // compile-flags: -Zmir-enable-passes=+SimplifyConstCondition-after-const-prop
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
 #[inline(never)]
 fn foo(_: i32) { }
 
-// EMIT_MIR switch_int.main.ConstProp.diff
+// EMIT_MIR switch_int.main.GVN.diff
 // EMIT_MIR switch_int.main.SimplifyConstCondition-after-const-prop.diff
 fn main() {
     // CHECK-LABEL: fn main(
diff --git a/tests/mir-opt/const_prop/transmute.from_char.ConstProp.64bit.diff b/tests/mir-opt/const_prop/transmute.from_char.GVN.32bit.diff
index febfebc8534..47dfb421ebc 100644
--- a/tests/mir-opt/const_prop/transmute.from_char.ConstProp.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.from_char.GVN.32bit.diff
@@ -1,5 +1,5 @@
-- // MIR for `from_char` before ConstProp
-+ // MIR for `from_char` after ConstProp
+- // MIR for `from_char` before GVN
++ // MIR for `from_char` after GVN
   
   fn from_char() -> i32 {
       let mut _0: i32;
diff --git a/tests/mir-opt/const_prop/transmute.from_char.ConstProp.32bit.diff b/tests/mir-opt/const_prop/transmute.from_char.GVN.64bit.diff
index febfebc8534..47dfb421ebc 100644
--- a/tests/mir-opt/const_prop/transmute.from_char.ConstProp.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.from_char.GVN.64bit.diff
@@ -1,5 +1,5 @@
-- // MIR for `from_char` before ConstProp
-+ // MIR for `from_char` after ConstProp
+- // MIR for `from_char` before GVN
++ // MIR for `from_char` after GVN
   
   fn from_char() -> i32 {
       let mut _0: i32;
diff --git a/tests/mir-opt/const_prop/transmute.invalid_bool.ConstProp.32bit.diff b/tests/mir-opt/const_prop/transmute.invalid_bool.GVN.32bit.diff
index 38a1eb5a15b..f0c6f55f775 100644
--- a/tests/mir-opt/const_prop/transmute.invalid_bool.ConstProp.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.invalid_bool.GVN.32bit.diff
@@ -1,5 +1,5 @@
-- // MIR for `invalid_bool` before ConstProp
-+ // MIR for `invalid_bool` after ConstProp
+- // MIR for `invalid_bool` before GVN
++ // MIR for `invalid_bool` after GVN
   
   fn invalid_bool() -> bool {
       let mut _0: bool;
diff --git a/tests/mir-opt/const_prop/transmute.invalid_bool.ConstProp.64bit.diff b/tests/mir-opt/const_prop/transmute.invalid_bool.GVN.64bit.diff
index 38a1eb5a15b..f0c6f55f775 100644
--- a/tests/mir-opt/const_prop/transmute.invalid_bool.ConstProp.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.invalid_bool.GVN.64bit.diff
@@ -1,5 +1,5 @@
-- // MIR for `invalid_bool` before ConstProp
-+ // MIR for `invalid_bool` after ConstProp
+- // MIR for `invalid_bool` before GVN
++ // MIR for `invalid_bool` after GVN
   
   fn invalid_bool() -> bool {
       let mut _0: bool;
diff --git a/tests/mir-opt/const_prop/transmute.invalid_char.ConstProp.32bit.diff b/tests/mir-opt/const_prop/transmute.invalid_char.GVN.32bit.diff
index 2c0998f77ea..a9e32d4d925 100644
--- a/tests/mir-opt/const_prop/transmute.invalid_char.ConstProp.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.invalid_char.GVN.32bit.diff
@@ -1,5 +1,5 @@
-- // MIR for `invalid_char` before ConstProp
-+ // MIR for `invalid_char` after ConstProp
+- // MIR for `invalid_char` before GVN
++ // MIR for `invalid_char` after GVN
   
   fn invalid_char() -> char {
       let mut _0: char;
diff --git a/tests/mir-opt/const_prop/transmute.invalid_char.ConstProp.64bit.diff b/tests/mir-opt/const_prop/transmute.invalid_char.GVN.64bit.diff
index 2c0998f77ea..a9e32d4d925 100644
--- a/tests/mir-opt/const_prop/transmute.invalid_char.ConstProp.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.invalid_char.GVN.64bit.diff
@@ -1,5 +1,5 @@
-- // MIR for `invalid_char` before ConstProp
-+ // MIR for `invalid_char` after ConstProp
+- // MIR for `invalid_char` before GVN
++ // MIR for `invalid_char` after GVN
   
   fn invalid_char() -> char {
       let mut _0: char;
diff --git a/tests/mir-opt/const_prop/transmute.less_as_i8.ConstProp.64bit.diff b/tests/mir-opt/const_prop/transmute.less_as_i8.GVN.32bit.diff
index 7ac7bed8a5f..5e0c076b981 100644
--- a/tests/mir-opt/const_prop/transmute.less_as_i8.ConstProp.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.less_as_i8.GVN.32bit.diff
@@ -1,5 +1,5 @@
-- // MIR for `less_as_i8` before ConstProp
-+ // MIR for `less_as_i8` after ConstProp
+- // MIR for `less_as_i8` before GVN
++ // MIR for `less_as_i8` after GVN
   
   fn less_as_i8() -> i8 {
       let mut _0: i8;
diff --git a/tests/mir-opt/const_prop/transmute.less_as_i8.ConstProp.32bit.diff b/tests/mir-opt/const_prop/transmute.less_as_i8.GVN.64bit.diff
index 7ac7bed8a5f..5e0c076b981 100644
--- a/tests/mir-opt/const_prop/transmute.less_as_i8.ConstProp.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.less_as_i8.GVN.64bit.diff
@@ -1,5 +1,5 @@
-- // MIR for `less_as_i8` before ConstProp
-+ // MIR for `less_as_i8` after ConstProp
+- // MIR for `less_as_i8` before GVN
++ // MIR for `less_as_i8` after GVN
   
   fn less_as_i8() -> i8 {
       let mut _0: i8;
diff --git a/tests/mir-opt/const_prop/transmute.rs b/tests/mir-opt/const_prop/transmute.rs
index 99988d05994..6ff0ba422f4 100644
--- a/tests/mir-opt/const_prop/transmute.rs
+++ b/tests/mir-opt/const_prop/transmute.rs
@@ -1,46 +1,46 @@
-// unit-test: ConstProp
+// unit-test: GVN
 // compile-flags: -O --crate-type=lib
 // ignore-endian-big
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 
 use std::mem::transmute;
 
-// EMIT_MIR transmute.less_as_i8.ConstProp.diff
+// EMIT_MIR transmute.less_as_i8.GVN.diff
 pub fn less_as_i8() -> i8 {
     // CHECK-LABEL: fn less_as_i8(
     // CHECK: _0 = const -1_i8;
     unsafe { transmute(std::cmp::Ordering::Less) }
 }
 
-// EMIT_MIR transmute.from_char.ConstProp.diff
+// EMIT_MIR transmute.from_char.GVN.diff
 pub fn from_char() -> i32 {
     // CHECK-LABEL: fn from_char(
     // CHECK: _0 = const 82_i32;
     unsafe { transmute('R') }
 }
 
-// EMIT_MIR transmute.valid_char.ConstProp.diff
+// EMIT_MIR transmute.valid_char.GVN.diff
 pub fn valid_char() -> char {
     // CHECK-LABEL: fn valid_char(
     // CHECK: _0 = const 'R';
     unsafe { transmute(0x52_u32) }
 }
 
-// EMIT_MIR transmute.invalid_char.ConstProp.diff
+// EMIT_MIR transmute.invalid_char.GVN.diff
 pub unsafe fn invalid_char() -> char {
     // CHECK-LABEL: fn invalid_char(
     // CHECK: _0 = const {transmute(0x7fffffff): char};
     unsafe { transmute(i32::MAX) }
 }
 
-// EMIT_MIR transmute.invalid_bool.ConstProp.diff
+// EMIT_MIR transmute.invalid_bool.GVN.diff
 pub unsafe fn invalid_bool() -> bool {
     // CHECK-LABEL: fn invalid_bool(
     // CHECK: _0 = const {transmute(0xff): bool};
     unsafe { transmute(-1_i8) }
 }
 
-// EMIT_MIR transmute.undef_union_as_integer.ConstProp.diff
+// EMIT_MIR transmute.undef_union_as_integer.GVN.diff
 pub unsafe fn undef_union_as_integer() -> u32 {
     // CHECK-LABEL: fn undef_union_as_integer(
     // CHECK: _1 = Union32 {
@@ -49,16 +49,16 @@ pub unsafe fn undef_union_as_integer() -> u32 {
     unsafe { transmute(Union32 { unit: () }) }
 }
 
-// EMIT_MIR transmute.unreachable_direct.ConstProp.diff
+// EMIT_MIR transmute.unreachable_direct.GVN.diff
 pub unsafe fn unreachable_direct() -> ! {
     // CHECK-LABEL: fn unreachable_direct(
-    // CHECK: [[unit:_.*]] = ();
-    // CHECK: move [[unit]] as Never (Transmute);
+    // CHECK: = const ();
+    // CHECK: = const () as Never (Transmute);
     let x: Never = unsafe { transmute(()) };
     match x {}
 }
 
-// EMIT_MIR transmute.unreachable_ref.ConstProp.diff
+// EMIT_MIR transmute.unreachable_ref.GVN.diff
 pub unsafe fn unreachable_ref() -> ! {
     // CHECK-LABEL: fn unreachable_ref(
     // CHECK: = const {0x1 as &Never};
@@ -66,7 +66,7 @@ pub unsafe fn unreachable_ref() -> ! {
     match *x {}
 }
 
-// EMIT_MIR transmute.unreachable_mut.ConstProp.diff
+// EMIT_MIR transmute.unreachable_mut.GVN.diff
 pub unsafe fn unreachable_mut() -> ! {
     // CHECK-LABEL: fn unreachable_mut(
     // CHECK: = const {0x1 as &mut Never};
@@ -74,7 +74,7 @@ pub unsafe fn unreachable_mut() -> ! {
     match *x {}
 }
 
-// EMIT_MIR transmute.unreachable_box.ConstProp.diff
+// EMIT_MIR transmute.unreachable_box.GVN.diff
 pub unsafe fn unreachable_box() -> ! {
     // CHECK-LABEL: fn unreachable_box(
     // CHECK: = const Box::<Never>(
diff --git a/tests/mir-opt/const_prop/transmute.undef_union_as_integer.ConstProp.64bit.diff b/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.32bit.diff
index afedf2a3061..c6a428019d8 100644
--- a/tests/mir-opt/const_prop/transmute.undef_union_as_integer.ConstProp.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.32bit.diff
@@ -1,5 +1,5 @@
-- // MIR for `undef_union_as_integer` before ConstProp
-+ // MIR for `undef_union_as_integer` after ConstProp
+- // MIR for `undef_union_as_integer` before GVN
++ // MIR for `undef_union_as_integer` after GVN
   
   fn undef_union_as_integer() -> u32 {
       let mut _0: u32;
@@ -11,7 +11,8 @@
       bb0: {
           StorageLive(_1);
           StorageLive(_2);
-          _2 = ();
+-         _2 = ();
++         _2 = const ();
           _1 = Union32 { value: move _2 };
           StorageDead(_2);
           _0 = move _1 as u32 (Transmute);
diff --git a/tests/mir-opt/const_prop/transmute.undef_union_as_integer.ConstProp.32bit.diff b/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.64bit.diff
index afedf2a3061..c6a428019d8 100644
--- a/tests/mir-opt/const_prop/transmute.undef_union_as_integer.ConstProp.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.64bit.diff
@@ -1,5 +1,5 @@
-- // MIR for `undef_union_as_integer` before ConstProp
-+ // MIR for `undef_union_as_integer` after ConstProp
+- // MIR for `undef_union_as_integer` before GVN
++ // MIR for `undef_union_as_integer` after GVN
   
   fn undef_union_as_integer() -> u32 {
       let mut _0: u32;
@@ -11,7 +11,8 @@
       bb0: {
           StorageLive(_1);
           StorageLive(_2);
-          _2 = ();
+-         _2 = ();
++         _2 = const ();
           _1 = Union32 { value: move _2 };
           StorageDead(_2);
           _0 = move _1 as u32 (Transmute);
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.32bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.32bit.diff
index 16519749b82..2ef83abfac0 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.32bit.diff
@@ -1,5 +1,5 @@
-- // MIR for `unreachable_box` before ConstProp
-+ // MIR for `unreachable_box` after ConstProp
+- // MIR for `unreachable_box` before GVN
++ // MIR for `unreachable_box` after GVN
   
   fn unreachable_box() -> ! {
       let mut _0: !;
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.64bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.64bit.diff
index 16519749b82..2ef83abfac0 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_box.GVN.64bit.diff
@@ -1,5 +1,5 @@
-- // MIR for `unreachable_box` before ConstProp
-+ // MIR for `unreachable_box` after ConstProp
+- // MIR for `unreachable_box` before GVN
++ // MIR for `unreachable_box` after GVN
   
   fn unreachable_box() -> ! {
       let mut _0: !;
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.32bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.32bit.diff
index 896608e7eff..b2e91014625 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.32bit.diff
@@ -1,5 +1,5 @@
-- // MIR for `unreachable_direct` before ConstProp
-+ // MIR for `unreachable_direct` after ConstProp
+- // MIR for `unreachable_direct` before GVN
++ // MIR for `unreachable_direct` after GVN
   
   fn unreachable_direct() -> ! {
       let mut _0: !;
@@ -14,8 +14,10 @@
       bb0: {
           StorageLive(_1);
           StorageLive(_2);
-          _2 = ();
-          _1 = move _2 as Never (Transmute);
+-         _2 = ();
+-         _1 = move _2 as Never (Transmute);
++         _2 = const ();
++         _1 = const () as Never (Transmute);
           unreachable;
       }
   }
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.64bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.64bit.diff
index 896608e7eff..b2e91014625 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_direct.GVN.64bit.diff
@@ -1,5 +1,5 @@
-- // MIR for `unreachable_direct` before ConstProp
-+ // MIR for `unreachable_direct` after ConstProp
+- // MIR for `unreachable_direct` before GVN
++ // MIR for `unreachable_direct` after GVN
   
   fn unreachable_direct() -> ! {
       let mut _0: !;
@@ -14,8 +14,10 @@
       bb0: {
           StorageLive(_1);
           StorageLive(_2);
-          _2 = ();
-          _1 = move _2 as Never (Transmute);
+-         _2 = ();
+-         _1 = move _2 as Never (Transmute);
++         _2 = const ();
++         _1 = const () as Never (Transmute);
           unreachable;
       }
   }
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.32bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_mut.GVN.32bit.diff
index c9d5ccf0bfd..93dfef96cf1 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_mut.GVN.32bit.diff
@@ -1,5 +1,5 @@
-- // MIR for `unreachable_mut` before ConstProp
-+ // MIR for `unreachable_mut` after ConstProp
+- // MIR for `unreachable_mut` before GVN
++ // MIR for `unreachable_mut` after GVN
   
   fn unreachable_mut() -> ! {
       let mut _0: !;
@@ -13,11 +13,13 @@
   
       bb0: {
           StorageLive(_1);
-          StorageLive(_2);
+-         StorageLive(_2);
 -         _2 = const 1_usize as &mut Never (Transmute);
++         nop;
 +         _2 = const {0x1 as &mut Never};
           _1 = &mut (*_2);
-          StorageDead(_2);
+-         StorageDead(_2);
++         nop;
           unreachable;
       }
   }
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.64bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_mut.GVN.64bit.diff
index c9d5ccf0bfd..93dfef96cf1 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_mut.GVN.64bit.diff
@@ -1,5 +1,5 @@
-- // MIR for `unreachable_mut` before ConstProp
-+ // MIR for `unreachable_mut` after ConstProp
+- // MIR for `unreachable_mut` before GVN
++ // MIR for `unreachable_mut` after GVN
   
   fn unreachable_mut() -> ! {
       let mut _0: !;
@@ -13,11 +13,13 @@
   
       bb0: {
           StorageLive(_1);
-          StorageLive(_2);
+-         StorageLive(_2);
 -         _2 = const 1_usize as &mut Never (Transmute);
++         nop;
 +         _2 = const {0x1 as &mut Never};
           _1 = &mut (*_2);
-          StorageDead(_2);
+-         StorageDead(_2);
++         nop;
           unreachable;
       }
   }
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.32bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_ref.GVN.32bit.diff
index b684ba34c69..430d16c97a6 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_ref.GVN.32bit.diff
@@ -1,5 +1,5 @@
-- // MIR for `unreachable_ref` before ConstProp
-+ // MIR for `unreachable_ref` after ConstProp
+- // MIR for `unreachable_ref` before GVN
++ // MIR for `unreachable_ref` after GVN
   
   fn unreachable_ref() -> ! {
       let mut _0: !;
diff --git a/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.64bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_ref.GVN.64bit.diff
index b684ba34c69..430d16c97a6 100644
--- a/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.unreachable_ref.GVN.64bit.diff
@@ -1,5 +1,5 @@
-- // MIR for `unreachable_ref` before ConstProp
-+ // MIR for `unreachable_ref` after ConstProp
+- // MIR for `unreachable_ref` before GVN
++ // MIR for `unreachable_ref` after GVN
   
   fn unreachable_ref() -> ! {
       let mut _0: !;
diff --git a/tests/mir-opt/const_prop/transmute.valid_char.ConstProp.32bit.diff b/tests/mir-opt/const_prop/transmute.valid_char.GVN.32bit.diff
index f215b3ca398..f9d002f96ab 100644
--- a/tests/mir-opt/const_prop/transmute.valid_char.ConstProp.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.valid_char.GVN.32bit.diff
@@ -1,5 +1,5 @@
-- // MIR for `valid_char` before ConstProp
-+ // MIR for `valid_char` after ConstProp
+- // MIR for `valid_char` before GVN
++ // MIR for `valid_char` after GVN
   
   fn valid_char() -> char {
       let mut _0: char;
diff --git a/tests/mir-opt/const_prop/transmute.valid_char.ConstProp.64bit.diff b/tests/mir-opt/const_prop/transmute.valid_char.GVN.64bit.diff
index f215b3ca398..f9d002f96ab 100644
--- a/tests/mir-opt/const_prop/transmute.valid_char.ConstProp.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.valid_char.GVN.64bit.diff
@@ -1,5 +1,5 @@
-- // MIR for `valid_char` before ConstProp
-+ // MIR for `valid_char` after ConstProp
+- // MIR for `valid_char` before GVN
++ // MIR for `valid_char` after GVN
   
   fn valid_char() -> char {
       let mut _0: char;
diff --git a/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-abort.diff
index f19650d5a83..c2f3fb1b3b5 100644
--- a/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.panic-abort.diff
+++ b/tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -11,8 +11,9 @@
       }
   
       bb0: {
-          StorageLive(_1);
+-         StorageLive(_1);
 -         _1 = (const 1_u32, const 2_u32);
++         nop;
 +         _1 = const (1_u32, 2_u32);
           StorageLive(_2);
           StorageLive(_3);
@@ -26,20 +27,13 @@
           StorageDead(_3);
           StorageDead(_2);
           _0 = const ();
-          StorageDead(_1);
+-         StorageDead(_1);
++         nop;
           return;
       }
 + }
 + 
 + ALLOC0 (size: 8, align: 4) {
 +     01 00 00 00 02 00 00 00                         │ ........
-+ }
-+ 
-+ ALLOC1 (size: 8, align: 4) {
-+     01 00 00 00 02 00 00 00                         │ ........
-+ }
-+ 
-+ ALLOC2 (size: 8, align: 4) {
-+     01 00 00 00 02 00 00 00                         │ ........
   }
   
diff --git a/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-unwind.diff
index 67307c42331..55d9a3b0cac 100644
--- a/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/tuple_literal_propagation.main.GVN.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -11,8 +11,9 @@
       }
   
       bb0: {
-          StorageLive(_1);
+-         StorageLive(_1);
 -         _1 = (const 1_u32, const 2_u32);
++         nop;
 +         _1 = const (1_u32, 2_u32);
           StorageLive(_2);
           StorageLive(_3);
@@ -26,20 +27,13 @@
           StorageDead(_3);
           StorageDead(_2);
           _0 = const ();
-          StorageDead(_1);
+-         StorageDead(_1);
++         nop;
           return;
       }
 + }
 + 
 + ALLOC0 (size: 8, align: 4) {
 +     01 00 00 00 02 00 00 00                         │ ........
-+ }
-+ 
-+ ALLOC1 (size: 8, align: 4) {
-+     01 00 00 00 02 00 00 00                         │ ........
-+ }
-+ 
-+ ALLOC2 (size: 8, align: 4) {
-+     01 00 00 00 02 00 00 00                         │ ........
   }
   
diff --git a/tests/mir-opt/const_prop/tuple_literal_propagation.rs b/tests/mir-opt/const_prop/tuple_literal_propagation.rs
index dfc4a6f3fbb..6803612f0a5 100644
--- a/tests/mir-opt/const_prop/tuple_literal_propagation.rs
+++ b/tests/mir-opt/const_prop/tuple_literal_propagation.rs
@@ -1,6 +1,6 @@
-// unit-test: ConstProp
+// unit-test: GVN
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
-// EMIT_MIR tuple_literal_propagation.main.ConstProp.diff
+// EMIT_MIR tuple_literal_propagation.main.GVN.diff
 
 fn main() {
     // CHECK-LABEL: fn main(
diff --git a/tests/mir-opt/const_prop/while_let_loops.change_loop_body.ConstProp.diff b/tests/mir-opt/const_prop/while_let_loops.change_loop_body.GVN.diff
index f54908b4a38..9548afc9d40 100644
--- a/tests/mir-opt/const_prop/while_let_loops.change_loop_body.ConstProp.diff
+++ b/tests/mir-opt/const_prop/while_let_loops.change_loop_body.GVN.diff
@@ -1,5 +1,5 @@
-- // MIR for `change_loop_body` before ConstProp
-+ // MIR for `change_loop_body` after ConstProp
+- // MIR for `change_loop_body` before GVN
++ // MIR for `change_loop_body` after GVN
   
   fn change_loop_body() -> () {
       let mut _0: ();
@@ -21,15 +21,17 @@
           StorageLive(_1);
           _1 = const 0_i32;
           StorageLive(_3);
-          _3 = Option::<u32>::None;
+-         _3 = Option::<u32>::None;
 -         _4 = discriminant(_3);
 -         switchInt(move _4) -> [1: bb1, otherwise: bb3];
++         _3 = const Option::<u32>::None;
 +         _4 = const 0_isize;
 +         switchInt(const 0_isize) -> [1: bb1, otherwise: bb3];
       }
   
       bb1: {
-          switchInt(((_3 as Some).0: u32)) -> [0: bb2, otherwise: bb3];
+-         switchInt(((_3 as Some).0: u32)) -> [0: bb2, otherwise: bb3];
++         switchInt(const Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: u32) -> [0: bb2, otherwise: bb3];
       }
   
       bb2: {
@@ -50,5 +52,9 @@
           StorageDead(_1);
           return;
       }
++ }
++ 
++ ALLOC0 (size: 8, align: 4) {
++     00 00 00 00 __ __ __ __                         │ ....░░░░
   }
   
diff --git a/tests/mir-opt/const_prop/while_let_loops.rs b/tests/mir-opt/const_prop/while_let_loops.rs
index 8b2a73438d6..d6527552bb0 100644
--- a/tests/mir-opt/const_prop/while_let_loops.rs
+++ b/tests/mir-opt/const_prop/while_let_loops.rs
@@ -1,5 +1,5 @@
-// unit-test: ConstProp
-// EMIT_MIR while_let_loops.change_loop_body.ConstProp.diff
+// unit-test: GVN
+// EMIT_MIR while_let_loops.change_loop_body.GVN.diff
 
 pub fn change_loop_body() {
     // CHECK-LABEL: fn change_loop_body(
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff
index ddfe2e8c831..6925fdb1e70 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff
@@ -74,18 +74,18 @@
           StorageDead(_7);
           StorageLive(_8);
           StorageLive(_9);
-          _8 = const {0x1 as *const [bool; 0]};
-          _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }};
+          _8 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer));
+          _5 = NonNull::<[bool; 0]> { pointer: _8 };
           StorageDead(_9);
           StorageDead(_8);
           StorageDead(_6);
-          _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }};
+          _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
           StorageDead(_5);
-          _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }};
+          _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
           StorageDead(_4);
-          _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
+          _2 = Box::<[bool]>(_3, const std::alloc::Global);
           StorageDead(_3);
-          _1 = A { foo: const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) };
+          _1 = A { foo: move _2 };
           StorageDead(_2);
           _0 = const ();
           drop(_1) -> [return: bb1, unwind unreachable];
@@ -97,15 +97,3 @@
       }
   }
   
-  ALLOC2 (size: 8, align: 4) {
-      01 00 00 00 00 00 00 00                         │ ........
-  }
-  
-  ALLOC1 (size: 8, align: 4) {
-      01 00 00 00 00 00 00 00                         │ ........
-  }
-  
-  ALLOC0 (size: 8, align: 4) {
-      01 00 00 00 00 00 00 00                         │ ........
-  }
-  
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff
index 861295faa5a..82ad842505c 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff
@@ -74,18 +74,18 @@
           StorageDead(_7);
           StorageLive(_8);
           StorageLive(_9);
-          _8 = const {0x1 as *const [bool; 0]};
-          _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }};
+          _8 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer));
+          _5 = NonNull::<[bool; 0]> { pointer: _8 };
           StorageDead(_9);
           StorageDead(_8);
           StorageDead(_6);
-          _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }};
+          _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
           StorageDead(_5);
-          _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }};
+          _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
           StorageDead(_4);
-          _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
+          _2 = Box::<[bool]>(_3, const std::alloc::Global);
           StorageDead(_3);
-          _1 = A { foo: const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) };
+          _1 = A { foo: move _2 };
           StorageDead(_2);
           _0 = const ();
           drop(_1) -> [return: bb1, unwind: bb2];
@@ -101,15 +101,3 @@
       }
   }
   
-  ALLOC2 (size: 8, align: 4) {
-      01 00 00 00 00 00 00 00                         │ ........
-  }
-  
-  ALLOC1 (size: 8, align: 4) {
-      01 00 00 00 00 00 00 00                         │ ........
-  }
-  
-  ALLOC0 (size: 8, align: 4) {
-      01 00 00 00 00 00 00 00                         │ ........
-  }
-  
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff
index cbb639edc53..6925fdb1e70 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff
@@ -74,18 +74,18 @@
           StorageDead(_7);
           StorageLive(_8);
           StorageLive(_9);
-          _8 = const {0x1 as *const [bool; 0]};
-          _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }};
+          _8 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer));
+          _5 = NonNull::<[bool; 0]> { pointer: _8 };
           StorageDead(_9);
           StorageDead(_8);
           StorageDead(_6);
-          _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }};
+          _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
           StorageDead(_5);
-          _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }};
+          _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
           StorageDead(_4);
-          _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
+          _2 = Box::<[bool]>(_3, const std::alloc::Global);
           StorageDead(_3);
-          _1 = A { foo: const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) };
+          _1 = A { foo: move _2 };
           StorageDead(_2);
           _0 = const ();
           drop(_1) -> [return: bb1, unwind unreachable];
@@ -97,15 +97,3 @@
       }
   }
   
-  ALLOC2 (size: 16, align: 8) {
-      01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
-  }
-  
-  ALLOC1 (size: 16, align: 8) {
-      01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
-  }
-  
-  ALLOC0 (size: 16, align: 8) {
-      01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
-  }
-  
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff
index 656846e9f97..82ad842505c 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff
@@ -74,18 +74,18 @@
           StorageDead(_7);
           StorageLive(_8);
           StorageLive(_9);
-          _8 = const {0x1 as *const [bool; 0]};
-          _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }};
+          _8 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer));
+          _5 = NonNull::<[bool; 0]> { pointer: _8 };
           StorageDead(_9);
           StorageDead(_8);
           StorageDead(_6);
-          _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }};
+          _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
           StorageDead(_5);
-          _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }};
+          _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
           StorageDead(_4);
-          _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
+          _2 = Box::<[bool]>(_3, const std::alloc::Global);
           StorageDead(_3);
-          _1 = A { foo: const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) };
+          _1 = A { foo: move _2 };
           StorageDead(_2);
           _0 = const ();
           drop(_1) -> [return: bb1, unwind: bb2];
@@ -101,15 +101,3 @@
       }
   }
   
-  ALLOC2 (size: 16, align: 8) {
-      01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
-  }
-  
-  ALLOC1 (size: 16, align: 8) {
-      01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
-  }
-  
-  ALLOC0 (size: 16, align: 8) {
-      01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
-  }
-  
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff
index 8363783e64e..13545aa464a 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.32bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -77,23 +77,18 @@
           StorageLive(_8);
           StorageLive(_9);
 -         _8 = _6 as *const [bool; 0] (PointerCoercion(MutToConstPointer));
--         _5 = NonNull::<[bool; 0]> { pointer: _8 };
-+         _8 = const {0x1 as *const [bool; 0]};
-+         _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }};
++         _8 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer));
+          _5 = NonNull::<[bool; 0]> { pointer: _8 };
           StorageDead(_9);
           StorageDead(_8);
           StorageDead(_6);
--         _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
-+         _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }};
+          _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
           StorageDead(_5);
--         _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
-+         _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }};
+          _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
           StorageDead(_4);
--         _2 = Box::<[bool]>(_3, const std::alloc::Global);
-+         _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
+          _2 = Box::<[bool]>(_3, const std::alloc::Global);
           StorageDead(_3);
--         _1 = A { foo: move _2 };
-+         _1 = A { foo: const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) };
+          _1 = A { foo: move _2 };
           StorageDead(_2);
           _0 = const ();
           drop(_1) -> [return: bb1, unwind unreachable];
@@ -103,17 +98,5 @@
           StorageDead(_1);
           return;
       }
-+ }
-+ 
-+ ALLOC2 (size: 8, align: 4) {
-+     01 00 00 00 00 00 00 00                         │ ........
-+ }
-+ 
-+ ALLOC1 (size: 8, align: 4) {
-+     01 00 00 00 00 00 00 00                         │ ........
-+ }
-+ 
-+ ALLOC0 (size: 8, align: 4) {
-+     01 00 00 00 00 00 00 00                         │ ........
   }
   
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff
index 19326b6a933..bf326915381 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.32bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.32bit.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -77,23 +77,18 @@
           StorageLive(_8);
           StorageLive(_9);
 -         _8 = _6 as *const [bool; 0] (PointerCoercion(MutToConstPointer));
--         _5 = NonNull::<[bool; 0]> { pointer: _8 };
-+         _8 = const {0x1 as *const [bool; 0]};
-+         _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }};
++         _8 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer));
+          _5 = NonNull::<[bool; 0]> { pointer: _8 };
           StorageDead(_9);
           StorageDead(_8);
           StorageDead(_6);
--         _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
-+         _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }};
+          _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
           StorageDead(_5);
--         _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
-+         _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }};
+          _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
           StorageDead(_4);
--         _2 = Box::<[bool]>(_3, const std::alloc::Global);
-+         _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
+          _2 = Box::<[bool]>(_3, const std::alloc::Global);
           StorageDead(_3);
--         _1 = A { foo: move _2 };
-+         _1 = A { foo: const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) };
+          _1 = A { foo: move _2 };
           StorageDead(_2);
           _0 = const ();
           drop(_1) -> [return: bb1, unwind: bb2];
@@ -107,17 +102,5 @@
       bb2 (cleanup): {
           resume;
       }
-+ }
-+ 
-+ ALLOC2 (size: 8, align: 4) {
-+     01 00 00 00 00 00 00 00                         │ ........
-+ }
-+ 
-+ ALLOC1 (size: 8, align: 4) {
-+     01 00 00 00 00 00 00 00                         │ ........
-+ }
-+ 
-+ ALLOC0 (size: 8, align: 4) {
-+     01 00 00 00 00 00 00 00                         │ ........
   }
   
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff
index 0d1e2430ce3..13545aa464a 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.64bit.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -77,23 +77,18 @@
           StorageLive(_8);
           StorageLive(_9);
 -         _8 = _6 as *const [bool; 0] (PointerCoercion(MutToConstPointer));
--         _5 = NonNull::<[bool; 0]> { pointer: _8 };
-+         _8 = const {0x1 as *const [bool; 0]};
-+         _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }};
++         _8 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer));
+          _5 = NonNull::<[bool; 0]> { pointer: _8 };
           StorageDead(_9);
           StorageDead(_8);
           StorageDead(_6);
--         _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
-+         _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }};
+          _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
           StorageDead(_5);
--         _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
-+         _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }};
+          _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
           StorageDead(_4);
--         _2 = Box::<[bool]>(_3, const std::alloc::Global);
-+         _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
+          _2 = Box::<[bool]>(_3, const std::alloc::Global);
           StorageDead(_3);
--         _1 = A { foo: move _2 };
-+         _1 = A { foo: const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) };
+          _1 = A { foo: move _2 };
           StorageDead(_2);
           _0 = const ();
           drop(_1) -> [return: bb1, unwind unreachable];
@@ -103,17 +98,5 @@
           StorageDead(_1);
           return;
       }
-+ }
-+ 
-+ ALLOC2 (size: 16, align: 8) {
-+     01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
-+ }
-+ 
-+ ALLOC1 (size: 16, align: 8) {
-+     01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
-+ }
-+ 
-+ ALLOC0 (size: 16, align: 8) {
-+     01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
   }
   
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff
index 35f1e5ba796..bf326915381 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.64bit.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.GVN.64bit.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
@@ -77,23 +77,18 @@
           StorageLive(_8);
           StorageLive(_9);
 -         _8 = _6 as *const [bool; 0] (PointerCoercion(MutToConstPointer));
--         _5 = NonNull::<[bool; 0]> { pointer: _8 };
-+         _8 = const {0x1 as *const [bool; 0]};
-+         _5 = const NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }};
++         _8 = const {0x1 as *mut [bool; 0]} as *const [bool; 0] (PointerCoercion(MutToConstPointer));
+          _5 = NonNull::<[bool; 0]> { pointer: _8 };
           StorageDead(_9);
           StorageDead(_8);
           StorageDead(_6);
--         _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
-+         _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }};
+          _4 = Unique::<[bool; 0]> { pointer: move _5, _marker: const PhantomData::<[bool; 0]> };
           StorageDead(_5);
--         _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
-+         _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }};
+          _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize));
           StorageDead(_4);
--         _2 = Box::<[bool]>(_3, const std::alloc::Global);
-+         _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global);
+          _2 = Box::<[bool]>(_3, const std::alloc::Global);
           StorageDead(_3);
--         _1 = A { foo: move _2 };
-+         _1 = A { foo: const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) };
+          _1 = A { foo: move _2 };
           StorageDead(_2);
           _0 = const ();
           drop(_1) -> [return: bb1, unwind: bb2];
@@ -107,17 +102,5 @@
       bb2 (cleanup): {
           resume;
       }
-+ }
-+ 
-+ ALLOC2 (size: 16, align: 8) {
-+     01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
-+ }
-+ 
-+ ALLOC1 (size: 16, align: 8) {
-+     01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
-+ }
-+ 
-+ ALLOC0 (size: 16, align: 8) {
-+     01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
   }
   
diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs
index 1bb052736c0..8006bd510e1 100644
--- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs
+++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.rs
@@ -1,6 +1,6 @@
 // skip-filecheck
 // unit-test: DataflowConstProp
-// compile-flags: -Zmir-enable-passes=+ConstProp,+Inline
+// compile-flags: -Zmir-enable-passes=+GVN,+Inline
 // ignore-debug assertions change the output MIR
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
@@ -9,7 +9,7 @@ struct A {
     foo: Box<[bool]>,
 }
 
-// EMIT_MIR default_boxed_slice.main.ConstProp.diff
+// EMIT_MIR default_boxed_slice.main.GVN.diff
 // EMIT_MIR default_boxed_slice.main.DataflowConstProp.diff
 fn main() {
     // ConstProp will create a constant of type `Box<[bool]>`.
diff --git a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff
index 142e08f4d6c..993e0f1d1a6 100644
--- a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff
+++ b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff
@@ -4,12 +4,13 @@
   fn main() -> () {
       let mut _0: ();
       let _1: main::Un;
+      let mut _2: u32;
       scope 1 {
           debug un => _1;
           scope 2 {
           }
           scope 4 (inlined std::mem::drop::<u32>) {
-              debug _x => const 1_u32;
+              debug _x => _2;
           }
       }
       scope 3 (inlined val) {
@@ -18,6 +19,9 @@
       bb0: {
           StorageLive(_1);
           _1 = Un { us: const 1_u32 };
+          StorageLive(_2);
+          _2 = (_1.0: u32);
+          StorageDead(_2);
           StorageDead(_1);
           return;
       }
diff --git a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff
index 142e08f4d6c..993e0f1d1a6 100644
--- a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff
+++ b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff
@@ -4,12 +4,13 @@
   fn main() -> () {
       let mut _0: ();
       let _1: main::Un;
+      let mut _2: u32;
       scope 1 {
           debug un => _1;
           scope 2 {
           }
           scope 4 (inlined std::mem::drop::<u32>) {
-              debug _x => const 1_u32;
+              debug _x => _2;
           }
       }
       scope 3 (inlined val) {
@@ -18,6 +19,9 @@
       bb0: {
           StorageLive(_1);
           _1 = Un { us: const 1_u32 };
+          StorageLive(_2);
+          _2 = (_1.0: u32);
+          StorageDead(_2);
           StorageDead(_1);
           return;
       }
diff --git a/tests/mir-opt/dest-prop/unreachable.f.DestinationPropagation.panic-abort.diff b/tests/mir-opt/dest-prop/unreachable.f.DestinationPropagation.panic-abort.diff
index 97ca825092e..80b5681ad06 100644
--- a/tests/mir-opt/dest-prop/unreachable.f.DestinationPropagation.panic-abort.diff
+++ b/tests/mir-opt/dest-prop/unreachable.f.DestinationPropagation.panic-abort.diff
@@ -33,8 +33,8 @@
 -         StorageLive(_5);
 -         _5 = _1;
 -         StorageLive(_6);
--         _6 = _2;
--         _4 = g::<T>(move _5, move _6) -> [return: bb2, unwind unreachable];
+-         _6 = _1;
+-         _4 = g::<T>(_1, _1) -> [return: bb2, unwind unreachable];
 -     }
 - 
 -     bb2: {
@@ -48,20 +48,22 @@
 -     bb3: {
           StorageLive(_7);
 -         StorageLive(_8);
--         _8 = _2;
+-         _8 = _1;
+-         StorageLive(_9);
+-         _9 = _1;
+-         _7 = g::<T>(_1, _1) -> [return: bb4, unwind unreachable];
 +         nop;
 +         nop;
-          StorageLive(_9);
--         _9 = _2;
--         _7 = g::<T>(move _8, move _9) -> [return: bb4, unwind unreachable];
-+         _9 = _1;
-+         _7 = g::<T>(move _1, move _9) -> [return: bb2, unwind unreachable];
++         nop;
++         nop;
++         _7 = g::<T>(_1, _1) -> [return: bb2, unwind unreachable];
       }
   
 -     bb4: {
-+     bb2: {
-          StorageDead(_9);
+-         StorageDead(_9);
 -         StorageDead(_8);
++     bb2: {
++         nop;
 +         nop;
           StorageDead(_7);
           _0 = const ();
diff --git a/tests/mir-opt/dest-prop/unreachable.f.DestinationPropagation.panic-unwind.diff b/tests/mir-opt/dest-prop/unreachable.f.DestinationPropagation.panic-unwind.diff
index 7f730a77b06..eae7dd17b48 100644
--- a/tests/mir-opt/dest-prop/unreachable.f.DestinationPropagation.panic-unwind.diff
+++ b/tests/mir-opt/dest-prop/unreachable.f.DestinationPropagation.panic-unwind.diff
@@ -33,8 +33,8 @@
 -         StorageLive(_5);
 -         _5 = _1;
 -         StorageLive(_6);
--         _6 = _2;
--         _4 = g::<T>(move _5, move _6) -> [return: bb2, unwind continue];
+-         _6 = _1;
+-         _4 = g::<T>(_1, _1) -> [return: bb2, unwind continue];
 -     }
 - 
 -     bb2: {
@@ -48,20 +48,22 @@
 -     bb3: {
           StorageLive(_7);
 -         StorageLive(_8);
--         _8 = _2;
+-         _8 = _1;
+-         StorageLive(_9);
+-         _9 = _1;
+-         _7 = g::<T>(_1, _1) -> [return: bb4, unwind continue];
 +         nop;
 +         nop;
-          StorageLive(_9);
--         _9 = _2;
--         _7 = g::<T>(move _8, move _9) -> [return: bb4, unwind continue];
-+         _9 = _1;
-+         _7 = g::<T>(move _1, move _9) -> [return: bb2, unwind continue];
++         nop;
++         nop;
++         _7 = g::<T>(_1, _1) -> [return: bb2, unwind continue];
       }
   
 -     bb4: {
-+     bb2: {
-          StorageDead(_9);
+-         StorageDead(_9);
 -         StorageDead(_8);
++     bb2: {
++         nop;
 +         nop;
           StorageDead(_7);
           _0 = const ();
diff --git a/tests/mir-opt/dest-prop/unreachable.rs b/tests/mir-opt/dest-prop/unreachable.rs
index a47d2a0c8e2..0bde157ff61 100644
--- a/tests/mir-opt/dest-prop/unreachable.rs
+++ b/tests/mir-opt/dest-prop/unreachable.rs
@@ -4,7 +4,7 @@
 // Regression test for issue #105428.
 //
 // compile-flags: --crate-type=lib -Zmir-opt-level=0
-// compile-flags: -Zmir-enable-passes=+ConstProp,+SimplifyConstCondition-after-const-prop,+DestinationPropagation
+// compile-flags: -Zmir-enable-passes=+GVN,+SimplifyConstCondition-after-const-prop,+DestinationPropagation
 
 // EMIT_MIR unreachable.f.DestinationPropagation.diff
 pub fn f<T: Copy>(a: T) {
diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.panic-abort.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff
index 298a6084899..0ba1bac0a03 100644
--- a/tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.panic-abort.diff
+++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `float_to_exponential_common` before ConstProp
-+ // MIR for `float_to_exponential_common` after ConstProp
+- // MIR for `float_to_exponential_common` before GVN
++ // MIR for `float_to_exponential_common` after GVN
   
   fn float_to_exponential_common(_1: &mut Formatter<'_>, _2: &T, _3: bool) -> Result<(), std::fmt::Error> {
       debug fmt => _1;
diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.panic-unwind.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff
index 037f4f7cfac..27ea43ef12b 100644
--- a/tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/funky_arms.float_to_exponential_common.GVN.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `float_to_exponential_common` before ConstProp
-+ // MIR for `float_to_exponential_common` after ConstProp
+- // MIR for `float_to_exponential_common` before GVN
++ // MIR for `float_to_exponential_common` after GVN
   
   fn float_to_exponential_common(_1: &mut Formatter<'_>, _2: &T, _3: bool) -> Result<(), std::fmt::Error> {
       debug fmt => _1;
diff --git a/tests/mir-opt/funky_arms.rs b/tests/mir-opt/funky_arms.rs
index 14aad039946..eae158f9f77 100644
--- a/tests/mir-opt/funky_arms.rs
+++ b/tests/mir-opt/funky_arms.rs
@@ -9,7 +9,7 @@ extern crate core;
 use core::num::flt2dec;
 use std::fmt::{Formatter, Result};
 
-// EMIT_MIR funky_arms.float_to_exponential_common.ConstProp.diff
+// EMIT_MIR funky_arms.float_to_exponential_common.GVN.diff
 pub fn float_to_exponential_common<T>(fmt: &mut Formatter<'_>, num: &T, upper: bool) -> Result
 where
     T: flt2dec::DecodableFloat,
diff --git a/tests/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir b/tests/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir
index 62d7e839f5a..408cc5bb341 100644
--- a/tests/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir
+++ b/tests/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir
@@ -19,7 +19,7 @@ fn b(_1: &mut Box<T>) -> &mut T {
         _4 = &mut (*_1);
         StorageLive(_5);
         StorageLive(_6);
-        _5 = deref_copy (*_4);
+        _5 = (*_4);
         _6 = (((_5.0: std::ptr::Unique<T>).0: std::ptr::NonNull<T>).0: *const T);
         _3 = &mut (*_6);
         StorageDead(_6);
diff --git a/tests/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir b/tests/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir
index bc0aa06a752..4d20f6c4419 100644
--- a/tests/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir
+++ b/tests/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir
@@ -17,7 +17,7 @@ fn d(_1: &Box<T>) -> &T {
         _3 = &(*_1);
         StorageLive(_4);
         StorageLive(_5);
-        _4 = deref_copy (*_3);
+        _4 = (*_3);
         _5 = (((_4.0: std::ptr::Unique<T>).0: std::ptr::NonNull<T>).0: *const T);
         _2 = &(*_5);
         StorageDead(_5);
diff --git a/tests/mir-opt/issue_101973.inner.ConstProp.panic-abort.diff b/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff
index 3748d148380..d2db8f61916 100644
--- a/tests/mir-opt/issue_101973.inner.ConstProp.panic-abort.diff
+++ b/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `inner` before ConstProp
-+ // MIR for `inner` after ConstProp
+- // MIR for `inner` before GVN
++ // MIR for `inner` after GVN
   
   fn inner(_1: u32) -> i64 {
       debug fields => _1;
diff --git a/tests/mir-opt/issue_101973.inner.ConstProp.panic-unwind.diff b/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff
index 9dab4233c56..514183b3bc0 100644
--- a/tests/mir-opt/issue_101973.inner.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `inner` before ConstProp
-+ // MIR for `inner` after ConstProp
+- // MIR for `inner` before GVN
++ // MIR for `inner` after GVN
   
   fn inner(_1: u32) -> i64 {
       debug fields => _1;
diff --git a/tests/mir-opt/issue_101973.rs b/tests/mir-opt/issue_101973.rs
index 3de325bc170..83a4dfb20b5 100644
--- a/tests/mir-opt/issue_101973.rs
+++ b/tests/mir-opt/issue_101973.rs
@@ -1,7 +1,7 @@
 // skip-filecheck
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 // compile-flags: -O -C debug-assertions=on
-// This needs inlining followed by ConstProp to reproduce, so we cannot use "unit-test".
+// This needs inlining followed by GVN to reproduce, so we cannot use "unit-test".
 
 #[inline]
 pub fn imm8(x: u32) -> u32 {
@@ -10,7 +10,7 @@ pub fn imm8(x: u32) -> u32 {
     out
 }
 
-// EMIT_MIR issue_101973.inner.ConstProp.diff
+// EMIT_MIR issue_101973.inner.GVN.diff
 #[inline(never)]
 pub fn inner(fields: u32) -> i64 {
     imm8(fields).rotate_right(((fields >> 8) & 0xf) << 1) as i32 as i64
diff --git a/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.mir
index 8304cb45b35..9c6c30214aa 100644
--- a/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/checked_ops.checked_shl.PreCodegen.after.mir
@@ -55,7 +55,7 @@ fn checked_shl(_1: u32, _2: u32) -> Option<u32> {
     }
 
     bb3: {
-        _0 = Option::<u32>::None;
+        _0 = const Option::<u32>::None;
         goto -> bb4;
     }
 
@@ -66,3 +66,7 @@ fn checked_shl(_1: u32, _2: u32) -> Option<u32> {
         return;
     }
 }
+
+ALLOC0 (size: 8, align: 4) {
+    00 00 00 00 __ __ __ __                         │ ....░░░░
+}
diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff
index d5628dc7a6e..5cb528c0d5f 100644
--- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff
@@ -55,8 +55,10 @@
 -         _2 = Option::<Layout>::None;
 +         _2 = const Option::<Layout>::None;
           StorageLive(_10);
-          _10 = const 0_isize;
-          switchInt(const 0_isize) -> [0: bb1, 1: bb3, otherwise: bb2];
+-         _10 = discriminant(_2);
+-         switchInt(move _10) -> [0: bb1, 1: bb3, otherwise: bb2];
++         _10 = const 0_isize;
++         switchInt(const 0_isize) -> [0: bb1, 1: bb3, otherwise: bb2];
       }
   
       bb1: {
diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff
index d28059458ae..1e1585f20ae 100644
--- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff
@@ -40,8 +40,10 @@
 -         _2 = Option::<Layout>::None;
 +         _2 = const Option::<Layout>::None;
           StorageLive(_10);
-          _10 = const 0_isize;
-          switchInt(const 0_isize) -> [0: bb2, 1: bb4, otherwise: bb3];
+-         _10 = discriminant(_2);
+-         switchInt(move _10) -> [0: bb2, 1: bb4, otherwise: bb3];
++         _10 = const 0_isize;
++         switchInt(const 0_isize) -> [0: bb2, 1: bb4, otherwise: bb3];
       }
   
       bb1: {
diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff
index d139fc73e21..e655af559a1 100644
--- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff
@@ -55,8 +55,10 @@
 -         _2 = Option::<Layout>::None;
 +         _2 = const Option::<Layout>::None;
           StorageLive(_10);
-          _10 = const 0_isize;
-          switchInt(const 0_isize) -> [0: bb1, 1: bb3, otherwise: bb2];
+-         _10 = discriminant(_2);
+-         switchInt(move _10) -> [0: bb1, 1: bb3, otherwise: bb2];
++         _10 = const 0_isize;
++         switchInt(const 0_isize) -> [0: bb1, 1: bb3, otherwise: bb2];
       }
   
       bb1: {
diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff
index 63db9553b37..a6658713a02 100644
--- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff
@@ -40,8 +40,10 @@
 -         _2 = Option::<Layout>::None;
 +         _2 = const Option::<Layout>::None;
           StorageLive(_10);
-          _10 = const 0_isize;
-          switchInt(const 0_isize) -> [0: bb2, 1: bb4, otherwise: bb3];
+-         _10 = discriminant(_2);
+-         switchInt(move _10) -> [0: bb2, 1: bb4, otherwise: bb3];
++         _10 = const 0_isize;
++         switchInt(const 0_isize) -> [0: bb2, 1: bb4, otherwise: bb3];
       }
   
       bb1: {
diff --git a/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir
index 73a3be7f301..42c7eb3c6aa 100644
--- a/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir
@@ -72,7 +72,7 @@ fn int_range(_1: usize, _2: usize) -> () {
     bb2: {
         StorageDead(_7);
         StorageDead(_6);
-        _11 = Option::<usize>::None;
+        _11 = const Option::<usize>::None;
         goto -> bb5;
     }
 
@@ -118,3 +118,7 @@ fn int_range(_1: usize, _2: usize) -> () {
         unreachable;
     }
 }
+
+ALLOC0 (size: 16, align: 8) {
+    00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ __ │ ........░░░░░░░░
+}
diff --git a/tests/mir-opt/pre-codegen/loops.rs b/tests/mir-opt/pre-codegen/loops.rs
index 7f9c26f4fff..9412c3f234e 100644
--- a/tests/mir-opt/pre-codegen/loops.rs
+++ b/tests/mir-opt/pre-codegen/loops.rs
@@ -1,6 +1,7 @@
 // skip-filecheck
 // compile-flags: -O -Zmir-opt-level=2 -g
 // needs-unwind
+// only-64bit
 
 #![crate_type = "lib"]
 
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff
index bddd961c933..4e34233a979 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.64bit.panic-abort.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff
index 297ebd79fad..275f17e52ae 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.64bit.panic-unwind.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.32bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff
index bddd961c933..4e34233a979 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.32bit.panic-abort.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff
index 297ebd79fad..275f17e52ae 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.32bit.panic-unwind.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.rs b/tests/mir-opt/pre-codegen/optimizes_into_variable.rs
index bb089ea4455..fb634ca85ef 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.rs
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.rs
@@ -9,7 +9,7 @@ struct Point {
 
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 // EMIT_MIR optimizes_into_variable.main.ScalarReplacementOfAggregates.diff
-// EMIT_MIR optimizes_into_variable.main.ConstProp.diff
+// EMIT_MIR optimizes_into_variable.main.GVN.diff
 // EMIT_MIR optimizes_into_variable.main.SimplifyLocals-final.after.mir
 // EMIT_MIR optimizes_into_variable.main.PreCodegen.after.mir
 fn main() {
diff --git a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir
index cd734b10fea..e5940bd8201 100644
--- a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir
@@ -75,7 +75,7 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () {
     bb2: {
         StorageDead(_8);
         StorageDead(_7);
-        _12 = Option::<u32>::None;
+        _12 = const Option::<u32>::None;
         goto -> bb5;
     }
 
@@ -131,3 +131,7 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () {
         unreachable;
     }
 }
+
+ALLOC0 (size: 8, align: 4) {
+    00 00 00 00 __ __ __ __                         │ ....░░░░
+}
diff --git a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir
index 3342da545ae..87e7485cb36 100644
--- a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir
@@ -75,7 +75,7 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () {
     bb2: {
         StorageDead(_8);
         StorageDead(_7);
-        _12 = Option::<u32>::None;
+        _12 = const Option::<u32>::None;
         goto -> bb5;
     }
 
@@ -139,3 +139,7 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () {
         resume;
     }
 }
+
+ALLOC0 (size: 8, align: 4) {
+    00 00 00 00 __ __ __ __                         │ ....░░░░
+}
diff --git a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir
index 6ed3d73b11d..f674f6a3009 100644
--- a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-abort.mir
@@ -46,7 +46,7 @@ fn range_iter_next(_1: &mut std::ops::Range<u32>) -> Option<u32> {
     bb1: {
         StorageDead(_3);
         StorageDead(_2);
-        _0 = Option::<u32>::None;
+        _0 = const Option::<u32>::None;
         goto -> bb4;
     }
 
@@ -71,3 +71,7 @@ fn range_iter_next(_1: &mut std::ops::Range<u32>) -> Option<u32> {
         return;
     }
 }
+
+ALLOC0 (size: 8, align: 4) {
+    00 00 00 00 __ __ __ __                         │ ....░░░░
+}
diff --git a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir
index a030647deae..a5029dcad3a 100644
--- a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir
@@ -46,7 +46,7 @@ fn range_iter_next(_1: &mut std::ops::Range<u32>) -> Option<u32> {
     bb1: {
         StorageDead(_3);
         StorageDead(_2);
-        _0 = Option::<u32>::None;
+        _0 = const Option::<u32>::None;
         goto -> bb4;
     }
 
@@ -71,3 +71,7 @@ fn range_iter_next(_1: &mut std::ops::Range<u32>) -> Option<u32> {
         return;
     }
 }
+
+ALLOC0 (size: 8, align: 4) {
+    00 00 00 00 __ __ __ __                         │ ....░░░░
+}
diff --git a/tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir
index af5d385a979..718dba21a95 100644
--- a/tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/simple_option_map.ezmap.PreCodegen.after.mir
@@ -24,7 +24,7 @@ fn ezmap(_1: Option<i32>) -> Option<i32> {
     }
 
     bb1: {
-        _0 = Option::<i32>::None;
+        _0 = const Option::<i32>::None;
         goto -> bb3;
     }
 
@@ -46,3 +46,7 @@ fn ezmap(_1: Option<i32>) -> Option<i32> {
         unreachable;
     }
 }
+
+ALLOC0 (size: 8, align: 4) {
+    00 00 00 00 __ __ __ __                         │ ....░░░░
+}
diff --git a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir
index 05f16cdacce..cc009e45e7e 100644
--- a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir
@@ -4,239 +4,217 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:8:25: 8:39}, _2
     let mut _0: bool;
     let mut _3: &(usize, usize, usize, usize);
     let _4: &usize;
-    let mut _5: &(usize, usize, usize, usize);
+    let _5: &usize;
     let _6: &usize;
-    let mut _7: &(usize, usize, usize, usize);
-    let _8: &usize;
-    let mut _9: &(usize, usize, usize, usize);
-    let _10: &usize;
-    let mut _11: &&usize;
-    let _12: &usize;
-    let mut _13: &&usize;
-    let mut _18: bool;
-    let mut _19: &&usize;
-    let _20: &usize;
-    let mut _21: &&usize;
-    let mut _26: bool;
-    let mut _27: &&usize;
-    let _28: &usize;
-    let mut _29: &&usize;
-    let mut _34: bool;
-    let mut _35: &&usize;
-    let _36: &usize;
-    let mut _37: &&usize;
+    let _7: &usize;
+    let mut _8: &&usize;
+    let _9: &usize;
+    let mut _10: &&usize;
+    let mut _15: bool;
+    let mut _16: &&usize;
+    let _17: &usize;
+    let mut _18: &&usize;
+    let mut _23: bool;
+    let mut _24: &&usize;
+    let _25: &usize;
+    let mut _26: &&usize;
+    let mut _31: bool;
+    let mut _32: &&usize;
+    let _33: &usize;
+    let mut _34: &&usize;
     scope 1 {
         debug a => _4;
-        debug b => _6;
-        debug c => _8;
-        debug d => _10;
+        debug b => _5;
+        debug c => _6;
+        debug d => _7;
         scope 2 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
-            debug self => _11;
-            debug other => _13;
-            let mut _14: &usize;
-            let mut _15: &usize;
+            debug self => _8;
+            debug other => _10;
+            let mut _11: &usize;
+            let mut _12: &usize;
             scope 3 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
-                debug self => _14;
-                debug other => _15;
-                let mut _16: usize;
-                let mut _17: usize;
+                debug self => _11;
+                debug other => _12;
+                let mut _13: usize;
+                let mut _14: usize;
             }
         }
         scope 4 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
-            debug self => _19;
-            debug other => _21;
-            let mut _22: &usize;
-            let mut _23: &usize;
+            debug self => _16;
+            debug other => _18;
+            let mut _19: &usize;
+            let mut _20: &usize;
             scope 5 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
-                debug self => _22;
-                debug other => _23;
-                let mut _24: usize;
-                let mut _25: usize;
+                debug self => _19;
+                debug other => _20;
+                let mut _21: usize;
+                let mut _22: usize;
             }
         }
         scope 6 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
-            debug self => _27;
-            debug other => _29;
-            let mut _30: &usize;
-            let mut _31: &usize;
+            debug self => _24;
+            debug other => _26;
+            let mut _27: &usize;
+            let mut _28: &usize;
             scope 7 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
-                debug self => _30;
-                debug other => _31;
-                let mut _32: usize;
-                let mut _33: usize;
+                debug self => _27;
+                debug other => _28;
+                let mut _29: usize;
+                let mut _30: usize;
             }
         }
         scope 8 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
-            debug self => _35;
-            debug other => _37;
-            let mut _38: &usize;
-            let mut _39: &usize;
+            debug self => _32;
+            debug other => _34;
+            let mut _35: &usize;
+            let mut _36: &usize;
             scope 9 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
-                debug self => _38;
-                debug other => _39;
-                let mut _40: usize;
-                let mut _41: usize;
+                debug self => _35;
+                debug other => _36;
+                let mut _37: usize;
+                let mut _38: usize;
             }
         }
     }
 
     bb0: {
         StorageLive(_4);
-        _3 = deref_copy (*_2);
+        _3 = (*_2);
         _4 = &((*_3).0: usize);
+        StorageLive(_5);
+        _5 = &((*_3).1: usize);
         StorageLive(_6);
-        _5 = deref_copy (*_2);
-        _6 = &((*_5).1: usize);
+        _6 = &((*_3).2: usize);
+        StorageLive(_7);
+        _7 = &((*_3).3: usize);
+        StorageLive(_15);
         StorageLive(_8);
-        _7 = deref_copy (*_2);
-        _8 = &((*_7).2: usize);
+        _8 = &_4;
         StorageLive(_10);
-        _9 = deref_copy (*_2);
-        _10 = &((*_9).3: usize);
-        StorageLive(_18);
-        StorageLive(_11);
-        _11 = &_4;
+        StorageLive(_9);
+        _9 = _6;
+        _10 = &_9;
+        _11 = _4;
+        _12 = _9;
         StorageLive(_13);
-        StorageLive(_12);
-        _12 = _8;
-        _13 = &_12;
+        _13 = (*_11);
         StorageLive(_14);
-        StorageLive(_15);
-        _14 = deref_copy _4;
-        _15 = deref_copy _12;
-        StorageLive(_16);
-        _16 = (*_14);
-        StorageLive(_17);
-        _17 = (*_15);
-        _18 = Le(move _16, move _17);
-        StorageDead(_17);
-        StorageDead(_16);
-        StorageDead(_15);
+        _14 = (*_12);
+        _15 = Le(move _13, move _14);
         StorageDead(_14);
-        switchInt(move _18) -> [0: bb1, otherwise: bb2];
+        StorageDead(_13);
+        switchInt(move _15) -> [0: bb1, otherwise: bb2];
     }
 
     bb1: {
-        StorageDead(_12);
-        StorageDead(_13);
-        StorageDead(_11);
+        StorageDead(_9);
+        StorageDead(_10);
+        StorageDead(_8);
         goto -> bb4;
     }
 
     bb2: {
-        StorageDead(_12);
-        StorageDead(_13);
-        StorageDead(_11);
-        StorageLive(_26);
-        StorageLive(_19);
-        _19 = &_10;
+        StorageDead(_9);
+        StorageDead(_10);
+        StorageDead(_8);
+        StorageLive(_23);
+        StorageLive(_16);
+        _16 = &_7;
+        StorageLive(_18);
+        StorageLive(_17);
+        _17 = _5;
+        _18 = &_17;
+        _19 = _7;
+        _20 = _17;
         StorageLive(_21);
-        StorageLive(_20);
-        _20 = _6;
-        _21 = &_20;
+        _21 = (*_19);
         StorageLive(_22);
-        StorageLive(_23);
-        _22 = deref_copy _10;
-        _23 = deref_copy _20;
-        StorageLive(_24);
-        _24 = (*_22);
-        StorageLive(_25);
-        _25 = (*_23);
-        _26 = Le(move _24, move _25);
-        StorageDead(_25);
-        StorageDead(_24);
-        StorageDead(_23);
+        _22 = (*_20);
+        _23 = Le(move _21, move _22);
         StorageDead(_22);
-        switchInt(move _26) -> [0: bb3, otherwise: bb8];
+        StorageDead(_21);
+        switchInt(move _23) -> [0: bb3, otherwise: bb8];
     }
 
     bb3: {
-        StorageDead(_20);
-        StorageDead(_21);
-        StorageDead(_19);
+        StorageDead(_17);
+        StorageDead(_18);
+        StorageDead(_16);
         goto -> bb4;
     }
 
     bb4: {
-        StorageLive(_34);
-        StorageLive(_27);
-        _27 = &_8;
+        StorageLive(_31);
+        StorageLive(_24);
+        _24 = &_6;
+        StorageLive(_26);
+        StorageLive(_25);
+        _25 = _4;
+        _26 = &_25;
+        _27 = _6;
+        _28 = _25;
         StorageLive(_29);
-        StorageLive(_28);
-        _28 = _4;
-        _29 = &_28;
+        _29 = (*_27);
         StorageLive(_30);
-        StorageLive(_31);
-        _30 = deref_copy _8;
-        _31 = deref_copy _28;
-        StorageLive(_32);
-        _32 = (*_30);
-        StorageLive(_33);
-        _33 = (*_31);
-        _34 = Le(move _32, move _33);
-        StorageDead(_33);
-        StorageDead(_32);
-        StorageDead(_31);
+        _30 = (*_28);
+        _31 = Le(move _29, move _30);
         StorageDead(_30);
-        switchInt(move _34) -> [0: bb5, otherwise: bb6];
+        StorageDead(_29);
+        switchInt(move _31) -> [0: bb5, otherwise: bb6];
     }
 
     bb5: {
-        StorageDead(_28);
-        StorageDead(_29);
-        StorageDead(_27);
+        StorageDead(_25);
+        StorageDead(_26);
+        StorageDead(_24);
         _0 = const false;
         goto -> bb7;
     }
 
     bb6: {
-        StorageDead(_28);
-        StorageDead(_29);
-        StorageDead(_27);
-        StorageLive(_35);
-        _35 = &_6;
+        StorageDead(_25);
+        StorageDead(_26);
+        StorageDead(_24);
+        StorageLive(_32);
+        _32 = &_5;
+        StorageLive(_34);
+        StorageLive(_33);
+        _33 = _7;
+        _34 = &_33;
+        _35 = _5;
+        _36 = _33;
         StorageLive(_37);
-        StorageLive(_36);
-        _36 = _10;
-        _37 = &_36;
+        _37 = (*_35);
         StorageLive(_38);
-        StorageLive(_39);
-        _38 = deref_copy _6;
-        _39 = deref_copy _36;
-        StorageLive(_40);
-        _40 = (*_38);
-        StorageLive(_41);
-        _41 = (*_39);
-        _0 = Le(move _40, move _41);
-        StorageDead(_41);
-        StorageDead(_40);
-        StorageDead(_39);
+        _38 = (*_36);
+        _0 = Le(move _37, move _38);
         StorageDead(_38);
-        StorageDead(_36);
         StorageDead(_37);
-        StorageDead(_35);
+        StorageDead(_33);
+        StorageDead(_34);
+        StorageDead(_32);
         goto -> bb7;
     }
 
     bb7: {
-        StorageDead(_34);
+        StorageDead(_31);
         goto -> bb9;
     }
 
     bb8: {
-        StorageDead(_20);
-        StorageDead(_21);
-        StorageDead(_19);
+        StorageDead(_17);
+        StorageDead(_18);
+        StorageDead(_16);
         _0 = const true;
         goto -> bb9;
     }
 
     bb9: {
-        StorageDead(_26);
-        StorageDead(_18);
-        StorageDead(_10);
-        StorageDead(_8);
+        StorageDead(_23);
+        StorageDead(_15);
+        StorageDead(_7);
         StorageDead(_6);
+        StorageDead(_5);
         StorageDead(_4);
         return;
     }
diff --git a/tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir
index e2ed1d101dc..5477796512c 100644
--- a/tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir
@@ -4,46 +4,40 @@ fn variant_b::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:12:25: 12:41},
     let mut _0: bool;
     let mut _3: &(usize, usize, usize, usize);
     let _4: usize;
-    let mut _5: &(usize, usize, usize, usize);
+    let _5: usize;
     let _6: usize;
-    let mut _7: &(usize, usize, usize, usize);
-    let _8: usize;
-    let mut _9: &(usize, usize, usize, usize);
-    let _10: usize;
-    let mut _11: bool;
-    let mut _12: bool;
-    let mut _13: bool;
+    let _7: usize;
+    let mut _8: bool;
+    let mut _9: bool;
+    let mut _10: bool;
     scope 1 {
         debug a => _4;
-        debug b => _6;
-        debug c => _8;
-        debug d => _10;
+        debug b => _5;
+        debug c => _6;
+        debug d => _7;
     }
 
     bb0: {
-        _3 = deref_copy (*_2);
+        _3 = (*_2);
         _4 = ((*_3).0: usize);
-        _5 = deref_copy (*_2);
-        _6 = ((*_5).1: usize);
-        _7 = deref_copy (*_2);
-        _8 = ((*_7).2: usize);
-        _9 = deref_copy (*_2);
-        _10 = ((*_9).3: usize);
-        StorageLive(_11);
-        _11 = Le(_4, _8);
-        switchInt(move _11) -> [0: bb2, otherwise: bb1];
+        _5 = ((*_3).1: usize);
+        _6 = ((*_3).2: usize);
+        _7 = ((*_3).3: usize);
+        StorageLive(_8);
+        _8 = Le(_4, _6);
+        switchInt(move _8) -> [0: bb2, otherwise: bb1];
     }
 
     bb1: {
-        StorageLive(_12);
-        _12 = Le(_10, _6);
-        switchInt(move _12) -> [0: bb2, otherwise: bb6];
+        StorageLive(_9);
+        _9 = Le(_7, _5);
+        switchInt(move _9) -> [0: bb2, otherwise: bb6];
     }
 
     bb2: {
-        StorageLive(_13);
-        _13 = Le(_8, _4);
-        switchInt(move _13) -> [0: bb3, otherwise: bb4];
+        StorageLive(_10);
+        _10 = Le(_6, _4);
+        switchInt(move _10) -> [0: bb3, otherwise: bb4];
     }
 
     bb3: {
@@ -52,12 +46,12 @@ fn variant_b::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:12:25: 12:41},
     }
 
     bb4: {
-        _0 = Le(_6, _10);
+        _0 = Le(_5, _7);
         goto -> bb5;
     }
 
     bb5: {
-        StorageDead(_13);
+        StorageDead(_10);
         goto -> bb7;
     }
 
@@ -67,8 +61,8 @@ fn variant_b::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:12:25: 12:41},
     }
 
     bb7: {
-        StorageDead(_12);
-        StorageDead(_11);
+        StorageDead(_9);
+        StorageDead(_8);
         return;
     }
 }
diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir
index e4d9060d4cf..a12411a0413 100644
--- a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir
@@ -50,7 +50,6 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> {
     }
 
     bb0: {
-        StorageLive(_7);
         StorageLive(_4);
         StorageLive(_3);
         _3 = Len((*_1));
@@ -86,7 +85,6 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> {
 
     bb3: {
         StorageDead(_4);
-        StorageDead(_7);
         return;
     }
 }
diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir
index e4d9060d4cf..a12411a0413 100644
--- a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir
@@ -50,7 +50,6 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> {
     }
 
     bb0: {
-        StorageLive(_7);
         StorageLive(_4);
         StorageLive(_3);
         _3 = Len((*_1));
@@ -86,7 +85,6 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> {
 
     bb3: {
         StorageDead(_4);
-        StorageDead(_7);
         return;
     }
 }
diff --git a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir
index db6922968ae..6a99f15774f 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir
@@ -84,7 +84,7 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
     bb2: {
         StorageDead(_8);
         StorageDead(_7);
-        _12 = Option::<usize>::None;
+        _12 = const Option::<usize>::None;
         goto -> bb5;
     }
 
@@ -147,3 +147,7 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
         unreachable;
     }
 }
+
+ALLOC0 (size: 16, align: 8) {
+    00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ __ │ ........░░░░░░░░
+}
diff --git a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir
index 81d1832eebb..4f028fa0a64 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir
@@ -84,7 +84,7 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
     bb2: {
         StorageDead(_8);
         StorageDead(_7);
-        _12 = Option::<usize>::None;
+        _12 = const Option::<usize>::None;
         goto -> bb5;
     }
 
@@ -155,3 +155,7 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
         resume;
     }
 }
+
+ALLOC0 (size: 16, align: 8) {
+    00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ __ │ ........░░░░░░░░
+}
diff --git a/tests/mir-opt/simplify_match.main.ConstProp.panic-abort.diff b/tests/mir-opt/simplify_match.main.GVN.panic-abort.diff
index 6025abb7382..825babe7994 100644
--- a/tests/mir-opt/simplify_match.main.ConstProp.panic-abort.diff
+++ b/tests/mir-opt/simplify_match.main.GVN.panic-abort.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/simplify_match.main.ConstProp.panic-unwind.diff b/tests/mir-opt/simplify_match.main.GVN.panic-unwind.diff
index c881dec28c7..24ab6c39788 100644
--- a/tests/mir-opt/simplify_match.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/simplify_match.main.GVN.panic-unwind.diff
@@ -1,5 +1,5 @@
-- // MIR for `main` before ConstProp
-+ // MIR for `main` after ConstProp
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
   
   fn main() -> () {
       let mut _0: ();
diff --git a/tests/mir-opt/simplify_match.rs b/tests/mir-opt/simplify_match.rs
index eb385005cd9..2eac93edbb8 100644
--- a/tests/mir-opt/simplify_match.rs
+++ b/tests/mir-opt/simplify_match.rs
@@ -3,7 +3,7 @@
 #[inline(never)]
 fn noop() {}
 
-// EMIT_MIR simplify_match.main.ConstProp.diff
+// EMIT_MIR simplify_match.main.GVN.diff
 fn main() {
     match { let x = false; x } {
         true => noop(),
diff --git a/tests/rustdoc-js-std/asrawfd.js b/tests/rustdoc-js-std/asrawfd.js
index 5b3cfeabbcd..5dbc4ba95d9 100644
--- a/tests/rustdoc-js-std/asrawfd.js
+++ b/tests/rustdoc-js-std/asrawfd.js
@@ -7,7 +7,6 @@ const EXPECTED = {
         // Validate that type alias methods get the correct path.
         { 'path': 'std::os::fd::AsRawFd', 'name': 'as_raw_fd' },
         { 'path': 'std::os::fd::AsRawFd', 'name': 'as_raw_fd' },
-        { 'path': 'std::os::linux::process::PidFd', 'name': 'as_raw_fd' },
         { 'path': 'std::os::fd::RawFd', 'name': 'as_raw_fd' },
     ],
 };
diff --git a/tests/rustdoc-js-std/path-maxeditdistance.js b/tests/rustdoc-js-std/path-maxeditdistance.js
new file mode 100644
index 00000000000..822389aaa4f
--- /dev/null
+++ b/tests/rustdoc-js-std/path-maxeditdistance.js
@@ -0,0 +1,42 @@
+// exact-check
+const FILTER_CRATE = "std";
+const EXPECTED = [
+    {
+        query: 'vec::intoiterator',
+        others: [
+            // trait std::iter::IntoIterator is not the first result
+            { 'path': 'std::vec', 'name': 'IntoIter' },
+            { 'path': 'std::vec::Vec', 'name': 'into_iter' },
+            { 'path': 'std::vec::Drain', 'name': 'into_iter' },
+            { 'path': 'std::vec::IntoIter', 'name': 'into_iter' },
+            { 'path': 'std::vec::ExtractIf', 'name': 'into_iter' },
+            { 'path': 'std::vec::Splice', 'name': 'into_iter' },
+            { 'path': 'std::collections::VecDeque', 'name': 'into_iter' },
+        ],
+    },
+    {
+        query: 'vec::iter',
+        others: [
+            // std::net::ToSocketAttrs::iter should not show up here
+            { 'path': 'std::vec', 'name': 'IntoIter' },
+            { 'path': 'std::vec::Vec', 'name': 'from_iter' },
+            { 'path': 'std::vec::Vec', 'name': 'into_iter' },
+            { 'path': 'std::vec::Drain', 'name': 'into_iter' },
+            { 'path': 'std::vec::IntoIter', 'name': 'into_iter' },
+            { 'path': 'std::vec::ExtractIf', 'name': 'into_iter' },
+            { 'path': 'std::vec::Splice', 'name': 'into_iter' },
+            { 'path': 'std::collections::VecDeque', 'name': 'iter' },
+            { 'path': 'std::collections::VecDeque', 'name': 'iter_mut' },
+            { 'path': 'std::collections::VecDeque', 'name': 'from_iter' },
+            { 'path': 'std::collections::VecDeque', 'name': 'into_iter' },
+        ],
+    },
+    {
+        query: 'slice::itermut',
+        others: [
+            // std::collections::btree_map::itermut should not show up here
+            { 'path': 'std::slice', 'name': 'IterMut' },
+            { 'path': 'std::slice', 'name': 'iter_mut' },
+        ],
+    },
+];
diff --git a/tests/rustdoc-js-std/path-ordering.js b/tests/rustdoc-js-std/path-ordering.js
index c3d61d238cc..e6b7bfab1e5 100644
--- a/tests/rustdoc-js-std/path-ordering.js
+++ b/tests/rustdoc-js-std/path-ordering.js
@@ -1,11 +1,20 @@
-const EXPECTED = {
-    query: 'hashset::insert',
-    others: [
-        // ensure hashset::insert comes first
-        { 'path': 'std::collections::hash_set::HashSet', 'name': 'insert' },
-        { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert' },
-        { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert_with' },
-        { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert_owned' },
-        { 'path': 'std::collections::hash_map::HashMap', 'name': 'insert' },
-    ],
-};
+const EXPECTED = [
+    {
+        query: 'hashset::insert',
+        others: [
+            // ensure hashset::insert comes first
+            { 'path': 'std::collections::hash_set::HashSet', 'name': 'insert' },
+            { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert' },
+            { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert_with' },
+            { 'path': 'std::collections::hash_set::HashSet', 'name': 'get_or_insert_owned' },
+        ],
+    },
+    {
+        query: 'hash::insert',
+        others: [
+            // ensure hashset/hashmap::insert come first
+            { 'path': 'std::collections::hash_map::HashMap', 'name': 'insert' },
+            { 'path': 'std::collections::hash_set::HashSet', 'name': 'insert' },
+        ],
+    },
+];
diff --git a/tests/rustdoc-js/exact-match.js b/tests/rustdoc-js/exact-match.js
index ce3a76f9b7d..9e47d27490b 100644
--- a/tests/rustdoc-js/exact-match.js
+++ b/tests/rustdoc-js/exact-match.js
@@ -3,6 +3,5 @@ const EXPECTED = {
     'others': [
         { 'path': 'exact_match::Si', 'name': 'pc' },
         { 'path': 'exact_match::Psi', 'name': 'pc' },
-        { 'path': 'exact_match::Si', 'name': 'pa' },
     ],
 };
diff --git a/tests/rustdoc-js/module-substring.js b/tests/rustdoc-js/module-substring.js
index 7a10397ebc6..74c421d7f0b 100644
--- a/tests/rustdoc-js/module-substring.js
+++ b/tests/rustdoc-js/module-substring.js
@@ -1,7 +1,15 @@
-const EXPECTED = {
-    'query': 'ig::pc',
-    'others': [
-        { 'path': 'module_substring::Sig', 'name': 'pc' },
-        { 'path': 'module_substring::Si', 'name': 'pc' },
-    ],
-};
+const EXPECTED = [
+    {
+        'query': 'ig::pc',
+        'others': [
+            { 'path': 'module_substring::Sig', 'name': 'pc' },
+        ],
+    },
+    {
+        'query': 'si::pc',
+        'others': [
+            { 'path': 'module_substring::Si', 'name': 'pc' },
+            { 'path': 'module_substring::Sig', 'name': 'pc' },
+        ],
+    },
+];
diff --git a/tests/rustdoc-js/path-maxeditdistance.js b/tests/rustdoc-js/path-maxeditdistance.js
new file mode 100644
index 00000000000..73b24a6dddf
--- /dev/null
+++ b/tests/rustdoc-js/path-maxeditdistance.js
@@ -0,0 +1,35 @@
+// exact-check
+
+const EXPECTED = [
+    {
+        'query': 'xxxxxxxxxxx::hocuspocusprestidigitation',
+        // do not match abracadabra::hocuspocusprestidigitation
+        'others': [],
+    },
+    {
+        // exact match
+        'query': 'abracadabra::hocuspocusprestidigitation',
+        'others': [
+            { 'path': 'abracadabra', 'name': 'HocusPocusPrestidigitation' },
+        ],
+    },
+    {
+        // swap br/rb; that's edit distance 2, where maxPathEditDistance = 3 (11 / 3)
+        'query': 'arbacadarba::hocuspocusprestidigitation',
+        'others': [
+            { 'path': 'abracadabra', 'name': 'HocusPocusPrestidigitation' },
+        ],
+    },
+    {
+        // truncate 5 chars, where maxEditDistance = 7 (21 / 3)
+        'query': 'abracadarba::hocusprestidigitation',
+        'others': [
+            { 'path': 'abracadabra', 'name': 'HocusPocusPrestidigitation' },
+        ],
+    },
+    {
+        // truncate 9 chars, where maxEditDistance = 5 (17 / 3)
+        'query': 'abracadarba::hprestidigitation',
+        'others': [],
+    },
+];
diff --git a/tests/rustdoc-js/path-maxeditdistance.rs b/tests/rustdoc-js/path-maxeditdistance.rs
new file mode 100644
index 00000000000..3861280d59b
--- /dev/null
+++ b/tests/rustdoc-js/path-maxeditdistance.rs
@@ -0,0 +1,3 @@
+#![crate_name="abracadabra"]
+
+pub struct HocusPocusPrestidigitation;
diff --git a/tests/rustdoc-js/path-ordering.js b/tests/rustdoc-js/path-ordering.js
index f2e6fe2fa61..73d3f4b2755 100644
--- a/tests/rustdoc-js/path-ordering.js
+++ b/tests/rustdoc-js/path-ordering.js
@@ -1,13 +1,13 @@
 // exact-check
 
 const EXPECTED = {
-    'query': 'b::ccccccc',
+    'query': 'bbbbbb::ccccccc',
     'others': [
         // `ccccccc` is an exact match for all three of these.
         // However `b` is a closer match for `bb` than for any
         // of the others, so it ought to go first.
-        { 'path': 'path_ordering::bb', 'name': 'Ccccccc' },
-        { 'path': 'path_ordering::aa', 'name': 'Ccccccc' },
-        { 'path': 'path_ordering::dd', 'name': 'Ccccccc' },
+        { 'path': 'path_ordering::bbbbbb', 'name': 'Ccccccc' },
+        { 'path': 'path_ordering::abbbbb', 'name': 'Ccccccc' },
+        { 'path': 'path_ordering::dbbbbb', 'name': 'Ccccccc' },
     ],
 };
diff --git a/tests/rustdoc-js/path-ordering.rs b/tests/rustdoc-js/path-ordering.rs
index 7843cf7f9dc..71e24923ed1 100644
--- a/tests/rustdoc-js/path-ordering.rs
+++ b/tests/rustdoc-js/path-ordering.rs
@@ -1,9 +1,9 @@
-pub mod dd {
+pub mod dbbbbb {
     pub struct Ccccccc;
 }
-pub mod aa {
+pub mod abbbbb {
     pub struct Ccccccc;
 }
-pub mod bb {
+pub mod bbbbbb {
     pub struct Ccccccc;
 }
diff --git a/tests/ui/consts/const-eval/issue-50814-2.mir-opt.stderr b/tests/ui/consts/const-eval/issue-50814-2.mir-opt.stderr
index f3ec3200f94..7e764ca7239 100644
--- a/tests/ui/consts/const-eval/issue-50814-2.mir-opt.stderr
+++ b/tests/ui/consts/const-eval/issue-50814-2.mir-opt.stderr
@@ -10,12 +10,6 @@ note: erroneous constant encountered
 LL |     &<A<T> as Foo<T>>::BAR
    |      ^^^^^^^^^^^^^^^^^^^^^
 
-note: erroneous constant encountered
-  --> $DIR/issue-50814-2.rs:20:5
-   |
-LL |     &<A<T> as Foo<T>>::BAR
-   |     ^^^^^^^^^^^^^^^^^^^^^^
-
 error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/error-codes/E0453.rs b/tests/ui/error-codes/E0453.rs
index ca9573c5b46..8ed724dd3fc 100644
--- a/tests/ui/error-codes/E0453.rs
+++ b/tests/ui/error-codes/E0453.rs
@@ -2,6 +2,5 @@
 
 #[allow(non_snake_case)]
 //~^ ERROR allow(non_snake_case) incompatible
-//~| ERROR allow(non_snake_case) incompatible
 fn main() {
 }
diff --git a/tests/ui/error-codes/E0453.stderr b/tests/ui/error-codes/E0453.stderr
index bb2c39298c0..9a89f0d41e4 100644
--- a/tests/ui/error-codes/E0453.stderr
+++ b/tests/ui/error-codes/E0453.stderr
@@ -7,17 +7,6 @@ LL |
 LL | #[allow(non_snake_case)]
    |         ^^^^^^^^^^^^^^ overruled by previous forbid
 
-error[E0453]: allow(non_snake_case) incompatible with previous forbid
-  --> $DIR/E0453.rs:3:9
-   |
-LL | #![forbid(non_snake_case)]
-   |           -------------- `forbid` level set here
-LL |
-LL | #[allow(non_snake_case)]
-   |         ^^^^^^^^^^^^^^ overruled by previous forbid
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0453`.
diff --git a/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.rs b/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.rs
index 0467dea621b..4e296b96ca9 100644
--- a/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.rs
+++ b/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.rs
@@ -2,11 +2,7 @@
 
 #![deny(multiple_supertrait_upcastable)]
 //~^ WARNING unknown lint: `multiple_supertrait_upcastable`
-//~| WARNING unknown lint: `multiple_supertrait_upcastable`
-//~| WARNING unknown lint: `multiple_supertrait_upcastable`
 #![warn(multiple_supertrait_upcastable)]
 //~^ WARNING unknown lint: `multiple_supertrait_upcastable`
-//~| WARNING unknown lint: `multiple_supertrait_upcastable`
-//~| WARNING unknown lint: `multiple_supertrait_upcastable`
 
 fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.stderr b/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.stderr
index 5e14bf6397f..f6fcf4ee3ed 100644
--- a/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.stderr
+++ b/tests/ui/feature-gates/feature-gate-multiple_supertrait_upcastable.stderr
@@ -9,7 +9,7 @@ LL | #![deny(multiple_supertrait_upcastable)]
    = note: `#[warn(unknown_lints)]` on by default
 
 warning: unknown lint: `multiple_supertrait_upcastable`
-  --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:7:1
+  --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:5:1
    |
 LL | #![warn(multiple_supertrait_upcastable)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -17,45 +17,5 @@ LL | #![warn(multiple_supertrait_upcastable)]
    = note: the `multiple_supertrait_upcastable` lint is unstable
    = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable
 
-warning: unknown lint: `multiple_supertrait_upcastable`
-  --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:3:1
-   |
-LL | #![deny(multiple_supertrait_upcastable)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the `multiple_supertrait_upcastable` lint is unstable
-   = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: unknown lint: `multiple_supertrait_upcastable`
-  --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:7:1
-   |
-LL | #![warn(multiple_supertrait_upcastable)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the `multiple_supertrait_upcastable` lint is unstable
-   = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: unknown lint: `multiple_supertrait_upcastable`
-  --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:3:1
-   |
-LL | #![deny(multiple_supertrait_upcastable)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the `multiple_supertrait_upcastable` lint is unstable
-   = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: unknown lint: `multiple_supertrait_upcastable`
-  --> $DIR/feature-gate-multiple_supertrait_upcastable.rs:7:1
-   |
-LL | #![warn(multiple_supertrait_upcastable)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the `multiple_supertrait_upcastable` lint is unstable
-   = help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: 6 warnings emitted
+warning: 2 warnings emitted
 
diff --git a/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs b/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs
index 1922bfb4913..1db3c2ccdde 100644
--- a/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs
+++ b/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs
@@ -2,12 +2,8 @@
 
 #![deny(non_exhaustive_omitted_patterns)]
 //~^ WARNING unknown lint: `non_exhaustive_omitted_patterns`
-//~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
-//~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
 #![allow(non_exhaustive_omitted_patterns)]
 //~^ WARNING unknown lint: `non_exhaustive_omitted_patterns`
-//~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
-//~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
 
 fn main() {
     enum Foo {
@@ -19,9 +15,6 @@ fn main() {
     #[allow(non_exhaustive_omitted_patterns)]
     //~^ WARNING unknown lint: `non_exhaustive_omitted_patterns`
     //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
-    //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
-    //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
-    //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
     match Foo::A {
         //~^ ERROR non-exhaustive patterns: `Foo::C` not covered
         Foo::A => {}
@@ -31,9 +24,6 @@ fn main() {
     #[warn(non_exhaustive_omitted_patterns)]
     //~^ WARNING unknown lint: `non_exhaustive_omitted_patterns`
     //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
-    //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
-    //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
-    //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
     match Foo::A {
         Foo::A => {}
         Foo::B => {}
diff --git a/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr b/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr
index a5333713977..955d7fe3f3e 100644
--- a/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr
+++ b/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr
@@ -10,7 +10,7 @@ LL | #![deny(non_exhaustive_omitted_patterns)]
    = note: `#[warn(unknown_lints)]` on by default
 
 warning: unknown lint: `non_exhaustive_omitted_patterns`
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:7:1
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:5:1
    |
 LL | #![allow(non_exhaustive_omitted_patterns)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -20,7 +20,7 @@ LL | #![allow(non_exhaustive_omitted_patterns)]
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
 warning: unknown lint: `non_exhaustive_omitted_patterns`
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:19:5
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5
    |
 LL |     #[allow(non_exhaustive_omitted_patterns)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -30,7 +30,7 @@ LL |     #[allow(non_exhaustive_omitted_patterns)]
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
 warning: unknown lint: `non_exhaustive_omitted_patterns`
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:19:5
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5
    |
 LL |     #[allow(non_exhaustive_omitted_patterns)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -41,7 +41,7 @@ LL |     #[allow(non_exhaustive_omitted_patterns)]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 warning: unknown lint: `non_exhaustive_omitted_patterns`
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:31:5
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:24:5
    |
 LL |     #[warn(non_exhaustive_omitted_patterns)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -51,73 +51,7 @@ LL |     #[warn(non_exhaustive_omitted_patterns)]
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
 warning: unknown lint: `non_exhaustive_omitted_patterns`
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:31:5
-   |
-LL |     #[warn(non_exhaustive_omitted_patterns)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the `non_exhaustive_omitted_patterns` lint is unstable
-   = 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
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: unknown lint: `non_exhaustive_omitted_patterns`
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:3:1
-   |
-LL | #![deny(non_exhaustive_omitted_patterns)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the `non_exhaustive_omitted_patterns` lint is unstable
-   = 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
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: unknown lint: `non_exhaustive_omitted_patterns`
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:7:1
-   |
-LL | #![allow(non_exhaustive_omitted_patterns)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the `non_exhaustive_omitted_patterns` lint is unstable
-   = 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
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: unknown lint: `non_exhaustive_omitted_patterns`
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:19:5
-   |
-LL |     #[allow(non_exhaustive_omitted_patterns)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the `non_exhaustive_omitted_patterns` lint is unstable
-   = 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
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: unknown lint: `non_exhaustive_omitted_patterns`
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:19:5
-   |
-LL |     #[allow(non_exhaustive_omitted_patterns)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the `non_exhaustive_omitted_patterns` lint is unstable
-   = 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
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: unknown lint: `non_exhaustive_omitted_patterns`
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:31:5
-   |
-LL |     #[warn(non_exhaustive_omitted_patterns)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the `non_exhaustive_omitted_patterns` lint is unstable
-   = 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
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: unknown lint: `non_exhaustive_omitted_patterns`
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:31:5
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:24:5
    |
 LL |     #[warn(non_exhaustive_omitted_patterns)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -128,13 +62,13 @@ LL |     #[warn(non_exhaustive_omitted_patterns)]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0004]: non-exhaustive patterns: `Foo::C` not covered
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:25:11
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:18:11
    |
 LL |     match Foo::A {
    |           ^^^^^^ pattern `Foo::C` not covered
    |
 note: `Foo` defined here
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:13:10
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:9:10
    |
 LL |     enum Foo {
    |          ^^^
@@ -148,50 +82,6 @@ LL ~         Foo::B => {},
 LL +         Foo::C => todo!()
    |
 
-warning: unknown lint: `non_exhaustive_omitted_patterns`
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:3:1
-   |
-LL | #![deny(non_exhaustive_omitted_patterns)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the `non_exhaustive_omitted_patterns` lint is unstable
-   = 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
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: unknown lint: `non_exhaustive_omitted_patterns`
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:7:1
-   |
-LL | #![allow(non_exhaustive_omitted_patterns)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the `non_exhaustive_omitted_patterns` lint is unstable
-   = 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
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: unknown lint: `non_exhaustive_omitted_patterns`
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:19:5
-   |
-LL |     #[allow(non_exhaustive_omitted_patterns)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the `non_exhaustive_omitted_patterns` lint is unstable
-   = 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
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: unknown lint: `non_exhaustive_omitted_patterns`
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:31:5
-   |
-LL |     #[warn(non_exhaustive_omitted_patterns)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the `non_exhaustive_omitted_patterns` lint is unstable
-   = 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
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 1 previous error; 16 warnings emitted
+error: aborting due to 1 previous error; 6 warnings emitted
 
 For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/feature-gates/feature-gate-strict_provenance.rs b/tests/ui/feature-gates/feature-gate-strict_provenance.rs
index 75d0ee5700d..24b8369b3d8 100644
--- a/tests/ui/feature-gates/feature-gate-strict_provenance.rs
+++ b/tests/ui/feature-gates/feature-gate-strict_provenance.rs
@@ -2,12 +2,8 @@
 
 #![deny(fuzzy_provenance_casts)]
 //~^ WARNING unknown lint: `fuzzy_provenance_casts`
-//~| WARNING unknown lint: `fuzzy_provenance_casts`
-//~| WARNING unknown lint: `fuzzy_provenance_casts`
 #![deny(lossy_provenance_casts)]
 //~^ WARNING unknown lint: `lossy_provenance_casts`
-//~| WARNING unknown lint: `lossy_provenance_casts`
-//~| WARNING unknown lint: `lossy_provenance_casts`
 
 fn main() {
     // no warnings emitted since the lints are not activated
diff --git a/tests/ui/feature-gates/feature-gate-strict_provenance.stderr b/tests/ui/feature-gates/feature-gate-strict_provenance.stderr
index 1e6d762a540..36224ee864b 100644
--- a/tests/ui/feature-gates/feature-gate-strict_provenance.stderr
+++ b/tests/ui/feature-gates/feature-gate-strict_provenance.stderr
@@ -10,7 +10,7 @@ LL | #![deny(fuzzy_provenance_casts)]
    = note: `#[warn(unknown_lints)]` on by default
 
 warning: unknown lint: `lossy_provenance_casts`
-  --> $DIR/feature-gate-strict_provenance.rs:7:1
+  --> $DIR/feature-gate-strict_provenance.rs:5:1
    |
 LL | #![deny(lossy_provenance_casts)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -19,49 +19,5 @@ LL | #![deny(lossy_provenance_casts)]
    = note: see issue #95228 <https://github.com/rust-lang/rust/issues/95228> for more information
    = help: add `#![feature(strict_provenance)]` to the crate attributes to enable
 
-warning: unknown lint: `fuzzy_provenance_casts`
-  --> $DIR/feature-gate-strict_provenance.rs:3:1
-   |
-LL | #![deny(fuzzy_provenance_casts)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the `fuzzy_provenance_casts` lint is unstable
-   = note: see issue #95228 <https://github.com/rust-lang/rust/issues/95228> for more information
-   = help: add `#![feature(strict_provenance)]` to the crate attributes to enable
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: unknown lint: `lossy_provenance_casts`
-  --> $DIR/feature-gate-strict_provenance.rs:7:1
-   |
-LL | #![deny(lossy_provenance_casts)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the `lossy_provenance_casts` lint is unstable
-   = note: see issue #95228 <https://github.com/rust-lang/rust/issues/95228> for more information
-   = help: add `#![feature(strict_provenance)]` to the crate attributes to enable
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: unknown lint: `fuzzy_provenance_casts`
-  --> $DIR/feature-gate-strict_provenance.rs:3:1
-   |
-LL | #![deny(fuzzy_provenance_casts)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the `fuzzy_provenance_casts` lint is unstable
-   = note: see issue #95228 <https://github.com/rust-lang/rust/issues/95228> for more information
-   = help: add `#![feature(strict_provenance)]` to the crate attributes to enable
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: unknown lint: `lossy_provenance_casts`
-  --> $DIR/feature-gate-strict_provenance.rs:7:1
-   |
-LL | #![deny(lossy_provenance_casts)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the `lossy_provenance_casts` lint is unstable
-   = note: see issue #95228 <https://github.com/rust-lang/rust/issues/95228> for more information
-   = help: add `#![feature(strict_provenance)]` to the crate attributes to enable
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: 6 warnings emitted
+warning: 2 warnings emitted
 
diff --git a/tests/ui/feature-gates/feature-gate-test_unstable_lint.rs b/tests/ui/feature-gates/feature-gate-test_unstable_lint.rs
index c398394cbe1..3882ba9a227 100644
--- a/tests/ui/feature-gates/feature-gate-test_unstable_lint.rs
+++ b/tests/ui/feature-gates/feature-gate-test_unstable_lint.rs
@@ -3,7 +3,5 @@
 // `test_unstable_lint` is for testing and should never be stabilized.
 #![allow(test_unstable_lint)]
 //~^ WARNING unknown lint: `test_unstable_lint`
-//~| WARNING unknown lint: `test_unstable_lint`
-//~| WARNING unknown lint: `test_unstable_lint`
 
 fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-test_unstable_lint.stderr b/tests/ui/feature-gates/feature-gate-test_unstable_lint.stderr
index 562aa478a93..aec32ac4abb 100644
--- a/tests/ui/feature-gates/feature-gate-test_unstable_lint.stderr
+++ b/tests/ui/feature-gates/feature-gate-test_unstable_lint.stderr
@@ -8,25 +8,5 @@ LL | #![allow(test_unstable_lint)]
    = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
    = note: `#[warn(unknown_lints)]` on by default
 
-warning: unknown lint: `test_unstable_lint`
-  --> $DIR/feature-gate-test_unstable_lint.rs:4:1
-   |
-LL | #![allow(test_unstable_lint)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the `test_unstable_lint` lint is unstable
-   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: unknown lint: `test_unstable_lint`
-  --> $DIR/feature-gate-test_unstable_lint.rs:4:1
-   |
-LL | #![allow(test_unstable_lint)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the `test_unstable_lint` lint is unstable
-   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: 3 warnings emitted
+warning: 1 warning emitted
 
diff --git a/tests/ui/feature-gates/feature-gate-type_privacy_lints.rs b/tests/ui/feature-gates/feature-gate-type_privacy_lints.rs
index 8bb9736f1b4..80e51b265db 100644
--- a/tests/ui/feature-gates/feature-gate-type_privacy_lints.rs
+++ b/tests/ui/feature-gates/feature-gate-type_privacy_lints.rs
@@ -1,6 +1,4 @@
 // check-pass
 
 #![warn(unnameable_types)] //~ WARN unknown lint
-                           //~| WARN unknown lint
-                           //~| WARN unknown lint
 fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-type_privacy_lints.stderr b/tests/ui/feature-gates/feature-gate-type_privacy_lints.stderr
index 2614f2b3c35..5cc30de9c57 100644
--- a/tests/ui/feature-gates/feature-gate-type_privacy_lints.stderr
+++ b/tests/ui/feature-gates/feature-gate-type_privacy_lints.stderr
@@ -9,27 +9,5 @@ LL | #![warn(unnameable_types)]
    = help: add `#![feature(type_privacy_lints)]` to the crate attributes to enable
    = note: `#[warn(unknown_lints)]` on by default
 
-warning: unknown lint: `unnameable_types`
-  --> $DIR/feature-gate-type_privacy_lints.rs:3:1
-   |
-LL | #![warn(unnameable_types)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the `unnameable_types` lint is unstable
-   = note: see issue #48054 <https://github.com/rust-lang/rust/issues/48054> for more information
-   = help: add `#![feature(type_privacy_lints)]` to the crate attributes to enable
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: unknown lint: `unnameable_types`
-  --> $DIR/feature-gate-type_privacy_lints.rs:3:1
-   |
-LL | #![warn(unnameable_types)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the `unnameable_types` lint is unstable
-   = note: see issue #48054 <https://github.com/rust-lang/rust/issues/48054> for more information
-   = help: add `#![feature(type_privacy_lints)]` to the crate attributes to enable
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: 3 warnings emitted
+warning: 1 warning emitted
 
diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions1.rs b/tests/ui/half-open-range-patterns/range_pat_interactions1.rs
index 9ffc2190d20..55353999b67 100644
--- a/tests/ui/half-open-range-patterns/range_pat_interactions1.rs
+++ b/tests/ui/half-open-range-patterns/range_pat_interactions1.rs
@@ -17,7 +17,7 @@ fn main() {
         }
         match x as i32 {
             0..5+1 => errors_only.push(x),
-            //~^ error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `+`
+            //~^ error: expected one of `=>`, `if`, or `|`, found `+`
             1 | -3..0 => first_or.push(x),
             y @ (0..5 | 6) => or_two.push(y),
             y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr b/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr
index 05235c9b922..19ebcaf0f36 100644
--- a/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr
+++ b/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr
@@ -1,8 +1,8 @@
-error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `+`
+error: expected one of `=>`, `if`, or `|`, found `+`
   --> $DIR/range_pat_interactions1.rs:19:17
    |
 LL |             0..5+1 => errors_only.push(x),
-   |                 ^ expected one of `,`, `=>`, `if`, `|`, or `}`
+   |                 ^ expected one of `=>`, `if`, or `|`
 
 error[E0408]: variable `n` is not bound in all patterns
   --> $DIR/range_pat_interactions1.rs:10:25
diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions2.rs b/tests/ui/half-open-range-patterns/range_pat_interactions2.rs
index b212bfbe093..4615ebd688a 100644
--- a/tests/ui/half-open-range-patterns/range_pat_interactions2.rs
+++ b/tests/ui/half-open-range-patterns/range_pat_interactions2.rs
@@ -9,7 +9,7 @@ fn main() {
         match x as i32 {
             0..=(5+1) => errors_only.push(x),
             //~^ error: inclusive range with no end
-            //~| error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `(`
+            //~| error: expected one of `=>`, `if`, or `|`, found `(`
             1 | -3..0 => first_or.push(x),
             y @ (0..5 | 6) => or_two.push(y),
             y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr b/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr
index 0129f927e34..13a5542a474 100644
--- a/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr
+++ b/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr
@@ -6,11 +6,11 @@ LL |             0..=(5+1) => errors_only.push(x),
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
-error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `(`
+error: expected one of `=>`, `if`, or `|`, found `(`
   --> $DIR/range_pat_interactions2.rs:10:17
    |
 LL |             0..=(5+1) => errors_only.push(x),
-   |                 ^ expected one of `,`, `=>`, `if`, `|`, or `}`
+   |                 ^ expected one of `=>`, `if`, or `|`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/impl-trait/associated-impl-trait-type-issue-114325.rs b/tests/ui/impl-trait/associated-impl-trait-type-issue-114325.rs
new file mode 100644
index 00000000000..8173f8df11b
--- /dev/null
+++ b/tests/ui/impl-trait/associated-impl-trait-type-issue-114325.rs
@@ -0,0 +1,55 @@
+// This is a non-regression test for issue #114325: an "unexpected unsized tail" ICE happened during
+// codegen, and was fixed by MIR drop tracking #107421.
+
+// edition: 2021
+// build-pass: ICEd during codegen.
+
+#![feature(impl_trait_in_assoc_type)]
+
+use std::future::Future;
+
+fn main() {
+    RuntimeRef::spawn_local(actor_fn(http_actor));
+}
+
+async fn http_actor() {
+    async fn respond(body: impl Body) {
+        body.write_message().await;
+    }
+
+    respond(&()).await;
+}
+
+trait Body {
+    type WriteFuture: Future;
+
+    fn write_message(self) -> Self::WriteFuture;
+}
+
+impl Body for &'static () {
+    type WriteFuture = impl Future<Output = ()>;
+
+    fn write_message(self) -> Self::WriteFuture {
+        async {}
+    }
+}
+
+trait NewActor {
+    type RuntimeAccess;
+}
+
+fn actor_fn<T, A>(_d: T) -> (T, A) {
+    loop {}
+}
+
+impl<F: FnMut() -> A, A> NewActor for (F, A) {
+    type RuntimeAccess = RuntimeRef;
+}
+struct RuntimeRef(Vec<()>);
+
+impl RuntimeRef {
+    fn spawn_local<NA: NewActor<RuntimeAccess = RuntimeRef>>(_f: NA) {
+        struct ActorFuture<NA: NewActor>(NA::RuntimeAccess);
+        (ActorFuture::<NA>(RuntimeRef(vec![])), _f);
+    }
+}
diff --git a/tests/ui/impl-trait/not_general_enough_regression_106630.rs b/tests/ui/impl-trait/not_general_enough_regression_106630.rs
new file mode 100644
index 00000000000..439973950f3
--- /dev/null
+++ b/tests/ui/impl-trait/not_general_enough_regression_106630.rs
@@ -0,0 +1,33 @@
+// edition:2018
+// run-pass
+
+use std::future::Future;
+
+trait AsyncCallback<'a> {
+    type Out;
+}
+
+impl<'a, Fut, T, F> AsyncCallback<'a> for F
+where
+    F: FnOnce(&'a mut ()) -> Fut,
+    Fut: Future<Output = T> + Send + 'a,
+{
+    type Out = T;
+}
+
+trait CallbackMarker {}
+
+impl<F, T> CallbackMarker for F
+where
+    T: 'static,
+    for<'a> F: AsyncCallback<'a, Out = T> + Send,
+{
+}
+
+fn do_sth<F: CallbackMarker>(_: F) {}
+
+async fn callback(_: &mut ()) -> impl Send {}
+
+fn main() {
+    do_sth(callback);
+}
diff --git a/tests/ui/lint/crate_level_only_lint.rs b/tests/ui/lint/crate_level_only_lint.rs
index d9673faa214..6679cc0862f 100644
--- a/tests/ui/lint/crate_level_only_lint.rs
+++ b/tests/ui/lint/crate_level_only_lint.rs
@@ -3,20 +3,14 @@
 mod foo {
 #![allow(uncommon_codepoints)]
 //~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
-//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
-//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
 
 #[allow(uncommon_codepoints)]
 //~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
-//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
-//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
 const BAR: f64 = 0.000001;
 
 }
 
 #[allow(uncommon_codepoints)]
 //~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
-//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
-//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
 fn main() {
 }
diff --git a/tests/ui/lint/crate_level_only_lint.stderr b/tests/ui/lint/crate_level_only_lint.stderr
index fbb1ec381c8..34d27f873f6 100644
--- a/tests/ui/lint/crate_level_only_lint.stderr
+++ b/tests/ui/lint/crate_level_only_lint.stderr
@@ -11,64 +11,16 @@ LL | #![deny(uncommon_codepoints, unused_attributes)]
    |                              ^^^^^^^^^^^^^^^^^
 
 error: allow(uncommon_codepoints) is ignored unless specified at crate level
-  --> $DIR/crate_level_only_lint.rs:9:9
+  --> $DIR/crate_level_only_lint.rs:7:9
    |
 LL | #[allow(uncommon_codepoints)]
    |         ^^^^^^^^^^^^^^^^^^^
 
 error: allow(uncommon_codepoints) is ignored unless specified at crate level
-  --> $DIR/crate_level_only_lint.rs:17:9
+  --> $DIR/crate_level_only_lint.rs:13:9
    |
 LL | #[allow(uncommon_codepoints)]
    |         ^^^^^^^^^^^^^^^^^^^
 
-error: allow(uncommon_codepoints) is ignored unless specified at crate level
-  --> $DIR/crate_level_only_lint.rs:4:10
-   |
-LL | #![allow(uncommon_codepoints)]
-   |          ^^^^^^^^^^^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: allow(uncommon_codepoints) is ignored unless specified at crate level
-  --> $DIR/crate_level_only_lint.rs:9:9
-   |
-LL | #[allow(uncommon_codepoints)]
-   |         ^^^^^^^^^^^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: allow(uncommon_codepoints) is ignored unless specified at crate level
-  --> $DIR/crate_level_only_lint.rs:17:9
-   |
-LL | #[allow(uncommon_codepoints)]
-   |         ^^^^^^^^^^^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: allow(uncommon_codepoints) is ignored unless specified at crate level
-  --> $DIR/crate_level_only_lint.rs:4:10
-   |
-LL | #![allow(uncommon_codepoints)]
-   |          ^^^^^^^^^^^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: allow(uncommon_codepoints) is ignored unless specified at crate level
-  --> $DIR/crate_level_only_lint.rs:9:9
-   |
-LL | #[allow(uncommon_codepoints)]
-   |         ^^^^^^^^^^^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: allow(uncommon_codepoints) is ignored unless specified at crate level
-  --> $DIR/crate_level_only_lint.rs:17:9
-   |
-LL | #[allow(uncommon_codepoints)]
-   |         ^^^^^^^^^^^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 9 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/tests/ui/lint/forbid-group-group-2.rs b/tests/ui/lint/forbid-group-group-2.rs
index b12fd72da74..b3d3e30fb8d 100644
--- a/tests/ui/lint/forbid-group-group-2.rs
+++ b/tests/ui/lint/forbid-group-group-2.rs
@@ -11,16 +11,4 @@
 //~| WARNING previously accepted by the compiler
 //~| ERROR incompatible with previous
 //~| WARNING previously accepted by the compiler
-//~| ERROR incompatible with previous
-//~| WARNING previously accepted by the compiler
-//~| ERROR incompatible with previous
-//~| WARNING previously accepted by the compiler
-//~| ERROR incompatible with previous
-//~| WARNING previously accepted by the compiler
-//~| ERROR incompatible with previous
-//~| WARNING previously accepted by the compiler
-//~| ERROR incompatible with previous
-//~| WARNING previously accepted by the compiler
-//~| ERROR incompatible with previous
-//~| WARNING previously accepted by the compiler
 fn main() {}
diff --git a/tests/ui/lint/forbid-group-group-2.stderr b/tests/ui/lint/forbid-group-group-2.stderr
index 4a2c8fbd68a..80e2f566eb8 100644
--- a/tests/ui/lint/forbid-group-group-2.stderr
+++ b/tests/ui/lint/forbid-group-group-2.stderr
@@ -41,83 +41,5 @@ LL | #[allow(nonstandard_style)]
    = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: allow(nonstandard_style) incompatible with previous forbid
-  --> $DIR/forbid-group-group-2.rs:7:9
-   |
-LL | #![forbid(warnings)]
-   |           -------- `forbid` level set here
-...
-LL | #[allow(nonstandard_style)]
-   |         ^^^^^^^^^^^^^^^^^ overruled by previous forbid
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: allow(nonstandard_style) incompatible with previous forbid
-  --> $DIR/forbid-group-group-2.rs:7:9
-   |
-LL | #![forbid(warnings)]
-   |           -------- `forbid` level set here
-...
-LL | #[allow(nonstandard_style)]
-   |         ^^^^^^^^^^^^^^^^^ overruled by previous forbid
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: allow(nonstandard_style) incompatible with previous forbid
-  --> $DIR/forbid-group-group-2.rs:7:9
-   |
-LL | #![forbid(warnings)]
-   |           -------- `forbid` level set here
-...
-LL | #[allow(nonstandard_style)]
-   |         ^^^^^^^^^^^^^^^^^ overruled by previous forbid
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: allow(nonstandard_style) incompatible with previous forbid
-  --> $DIR/forbid-group-group-2.rs:7:9
-   |
-LL | #![forbid(warnings)]
-   |           -------- `forbid` level set here
-...
-LL | #[allow(nonstandard_style)]
-   |         ^^^^^^^^^^^^^^^^^ overruled by previous forbid
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: allow(nonstandard_style) incompatible with previous forbid
-  --> $DIR/forbid-group-group-2.rs:7:9
-   |
-LL | #![forbid(warnings)]
-   |           -------- `forbid` level set here
-...
-LL | #[allow(nonstandard_style)]
-   |         ^^^^^^^^^^^^^^^^^ overruled by previous forbid
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: allow(nonstandard_style) incompatible with previous forbid
-  --> $DIR/forbid-group-group-2.rs:7:9
-   |
-LL | #![forbid(warnings)]
-   |           -------- `forbid` level set here
-...
-LL | #[allow(nonstandard_style)]
-   |         ^^^^^^^^^^^^^^^^^ overruled by previous forbid
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 9 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/tests/ui/lint/forbid-group-member.rs b/tests/ui/lint/forbid-group-member.rs
index 664edeaa8b4..d03e858438b 100644
--- a/tests/ui/lint/forbid-group-member.rs
+++ b/tests/ui/lint/forbid-group-member.rs
@@ -8,10 +8,6 @@
 #[allow(unused_variables)]
 //~^ WARNING incompatible with previous forbid
 //~| WARNING previously accepted
-//~| WARNING incompatible with previous forbid
-//~| WARNING previously accepted
-//~| WARNING incompatible with previous forbid
-//~| WARNING previously accepted
 fn main() {
     let a: ();
 }
diff --git a/tests/ui/lint/forbid-group-member.stderr b/tests/ui/lint/forbid-group-member.stderr
index ddaaafa12ec..8794591bd31 100644
--- a/tests/ui/lint/forbid-group-member.stderr
+++ b/tests/ui/lint/forbid-group-member.stderr
@@ -11,31 +11,5 @@ LL | #[allow(unused_variables)]
    = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
    = note: `#[warn(forbidden_lint_groups)]` on by default
 
-warning: allow(unused_variables) incompatible with previous forbid
-  --> $DIR/forbid-group-member.rs:8:9
-   |
-LL | #![forbid(unused)]
-   |           ------ `forbid` level set here
-LL |
-LL | #[allow(unused_variables)]
-   |         ^^^^^^^^^^^^^^^^ overruled by previous forbid
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: allow(unused_variables) incompatible with previous forbid
-  --> $DIR/forbid-group-member.rs:8:9
-   |
-LL | #![forbid(unused)]
-   |           ------ `forbid` level set here
-LL |
-LL | #[allow(unused_variables)]
-   |         ^^^^^^^^^^^^^^^^ overruled by previous forbid
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: 3 warnings emitted
+warning: 1 warning emitted
 
diff --git a/tests/ui/lint/forbid-member-group.rs b/tests/ui/lint/forbid-member-group.rs
index e2f76825a2d..d1874aa81a5 100644
--- a/tests/ui/lint/forbid-member-group.rs
+++ b/tests/ui/lint/forbid-member-group.rs
@@ -5,7 +5,6 @@
 
 #[allow(unused)]
 //~^ ERROR incompatible with previous forbid
-//~| ERROR incompatible with previous forbid
 fn main() {
     let a: ();
 }
diff --git a/tests/ui/lint/forbid-member-group.stderr b/tests/ui/lint/forbid-member-group.stderr
index 612dccd8d6c..9b32c00a3c3 100644
--- a/tests/ui/lint/forbid-member-group.stderr
+++ b/tests/ui/lint/forbid-member-group.stderr
@@ -7,17 +7,6 @@ LL |
 LL | #[allow(unused)]
    |         ^^^^^^ overruled by previous forbid
 
-error[E0453]: allow(unused) incompatible with previous forbid
-  --> $DIR/forbid-member-group.rs:6:9
-   |
-LL | #![forbid(unused_variables)]
-   |           ---------------- `forbid` level set here
-LL |
-LL | #[allow(unused)]
-   |         ^^^^^^ overruled by previous forbid
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0453`.
diff --git a/tests/ui/lint/issue-80988.rs b/tests/ui/lint/issue-80988.rs
index 1e116206f7b..5b910f1d8df 100644
--- a/tests/ui/lint/issue-80988.rs
+++ b/tests/ui/lint/issue-80988.rs
@@ -7,8 +7,4 @@
 #[deny(warnings)]
 //~^ WARNING incompatible with previous forbid
 //~| WARNING being phased out
-//~| WARNING incompatible with previous forbid
-//~| WARNING being phased out
-//~| WARNING incompatible with previous forbid
-//~| WARNING being phased out
 fn main() {}
diff --git a/tests/ui/lint/issue-80988.stderr b/tests/ui/lint/issue-80988.stderr
index 7a65881b5ed..afc93fcfeef 100644
--- a/tests/ui/lint/issue-80988.stderr
+++ b/tests/ui/lint/issue-80988.stderr
@@ -11,31 +11,5 @@ LL | #[deny(warnings)]
    = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
    = note: `#[warn(forbidden_lint_groups)]` on by default
 
-warning: deny(warnings) incompatible with previous forbid
-  --> $DIR/issue-80988.rs:7:8
-   |
-LL | #![forbid(warnings)]
-   |           -------- `forbid` level set here
-LL |
-LL | #[deny(warnings)]
-   |        ^^^^^^^^ overruled by previous forbid
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: deny(warnings) incompatible with previous forbid
-  --> $DIR/issue-80988.rs:7:8
-   |
-LL | #![forbid(warnings)]
-   |           -------- `forbid` level set here
-LL |
-LL | #[deny(warnings)]
-   |        ^^^^^^^^ overruled by previous forbid
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #81670 <https://github.com/rust-lang/rust/issues/81670>
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: 3 warnings emitted
+warning: 1 warning emitted
 
diff --git a/tests/ui/lint/lint-forbid-attr.rs b/tests/ui/lint/lint-forbid-attr.rs
index 6d4cfd83424..270a379c2f8 100644
--- a/tests/ui/lint/lint-forbid-attr.rs
+++ b/tests/ui/lint/lint-forbid-attr.rs
@@ -2,6 +2,5 @@
 
 #[allow(deprecated)]
 //~^ ERROR allow(deprecated) incompatible
-//~| ERROR allow(deprecated) incompatible
 fn main() {
 }
diff --git a/tests/ui/lint/lint-forbid-attr.stderr b/tests/ui/lint/lint-forbid-attr.stderr
index bd476a0e362..fa7106b5e11 100644
--- a/tests/ui/lint/lint-forbid-attr.stderr
+++ b/tests/ui/lint/lint-forbid-attr.stderr
@@ -7,17 +7,6 @@ LL |
 LL | #[allow(deprecated)]
    |         ^^^^^^^^^^ overruled by previous forbid
 
-error[E0453]: allow(deprecated) incompatible with previous forbid
-  --> $DIR/lint-forbid-attr.rs:3:9
-   |
-LL | #![forbid(deprecated)]
-   |           ---------- `forbid` level set here
-LL |
-LL | #[allow(deprecated)]
-   |         ^^^^^^^^^^ overruled by previous forbid
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0453`.
diff --git a/tests/ui/lint/lint-forbid-cmdline.rs b/tests/ui/lint/lint-forbid-cmdline.rs
index 5246ccb57a6..32a92e09b14 100644
--- a/tests/ui/lint/lint-forbid-cmdline.rs
+++ b/tests/ui/lint/lint-forbid-cmdline.rs
@@ -1,6 +1,5 @@
 // compile-flags: -F deprecated
 
 #[allow(deprecated)] //~ ERROR allow(deprecated) incompatible
-                     //~| ERROR allow(deprecated) incompatible
 fn main() {
 }
diff --git a/tests/ui/lint/lint-forbid-cmdline.stderr b/tests/ui/lint/lint-forbid-cmdline.stderr
index ed49a2cb427..3920a742976 100644
--- a/tests/ui/lint/lint-forbid-cmdline.stderr
+++ b/tests/ui/lint/lint-forbid-cmdline.stderr
@@ -6,15 +6,6 @@ LL | #[allow(deprecated)]
    |
    = note: `forbid` lint level was set on command line
 
-error[E0453]: allow(deprecated) incompatible with previous forbid
-  --> $DIR/lint-forbid-cmdline.rs:3:9
-   |
-LL | #[allow(deprecated)]
-   |         ^^^^^^^^^^ overruled by previous forbid
-   |
-   = note: `forbid` lint level was set on command line
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0453`.
diff --git a/tests/ui/lint/must_not_suspend/gated.rs b/tests/ui/lint/must_not_suspend/gated.rs
index b73a7655529..fe8192b0eaa 100644
--- a/tests/ui/lint/must_not_suspend/gated.rs
+++ b/tests/ui/lint/must_not_suspend/gated.rs
@@ -3,8 +3,6 @@
 // edition:2018
 #![deny(must_not_suspend)]
 //~^ WARNING unknown lint: `must_not_suspend`
-//~| WARNING unknown lint: `must_not_suspend`
-//~| WARNING unknown lint: `must_not_suspend`
 
 async fn other() {}
 
diff --git a/tests/ui/lint/must_not_suspend/gated.stderr b/tests/ui/lint/must_not_suspend/gated.stderr
index f0d2117d42b..c238c1f3351 100644
--- a/tests/ui/lint/must_not_suspend/gated.stderr
+++ b/tests/ui/lint/must_not_suspend/gated.stderr
@@ -9,27 +9,5 @@ LL | #![deny(must_not_suspend)]
    = help: add `#![feature(must_not_suspend)]` to the crate attributes to enable
    = note: `#[warn(unknown_lints)]` on by default
 
-warning: unknown lint: `must_not_suspend`
-  --> $DIR/gated.rs:4:1
-   |
-LL | #![deny(must_not_suspend)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the `must_not_suspend` lint is unstable
-   = note: see issue #83310 <https://github.com/rust-lang/rust/issues/83310> for more information
-   = help: add `#![feature(must_not_suspend)]` to the crate attributes to enable
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: unknown lint: `must_not_suspend`
-  --> $DIR/gated.rs:4:1
-   |
-LL | #![deny(must_not_suspend)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the `must_not_suspend` lint is unstable
-   = note: see issue #83310 <https://github.com/rust-lang/rust/issues/83310> for more information
-   = help: add `#![feature(must_not_suspend)]` to the crate attributes to enable
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: 3 warnings emitted
+warning: 1 warning emitted
 
diff --git a/tests/ui/lint/unused/issue-119383-if-let-guard.rs b/tests/ui/lint/unused/issue-119383-if-let-guard.rs
new file mode 100644
index 00000000000..71197444f45
--- /dev/null
+++ b/tests/ui/lint/unused/issue-119383-if-let-guard.rs
@@ -0,0 +1,9 @@
+#![feature(if_let_guard)]
+#![deny(unused_variables)]
+
+fn main() {
+    match () {
+        () if let Some(b) = Some(()) => {} //~ ERROR unused variable: `b`
+        _ => {}
+    }
+}
diff --git a/tests/ui/lint/unused/issue-119383-if-let-guard.stderr b/tests/ui/lint/unused/issue-119383-if-let-guard.stderr
new file mode 100644
index 00000000000..5bf48bb80a8
--- /dev/null
+++ b/tests/ui/lint/unused/issue-119383-if-let-guard.stderr
@@ -0,0 +1,14 @@
+error: unused variable: `b`
+  --> $DIR/issue-119383-if-let-guard.rs:6:24
+   |
+LL |         () if let Some(b) = Some(()) => {}
+   |                        ^ help: if this is intentional, prefix it with an underscore: `_b`
+   |
+note: the lint level is defined here
+  --> $DIR/issue-119383-if-let-guard.rs:2:9
+   |
+LL | #![deny(unused_variables)]
+   |         ^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/methods/disambiguate-associated-function-first-arg.rs b/tests/ui/methods/disambiguate-associated-function-first-arg.rs
new file mode 100644
index 00000000000..4c8192fc14b
--- /dev/null
+++ b/tests/ui/methods/disambiguate-associated-function-first-arg.rs
@@ -0,0 +1,49 @@
+struct A {}
+
+fn main() {
+    let _a = A {};
+    _a.new(1);
+    //~^ ERROR no method named `new` found for struct `A` in the current scope
+}
+
+trait M {
+    fn new(_a: i32);
+}
+impl M for A {
+    fn new(_a: i32) {}
+}
+
+trait N {
+    fn new(_a: Self, _b: i32);
+}
+impl N for A {
+    fn new(_a: Self, _b: i32) {}
+}
+
+trait O {
+    fn new(_a: Self, _b: i32);
+}
+impl O for A {
+    fn new(_a: A, _b: i32) {}
+}
+
+struct S;
+
+trait TraitA {
+    fn f(self);
+}
+trait TraitB {
+    fn f(self);
+}
+
+impl<T> TraitA for T {
+    fn f(self) {}
+}
+impl<T> TraitB for T {
+    fn f(self) {}
+}
+
+fn test() {
+    S.f();
+   //~^ multiple applicable items in scope
+}
diff --git a/tests/ui/methods/disambiguate-associated-function-first-arg.stderr b/tests/ui/methods/disambiguate-associated-function-first-arg.stderr
new file mode 100644
index 00000000000..341b7a91003
--- /dev/null
+++ b/tests/ui/methods/disambiguate-associated-function-first-arg.stderr
@@ -0,0 +1,67 @@
+error[E0599]: no method named `new` found for struct `A` in the current scope
+  --> $DIR/disambiguate-associated-function-first-arg.rs:5:8
+   |
+LL | struct A {}
+   | -------- method `new` not found for this struct
+...
+LL |     _a.new(1);
+   |        ^^^ this is an associated function, not a method
+   |
+   = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
+note: candidate #1 is defined in the trait `M`
+  --> $DIR/disambiguate-associated-function-first-arg.rs:10:5
+   |
+LL |     fn new(_a: i32);
+   |     ^^^^^^^^^^^^^^^^
+note: candidate #2 is defined in the trait `N`
+  --> $DIR/disambiguate-associated-function-first-arg.rs:17:5
+   |
+LL |     fn new(_a: Self, _b: i32);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: candidate #3 is defined in the trait `O`
+  --> $DIR/disambiguate-associated-function-first-arg.rs:24:5
+   |
+LL |     fn new(_a: Self, _b: i32);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: disambiguate the associated function for candidate #1
+   |
+LL |     <A as M>::new(1);
+   |     ~~~~~~~~~~~~~~~~
+help: disambiguate the associated function for candidate #2
+   |
+LL |     <A as N>::new(_a, 1);
+   |     ~~~~~~~~~~~~~~~~~~~~
+help: disambiguate the associated function for candidate #3
+   |
+LL |     <A as O>::new(_a, 1);
+   |     ~~~~~~~~~~~~~~~~~~~~
+
+error[E0034]: multiple applicable items in scope
+  --> $DIR/disambiguate-associated-function-first-arg.rs:47:7
+   |
+LL |     S.f();
+   |       ^ multiple `f` found
+   |
+note: candidate #1 is defined in an impl of the trait `TraitA` for the type `T`
+  --> $DIR/disambiguate-associated-function-first-arg.rs:40:5
+   |
+LL |     fn f(self) {}
+   |     ^^^^^^^^^^
+note: candidate #2 is defined in an impl of the trait `TraitB` for the type `T`
+  --> $DIR/disambiguate-associated-function-first-arg.rs:43:5
+   |
+LL |     fn f(self) {}
+   |     ^^^^^^^^^^
+help: disambiguate the method for candidate #1
+   |
+LL |     TraitA::f(S);
+   |     ~~~~~~~~~~~~
+help: disambiguate the method for candidate #2
+   |
+LL |     TraitB::f(S);
+   |     ~~~~~~~~~~~~
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0034, E0599.
+For more information about an error, try `rustc --explain E0034`.
diff --git a/tests/ui/methods/method-ambiguity-no-rcvr.stderr b/tests/ui/methods/method-ambiguity-no-rcvr.stderr
index 73f6043f256..3b6eb07393a 100644
--- a/tests/ui/methods/method-ambiguity-no-rcvr.stderr
+++ b/tests/ui/methods/method-ambiguity-no-rcvr.stderr
@@ -20,12 +20,12 @@ LL |     fn foo() {}
    |     ^^^^^^^^
 help: disambiguate the associated function for candidate #1
    |
-LL |     <Qux as Foo>::foo(Qux);
-   |     ~~~~~~~~~~~~~~~~~~~~~~
+LL |     <Qux as Foo>::foo();
+   |     ~~~~~~~~~~~~~~~~~~~
 help: disambiguate the associated function for candidate #2
    |
-LL |     <Qux as FooBar>::foo(Qux);
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |     <Qux as FooBar>::foo();
+   |     ~~~~~~~~~~~~~~~~~~~~~~
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs
index 2c402e4c65e..d1950087c4c 100644
--- a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs
+++ b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs
@@ -84,15 +84,15 @@ fn main() {}
 
 #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } }
 //~^ ERROR inclusive range with no end
-//~| ERROR expected one of `,`, `=>`, `if`, `|`, or `}`, found `#`
+//~| ERROR expected one of `=>`, `if`, or `|`, found `#`
 #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } }
 //~^ ERROR inclusive range with no end
-//~| ERROR expected one of `,`, `=>`, `if`, `|`, or `}`, found `#`
+//~| ERROR expected one of `=>`, `if`, or `|`, found `#`
 #[cfg(FALSE)] fn e() { match 0 { 0..=-#[attr] 10 => () } }
 //~^ ERROR unexpected token: `#`
 #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } }
 //~^ ERROR inclusive range with no end
-//~| ERROR expected one of `,`, `=>`, `if`, `|`, or `}`, found `#`
+//~| ERROR expected one of `=>`, `if`, or `|`, found `#`
 
 #[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); }
 //~^ ERROR unexpected token: `#`
diff --git a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr
index a0e95c5c1ed..e46c591080d 100644
--- a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr
+++ b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr
@@ -365,11 +365,11 @@ LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } }
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
-error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `#`
+error: expected one of `=>`, `if`, or `|`, found `#`
   --> $DIR/attr-stmt-expr-attr-bad.rs:85:38
    |
 LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } }
-   |                                      ^ expected one of `,`, `=>`, `if`, `|`, or `}`
+   |                                      ^ expected one of `=>`, `if`, or `|`
 
 error[E0586]: inclusive range with no end
   --> $DIR/attr-stmt-expr-attr-bad.rs:88:35
@@ -379,11 +379,11 @@ LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } }
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
-error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `#`
+error: expected one of `=>`, `if`, or `|`, found `#`
   --> $DIR/attr-stmt-expr-attr-bad.rs:88:38
    |
 LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } }
-   |                                      ^ expected one of `,`, `=>`, `if`, `|`, or `}`
+   |                                      ^ expected one of `=>`, `if`, or `|`
 
 error: unexpected token: `#`
   --> $DIR/attr-stmt-expr-attr-bad.rs:91:39
@@ -399,11 +399,11 @@ LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } }
    |
    = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
 
-error: expected one of `,`, `=>`, `if`, `|`, or `}`, found `#`
+error: expected one of `=>`, `if`, or `|`, found `#`
   --> $DIR/attr-stmt-expr-attr-bad.rs:93:38
    |
 LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } }
-   |                                      ^ expected one of `,`, `=>`, `if`, `|`, or `}`
+   |                                      ^ expected one of `=>`, `if`, or `|`
 
 error: unexpected token: `#`
   --> $DIR/attr-stmt-expr-attr-bad.rs:97:34
diff --git a/tests/ui/parser/issues/issue-24375.rs b/tests/ui/parser/issues/issue-24375.rs
index 8d1bc579e7b..1d128d33e4f 100644
--- a/tests/ui/parser/issues/issue-24375.rs
+++ b/tests/ui/parser/issues/issue-24375.rs
@@ -3,7 +3,7 @@ static tmp : [&'static str; 2]  = ["hello", "he"];
 fn main() {
     let z = "hello";
     match z {
-        tmp[0] => {} //~ ERROR expected one of `,`, `=>`, `@`, `if`, `|`, or `}`, found `[`
+        tmp[0] => {} //~ ERROR expected one of `=>`, `@`, `if`, or `|`, found `[`
         _ => {}
     }
 }
diff --git a/tests/ui/parser/issues/issue-24375.stderr b/tests/ui/parser/issues/issue-24375.stderr
index 2b980a5520f..bb1e19e9e6d 100644
--- a/tests/ui/parser/issues/issue-24375.stderr
+++ b/tests/ui/parser/issues/issue-24375.stderr
@@ -1,8 +1,8 @@
-error: expected one of `,`, `=>`, `@`, `if`, `|`, or `}`, found `[`
+error: expected one of `=>`, `@`, `if`, or `|`, found `[`
   --> $DIR/issue-24375.rs:6:12
    |
 LL |         tmp[0] => {}
-   |            ^ expected one of `,`, `=>`, `@`, `if`, `|`, or `}`
+   |            ^ expected one of `=>`, `@`, `if`, or `|`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/match-arm-without-body.stderr b/tests/ui/parser/match-arm-without-body.stderr
index d98c7ec2826..a3f7e32c177 100644
--- a/tests/ui/parser/match-arm-without-body.stderr
+++ b/tests/ui/parser/match-arm-without-body.stderr
@@ -1,8 +1,8 @@
-error: expected one of `,`, `=>`, `if`, `|`, or `}`, found reserved identifier `_`
+error: expected one of `=>`, `if`, or `|`, found reserved identifier `_`
   --> $DIR/match-arm-without-body.rs:13:9
    |
 LL |         Some(_)
-   |                - expected one of `,`, `=>`, `if`, `|`, or `}`
+   |                - expected one of `=>`, `if`, or `|`
 LL |         _ => {}
    |         ^ unexpected token
 
@@ -44,11 +44,11 @@ LL +
 LL ~         _ => {}
    |
 
-error: expected one of `,`, `.`, `=>`, `?`, `}`, or an operator, found reserved identifier `_`
+error: expected one of `.`, `=>`, `?`, or an operator, found reserved identifier `_`
   --> $DIR/match-arm-without-body.rs:36:9
    |
 LL |         Some(_) if true
-   |                        - expected one of `,`, `.`, `=>`, `?`, `}`, or an operator
+   |                        - expected one of `.`, `=>`, `?`, or an operator
 LL |         _ => {}
    |         ^ unexpected token
 
diff --git a/tests/ui/parser/pat-lt-bracket-1.rs b/tests/ui/parser/pat-lt-bracket-1.rs
index 33da15adb9e..2e2001434f2 100644
--- a/tests/ui/parser/pat-lt-bracket-1.rs
+++ b/tests/ui/parser/pat-lt-bracket-1.rs
@@ -1,7 +1,7 @@
 fn main() {
   match 42 {
     x < 7 => (),
-   //~^ error: expected one of `,`, `=>`, `@`, `if`, `|`, or `}`, found `<`
+   //~^ error: expected one of `=>`, `@`, `if`, or `|`, found `<`
     _ => ()
   }
 }
diff --git a/tests/ui/parser/pat-lt-bracket-1.stderr b/tests/ui/parser/pat-lt-bracket-1.stderr
index f39487052ad..14e679bbee0 100644
--- a/tests/ui/parser/pat-lt-bracket-1.stderr
+++ b/tests/ui/parser/pat-lt-bracket-1.stderr
@@ -1,8 +1,8 @@
-error: expected one of `,`, `=>`, `@`, `if`, `|`, or `}`, found `<`
+error: expected one of `=>`, `@`, `if`, or `|`, found `<`
   --> $DIR/pat-lt-bracket-1.rs:3:7
    |
 LL |     x < 7 => (),
-   |       ^ expected one of `,`, `=>`, `@`, `if`, `|`, or `}`
+   |       ^ expected one of `=>`, `@`, `if`, or `|`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/unknown-unstable-lints/deny-unstable-lint-command-line.stderr b/tests/ui/unknown-unstable-lints/deny-unstable-lint-command-line.stderr
index f0450aea49a..df83c103084 100644
--- a/tests/ui/unknown-unstable-lints/deny-unstable-lint-command-line.stderr
+++ b/tests/ui/unknown-unstable-lints/deny-unstable-lint-command-line.stderr
@@ -4,17 +4,5 @@ error: unknown lint: `test_unstable_lint`
    = help: add `-Zcrate-attr="feature(test_unstable_lint)"` to the command-line options to enable
    = note: requested on the command line with `-D unknown-lints`
 
-error: unknown lint: `test_unstable_lint`
-   |
-   = note: the `test_unstable_lint` lint is unstable
-   = help: add `-Zcrate-attr="feature(test_unstable_lint)"` to the command-line options to enable
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: unknown lint: `test_unstable_lint`
-   |
-   = note: the `test_unstable_lint` lint is unstable
-   = help: add `-Zcrate-attr="feature(test_unstable_lint)"` to the command-line options to enable
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 3 previous errors
+error: aborting due to 1 previous error
 
diff --git a/tests/ui/unknown-unstable-lints/deny-unstable-lint-inline.rs b/tests/ui/unknown-unstable-lints/deny-unstable-lint-inline.rs
index c6c60b12d83..29c6547abc1 100644
--- a/tests/ui/unknown-unstable-lints/deny-unstable-lint-inline.rs
+++ b/tests/ui/unknown-unstable-lints/deny-unstable-lint-inline.rs
@@ -3,7 +3,5 @@
 #![deny(unknown_lints)]
 #![allow(test_unstable_lint)]
 //~^ ERROR unknown lint: `test_unstable_lint`
-//~| ERROR unknown lint: `test_unstable_lint`
-//~| ERROR unknown lint: `test_unstable_lint`
 
 fn main() {}
diff --git a/tests/ui/unknown-unstable-lints/deny-unstable-lint-inline.stderr b/tests/ui/unknown-unstable-lints/deny-unstable-lint-inline.stderr
index 20a36b28dc6..0afe3d55c98 100644
--- a/tests/ui/unknown-unstable-lints/deny-unstable-lint-inline.stderr
+++ b/tests/ui/unknown-unstable-lints/deny-unstable-lint-inline.stderr
@@ -12,25 +12,5 @@ note: the lint level is defined here
 LL | #![deny(unknown_lints)]
    |         ^^^^^^^^^^^^^
 
-error: unknown lint: `test_unstable_lint`
-  --> $DIR/deny-unstable-lint-inline.rs:4:1
-   |
-LL | #![allow(test_unstable_lint)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the `test_unstable_lint` lint is unstable
-   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: unknown lint: `test_unstable_lint`
-  --> $DIR/deny-unstable-lint-inline.rs:4:1
-   |
-LL | #![allow(test_unstable_lint)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the `test_unstable_lint` lint is unstable
-   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 3 previous errors
+error: aborting due to 1 previous error
 
diff --git a/tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.stderr b/tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.stderr
index a2deecf1caf..c133b880ebd 100644
--- a/tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.stderr
+++ b/tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.stderr
@@ -4,17 +4,5 @@ warning: unknown lint: `test_unstable_lint`
    = help: add `-Zcrate-attr="feature(test_unstable_lint)"` to the command-line options to enable
    = note: requested on the command line with `-W unknown-lints`
 
-warning: unknown lint: `test_unstable_lint`
-   |
-   = note: the `test_unstable_lint` lint is unstable
-   = help: add `-Zcrate-attr="feature(test_unstable_lint)"` to the command-line options to enable
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: unknown lint: `test_unstable_lint`
-   |
-   = note: the `test_unstable_lint` lint is unstable
-   = help: add `-Zcrate-attr="feature(test_unstable_lint)"` to the command-line options to enable
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: 3 warnings emitted
+warning: 1 warning emitted
 
diff --git a/tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.rs b/tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.rs
index f4247e4569e..89db84e69f6 100644
--- a/tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.rs
+++ b/tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.rs
@@ -3,7 +3,5 @@
 #![warn(unknown_lints)]
 #![allow(test_unstable_lint)]
 //~^ WARNING unknown lint: `test_unstable_lint`
-//~| WARNING unknown lint: `test_unstable_lint`
-//~| WARNING unknown lint: `test_unstable_lint`
 
 fn main() {}
diff --git a/tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.stderr b/tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.stderr
index 12afb2e294a..48c83b49e29 100644
--- a/tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.stderr
+++ b/tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.stderr
@@ -12,25 +12,5 @@ note: the lint level is defined here
 LL | #![warn(unknown_lints)]
    |         ^^^^^^^^^^^^^
 
-warning: unknown lint: `test_unstable_lint`
-  --> $DIR/warn-unknown-unstable-lint-inline.rs:4:1
-   |
-LL | #![allow(test_unstable_lint)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the `test_unstable_lint` lint is unstable
-   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: unknown lint: `test_unstable_lint`
-  --> $DIR/warn-unknown-unstable-lint-inline.rs:4:1
-   |
-LL | #![allow(test_unstable_lint)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the `test_unstable_lint` lint is unstable
-   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: 3 warnings emitted
+warning: 1 warning emitted