about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock40
-rw-r--r--compiler/rustc_abi/src/lib.rs12
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs4
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs57
-rw-r--r--compiler/rustc_borrowck/src/constraints/graph.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs2
-rw-r--r--compiler/rustc_borrowck/src/lib.rs7
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs29
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/global_allocator.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/test.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/asm.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/back/archive.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/glue.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/intrinsic.rs12
-rw-r--r--compiler/rustc_const_eval/src/interpret/cast.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs11
-rw-r--r--compiler/rustc_const_eval/src/interpret/operator.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs2
-rw-r--r--compiler/rustc_error_codes/src/error_codes.rs2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0320.md27
-rw-r--r--compiler/rustc_error_messages/locales/en-US/mir_build.ftl301
-rw-r--r--compiler/rustc_error_messages/src/lib.rs1
-rw-r--r--compiler/rustc_expand/src/mbe/macro_check.rs4
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs7
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs14
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs11
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs14
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs11
-rw-r--r--compiler/rustc_incremental/src/assert_dep_graph.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs4
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs14
-rw-r--r--compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/undo_log.rs8
-rw-r--r--compiler/rustc_infer/src/traits/project.rs2
-rw-r--r--compiler/rustc_interface/src/queries.rs2
-rw-r--r--compiler/rustc_lint/src/builtin.rs4
-rw-r--r--compiler/rustc_lint/src/context.rs10
-rw-r--r--compiler/rustc_lint/src/for_loops_over_fallibles.rs6
-rw-r--r--compiler/rustc_lint/src/unused.rs2
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic.rs12
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs6
-rw-r--r--compiler/rustc_middle/src/middle/privacy.rs7
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs8
-rw-r--r--compiler/rustc_middle/src/mir/tcx.rs2
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs4
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs2
-rw-r--r--compiler/rustc_middle/src/ty/vtable.rs4
-rw-r--r--compiler/rustc_mir_build/Cargo.toml1
-rw-r--r--compiler/rustc_mir_build/src/build/custom/parse/instruction.rs51
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs17
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs280
-rw-r--r--compiler/rustc_mir_build/src/errors.rs616
-rw-r--r--compiler/rustc_mir_build/src/lib.rs1
-rw-r--r--compiler/rustc_mir_build/src/lints.rs13
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs230
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs39
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs4
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs7
-rw-r--r--compiler/rustc_mir_transform/src/sroa.rs2
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs4
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs8
-rw-r--r--compiler/rustc_parse/src/parser/path.rs3
-rw-r--r--compiler/rustc_passes/src/dead.rs1
-rw-r--r--compiler/rustc_passes/src/hir_stats.rs4
-rw-r--r--compiler/rustc_passes/src/lang_items.rs2
-rw-r--r--compiler/rustc_query_impl/src/on_disk_cache.rs2
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs2
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs8
-rw-r--r--compiler/rustc_resolve/src/lib.rs2
-rw-r--r--compiler/rustc_session/src/filesearch.rs4
-rw-r--r--compiler/rustc_session/src/session.rs2
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs22
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs43
-rw-r--r--compiler/rustc_transmute/src/layout/nfa.rs4
-rw-r--r--compiler/rustc_transmute/src/maybe_transmutable/query_context.rs6
-rw-r--r--library/alloc/src/fmt.rs4
-rw-r--r--library/core/src/fmt/mod.rs4
-rw-r--r--library/core/src/intrinsics/mir.rs39
-rw-r--r--library/core/src/slice/mod.rs11
-rw-r--r--library/std/src/fs/tests.rs28
-rw-r--r--library/std/src/process.rs10
-rw-r--r--library/std/src/sys/unix/fs.rs57
-rw-r--r--library/std/src/sys/unix/pipe.rs4
-rw-r--r--library/std/src/sys/unix/process/process_fuchsia.rs5
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs5
-rw-r--r--library/std/src/sys/unix/process/process_unsupported.rs4
-rw-r--r--library/std/src/sys/unix/process/process_vxworks.rs5
-rw-r--r--library/std/src/sys/unsupported/pipe.rs4
-rw-r--r--library/std/src/sys/unsupported/process.rs4
-rw-r--r--library/std/src/sys/windows/pipe.rs6
-rw-r--r--library/std/src/sys/windows/process.rs5
-rw-r--r--library/std/src/sys_common/process.rs31
-rw-r--r--src/bootstrap/builder.rs16
-rw-r--r--src/bootstrap/config.rs1
-rw-r--r--src/bootstrap/flags.rs6
-rw-r--r--src/bootstrap/format.rs23
-rw-r--r--src/bootstrap/install.rs6
-rw-r--r--src/bootstrap/lib.rs23
-rw-r--r--src/bootstrap/setup.rs70
-rw-r--r--src/ci/docker/host-x86_64/mingw-check/Dockerfile2
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version2
-rwxr-xr-xsrc/ci/run.sh25
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css13
-rw-r--r--src/test/codegen/dst-vtable-align-nonzero.rs18
-rw-r--r--src/test/codegen/dst-vtable-size-range.rs35
-rw-r--r--src/test/mir-opt/building/custom/terminators.assert_nonzero.built.after.mir17
-rw-r--r--src/test/mir-opt/building/custom/terminators.direct_call.built.after.mir16
-rw-r--r--src/test/mir-opt/building/custom/terminators.drop_first.built.after.mir13
-rw-r--r--src/test/mir-opt/building/custom/terminators.drop_second.built.after.mir13
-rw-r--r--src/test/mir-opt/building/custom/terminators.indirect_call.built.after.mir13
-rw-r--r--src/test/mir-opt/building/custom/terminators.rs108
-rw-r--r--src/test/mir-opt/dest-prop/unreachable.f.DestinationPropagation.diff86
-rw-r--r--src/test/mir-opt/dest-prop/unreachable.rs18
-rw-r--r--src/test/ui/argument-suggestions/basic.stderr4
-rw-r--r--src/test/ui/borrowck/issue-103095.rs30
-rw-r--r--src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr1
-rw-r--r--src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr1
-rw-r--r--src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr1
-rw-r--r--src/test/ui/error-codes/E0057.stderr4
-rw-r--r--src/test/ui/generator/ref-upvar-not-send.rs31
-rw-r--r--src/test/ui/generator/ref-upvar-not-send.stderr50
-rw-r--r--src/test/ui/higher-rank-trait-bounds/issue-58451.stderr4
-rw-r--r--src/test/ui/infinite/issue-41731-infinite-macro-print.rs15
-rw-r--r--src/test/ui/infinite/issue-41731-infinite-macro-print.stderr38
-rw-r--r--src/test/ui/infinite/issue-41731-infinite-macro-println.rs15
-rw-r--r--src/test/ui/infinite/issue-41731-infinite-macro-println.stderr38
-rw-r--r--src/test/ui/issues/issue-3044.stderr2
-rw-r--r--src/test/ui/lint/lint-uppercase-variables.rs10
-rw-r--r--src/test/ui/lint/lint-uppercase-variables.stderr12
-rw-r--r--src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr1
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/.github/workflows/clippy_bors.yml7
-rw-r--r--src/tools/clippy/CHANGELOG.md177
-rw-r--r--src/tools/clippy/Cargo.toml6
-rw-r--r--src/tools/clippy/book/src/README.md2
-rw-r--r--src/tools/clippy/build.rs14
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_lints/src/almost_complete_range.rs (renamed from src/tools/clippy/clippy_lints/src/almost_complete_letter_range.rs)24
-rw-r--r--src/tools/clippy/clippy_lints/src/box_default.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_macros.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/format_args.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/from_over_into.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/indexing_slicing.rs45
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs28
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/utils.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_assert.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs91
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_let_else.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_retain.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/misc.rs66
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs74
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/identity_op.rs74
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/mod.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/renamed_lints.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/semicolon_block.rs137
-rw-r--r--src/tools/clippy/clippy_lints/src/strings.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/conf.rs51
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs10
-rw-r--r--src/tools/clippy/clippy_utils/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/macros.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/msrvs.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs108
-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/rustc_tools_util/CHANGELOG.md6
-rw-r--r--src/tools/clippy/rustc_tools_util/Cargo.toml2
-rw-r--r--src/tools/clippy/rustc_tools_util/README.md38
-rw-r--r--src/tools/clippy/rustc_tools_util/src/lib.rs48
-rw-r--r--src/tools/clippy/src/driver.rs1
-rw-r--r--src/tools/clippy/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr16
-rw-r--r--src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs123
-rw-r--r--src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.stderr58
-rw-r--r--src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml12
-rw-r--r--src/tools/clippy/tests/ui-toml/suppress_lint_in_const/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs60
-rw-r--r--src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr70
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr3
-rw-r--r--src/tools/clippy/tests/ui/almost_complete_letter_range.stderr113
-rw-r--r--src/tools/clippy/tests/ui/almost_complete_range.fixed (renamed from src/tools/clippy/tests/ui/almost_complete_letter_range.fixed)49
-rw-r--r--src/tools/clippy/tests/ui/almost_complete_range.rs (renamed from src/tools/clippy/tests/ui/almost_complete_letter_range.rs)49
-rw-r--r--src/tools/clippy/tests/ui/almost_complete_range.stderr235
-rw-r--r--src/tools/clippy/tests/ui/arithmetic_side_effects.stderr24
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/macro_rules.rs4
-rw-r--r--src/tools/clippy/tests/ui/cast_lossless_integer.fixed6
-rw-r--r--src/tools/clippy/tests/ui/cast_lossless_integer.rs6
-rw-r--r--src/tools/clippy/tests/ui/collapsible_str_replace.fixed11
-rw-r--r--src/tools/clippy/tests/ui/collapsible_str_replace.rs11
-rw-r--r--src/tools/clippy/tests/ui/collapsible_str_replace.stderr34
-rw-r--r--src/tools/clippy/tests/ui/explicit_counter_loop.rs30
-rw-r--r--src/tools/clippy/tests/ui/from_over_into.fixed7
-rw-r--r--src/tools/clippy/tests/ui/from_over_into.rs7
-rw-r--r--src/tools/clippy/tests/ui/from_over_into.stderr10
-rw-r--r--src/tools/clippy/tests/ui/identity_op.fixed6
-rw-r--r--src/tools/clippy/tests/ui/identity_op.rs4
-rw-r--r--src/tools/clippy/tests/ui/identity_op.stderr12
-rw-r--r--src/tools/clippy/tests/ui/implicit_clone.fixed10
-rw-r--r--src/tools/clippy/tests/ui/implicit_clone.rs10
-rw-r--r--src/tools/clippy/tests/ui/indexing_slicing_index.rs6
-rw-r--r--src/tools/clippy/tests/ui/indexing_slicing_index.stderr44
-rw-r--r--src/tools/clippy/tests/ui/len_zero.fixed40
-rw-r--r--src/tools/clippy/tests/ui/len_zero.rs40
-rw-r--r--src/tools/clippy/tests/ui/len_zero.stderr74
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.edition2018.fixed5
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.edition2021.fixed5
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.edition2021.stderr2
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.rs5
-rw-r--r--src/tools/clippy/tests/ui/manual_is_ascii_check.fixed13
-rw-r--r--src/tools/clippy/tests/ui/manual_is_ascii_check.rs13
-rw-r--r--src/tools/clippy/tests/ui/manual_is_ascii_check.stderr64
-rw-r--r--src/tools/clippy/tests/ui/manual_let_else_match.rs7
-rw-r--r--src/tools/clippy/tests/ui/manual_let_else_match.stderr15
-rw-r--r--src/tools/clippy/tests/ui/needless_parens_on_range_literals.fixed2
-rw-r--r--src/tools/clippy/tests/ui/needless_parens_on_range_literals.rs2
-rw-r--r--src/tools/clippy/tests/ui/new_ret_no_self.rs23
-rw-r--r--src/tools/clippy/tests/ui/new_ret_no_self.stderr42
-rw-r--r--src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed6
-rw-r--r--src/tools/clippy/tests/ui/redundant_static_lifetimes.rs6
-rw-r--r--src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr10
-rw-r--r--src/tools/clippy/tests/ui/rename.fixed2
-rw-r--r--src/tools/clippy/tests/ui/rename.rs2
-rw-r--r--src/tools/clippy/tests/ui/rename.stderr92
-rw-r--r--src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.fixed6
-rw-r--r--src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs6
-rw-r--r--src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.stderr2
-rw-r--r--src/tools/clippy/tests/ui/semicolon_inside_block.fixed85
-rw-r--r--src/tools/clippy/tests/ui/semicolon_inside_block.rs85
-rw-r--r--src/tools/clippy/tests/ui/semicolon_inside_block.stderr54
-rw-r--r--src/tools/clippy/tests/ui/semicolon_outside_block.fixed85
-rw-r--r--src/tools/clippy/tests/ui/semicolon_outside_block.rs85
-rw-r--r--src/tools/clippy/tests/ui/semicolon_outside_block.stderr54
-rw-r--r--src/tools/clippy/tests/ui/string_lit_as_bytes.fixed6
-rw-r--r--src/tools/clippy/tests/ui/string_lit_as_bytes.rs6
-rw-r--r--src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.fixed3
-rw-r--r--src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.fixed3
-rw-r--r--src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.stderr26
-rw-r--r--src/tools/clippy/tests/ui/uninlined_format_args_panic.rs3
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned.fixed20
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned.rs20
-rw-r--r--src/tools/clippy/tests/ui/zero_ptr_no_std.fixed21
-rw-r--r--src/tools/clippy/tests/ui/zero_ptr_no_std.rs21
-rw-r--r--src/tools/clippy/tests/ui/zero_ptr_no_std.stderr26
-rw-r--r--src/tools/clippy/tests/versioncheck.rs1
-rw-r--r--src/tools/clippy/triagebot.toml2
-rw-r--r--src/tools/remote-test-server/src/main.rs49
-rw-r--r--src/tools/tidy/src/main.rs22
-rw-r--r--src/tools/tidy/src/style.rs59
-rw-r--r--src/tools/x/src/main.rs72
279 files changed, 5241 insertions, 1405 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 5d05a09f038..1d9a9240ccf 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -294,7 +294,7 @@ dependencies = [
 
 [[package]]
 name = "cargo"
-version = "0.68.0"
+version = "0.69.0"
 dependencies = [
  "anyhow",
  "bytesize",
@@ -394,7 +394,7 @@ dependencies = [
  "directories",
  "rustc-build-sysroot",
  "rustc-workspace-hack",
- "rustc_tools_util",
+ "rustc_tools_util 0.2.1",
  "rustc_version",
  "serde",
  "serde_json",
@@ -658,7 +658,7 @@ dependencies = [
 
 [[package]]
 name = "clippy"
-version = "0.1.67"
+version = "0.1.68"
 dependencies = [
  "clippy_lints",
  "clippy_utils",
@@ -673,7 +673,7 @@ dependencies = [
  "regex",
  "rustc-semver",
  "rustc-workspace-hack",
- "rustc_tools_util",
+ "rustc_tools_util 0.3.0",
  "semver",
  "serde",
  "syn",
@@ -700,7 +700,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_lints"
-version = "0.1.67"
+version = "0.1.68"
 dependencies = [
  "cargo_metadata 0.14.0",
  "clippy_utils",
@@ -723,7 +723,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_utils"
-version = "0.1.67"
+version = "0.1.68"
 dependencies = [
  "arrayvec",
  "if_chain",
@@ -966,9 +966,9 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-deque"
-version = "0.8.1"
+version = "0.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
+checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"
 dependencies = [
  "cfg-if 1.0.0",
  "crossbeam-epoch",
@@ -977,25 +977,24 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-epoch"
-version = "0.9.6"
+version = "0.9.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97242a70df9b89a65d0b6df3c4bf5b9ce03c5b7309019777fbde37e7537f8762"
+checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a"
 dependencies = [
+ "autocfg",
  "cfg-if 1.0.0",
  "crossbeam-utils",
- "lazy_static",
  "memoffset",
  "scopeguard",
 ]
 
 [[package]]
 name = "crossbeam-utils"
-version = "0.8.8"
+version = "0.8.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
+checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
 dependencies = [
  "cfg-if 1.0.0",
- "lazy_static",
 ]
 
 [[package]]
@@ -1068,7 +1067,7 @@ checksum = "a0afaad2b26fa326569eb264b1363e8ae3357618c43982b3f285f0774ce76b69"
 
 [[package]]
 name = "declare_clippy_lint"
-version = "0.1.67"
+version = "0.1.68"
 dependencies = [
  "itertools",
  "quote",
@@ -2379,9 +2378,9 @@ dependencies = [
 
 [[package]]
 name = "memoffset"
-version = "0.6.5"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
+checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
 dependencies = [
  "autocfg",
 ]
@@ -4070,6 +4069,7 @@ dependencies = [
  "rustc_hir",
  "rustc_index",
  "rustc_infer",
+ "rustc_macros",
  "rustc_middle",
  "rustc_serialize",
  "rustc_session",
@@ -4430,6 +4430,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "598f48ce2a421542b3e64828aa742b687cc1b91d2f96591cfdb7ac5988cd6366"
 
 [[package]]
+name = "rustc_tools_util"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ba09476327c4b70ccefb6180f046ef588c26a24cf5d269a9feba316eb4f029f"
+
+[[package]]
 name = "rustc_trait_selection"
 version = "0.0.0"
 dependencies = [
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 8c71332bfab..4582d3c6bad 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -774,6 +774,18 @@ impl Integer {
         }
     }
 
+    /// Returns the largest signed value that can be represented by this Integer.
+    #[inline]
+    pub fn signed_max(self) -> i128 {
+        match self {
+            I8 => i8::MAX as i128,
+            I16 => i16::MAX as i128,
+            I32 => i32::MAX as i128,
+            I64 => i64::MAX as i128,
+            I128 => i128::MAX,
+        }
+    }
+
     /// Finds the smallest Integer type which can represent the signed value.
     #[inline]
     pub fn fit_signed(x: i128) -> Integer {
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 73065ab5163..9d4c2900eaf 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1,6 +1,6 @@
 use super::errors::{InvalidAbi, InvalidAbiSuggestion, MisplacedRelaxTraitBound};
 use super::ResolverAstLoweringExt;
-use super::{Arena, AstOwner, ImplTraitContext, ImplTraitPosition};
+use super::{AstOwner, ImplTraitContext, ImplTraitPosition};
 use super::{FnDeclKind, LoweringContext, ParamMode};
 
 use rustc_ast::ptr::P;
@@ -24,7 +24,6 @@ use thin_vec::ThinVec;
 pub(super) struct ItemLowerer<'a, 'hir> {
     pub(super) tcx: TyCtxt<'hir>,
     pub(super) resolver: &'a mut ResolverAstLowering,
-    pub(super) ast_arena: &'a Arena<'static>,
     pub(super) ast_index: &'a IndexVec<LocalDefId, AstOwner<'a>>,
     pub(super) owners: &'a mut IndexVec<LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>>,
 }
@@ -60,7 +59,6 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
             tcx: self.tcx,
             resolver: self.resolver,
             arena: self.tcx.hir_arena,
-            ast_arena: self.ast_arena,
 
             // HirId handling.
             bodies: Vec::new(),
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index d67ede6e130..0ef784a4453 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -42,7 +42,6 @@ extern crate tracing;
 
 use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait, TraitFnAsync};
 
-use rustc_arena::declare_arena;
 use rustc_ast::ptr::P;
 use rustc_ast::visit;
 use rustc_ast::{self as ast, *};
@@ -94,13 +93,6 @@ struct LoweringContext<'a, 'hir> {
     /// Used to allocate HIR nodes.
     arena: &'hir hir::Arena<'hir>,
 
-    /// Used to allocate temporary AST nodes for use during lowering.
-    /// This allows us to create "fake" AST -- these nodes can sometimes
-    /// be allocated on the stack, but other times we need them to live longer
-    /// than the current stack frame, so they can be collected into vectors
-    /// and things like that.
-    ast_arena: &'a Arena<'static>,
-
     /// Bodies inside the owner being lowered.
     bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>,
     /// Attributes inside the owner being lowered.
@@ -146,15 +138,6 @@ struct LoweringContext<'a, 'hir> {
     generics_def_id_map: Vec<FxHashMap<LocalDefId, LocalDefId>>,
 }
 
-declare_arena!([
-    [] tys: rustc_ast::Ty,
-    [] aba: rustc_ast::AngleBracketedArgs,
-    [] ptr: rustc_ast::PolyTraitRef,
-    // This _marker field is needed because `declare_arena` creates `Arena<'tcx>` and we need to
-    // use `'tcx`. If we don't have this we get a compile error.
-    [] _marker: std::marker::PhantomData<&'tcx ()>,
-]);
-
 trait ResolverAstLoweringExt {
     fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>>;
     fn get_partial_res(&self, id: NodeId) -> Option<PartialRes>;
@@ -442,13 +425,10 @@ pub fn lower_to_hir<'hir>(tcx: TyCtxt<'hir>, (): ()) -> hir::Crate<'hir> {
         tcx.definitions_untracked().def_index_count(),
     );
 
-    let ast_arena = Arena::default();
-
     for def_id in ast_index.indices() {
         item::ItemLowerer {
             tcx,
             resolver: &mut resolver,
-            ast_arena: &ast_arena,
             ast_index: &ast_index,
             owners: &mut owners,
         }
@@ -620,7 +600,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         self.impl_trait_defs = current_impl_trait_defs;
         self.impl_trait_bounds = current_impl_trait_bounds;
 
-        debug_assert!(self.children.iter().find(|(id, _)| id == &def_id).is_none());
+        debug_assert!(!self.children.iter().any(|(id, _)| id == &def_id));
         self.children.push((def_id, hir::MaybeOwner::Owner(info)));
     }
 
@@ -1001,8 +981,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 }
                 GenericArgs::Parenthesized(data) => {
                     self.emit_bad_parenthesized_trait_in_assoc_ty(data);
-                    let aba = self.ast_arena.aba.alloc(data.as_angle_bracketed_args());
-                    self.lower_angle_bracketed_parameter_data(aba, ParamMode::Explicit, itctx).0
+                    self.lower_angle_bracketed_parameter_data(
+                        &data.as_angle_bracketed_args(),
+                        ParamMode::Explicit,
+                        itctx,
+                    )
+                    .0
                 }
             };
             gen_args_ctor.into_generic_args(self)
@@ -1067,13 +1051,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
                     self.with_dyn_type_scope(false, |this| {
                         let node_id = this.next_node_id();
-                        let ty = this.ast_arena.tys.alloc(Ty {
-                            id: node_id,
-                            kind: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()),
-                            span: this.lower_span(constraint.span),
-                            tokens: None,
-                        });
-                        let ty = this.lower_ty(ty, itctx);
+                        let ty = this.lower_ty(
+                            &Ty {
+                                id: node_id,
+                                kind: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()),
+                                span: this.lower_span(constraint.span),
+                                tokens: None,
+                            },
+                            itctx,
+                        );
 
                         hir::TypeBindingKind::Equality { term: ty.into() }
                     })
@@ -1217,13 +1203,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             && let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) = partial_res.full_res()
         {
             let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| {
-                let poly_trait_ref = this.ast_arena.ptr.alloc(PolyTraitRef {
-                    bound_generic_params: vec![],
-                    trait_ref: TraitRef { path: path.clone(), ref_id: t.id },
-                    span: t.span
-                });
                 let bound = this.lower_poly_trait_ref(
-                    poly_trait_ref,
+                    &PolyTraitRef {
+                        bound_generic_params: vec![],
+                        trait_ref: TraitRef { path: path.clone(), ref_id: t.id },
+                        span: t.span
+                    },
                     itctx,
                 );
                 let bounds = this.arena.alloc_from_iter([bound]);
diff --git a/compiler/rustc_borrowck/src/constraints/graph.rs b/compiler/rustc_borrowck/src/constraints/graph.rs
index 385f153174c..c780d047992 100644
--- a/compiler/rustc_borrowck/src/constraints/graph.rs
+++ b/compiler/rustc_borrowck/src/constraints/graph.rs
@@ -148,7 +148,7 @@ impl<'s, 'tcx, D: ConstraintGraphDirecton> Iterator for Edges<'s, 'tcx, D> {
         if let Some(p) = self.pointer {
             self.pointer = self.graph.next_constraints[p];
 
-            Some(self.constraints[p].clone())
+            Some(self.constraints[p])
         } else if let Some(next_static_idx) = self.next_static_idx {
             self.next_static_idx = if next_static_idx == (self.graph.first_constraints.len() - 1) {
                 None
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 72c0257756e..8d5c5a7124f 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -649,7 +649,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         if !assign_value.is_empty() {
             err.span_suggestion_verbose(
                 sugg_span.shrink_to_hi(),
-                format!("consider assigning a value"),
+                "consider assigning a value",
                 format!(" = {}", assign_value),
                 Applicability::MaybeIncorrect,
             );
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 304683618d8..00f5e8a8397 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -270,7 +270,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
                 for extra in extra_info {
                     match extra {
                         ExtraConstraintInfo::PlaceholderFromPredicate(span) => {
-                            err.span_note(*span, format!("due to current limitations in the borrow checker, this implies a `'static` lifetime"));
+                            err.span_note(*span, "due to current limitations in the borrow checker, this implies a `'static` lifetime");
                         }
                     }
                 }
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index f8ec5e5e799..b5a0044e9e8 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -472,7 +472,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         for extra in extra_info {
             match extra {
                 ExtraConstraintInfo::PlaceholderFromPredicate(span) => {
-                    diag.span_note(span, format!("due to current limitations in the borrow checker, this implies a `'static` lifetime"));
+                    diag.span_note(span, "due to current limitations in the borrow checker, this implies a `'static` lifetime");
                 }
             }
         }
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 5289de9b0ab..d8c22fbe59f 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -2059,12 +2059,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     ) -> Option<InitIndex> {
         let mpi = self.move_data.rev_lookup.find_local(local);
         let ii = &self.move_data.init_path_map[mpi];
-        for &index in ii {
-            if flow_state.ever_inits.contains(index) {
-                return Some(index);
-            }
-        }
-        None
+        ii.into_iter().find(|&&index| flow_state.ever_inits.contains(index)).copied()
     }
 
     /// Adds the place into the used mutable variables set
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index e9c98bdc514..0d03346ef0a 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -831,7 +831,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             if self.eval_verify_bound(
                 infcx,
                 param_env,
-                body,
                 generic_ty,
                 type_test.lower_bound,
                 &type_test.verify_bound,
@@ -962,14 +961,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             // where `ur` is a local bound -- we are sometimes in a
             // position to prove things that our caller cannot.  See
             // #53570 for an example.
-            if self.eval_verify_bound(
-                infcx,
-                param_env,
-                body,
-                generic_ty,
-                ur,
-                &type_test.verify_bound,
-            ) {
+            if self.eval_verify_bound(infcx, param_env, generic_ty, ur, &type_test.verify_bound) {
                 continue;
             }
 
@@ -1190,7 +1182,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         &self,
         infcx: &InferCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        body: &Body<'tcx>,
         generic_ty: Ty<'tcx>,
         lower_bound: RegionVid,
         verify_bound: &VerifyBound<'tcx>,
@@ -1213,25 +1204,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             }
 
             VerifyBound::AnyBound(verify_bounds) => verify_bounds.iter().any(|verify_bound| {
-                self.eval_verify_bound(
-                    infcx,
-                    param_env,
-                    body,
-                    generic_ty,
-                    lower_bound,
-                    verify_bound,
-                )
+                self.eval_verify_bound(infcx, param_env, generic_ty, lower_bound, verify_bound)
             }),
 
             VerifyBound::AllBounds(verify_bounds) => verify_bounds.iter().all(|verify_bound| {
-                self.eval_verify_bound(
-                    infcx,
-                    param_env,
-                    body,
-                    generic_ty,
-                    lower_bound,
-                    verify_bound,
-                )
+                self.eval_verify_bound(infcx, param_env, generic_ty, lower_bound, verify_bound)
             }),
         }
     }
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 814bc275019..8d4a720f8ce 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -612,7 +612,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
 
         let locations = location.to_locations();
         for constraint in constraints.outlives().iter() {
-            let mut constraint = constraint.clone();
+            let mut constraint = *constraint;
             constraint.locations = locations;
             if let ConstraintCategory::Return(_)
             | ConstraintCategory::UseAsConst
diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs
index 41531580c19..f8761653bf5 100644
--- a/compiler/rustc_builtin_macros/src/global_allocator.rs
+++ b/compiler/rustc_builtin_macros/src/global_allocator.rs
@@ -35,7 +35,7 @@ pub fn expand(
             (item, true, ecx.with_def_site_ctxt(ty.span))
         } else {
             ecx.sess.parse_sess.span_diagnostic.span_err(item.span(), "allocators must be statics");
-            return vec![orig_item.clone()]
+            return vec![orig_item];
         };
 
     // Generate a bunch of new items using the AllocFnFactory
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index f5f02fc772a..729ae4071e2 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -239,8 +239,7 @@ pub fn expand_test_or_bench(
             cx.attr_nested_word(sym::cfg, sym::test, attr_sp),
             // #[rustc_test_marker = "test_case_sort_key"]
             cx.attr_name_value_str(sym::rustc_test_marker, test_path_symbol, attr_sp),
-        ]
-        .into(),
+        ],
         // const $ident: test::TestDescAndFn =
         ast::ItemKind::Const(
             ast::Defaultness::Final,
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index 219a4f8fa89..606f710641f 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -144,7 +144,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                     // We prefer the latter because it matches the behavior of
                     // Clang.
                     if late && matches!(reg, InlineAsmRegOrRegClass::Reg(_)) {
-                        constraints.push(format!("{}", reg_to_llvm(reg, Some(&in_value.layout))));
+                        constraints.push(reg_to_llvm(reg, Some(&in_value.layout)).to_string());
                     } else {
                         constraints.push(format!("{}", op_idx[&idx]));
                     }
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index e20dc906bce..6c0faf37a63 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -425,7 +425,7 @@ fn thin_lto(
         info!("going for that thin, thin LTO");
 
         let green_modules: FxHashMap<_, _> =
-            cached_modules.iter().map(|&(_, ref wp)| (wp.cgu_name.clone(), wp.clone())).collect();
+            cached_modules.iter().map(|(_, wp)| (wp.cgu_name.clone(), wp.clone())).collect();
 
         let full_scope_len = modules.len() + serialized_modules.len() + cached_modules.len();
         let mut thin_buffers = Vec::with_capacity(modules.len());
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 853a8b82853..5bf45a81e43 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -233,8 +233,8 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         // Set KCFI operand bundle
         let is_indirect_call = unsafe { llvm::LLVMIsAFunction(llfn).is_none() };
         let kcfi_bundle =
-            if self.tcx.sess.is_sanitizer_kcfi_enabled() && fn_abi.is_some() && is_indirect_call {
-                let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi.unwrap());
+            if self.tcx.sess.is_sanitizer_kcfi_enabled() && let Some(fn_abi) = fn_abi && is_indirect_call {
+                let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi);
                 Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)]))
             } else {
                 None
diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs
index 5266d8858d4..6eb120157da 100644
--- a/compiler/rustc_codegen_ssa/src/back/archive.rs
+++ b/compiler/rustc_codegen_ssa/src/back/archive.rs
@@ -123,7 +123,7 @@ fn try_filter_fat_archs<'a>(
 ) -> io::Result<Option<(&'a [u8], u64)>> {
     let archs = archs.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
 
-    let desired = match archs.iter().filter(|a| a.architecture() == target_arch).next() {
+    let desired = match archs.iter().find(|a| a.architecture() == target_arch) {
         Some(a) => a,
         None => return Ok(None),
     };
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index fe2e4b36cd0..a1c77ec0cfc 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -722,7 +722,7 @@ fn link_natively<'a>(
 
     linker::disable_localization(&mut cmd);
 
-    for &(ref k, ref v) in sess.target.link_env.as_ref() {
+    for (k, v) in sess.target.link_env.as_ref() {
         cmd.env(k.as_ref(), v.as_ref());
     }
     for k in sess.target.link_env_remove.as_ref() {
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index f087d903e55..0268659d3b9 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -108,7 +108,7 @@ pub fn get_linker<'a>(
     if sess.target.is_like_msvc {
         if let Some(ref tool) = msvc_tool {
             cmd.args(tool.args());
-            for &(ref k, ref v) in tool.env() {
+            for (k, v) in tool.env() {
                 if k == "PATH" {
                     new_path.extend(env::split_paths(v));
                     msvc_changed_path = true;
diff --git a/compiler/rustc_codegen_ssa/src/glue.rs b/compiler/rustc_codegen_ssa/src/glue.rs
index 6015d48deca..0f6e6032f9b 100644
--- a/compiler/rustc_codegen_ssa/src/glue.rs
+++ b/compiler/rustc_codegen_ssa/src/glue.rs
@@ -29,6 +29,9 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
             let align = meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_ALIGN)
                 .get_usize(bx, vtable);
 
+            // Size is always <= isize::MAX.
+            let size_bound = bx.data_layout().ptr_sized_integer().signed_max() as u128;
+            bx.range_metadata(size, WrappingRange { start: 0, end: size_bound });
             // Alignment is always nonzero.
             bx.range_metadata(align, WrappingRange { start: 1, end: !0 });
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 215edbe02c0..a75609260ed 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -110,10 +110,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     _ => bug!(),
                 };
                 let value = meth::VirtualIndex::from_index(idx).get_usize(bx, vtable);
-                if name == sym::vtable_align {
+                match name {
+                    // Size is always <= isize::MAX.
+                    sym::vtable_size => {
+                        let size_bound = bx.data_layout().ptr_sized_integer().signed_max() as u128;
+                        bx.range_metadata(value, WrappingRange { start: 0, end: size_bound });
+                    },
                     // Alignment is always nonzero.
-                    bx.range_metadata(value, WrappingRange { start: 1, end: !0 });
-                };
+                    sym::vtable_align => bx.range_metadata(value, WrappingRange { start: 1, end: !0 }),
+                    _ => {}
+                }
                 value
             }
             sym::pref_align_of
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index b1fdeb01b10..986b6d65530 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -332,7 +332,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     Immediate::new_slice(ptr, length.eval_usize(*self.tcx, self.param_env), self);
                 self.write_immediate(val, dest)
             }
-            (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
+            (ty::Dynamic(data_a, ..), ty::Dynamic(data_b, ..)) => {
                 let val = self.read_immediate(src)?;
                 if data_a.principal() == data_b.principal() {
                     // A NOP cast that doesn't actually change anything, should be allowed even with mismatching vtables.
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index 221e359d24a..f9e3a2bdc06 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -39,7 +39,7 @@ pub enum Immediate<Prov: Provenance = AllocId> {
 impl<Prov: Provenance> From<Scalar<Prov>> for Immediate<Prov> {
     #[inline(always)]
     fn from(val: Scalar<Prov>) -> Self {
-        Immediate::Scalar(val.into())
+        Immediate::Scalar(val)
     }
 }
 
@@ -53,7 +53,7 @@ impl<Prov: Provenance> Immediate<Prov> {
     }
 
     pub fn new_slice(val: Scalar<Prov>, len: u64, cx: &impl HasDataLayout) -> Self {
-        Immediate::ScalarPair(val.into(), Scalar::from_machine_usize(len, cx).into())
+        Immediate::ScalarPair(val, Scalar::from_machine_usize(len, cx))
     }
 
     pub fn new_dyn_trait(
@@ -61,7 +61,7 @@ impl<Prov: Provenance> Immediate<Prov> {
         vtable: Pointer<Option<Prov>>,
         cx: &impl HasDataLayout,
     ) -> Self {
-        Immediate::ScalarPair(val.into(), Scalar::from_maybe_pointer(vtable, cx))
+        Immediate::ScalarPair(val, Scalar::from_maybe_pointer(vtable, cx))
     }
 
     #[inline]
@@ -341,10 +341,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     alloc_range(b_offset, b_size),
                     /*read_provenance*/ b.is_ptr(),
                 )?;
-                Some(ImmTy {
-                    imm: Immediate::ScalarPair(a_val.into(), b_val.into()),
-                    layout: mplace.layout,
-                })
+                Some(ImmTy { imm: Immediate::ScalarPair(a_val, b_val), layout: mplace.layout })
             }
             _ => {
                 // Neither a scalar nor scalar pair.
diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs
index 949f95c5fa8..e8ff70e3a40 100644
--- a/compiler/rustc_const_eval/src/interpret/operator.rs
+++ b/compiler/rustc_const_eval/src/interpret/operator.rs
@@ -36,7 +36,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         if let Abi::ScalarPair(..) = dest.layout.abi {
             // We can use the optimized path and avoid `place_field` (which might do
             // `force_allocation`).
-            let pair = Immediate::ScalarPair(val.into(), Scalar::from_bool(overflowed).into());
+            let pair = Immediate::ScalarPair(val, Scalar::from_bool(overflowed));
             self.write_immediate(pair, dest)?;
         } else {
             assert!(self.tcx.sess.opts.unstable_opts.randomize_layout);
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 905eb71bb18..97a73e98abc 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -141,7 +141,7 @@ impl<Prov: Provenance> MemPlace<Prov> {
         match self.meta {
             MemPlaceMeta::None => Immediate::from(Scalar::from_maybe_pointer(self.ptr, cx)),
             MemPlaceMeta::Meta(meta) => {
-                Immediate::ScalarPair(Scalar::from_maybe_pointer(self.ptr, cx).into(), meta.into())
+                Immediate::ScalarPair(Scalar::from_maybe_pointer(self.ptr, cx), meta)
             }
         }
     }
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index 31a709c36d4..67c512e98d6 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -163,6 +163,7 @@ E0311: include_str!("./error_codes/E0311.md"),
 E0312: include_str!("./error_codes/E0312.md"),
 E0316: include_str!("./error_codes/E0316.md"),
 E0317: include_str!("./error_codes/E0317.md"),
+E0320: include_str!("./error_codes/E0320.md"),
 E0321: include_str!("./error_codes/E0321.md"),
 E0322: include_str!("./error_codes/E0322.md"),
 E0323: include_str!("./error_codes/E0323.md"),
@@ -575,7 +576,6 @@ E0791: include_str!("./error_codes/E0791.md"),
 //  E0314, // closure outlives stack frame
 //  E0315, // cannot invoke closure outside of its lifetime
 //  E0319, // trait impls for defaulted traits allowed just for structs/enums
-    E0320, // recursive overflow during dropck
 //  E0372, // coherence not object safe
     E0377, // the trait `CoerceUnsized` may only be implemented for a coercion
            // between structures with the same definition
diff --git a/compiler/rustc_error_codes/src/error_codes/E0320.md b/compiler/rustc_error_codes/src/error_codes/E0320.md
new file mode 100644
index 00000000000..e6e1b7c19a5
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0320.md
@@ -0,0 +1,27 @@
+Recursion limit reached while creating drop-check rules.
+
+Example of erroneous code:
+
+```compile_fail,E0320
+enum A<T> {
+    B,
+    C(T, Box<A<(T, T)>>)
+}
+
+fn foo<T>() {
+    A::<T>::B; // error: overflow while adding drop-check rules for A<T>
+}
+```
+
+The Rust compiler must be able to reason about how a type is [`Drop`]ped, and
+by extension the types of its fields, to be able to generate the glue to
+properly drop a value. The code example above shows a type where this inference
+is impossible because it is recursive. Note that this is *not* the same as
+[E0072](E0072.html), where a type has an infinite size; the type here has a
+finite size but any attempt to `Drop` it would recurse infinitely. For more
+information, read [the `Drop` docs](../std/ops/trait.Drop.html).
+
+It is not possible to define a type with recursive drop-check rules. All such
+recursion must be removed.
+
+[`Drop`]: ../std/ops/trait.Drop.html
diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
new file mode 100644
index 00000000000..60d3d3e69ab
--- /dev/null
+++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
@@ -0,0 +1,301 @@
+mir_build_unconditional_recursion = function cannot return without recursing
+    .label = cannot return without recursing
+    .help = a `loop` may express intention better if this is on purpose
+
+mir_build_unconditional_recursion_call_site_label = recursive call site
+
+mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe =
+    call to unsafe function `{$function}` is unsafe and requires unsafe block (error E0133)
+    .note = consult the function's documentation for information on how to avoid undefined behavior
+    .label = call to unsafe function
+
+mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe_nameless =
+    call to unsafe function is unsafe and requires unsafe block (error E0133)
+    .note = consult the function's documentation for information on how to avoid undefined behavior
+    .label = call to unsafe function
+
+mir_build_unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe =
+    use of inline assembly is unsafe and requires unsafe block (error E0133)
+    .note = inline assembly is entirely unchecked and can cause undefined behavior
+    .label = use of inline assembly
+
+mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe =
+    initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe
+    block (error E0133)
+    .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
+    .label = initializing type with `rustc_layout_scalar_valid_range` attr
+
+mir_build_unsafe_op_in_unsafe_fn_mutable_static_requires_unsafe =
+    use of mutable static is unsafe and requires unsafe block (error E0133)
+    .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+    .label = use of mutable static
+
+mir_build_unsafe_op_in_unsafe_fn_extern_static_requires_unsafe =
+    use of extern static is unsafe and requires unsafe block (error E0133)
+    .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+    .label = use of extern static
+
+mir_build_unsafe_op_in_unsafe_fn_deref_raw_pointer_requires_unsafe =
+    dereference of raw pointer is unsafe and requires unsafe block (error E0133)
+    .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+    .label = dereference of raw pointer
+
+mir_build_unsafe_op_in_unsafe_fn_union_field_requires_unsafe =
+    access to union field is unsafe and requires unsafe block (error E0133)
+    .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
+    .label = access to union field
+
+mir_build_unsafe_op_in_unsafe_fn_mutation_of_layout_constrained_field_requires_unsafe =
+    mutation of layout constrained field is unsafe and requires unsafe block (error E0133)
+    .note = mutating layout constrained fields cannot statically be checked for valid values
+    .label = mutation of layout constrained field
+
+mir_build_unsafe_op_in_unsafe_fn_borrow_of_layout_constrained_field_requires_unsafe =
+    borrow of layout constrained field with interior mutability is unsafe and requires unsafe block (error E0133)
+    .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
+    .label = borrow of layout constrained field with interior mutability
+
+mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe =
+    call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block (error E0133)
+    .note = can only be called if the required target features are available
+    .label = call to function with `#[target_feature]`
+
+mir_build_call_to_unsafe_fn_requires_unsafe =
+    call to unsafe function `{$function}` is unsafe and requires unsafe block
+    .note = consult the function's documentation for information on how to avoid undefined behavior
+    .label = call to unsafe function
+
+mir_build_call_to_unsafe_fn_requires_unsafe_nameless =
+    call to unsafe function is unsafe and requires unsafe block
+    .note = consult the function's documentation for information on how to avoid undefined behavior
+    .label = call to unsafe function
+
+mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    call to unsafe function `{$function}` is unsafe and requires unsafe function or block
+    .note = consult the function's documentation for information on how to avoid undefined behavior
+    .label = call to unsafe function
+
+mir_build_call_to_unsafe_fn_requires_unsafe_nameless_unsafe_op_in_unsafe_fn_allowed =
+    call to unsafe function is unsafe and requires unsafe function or block
+    .note = consult the function's documentation for information on how to avoid undefined behavior
+    .label = call to unsafe function
+
+mir_build_inline_assembly_requires_unsafe =
+    use of inline assembly is unsafe and requires unsafe block
+    .note = inline assembly is entirely unchecked and can cause undefined behavior
+    .label = use of inline assembly
+
+mir_build_inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    use of inline assembly is unsafe and requires unsafe function or block
+    .note = inline assembly is entirely unchecked and can cause undefined behavior
+    .label = use of inline assembly
+
+mir_build_initializing_type_with_requires_unsafe =
+    initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe block
+    .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
+    .label = initializing type with `rustc_layout_scalar_valid_range` attr
+
+mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block
+    .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
+    .label = initializing type with `rustc_layout_scalar_valid_range` attr
+
+mir_build_mutable_static_requires_unsafe =
+    use of mutable static is unsafe and requires unsafe block
+    .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+    .label = use of mutable static
+
+mir_build_mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    use of mutable static is unsafe and requires unsafe function or block
+    .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+    .label = use of mutable static
+
+mir_build_extern_static_requires_unsafe =
+    use of extern static is unsafe and requires unsafe block
+    .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+    .label = use of extern static
+
+mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    use of extern static is unsafe and requires unsafe function or block
+    .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+    .label = use of extern static
+
+mir_build_deref_raw_pointer_requires_unsafe =
+    dereference of raw pointer is unsafe and requires unsafe block
+    .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+    .label = dereference of raw pointer
+
+mir_build_deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    dereference of raw pointer is unsafe and requires unsafe function or block
+    .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+    .label = dereference of raw pointer
+
+mir_build_union_field_requires_unsafe =
+    access to union field is unsafe and requires unsafe block
+    .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
+    .label = access to union field
+
+mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    access to union field is unsafe and requires unsafe function or block
+    .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
+    .label = access to union field
+
+mir_build_mutation_of_layout_constrained_field_requires_unsafe =
+    mutation of layout constrained field is unsafe and requires unsafe block
+    .note = mutating layout constrained fields cannot statically be checked for valid values
+    .label = mutation of layout constrained field
+
+mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    mutation of layout constrained field is unsafe and requires unsafe function or block
+    .note = mutating layout constrained fields cannot statically be checked for valid values
+    .label = mutation of layout constrained field
+
+mir_build_borrow_of_layout_constrained_field_requires_unsafe =
+    borrow of layout constrained field with interior mutability is unsafe and requires unsafe block
+    .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
+    .label = borrow of layout constrained field with interior mutability
+
+mir_build_borrow_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block
+    .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
+    .label = borrow of layout constrained field with interior mutability
+
+mir_build_call_to_fn_with_requires_unsafe =
+    call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block
+    .note = can only be called if the required target features are available
+    .label = call to function with `#[target_feature]`
+
+mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+    call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe function or block
+    .note = can only be called if the required target features are available
+    .label = call to function with `#[target_feature]`
+
+mir_build_unused_unsafe = unnecessary `unsafe` block
+    .label = unnecessary `unsafe` block
+
+mir_build_unused_unsafe_enclosing_block_label = because it's nested under this `unsafe` block
+mir_build_unused_unsafe_enclosing_fn_label = because it's nested under this `unsafe` fn
+
+mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type `{$ty}` is non-empty
+    .def_note = `{$peeled_ty}` defined here
+    .type_note = the matched value is of type `{$ty}`
+    .non_exhaustive_type_note = the matched value is of type `{$ty}`, which is marked as non-exhaustive
+    .reference_note = references are always considered inhabited
+    .suggestion = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+    .help = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
+
+mir_build_static_in_pattern = statics cannot be referenced in patterns
+
+mir_build_assoc_const_in_pattern = associated consts cannot be referenced in patterns
+
+mir_build_const_param_in_pattern = const parameters cannot be referenced in patterns
+
+mir_build_non_const_path = runtime values cannot be referenced in patterns
+
+mir_build_unreachable_pattern = unreachable pattern
+    .label = unreachable pattern
+    .catchall_label = matches any value
+
+mir_build_const_pattern_depends_on_generic_parameter =
+    constant pattern depends on a generic parameter
+
+mir_build_could_not_eval_const_pattern = could not evaluate constant pattern
+
+mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper =
+    lower range bound must be less than or equal to upper
+    .label = lower bound larger than upper bound
+    .teach_note = When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range.
+
+mir_build_lower_range_bound_must_be_less_than_upper = lower range bound must be less than upper
+
+mir_build_leading_irrefutable_let_patterns = leading irrefutable {$count ->
+        [one] pattern
+        *[other] patterns
+    } in let chain
+    .note = {$count ->
+        [one] this pattern
+        *[other] these patterns
+    } will always match
+    .help = consider moving {$count ->
+        [one] it
+        *[other] them
+    } outside of the construct
+
+mir_build_trailing_irrefutable_let_patterns = trailing irrefutable {$count ->
+        [one] pattern
+        *[other] patterns
+    } in let chain
+    .note = {$count ->
+        [one] this pattern
+        *[other] these patterns
+    } will always match
+    .help = consider moving {$count ->
+        [one] it
+        *[other] them
+    } into the body
+
+mir_build_bindings_with_variant_name =
+    pattern binding `{$ident}` is named the same as one of the variants of the type `{$ty_path}`
+    .suggestion = to match on the variant, qualify the path
+
+mir_build_irrefutable_let_patterns_generic_let = irrefutable `let` {$count ->
+        [one] pattern
+        *[other] patterns
+    }
+    .note = {$count ->
+        [one] this pattern
+        *[other] these patterns
+    } will always match, so the `let` is useless
+    .help = consider removing `let`
+
+mir_build_irrefutable_let_patterns_if_let = irrefutable `if let` {$count ->
+        [one] pattern
+        *[other] patterns
+    }
+    .note = {$count ->
+        [one] this pattern
+        *[other] these patterns
+    } will always match, so the `if let` is useless
+    .help = consider replacing the `if let` with a `let`
+
+mir_build_irrefutable_let_patterns_if_let_guard = irrefutable `if let` guard {$count ->
+        [one] pattern
+        *[other] patterns
+    }
+    .note = {$count ->
+        [one] this pattern
+        *[other] these patterns
+    } will always match, so the guard is useless
+    .help = consider removing the guard and adding a `let` inside the match arm
+
+mir_build_irrefutable_let_patterns_let_else = irrefutable `let...else` {$count ->
+        [one] pattern
+        *[other] patterns
+    }
+    .note = {$count ->
+        [one] this pattern
+        *[other] these patterns
+    } will always match, so the `else` clause is useless
+    .help = consider removing the `else` clause
+
+mir_build_irrefutable_let_patterns_while_let = irrefutable `while let` {$count ->
+        [one] pattern
+        *[other] patterns
+    }
+    .note = {$count ->
+        [one] this pattern
+        *[other] these patterns
+    } will always match, so the loop will never exit
+    .help = consider instead using a `loop {"{"} ... {"}"}` with a `let` inside it
+
+mir_build_borrow_of_moved_value = borrow of moved value
+    .label = value moved into `{$name}` here
+    .occurs_because_label = move occurs because `{$name}` has type `{$ty}` which does not implement the `Copy` trait
+    .value_borrowed_label = value borrowed here after move
+    .suggestion = borrow this binding in the pattern to avoid moving the value
+
+mir_build_multiple_mut_borrows = cannot borrow value as mutable more than once at a time
+    .label = first mutable borrow, by `{$name}`, occurs here
+    .mutable_borrow = another mutable borrow, by `{$name_mut}`, occurs here
+    .immutable_borrow = also borrowed as immutable, by `{$name_immut}`, here
+    .moved = also moved into `{$name_moved}` here
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 418ba3c74d7..25d0e736e59 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -57,6 +57,7 @@ fluent_messages! {
     lint => "../locales/en-US/lint.ftl",
     metadata => "../locales/en-US/metadata.ftl",
     middle => "../locales/en-US/middle.ftl",
+    mir_build => "../locales/en-US/mir_build.ftl",
     mir_dataflow => "../locales/en-US/mir_dataflow.ftl",
     monomorphize => "../locales/en-US/monomorphize.ftl",
     parse => "../locales/en-US/parse.ftl",
diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs
index 8994a2f7891..0b8847f827d 100644
--- a/compiler/rustc_expand/src/mbe/macro_check.rs
+++ b/compiler/rustc_expand/src/mbe/macro_check.rs
@@ -468,7 +468,7 @@ fn check_nested_occurrences(
                 // We check that the meta-variable is correctly used.
                 check_occurrences(sess, node_id, tt, macros, binders, ops, valid);
             }
-            (NestedMacroState::MacroName, &TokenTree::Delimited(_, ref del))
+            (NestedMacroState::MacroName, TokenTree::Delimited(_, del))
                 if del.delim == Delimiter::Parenthesis =>
             {
                 state = NestedMacroState::MacroNameParen;
@@ -483,7 +483,7 @@ fn check_nested_occurrences(
                     valid,
                 );
             }
-            (NestedMacroState::MacroNameParen, &TokenTree::Delimited(_, ref del))
+            (NestedMacroState::MacroNameParen, TokenTree::Delimited(_, del))
                 if del.delim == Delimiter::Brace =>
             {
                 state = NestedMacroState::Empty;
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 2dbb90e2190..320c533a66e 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -792,7 +792,7 @@ impl<'tt> FirstSets<'tt> {
                 TokenTree::Sequence(sp, ref seq_rep) => {
                     let subfirst_owned;
                     let subfirst = match self.first.get(&sp.entire()) {
-                        Some(&Some(ref subfirst)) => subfirst,
+                        Some(Some(subfirst)) => subfirst,
                         Some(&None) => {
                             subfirst_owned = self.first(&seq_rep.tts);
                             &subfirst_owned
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 71f26eb60c9..e4c16ef9efa 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -2240,7 +2240,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     ),
                     "s",
                 ),
-                [only] => (format!("{only}"), ""),
+                [only] => (only.to_string(), ""),
                 [] => unreachable!(),
             };
             let last_span = *arg_spans.last().unwrap();
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index aa01feb3a1e..eee0ba2e5ed 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -99,18 +99,17 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
             ty: Ty<'tcx>,
             tcx: TyCtxt<'tcx>,
             param_env: ty::ParamEnv<'tcx>,
-            span: Span,
         ) -> bool {
             // We don't just accept all !needs_drop fields, due to semver concerns.
             match ty.kind() {
                 ty::Ref(..) => true, // references never drop (even mutable refs, which are non-Copy and hence fail the later check)
                 ty::Tuple(tys) => {
                     // allow tuples of allowed types
-                    tys.iter().all(|ty| allowed_union_field(ty, tcx, param_env, span))
+                    tys.iter().all(|ty| allowed_union_field(ty, tcx, param_env))
                 }
                 ty::Array(elem, _len) => {
                     // Like `Copy`, we do *not* special-case length 0.
-                    allowed_union_field(*elem, tcx, param_env, span)
+                    allowed_union_field(*elem, tcx, param_env)
                 }
                 _ => {
                     // Fallback case: allow `ManuallyDrop` and things that are `Copy`.
@@ -124,7 +123,7 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
         for field in &def.non_enum_variant().fields {
             let field_ty = field.ty(tcx, substs);
 
-            if !allowed_union_field(field_ty, tcx, param_env, span) {
+            if !allowed_union_field(field_ty, tcx, param_env) {
                 let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) {
                     // We are currently checking the type this field came from, so it must be local.
                     Some(Node::Field(field)) => (field.span, field.ty.span),
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 36cf4791492..8cdd12e4e34 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -1548,7 +1548,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                             cause,
                             expected,
                             found,
-                            coercion_error.clone(),
+                            coercion_error,
                             fcx,
                             parent_id,
                             expression,
@@ -1567,7 +1567,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                             cause,
                             expected,
                             found,
-                            coercion_error.clone(),
+                            coercion_error,
                             fcx,
                             id,
                             expression,
@@ -1583,7 +1583,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                             cause,
                             expected,
                             found,
-                            coercion_error.clone(),
+                            coercion_error,
                         );
                     }
                 }
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 6763e06c0cf..479aaf2e1a7 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -163,7 +163,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let expr = expr.peel_drop_temps();
         let cause = self.misc(expr.span);
         let expr_ty = self.resolve_vars_with_obligations(checked_ty);
-        let mut err = self.err_ctxt().report_mismatched_types(&cause, expected, expr_ty, e.clone());
+        let mut err = self.err_ctxt().report_mismatched_types(&cause, expected, expr_ty, e);
 
         let is_insufficiently_polymorphic =
             matches!(e, TypeError::RegionsInsufficientlyPolymorphic(..));
@@ -406,7 +406,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
 
                     let note_about_variant_field_privacy = (field_is_local && !field_is_accessible)
-                        .then(|| format!(" (its field is private, but it's local to this crate and its privacy can be changed)"));
+                        .then(|| " (its field is private, but it's local to this crate and its privacy can be changed)".to_string());
 
                     let sole_field_ty = sole_field.ty(self.tcx, substs);
                     if self.can_coerce(expr_ty, sole_field_ty) {
@@ -1275,7 +1275,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             };
 
         match (&expected_ty.kind(), &checked_ty.kind()) {
-            (&ty::Int(ref exp), &ty::Int(ref found)) => {
+            (ty::Int(exp), ty::Int(found)) => {
                 let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width())
                 {
                     (Some(exp), Some(found)) if exp < found => (true, false),
@@ -1288,7 +1288,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible);
                 true
             }
-            (&ty::Uint(ref exp), &ty::Uint(ref found)) => {
+            (ty::Uint(exp), ty::Uint(found)) => {
                 let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width())
                 {
                     (Some(exp), Some(found)) if exp < found => (true, false),
@@ -1321,7 +1321,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible);
                 true
             }
-            (&ty::Float(ref exp), &ty::Float(ref found)) => {
+            (ty::Float(exp), ty::Float(found)) => {
                 if found.bit_width() < exp.bit_width() {
                     suggest_to_change_suffix_or_into(err, false, true);
                 } else if literal_is_ty_suffixed(expr) {
@@ -1357,7 +1357,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
                 true
             }
-            (&ty::Float(ref exp), &ty::Uint(ref found)) => {
+            (ty::Float(exp), ty::Uint(found)) => {
                 // if `found` is `None` (meaning found is `usize`), don't suggest `.into()`
                 if exp.bit_width() > found.bit_width().unwrap_or(256) {
                     err.multipart_suggestion_verbose(
@@ -1386,7 +1386,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
                 true
             }
-            (&ty::Float(ref exp), &ty::Int(ref found)) => {
+            (ty::Float(exp), ty::Int(found)) => {
                 // if `found` is `None` (meaning found is `isize`), don't suggest `.into()`
                 if exp.bit_width() > found.bit_width().unwrap_or(256) {
                     err.multipart_suggestion_verbose(
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 866090260b2..edbbb7272ac 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -1874,7 +1874,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // I don't use 'is_range_literal' because only double-sided, half-open ranges count.
         if let ExprKind::Struct(
                 QPath::LangItem(LangItem::Range, ..),
-                &[ref range_start, ref range_end],
+                [range_start, range_end],
                 _,
             ) = last_expr_field.expr.kind
             && let variant_field =
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 8e520e563ff..d1e0964112b 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -28,7 +28,7 @@ use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty, TypeSuperVisitable, TypeVisitor};
 use rustc_session::Session;
-use rustc_span::symbol::Ident;
+use rustc_span::symbol::{kw, Ident};
 use rustc_span::{self, sym, Span};
 use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext};
 
@@ -1013,7 +1013,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             } else {
                                 args_span
                             };
-                            labels.push((span, format!("multiple arguments are missing")));
+                            labels.push((span, "multiple arguments are missing".to_string()));
                             suggestion_text = match suggestion_text {
                                 SuggestionText::None | SuggestionText::Provide(_) => {
                                     SuggestionText::Provide(true)
@@ -1141,6 +1141,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         "()".to_string()
                     } else if expected_ty.is_suggestable(tcx, false) {
                         format!("/* {} */", expected_ty)
+                    } else if let Some(fn_def_id) = fn_def_id
+                        && self.tcx.def_kind(fn_def_id).is_fn_like()
+                        && let self_implicit = matches!(call_expr.kind, hir::ExprKind::MethodCall(..)) as usize
+                        && let Some(arg) = self.tcx.fn_arg_names(fn_def_id).get(expected_idx.as_usize() + self_implicit)
+                        && arg.name != kw::SelfLower
+                    {
+                        format!("/* {} */", arg.name)
                     } else {
                         "/* value */".to_string()
                     }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 407d6ac8544..c9d179de39f 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -319,11 +319,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
             }
 
-            err.multipart_suggestion_verbose(
-                format!("use parentheses to call these"),
-                sugg,
-                applicability,
-            );
+            err.multipart_suggestion_verbose("use parentheses to call these", sugg, applicability);
 
             true
         } else {
@@ -754,7 +750,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     return true
                 }
             }
-            &hir::FnRetTy::Return(ref ty) => {
+            hir::FnRetTy::Return(ty) => {
                 // Only point to return type if the expected type is the return type, as if they
                 // are not, the expectation must have been caused by something else.
                 debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.kind);
@@ -1128,9 +1124,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         let hir = self.tcx.hir();
-        let cond_parent = hir.parent_iter(expr.hir_id).skip_while(|(_, node)| {
-            matches!(node, hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Binary(op, _, _), .. }) if op.node == hir::BinOpKind::And)
-        }).next();
+        let cond_parent = hir.parent_iter(expr.hir_id).find(|(_, node)| {
+            !matches!(node, hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Binary(op, _, _), .. }) if op.node == hir::BinOpKind::And)
+        });
         // Don't suggest:
         //     `let Some(_) = a.is_some() && b`
         //                     ++++++++++
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index d40a66715a2..7c5a9a333fe 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -1007,7 +1007,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         if def_kind == DefKind::AssocFn && lev_candidate.fn_has_self_parameter {
                             err.span_suggestion(
                                 span,
-                                &format!("there is a method with a similar name",),
+                                "there is a method with a similar name",
                                 lev_candidate.name,
                                 Applicability::MaybeIncorrect,
                             );
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 6810353f9e7..d3e88b1b80a 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -2130,7 +2130,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
         {
             let ty = self.resolve_vars_if_possible(ti.expected);
-            let is_slice_or_array_or_vector = self.is_slice_or_array_or_vector(&mut err, snippet.clone(), ty);
+            let is_slice_or_array_or_vector = self.is_slice_or_array_or_vector(ty);
             match is_slice_or_array_or_vector.1.kind() {
                 ty::Adt(adt_def, _)
                     if self.tcx.is_diagnostic_item(sym::Option, adt_def.did())
@@ -2159,17 +2159,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         err.emit();
     }
 
-    fn is_slice_or_array_or_vector(
-        &self,
-        err: &mut Diagnostic,
-        snippet: String,
-        ty: Ty<'tcx>,
-    ) -> (bool, Ty<'tcx>) {
+    fn is_slice_or_array_or_vector(&self, ty: Ty<'tcx>) -> (bool, Ty<'tcx>) {
         match ty.kind() {
             ty::Adt(adt_def, _) if self.tcx.is_diagnostic_item(sym::Vec, adt_def.did()) => {
                 (true, ty)
             }
-            ty::Ref(_, ty, _) => self.is_slice_or_array_or_vector(err, snippet, *ty),
+            ty::Ref(_, ty, _) => self.is_slice_or_array_or_vector(*ty),
             ty::Slice(..) | ty::Array(..) => (true, ty),
             _ => (false, ty),
         }
diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs
index 69e482ce854..b4bf9f4bcc7 100644
--- a/compiler/rustc_incremental/src/assert_dep_graph.rs
+++ b/compiler/rustc_incremental/src/assert_dep_graph.rs
@@ -249,7 +249,7 @@ fn dump_graph(query: &DepGraphQuery) {
         // dump a .txt file with just the edges:
         let txt_path = format!("{}.txt", path);
         let mut file = BufWriter::new(File::create(&txt_path).unwrap());
-        for &(ref source, ref target) in &edges {
+        for (source, target) in &edges {
             write!(file, "{:?} -> {:?}\n", source, target).unwrap();
         }
     }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 397fa43175f..269fc95420a 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -184,7 +184,7 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>(
             let text = if br.has_name() {
                 format!("the lifetime `{}` as defined here", br.name)
             } else {
-                format!("the anonymous lifetime as defined here")
+                "the anonymous lifetime as defined here".to_string()
             };
             (text, sp)
         }
@@ -203,7 +203,7 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>(
                             sp = param.span;
                         }
                         let text = if name == kw::UnderscoreLifetime {
-                            format!("the anonymous lifetime as defined here")
+                            "the anonymous lifetime as defined here".to_string()
                         } else {
                             format!("the lifetime `{}` as defined here", name)
                         };
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs
index c42240f2172..9534bce54ef 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs
@@ -44,7 +44,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
                         );
                     }
                     (Some(sub_span), Some(sup_span), _, Some(sup_symbol)) => {
-                        err.span_note(sub_span, format!("the lifetime defined here..."));
+                        err.span_note(sub_span, "the lifetime defined here...");
                         err.span_note(
                             sup_span,
                             format!("...must outlive the lifetime `{sup_symbol}` defined here"),
@@ -55,17 +55,11 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
                             sub_span,
                             format!("the lifetime `{sub_symbol}` defined here..."),
                         );
-                        err.span_note(
-                            sup_span,
-                            format!("...must outlive the lifetime defined here"),
-                        );
+                        err.span_note(sup_span, "...must outlive the lifetime defined here");
                     }
                     (Some(sub_span), Some(sup_span), _, _) => {
-                        err.span_note(sub_span, format!("the lifetime defined here..."));
-                        err.span_note(
-                            sup_span,
-                            format!("...must outlive the lifetime defined here"),
-                        );
+                        err.span_note(sub_span, "the lifetime defined here...");
+                        err.span_note(sup_span, "...must outlive the lifetime defined here");
                     }
                     _ => {}
                 }
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index ba990acfe6f..da2c6fbc05f 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -488,7 +488,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
                         // If this empty region is from a universe that can
                         // name the placeholder, then the placeholder is
                         // larger; otherwise, the only ancestor is `'static`.
-                        if a_ui.can_name(placeholder.universe) { true } else { false }
+                        return a_ui.can_name(placeholder.universe);
                     }
                 }
             }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 996148a7090..268b3bf1dcd 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -1920,7 +1920,7 @@ impl<'tcx> TypeTrace<'tcx> {
     ) -> TypeTrace<'tcx> {
         TypeTrace {
             cause: cause.clone(),
-            values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a.into(), b.into())),
+            values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a, b)),
         }
     }
 
diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs
index 611961ab1cc..955c54e8515 100644
--- a/compiler/rustc_infer/src/infer/undo_log.rs
+++ b/compiler/rustc_infer/src/infer/undo_log.rs
@@ -87,18 +87,12 @@ impl<'tcx> Rollback<UndoLog<'tcx>> for InferCtxtInner<'tcx> {
 
 /// The combined undo log for all the various unification tables. For each change to the storage
 /// for any kind of inference variable, we record an UndoLog entry in the vector here.
-#[derive(Clone)]
+#[derive(Clone, Default)]
 pub(crate) struct InferCtxtUndoLogs<'tcx> {
     logs: Vec<UndoLog<'tcx>>,
     num_open_snapshots: usize,
 }
 
-impl Default for InferCtxtUndoLogs<'_> {
-    fn default() -> Self {
-        Self { logs: Default::default(), num_open_snapshots: Default::default() }
-    }
-}
-
 /// The UndoLogs trait defines how we undo a particular kind of action (of type T). We can undo any
 /// action that is convertible into an UndoLog (per the From impls above).
 impl<'tcx, T> UndoLogs<T> for InferCtxtUndoLogs<'tcx>
diff --git a/compiler/rustc_infer/src/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs
index aade57be9fe..ac455055b43 100644
--- a/compiler/rustc_infer/src/traits/project.rs
+++ b/compiler/rustc_infer/src/traits/project.rs
@@ -200,7 +200,7 @@ impl<'tcx> ProjectionCache<'_, 'tcx> {
     pub fn complete(&mut self, key: ProjectionCacheKey<'tcx>, result: EvaluationResult) {
         let mut map = self.map();
         match map.get(&key) {
-            Some(&ProjectionCacheEntry::NormalizedTy { ref ty, complete: _ }) => {
+            Some(ProjectionCacheEntry::NormalizedTy { ty, complete: _ }) => {
                 info!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty);
                 let mut ty = ty.clone();
                 if result.must_apply_considering_regions() {
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index 39e1f2204b0..1d0c7f5b7a3 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -127,7 +127,7 @@ impl<'tcx> Queries<'tcx> {
 
     pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, Lrc<LintStore>)>> {
         self.register_plugins.compute(|| {
-            let crate_name = self.crate_name()?.peek().clone();
+            let crate_name = *self.crate_name()?.peek();
             let krate = self.parse()?.take();
 
             let empty: &(dyn Fn(&Session, &mut LintStore) + Sync + Send) = &|_, _| {};
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 43862570e80..cd19e65b6fc 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -270,7 +270,7 @@ impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns {
                             |lint| {
                                 let suggested_ident =
                                     format!("{}{}", binding_annot.prefix_str(), ident);
-                                lint.set_arg("ident", ident.clone()).span_suggestion(
+                                lint.set_arg("ident", ident).span_suggestion(
                                     fieldpat.span,
                                     fluent::suggestion,
                                     suggested_ident,
@@ -2052,7 +2052,7 @@ impl KeywordIdents {
             ident.span,
             fluent::lint_builtin_keyword_idents,
             |lint| {
-                lint.set_arg("kw", ident.clone()).set_arg("next", next_edition).span_suggestion(
+                lint.set_arg("kw", ident).set_arg("next", next_edition).span_suggestion(
                     ident.span,
                     fluent::suggestion,
                     format!("r#{}", ident),
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 40b2588388d..0417f375588 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -438,18 +438,18 @@ impl LintStore {
                         return CheckLintNameResult::Tool(Ok(&lint_ids));
                     }
                 },
-                Some(&Id(ref id)) => return CheckLintNameResult::Tool(Ok(slice::from_ref(id))),
+                Some(Id(id)) => return CheckLintNameResult::Tool(Ok(slice::from_ref(id))),
                 // If the lint was registered as removed or renamed by the lint tool, we don't need
                 // to treat tool_lints and rustc lints different and can use the code below.
                 _ => {}
             }
         }
         match self.by_name.get(&complete_name) {
-            Some(&Renamed(ref new_name, _)) => CheckLintNameResult::Warning(
+            Some(Renamed(new_name, _)) => CheckLintNameResult::Warning(
                 format!("lint `{}` has been renamed to `{}`", complete_name, new_name),
                 Some(new_name.to_owned()),
             ),
-            Some(&Removed(ref reason)) => CheckLintNameResult::Warning(
+            Some(Removed(reason)) => CheckLintNameResult::Warning(
                 format!("lint `{}` has been removed: {}", complete_name, reason),
                 None,
             ),
@@ -470,7 +470,7 @@ impl LintStore {
                     CheckLintNameResult::Ok(&lint_ids)
                 }
             },
-            Some(&Id(ref id)) => CheckLintNameResult::Ok(slice::from_ref(id)),
+            Some(Id(id)) => CheckLintNameResult::Ok(slice::from_ref(id)),
             Some(&Ignored) => CheckLintNameResult::Ok(&[]),
         }
     }
@@ -513,7 +513,7 @@ impl LintStore {
                     CheckLintNameResult::Tool(Err((Some(&lint_ids), complete_name)))
                 }
             },
-            Some(&Id(ref id)) => {
+            Some(Id(id)) => {
                 CheckLintNameResult::Tool(Err((Some(slice::from_ref(id)), complete_name)))
             }
             Some(other) => {
diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
index 4187850153c..182734fa9fc 100644
--- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs
+++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
@@ -71,11 +71,11 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles {
                 );
             } else {
                 lint.multipart_suggestion_verbose(
-                    format!("to check pattern in a loop use `while let`"),
+                    "to check pattern in a loop use `while let`",
                     vec![
                         // NB can't use `until` here because `expr.span` and `pat.span` have different syntax contexts
                         (expr.span.with_hi(pat.span.lo()), format!("while let {var}(")),
-                        (pat.span.between(arg.span), format!(") = ")),
+                        (pat.span.between(arg.span), ") = ".to_string()),
                     ],
                     Applicability::MaybeIncorrect
                 );
@@ -95,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles {
                 vec![
                     // NB can't use `until` here because `expr.span` and `pat.span` have different syntax contexts
                     (expr.span.with_hi(pat.span.lo()), format!("if let {var}(")),
-                    (pat.span.between(arg.span), format!(") = ")),
+                    (pat.span.between(arg.span), ") = ".to_string()),
                 ],
                 Applicability::MaybeIncorrect,
             )
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index d628a18dd01..3b8df61a0ea 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -1279,7 +1279,7 @@ impl UnusedImportBraces {
     fn check_use_tree(&self, cx: &EarlyContext<'_>, use_tree: &ast::UseTree, item: &ast::Item) {
         if let ast::UseTreeKind::Nested(ref items) = use_tree.kind {
             // Recursively check nested UseTrees
-            for &(ref tree, _) in items {
+            for (tree, _) in items {
                 self.check_use_tree(cx, tree, item);
             }
 
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
index 13f06fe7473..9ff94486404 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
@@ -39,10 +39,8 @@ impl<'a> DiagnosticDerive<'a> {
             let init = match builder.slug.value_ref() {
                 None => {
                     span_err(builder.span, "diagnostic slug not specified")
-                        .help(format!(
-                            "specify the slug as the first argument to the `#[diag(...)]` \
-                            attribute, such as `#[diag(hir_analysis_example_error)]`",
-                        ))
+                        .help("specify the slug as the first argument to the `#[diag(...)]` \
+                            attribute, such as `#[diag(hir_analysis_example_error)]`")
                         .emit();
                     return DiagnosticDeriveError::ErrorHandled.to_compile_error();
                 }
@@ -133,10 +131,8 @@ impl<'a> LintDiagnosticDerive<'a> {
             match builder.slug.value_ref() {
                 None => {
                     span_err(builder.span, "diagnostic slug not specified")
-                        .help(format!(
-                            "specify the slug as the first argument to the attribute, such as \
-                            `#[diag(compiletest_example)]`",
-                        ))
+                        .help("specify the slug as the first argument to the attribute, such as \
+                            `#[diag(compiletest_example)]`")
                         .emit();
                     DiagnosticDeriveError::ErrorHandled.to_compile_error()
                 }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 856f5bc4645..4af423f2a22 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -332,7 +332,7 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Symbol {
                     s.emit_str(self.as_str());
                 }
                 Entry::Occupied(o) => {
-                    let x = o.get().clone();
+                    let x = *o.get();
                     s.emit_u8(SYMBOL_OFFSET);
                     s.emit_usize(x);
                 }
@@ -1849,7 +1849,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         // the assumption that they are numbered 1 to n.
         // FIXME (#2166): This is not nearly enough to support correct versioning
         // but is enough to get transitive crate dependencies working.
-        self.lazy_array(deps.iter().map(|&(_, ref dep)| dep))
+        self.lazy_array(deps.iter().map(|(_, dep)| dep))
     }
 
     fn encode_lib_features(&mut self) -> LazyArray<(Symbol, Option<Symbol>)> {
@@ -1986,7 +1986,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         self.lazy_array(
             exported_symbols
                 .iter()
-                .filter(|&&(ref exported_symbol, _)| match *exported_symbol {
+                .filter(|&(exported_symbol, _)| match *exported_symbol {
                     ExportedSymbol::NoDefId(symbol_name) => symbol_name != metadata_symbol_name,
                     _ => true,
                 })
diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs
index fc08d58cc40..0e18ba73d71 100644
--- a/compiler/rustc_middle/src/middle/privacy.rs
+++ b/compiler/rustc_middle/src/middle/privacy.rs
@@ -103,12 +103,7 @@ impl EffectiveVisibilities {
 
     pub fn public_at_level(&self, id: LocalDefId) -> Option<Level> {
         self.effective_vis(id).and_then(|effective_vis| {
-            for level in Level::all_levels() {
-                if effective_vis.is_public_at_level(level) {
-                    return Some(level);
-                }
-            }
-            None
+            Level::all_levels().into_iter().find(|&level| effective_vis.is_public_at_level(level))
         })
     }
 
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 2a4ff4b8810..1ebfdbbd6ef 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -448,15 +448,15 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
 
             // FIXME: this is a poor version of `pretty_print_const_value`.
             let fmt_val = |val: &ConstValue<'tcx>| match val {
-                ConstValue::ZeroSized => format!("<ZST>"),
+                ConstValue::ZeroSized => "<ZST>".to_string(),
                 ConstValue::Scalar(s) => format!("Scalar({:?})", s),
-                ConstValue::Slice { .. } => format!("Slice(..)"),
-                ConstValue::ByRef { .. } => format!("ByRef(..)"),
+                ConstValue::Slice { .. } => "Slice(..)".to_string(),
+                ConstValue::ByRef { .. } => "ByRef(..)".to_string(),
             };
 
             let fmt_valtree = |valtree: &ty::ValTree<'tcx>| match valtree {
                 ty::ValTree::Leaf(leaf) => format!("ValTree::Leaf({:?})", leaf),
-                ty::ValTree::Branch(_) => format!("ValTree::Branch(..)"),
+                ty::ValTree::Branch(_) => "ValTree::Branch(..)".to_string(),
             };
 
             let val = match literal {
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index e3ca1f41d7e..1e289fc4abe 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -235,7 +235,7 @@ impl<'tcx> Operand<'tcx> {
     {
         match self {
             &Operand::Copy(ref l) | &Operand::Move(ref l) => l.ty(local_decls, tcx).ty,
-            &Operand::Constant(ref c) => c.literal.ty(),
+            Operand::Constant(c) => c.literal.ty(),
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index d283ccc3ad8..042b89bc4b0 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -95,7 +95,7 @@ impl FlagComputation {
                 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
             }
 
-            &ty::Generator(_, ref substs, _) => {
+            ty::Generator(_, substs, _) => {
                 let substs = substs.as_generator();
                 let should_remove_further_specializable =
                     !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
@@ -186,7 +186,7 @@ impl FlagComputation {
 
             &ty::Slice(tt) => self.add_ty(tt),
 
-            &ty::RawPtr(ref m) => {
+            ty::RawPtr(m) => {
                 self.add_ty(m.ty);
             }
 
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index c4116558bd2..4d34ca3d66b 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -428,7 +428,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
             Ok(a)
         }
 
-        (&ty::Param(ref a_p), &ty::Param(ref b_p)) if a_p.index == b_p.index => Ok(a),
+        (ty::Param(a_p), ty::Param(b_p)) if a_p.index == b_p.index => Ok(a),
 
         (ty::Placeholder(p1), ty::Placeholder(p2)) if p1 == p2 => Ok(a),
 
diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs
index 802925dfb04..f77bd9f0c6f 100644
--- a/compiler/rustc_middle/src/ty/vtable.rs
+++ b/compiler/rustc_middle/src/ty/vtable.rs
@@ -88,8 +88,8 @@ pub(super) fn vtable_allocation_provider<'tcx>(
                 let fn_ptr = Pointer::from(fn_alloc_id);
                 Scalar::from_pointer(fn_ptr, &tcx)
             }
-            VtblEntry::MetadataSize => Scalar::from_uint(size, ptr_size).into(),
-            VtblEntry::MetadataAlign => Scalar::from_uint(align, ptr_size).into(),
+            VtblEntry::MetadataSize => Scalar::from_uint(size, ptr_size),
+            VtblEntry::MetadataAlign => Scalar::from_uint(align, ptr_size),
             VtblEntry::Vacant => continue,
             VtblEntry::Method(instance) => {
                 // Prepare the fn ptr we write into the vtable.
diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml
index 2baa3bfcb64..4ad3343d303 100644
--- a/compiler/rustc_mir_build/Cargo.toml
+++ b/compiler/rustc_mir_build/Cargo.toml
@@ -17,6 +17,7 @@ rustc_index = { path = "../rustc_index" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_infer = { path = "../rustc_infer" }
+rustc_macros = { path = "../rustc_macros" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
index 2f26499a3b6..7c39a93a8eb 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
@@ -42,6 +42,29 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
             @call("mir_goto", args) => {
                 Ok(TerminatorKind::Goto { target: self.parse_block(args[0])? } )
             },
+            @call("mir_unreachable", _args) => {
+                Ok(TerminatorKind::Unreachable)
+            },
+            @call("mir_drop", args) => {
+                Ok(TerminatorKind::Drop {
+                    place: self.parse_place(args[0])?,
+                    target: self.parse_block(args[1])?,
+                    unwind: None,
+                })
+            },
+            @call("mir_drop_and_replace", args) => {
+                Ok(TerminatorKind::DropAndReplace {
+                    place: self.parse_place(args[0])?,
+                    value: self.parse_operand(args[1])?,
+                    target: self.parse_block(args[2])?,
+                    unwind: None,
+                })
+            },
+            @call("mir_call", args) => {
+                let destination = self.parse_place(args[0])?;
+                let target = self.parse_block(args[1])?;
+                self.parse_call(args[2], destination, target)
+            },
             ExprKind::Match { scrutinee, arms } => {
                 let discr = self.parse_operand(*scrutinee)?;
                 self.parse_match(arms, expr.span).map(|t| TerminatorKind::SwitchInt { discr, targets: t })
@@ -53,7 +76,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
         let Some((otherwise, rest)) = arms.split_last() else {
             return Err(ParseError {
                 span,
-                item_description: format!("no arms"),
+                item_description: "no arms".to_string(),
                 expected: "at least one arm".to_string(),
             })
         };
@@ -86,6 +109,32 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
         Ok(SwitchTargets::new(values.into_iter().zip(targets), otherwise))
     }
 
+    fn parse_call(
+        &self,
+        expr_id: ExprId,
+        destination: Place<'tcx>,
+        target: BasicBlock,
+    ) -> PResult<TerminatorKind<'tcx>> {
+        parse_by_kind!(self, expr_id, _, "function call",
+            ExprKind::Call { fun, args, from_hir_call, fn_span, .. } => {
+                let fun = self.parse_operand(*fun)?;
+                let args = args
+                    .iter()
+                    .map(|arg| self.parse_operand(*arg))
+                    .collect::<PResult<Vec<_>>>()?;
+                Ok(TerminatorKind::Call {
+                    func: fun,
+                    args,
+                    destination,
+                    target: Some(target),
+                    cleanup: None,
+                    from_hir_call: *from_hir_call,
+                    fn_span: *fn_span,
+                })
+            },
+        )
+    }
+
     fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> {
         parse_by_kind!(self, expr_id, _, "rvalue",
             @call("mir_discriminant", args) => self.parse_place(args[0]).map(Rvalue::Discriminant),
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index 8a35478dd8b..23a4f85386b 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -356,7 +356,7 @@ impl<'tcx> PlaceBuilder<'tcx> {
         match self {
             PlaceBuilder::Local { local, projection } => PlaceBuilder::Local {
                 local: *local,
-                projection: Vec::from_iter(projection.iter().copied().chain([elem.into()])),
+                projection: Vec::from_iter(projection.iter().copied().chain([elem])),
             },
             PlaceBuilder::Upvar { upvar, projection } => PlaceBuilder::Upvar {
                 upvar: *upvar,
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index 65a027111d7..6c10704c5db 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -551,16 +551,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             //
             // FIXME(#29623) we could use PatKind::Range to rule
             // things out here, in some cases.
-            (
-                &TestKind::SwitchInt { switch_ty: _, ref options },
-                &PatKind::Constant { ref value },
-            ) if is_switch_ty(match_pair.pattern.ty) => {
+            (TestKind::SwitchInt { switch_ty: _, options }, PatKind::Constant { value })
+                if is_switch_ty(match_pair.pattern.ty) =>
+            {
                 let index = options.get_index_of(value).unwrap();
                 self.candidate_without_match_pair(match_pair_index, candidate);
                 Some(index)
             }
 
-            (&TestKind::SwitchInt { switch_ty: _, ref options }, &PatKind::Range(ref range)) => {
+            (TestKind::SwitchInt { switch_ty: _, options }, PatKind::Range(range)) => {
                 let not_contained =
                     self.values_not_contained_in_range(&*range, options).unwrap_or(false);
 
@@ -578,7 +577,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
             (
                 &TestKind::Len { len: test_len, op: BinOp::Eq },
-                &PatKind::Slice { ref prefix, ref slice, ref suffix },
+                PatKind::Slice { prefix, slice, suffix },
             ) => {
                 let pat_len = (prefix.len() + suffix.len()) as u64;
                 match (test_len.cmp(&pat_len), slice) {
@@ -615,7 +614,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
             (
                 &TestKind::Len { len: test_len, op: BinOp::Ge },
-                &PatKind::Slice { ref prefix, ref slice, ref suffix },
+                PatKind::Slice { prefix, slice, suffix },
             ) => {
                 // the test is `$actual_len >= test_len`
                 let pat_len = (prefix.len() + suffix.len()) as u64;
@@ -651,7 +650,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 }
             }
 
-            (&TestKind::Range(ref test), &PatKind::Range(ref pat)) => {
+            (TestKind::Range(test), PatKind::Range(pat)) => {
                 use std::cmp::Ordering::*;
 
                 if test == pat {
@@ -678,7 +677,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 no_overlap
             }
 
-            (&TestKind::Range(ref range), &PatKind::Constant { value }) => {
+            (TestKind::Range(range), &PatKind::Constant { value }) => {
                 if let Some(false) = self.const_range_contains(&*range, value) {
                     // `value` is not contained in the testing range,
                     // so `value` can be matched only if this test fails.
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 3bb1f51650a..99e96ff77ce 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -1,7 +1,7 @@
 use crate::build::ExprCategory;
+use crate::errors::*;
 use rustc_middle::thir::visit::{self, Visitor};
 
-use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_middle::mir::BorrowKind;
 use rustc_middle::thir::*;
@@ -12,7 +12,6 @@ use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 
-use std::borrow::Cow;
 use std::ops::Bound;
 
 struct UnsafetyVisitor<'a, 'tcx> {
@@ -46,7 +45,9 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
             self.warn_unused_unsafe(
                 hir_id,
                 block_span,
-                Some((self.tcx.sess.source_map().guess_head_span(enclosing_span), "block")),
+                Some(UnusedUnsafeEnclosing::Block {
+                    span: self.tcx.sess.source_map().guess_head_span(enclosing_span),
+                }),
             );
             f(self);
         } else {
@@ -60,7 +61,9 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
                     hir_id,
                     span,
                     if self.unsafe_op_in_unsafe_fn_allowed() {
-                        self.body_unsafety.unsafe_fn_sig_span().map(|span| (span, "fn"))
+                        self.body_unsafety
+                            .unsafe_fn_sig_span()
+                            .map(|span| UnusedUnsafeEnclosing::Function { span })
                     } else {
                         None
                     },
@@ -83,30 +86,11 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
             }
             SafetyContext::UnsafeFn if unsafe_op_in_unsafe_fn_allowed => {}
             SafetyContext::UnsafeFn => {
-                let (description, note) = kind.description_and_note(self.tcx);
                 // unsafe_op_in_unsafe_fn is disallowed
-                self.tcx.struct_span_lint_hir(
-                    UNSAFE_OP_IN_UNSAFE_FN,
-                    self.hir_context,
-                    span,
-                    format!("{} is unsafe and requires unsafe block (error E0133)", description,),
-                    |lint| lint.span_label(span, kind.simple_description()).note(note),
-                )
+                kind.emit_unsafe_op_in_unsafe_fn_lint(self.tcx, self.hir_context, span);
             }
             SafetyContext::Safe => {
-                let (description, note) = kind.description_and_note(self.tcx);
-                let fn_sugg = if unsafe_op_in_unsafe_fn_allowed { " function or" } else { "" };
-                struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0133,
-                    "{} is unsafe and requires unsafe{} block",
-                    description,
-                    fn_sugg,
-                )
-                .span_label(span, kind.simple_description())
-                .note(note)
-                .emit();
+                kind.emit_requires_unsafe_err(self.tcx, span, unsafe_op_in_unsafe_fn_allowed);
             }
         }
     }
@@ -115,17 +99,15 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
         &self,
         hir_id: hir::HirId,
         block_span: Span,
-        enclosing_unsafe: Option<(Span, &'static str)>,
+        enclosing_unsafe: Option<UnusedUnsafeEnclosing>,
     ) {
         let block_span = self.tcx.sess.source_map().guess_head_span(block_span);
-        let msg = "unnecessary `unsafe` block";
-        self.tcx.struct_span_lint_hir(UNUSED_UNSAFE, hir_id, block_span, msg, |lint| {
-            lint.span_label(block_span, msg);
-            if let Some((span, kind)) = enclosing_unsafe {
-                lint.span_label(span, format!("because it's nested under this `unsafe` {}", kind));
-            }
-            lint
-        });
+        self.tcx.emit_spanned_lint(
+            UNUSED_UNSAFE,
+            hir_id,
+            block_span,
+            UnusedUnsafe { span: block_span, enclosing: enclosing_unsafe },
+        );
     }
 
     /// Whether the `unsafe_op_in_unsafe_fn` lint is `allow`ed at the current HIR node.
@@ -536,81 +518,189 @@ enum UnsafeOpKind {
 use UnsafeOpKind::*;
 
 impl UnsafeOpKind {
-    pub fn simple_description(&self) -> &'static str {
-        match self {
-            CallToUnsafeFunction(..) => "call to unsafe function",
-            UseOfInlineAssembly => "use of inline assembly",
-            InitializingTypeWith => "initializing type with `rustc_layout_scalar_valid_range` attr",
-            UseOfMutableStatic => "use of mutable static",
-            UseOfExternStatic => "use of extern static",
-            DerefOfRawPointer => "dereference of raw pointer",
-            AccessToUnionField => "access to union field",
-            MutationOfLayoutConstrainedField => "mutation of layout constrained field",
-            BorrowOfLayoutConstrainedField => {
-                "borrow of layout constrained field with interior mutability"
-            }
-            CallToFunctionWith(..) => "call to function with `#[target_feature]`",
-        }
-    }
-
-    pub fn description_and_note(&self, tcx: TyCtxt<'_>) -> (Cow<'static, str>, &'static str) {
+    pub fn emit_unsafe_op_in_unsafe_fn_lint(
+        &self,
+        tcx: TyCtxt<'_>,
+        hir_id: hir::HirId,
+        span: Span,
+    ) {
         match self {
-            CallToUnsafeFunction(did) => (
-                if let Some(did) = did {
-                    Cow::from(format!("call to unsafe function `{}`", tcx.def_path_str(*did)))
-                } else {
-                    Cow::Borrowed(self.simple_description())
+            CallToUnsafeFunction(did) if did.is_some() => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe {
+                    span,
+                    function: &tcx.def_path_str(did.unwrap()),
                 },
-                "consult the function's documentation for information on how to avoid undefined \
-                 behavior",
             ),
-            UseOfInlineAssembly => (
-                Cow::Borrowed(self.simple_description()),
-                "inline assembly is entirely unchecked and can cause undefined behavior",
+            CallToUnsafeFunction(..) => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafeNameless { span },
+            ),
+            UseOfInlineAssembly => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeFnUseOfInlineAssemblyRequiresUnsafe { span },
             ),
-            InitializingTypeWith => (
-                Cow::Borrowed(self.simple_description()),
-                "initializing a layout restricted type's field with a value outside the valid \
-                 range is undefined behavior",
+            InitializingTypeWith => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeFnInitializingTypeWithRequiresUnsafe { span },
             ),
-            UseOfMutableStatic => (
-                Cow::Borrowed(self.simple_description()),
-                "mutable statics can be mutated by multiple threads: aliasing violations or data \
-                 races will cause undefined behavior",
+            UseOfMutableStatic => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeFnUseOfMutableStaticRequiresUnsafe { span },
             ),
-            UseOfExternStatic => (
-                Cow::Borrowed(self.simple_description()),
-                "extern statics are not controlled by the Rust type system: invalid data, \
-                 aliasing violations or data races will cause undefined behavior",
+            UseOfExternStatic => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeFnUseOfExternStaticRequiresUnsafe { span },
             ),
-            DerefOfRawPointer => (
-                Cow::Borrowed(self.simple_description()),
-                "raw pointers may be null, dangling or unaligned; they can violate aliasing rules \
-                 and cause data races: all of these are undefined behavior",
+            DerefOfRawPointer => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeFnDerefOfRawPointerRequiresUnsafe { span },
             ),
-            AccessToUnionField => (
-                Cow::Borrowed(self.simple_description()),
-                "the field may not be properly initialized: using uninitialized data will cause \
-                 undefined behavior",
+            AccessToUnionField => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeFnAccessToUnionFieldRequiresUnsafe { span },
             ),
-            MutationOfLayoutConstrainedField => (
-                Cow::Borrowed(self.simple_description()),
-                "mutating layout constrained fields cannot statically be checked for valid values",
+            MutationOfLayoutConstrainedField => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeFnMutationOfLayoutConstrainedFieldRequiresUnsafe { span },
             ),
-            BorrowOfLayoutConstrainedField => (
-                Cow::Borrowed(self.simple_description()),
-                "references to fields of layout constrained fields lose the constraints. Coupled \
-                 with interior mutability, the field can be changed to invalid values",
+            BorrowOfLayoutConstrainedField => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe { span },
             ),
-            CallToFunctionWith(did) => (
-                Cow::from(format!(
-                    "call to function `{}` with `#[target_feature]`",
-                    tcx.def_path_str(*did)
-                )),
-                "can only be called if the required target features are available",
+            CallToFunctionWith(did) => tcx.emit_spanned_lint(
+                UNSAFE_OP_IN_UNSAFE_FN,
+                hir_id,
+                span,
+                UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe {
+                    span,
+                    function: &tcx.def_path_str(*did),
+                },
             ),
         }
     }
+
+    pub fn emit_requires_unsafe_err(
+        &self,
+        tcx: TyCtxt<'_>,
+        span: Span,
+        unsafe_op_in_unsafe_fn_allowed: bool,
+    ) {
+        match self {
+            CallToUnsafeFunction(did) if did.is_some() && unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+                    span,
+                    function: &tcx.def_path_str(did.unwrap()),
+                });
+            }
+            CallToUnsafeFunction(did) if did.is_some() => {
+                tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafe {
+                    span,
+                    function: &tcx.def_path_str(did.unwrap()),
+                });
+            }
+            CallToUnsafeFunction(..) if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess.emit_err(
+                    CallToUnsafeFunctionRequiresUnsafeNamelessUnsafeOpInUnsafeFnAllowed { span },
+                );
+            }
+            CallToUnsafeFunction(..) => {
+                tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafeNameless { span });
+            }
+            UseOfInlineAssembly if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess
+                    .emit_err(UseOfInlineAssemblyRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span });
+            }
+            UseOfInlineAssembly => {
+                tcx.sess.emit_err(UseOfInlineAssemblyRequiresUnsafe { span });
+            }
+            InitializingTypeWith if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess
+                    .emit_err(InitializingTypeWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span });
+            }
+            InitializingTypeWith => {
+                tcx.sess.emit_err(InitializingTypeWithRequiresUnsafe { span });
+            }
+            UseOfMutableStatic if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess
+                    .emit_err(UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span });
+            }
+            UseOfMutableStatic => {
+                tcx.sess.emit_err(UseOfMutableStaticRequiresUnsafe { span });
+            }
+            UseOfExternStatic if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess
+                    .emit_err(UseOfExternStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span });
+            }
+            UseOfExternStatic => {
+                tcx.sess.emit_err(UseOfExternStaticRequiresUnsafe { span });
+            }
+            DerefOfRawPointer if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess
+                    .emit_err(DerefOfRawPointerRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span });
+            }
+            DerefOfRawPointer => {
+                tcx.sess.emit_err(DerefOfRawPointerRequiresUnsafe { span });
+            }
+            AccessToUnionField if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess
+                    .emit_err(AccessToUnionFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span });
+            }
+            AccessToUnionField => {
+                tcx.sess.emit_err(AccessToUnionFieldRequiresUnsafe { span });
+            }
+            MutationOfLayoutConstrainedField if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess.emit_err(
+                    MutationOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+                        span,
+                    },
+                );
+            }
+            MutationOfLayoutConstrainedField => {
+                tcx.sess.emit_err(MutationOfLayoutConstrainedFieldRequiresUnsafe { span });
+            }
+            BorrowOfLayoutConstrainedField if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess.emit_err(
+                    BorrowOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span },
+                );
+            }
+            BorrowOfLayoutConstrainedField => {
+                tcx.sess.emit_err(BorrowOfLayoutConstrainedFieldRequiresUnsafe { span });
+            }
+            CallToFunctionWith(did) if unsafe_op_in_unsafe_fn_allowed => {
+                tcx.sess.emit_err(CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+                    span,
+                    function: &tcx.def_path_str(*did),
+                });
+            }
+            CallToFunctionWith(did) => {
+                tcx.sess.emit_err(CallToFunctionWithRequiresUnsafe {
+                    span,
+                    function: &tcx.def_path_str(*did),
+                });
+            }
+        }
+    }
 }
 
 pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalDefId>) {
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
new file mode 100644
index 00000000000..68179001b91
--- /dev/null
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -0,0 +1,616 @@
+use crate::thir::pattern::MatchCheckCtxt;
+use rustc_errors::Handler;
+use rustc_errors::{
+    error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, MultiSpan,
+};
+use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
+use rustc_middle::ty::{self, Ty};
+use rustc_span::{symbol::Ident, Span};
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_unconditional_recursion)]
+#[help]
+pub struct UnconditionalRecursion {
+    #[label]
+    pub span: Span,
+    #[label(mir_build_unconditional_recursion_call_site_label)]
+    pub call_sites: Vec<Span>,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe)]
+#[note]
+pub struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe<'a> {
+    #[label]
+    pub span: Span,
+    pub function: &'a str,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe_nameless)]
+#[note]
+pub struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafeNameless {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe)]
+#[note]
+pub struct UnsafeOpInUnsafeFnUseOfInlineAssemblyRequiresUnsafe {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe)]
+#[note]
+pub struct UnsafeOpInUnsafeFnInitializingTypeWithRequiresUnsafe {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_mutable_static_requires_unsafe)]
+#[note]
+pub struct UnsafeOpInUnsafeFnUseOfMutableStaticRequiresUnsafe {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_extern_static_requires_unsafe)]
+#[note]
+pub struct UnsafeOpInUnsafeFnUseOfExternStaticRequiresUnsafe {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_deref_raw_pointer_requires_unsafe)]
+#[note]
+pub struct UnsafeOpInUnsafeFnDerefOfRawPointerRequiresUnsafe {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_union_field_requires_unsafe)]
+#[note]
+pub struct UnsafeOpInUnsafeFnAccessToUnionFieldRequiresUnsafe {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_mutation_of_layout_constrained_field_requires_unsafe)]
+#[note]
+pub struct UnsafeOpInUnsafeFnMutationOfLayoutConstrainedFieldRequiresUnsafe {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_borrow_of_layout_constrained_field_requires_unsafe)]
+pub struct UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe)]
+#[note]
+pub struct UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe<'a> {
+    #[label]
+    pub span: Span,
+    pub function: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_call_to_unsafe_fn_requires_unsafe, code = "E0133")]
+#[note]
+pub struct CallToUnsafeFunctionRequiresUnsafe<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub function: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_call_to_unsafe_fn_requires_unsafe_nameless, code = "E0133")]
+#[note]
+pub struct CallToUnsafeFunctionRequiresUnsafeNameless {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
+#[note]
+pub struct CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub function: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(
+    mir_build_call_to_unsafe_fn_requires_unsafe_nameless_unsafe_op_in_unsafe_fn_allowed,
+    code = "E0133"
+)]
+#[note]
+pub struct CallToUnsafeFunctionRequiresUnsafeNamelessUnsafeOpInUnsafeFnAllowed {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_inline_assembly_requires_unsafe, code = "E0133")]
+#[note]
+pub struct UseOfInlineAssemblyRequiresUnsafe {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
+#[note]
+pub struct UseOfInlineAssemblyRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_initializing_type_with_requires_unsafe, code = "E0133")]
+#[note]
+pub struct InitializingTypeWithRequiresUnsafe {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(
+    mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed,
+    code = "E0133"
+)]
+#[note]
+pub struct InitializingTypeWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_mutable_static_requires_unsafe, code = "E0133")]
+#[note]
+pub struct UseOfMutableStaticRequiresUnsafe {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
+#[note]
+pub struct UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_extern_static_requires_unsafe, code = "E0133")]
+#[note]
+pub struct UseOfExternStaticRequiresUnsafe {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
+#[note]
+pub struct UseOfExternStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_deref_raw_pointer_requires_unsafe, code = "E0133")]
+#[note]
+pub struct DerefOfRawPointerRequiresUnsafe {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
+#[note]
+pub struct DerefOfRawPointerRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_union_field_requires_unsafe, code = "E0133")]
+#[note]
+pub struct AccessToUnionFieldRequiresUnsafe {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
+#[note]
+pub struct AccessToUnionFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_mutation_of_layout_constrained_field_requires_unsafe, code = "E0133")]
+#[note]
+pub struct MutationOfLayoutConstrainedFieldRequiresUnsafe {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(
+    mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed,
+    code = "E0133"
+)]
+#[note]
+pub struct MutationOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_borrow_of_layout_constrained_field_requires_unsafe, code = "E0133")]
+#[note]
+pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafe {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(
+    mir_build_borrow_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed,
+    code = "E0133"
+)]
+#[note]
+pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_call_to_fn_with_requires_unsafe, code = "E0133")]
+#[note]
+pub struct CallToFunctionWithRequiresUnsafe<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub function: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
+#[note]
+pub struct CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub function: &'a str,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_unused_unsafe)]
+pub struct UnusedUnsafe {
+    #[label]
+    pub span: Span,
+    #[subdiagnostic]
+    pub enclosing: Option<UnusedUnsafeEnclosing>,
+}
+
+#[derive(Subdiagnostic)]
+pub enum UnusedUnsafeEnclosing {
+    #[label(mir_build_unused_unsafe_enclosing_block_label)]
+    Block {
+        #[primary_span]
+        span: Span,
+    },
+    #[label(mir_build_unused_unsafe_enclosing_fn_label)]
+    Function {
+        #[primary_span]
+        span: Span,
+    },
+}
+
+pub(crate) struct NonExhaustivePatternsTypeNotEmpty<'p, 'tcx, 'm> {
+    pub cx: &'m MatchCheckCtxt<'p, 'tcx>,
+    pub expr_span: Span,
+    pub span: Span,
+    pub ty: Ty<'tcx>,
+}
+
+impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> {
+    fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
+        let mut diag = handler.struct_span_err_with_code(
+            self.span,
+            rustc_errors::fluent::mir_build_non_exhaustive_patterns_type_not_empty,
+            error_code!(E0004),
+        );
+
+        let peeled_ty = self.ty.peel_refs();
+        diag.set_arg("ty", self.ty);
+        diag.set_arg("peeled_ty", peeled_ty);
+
+        if let ty::Adt(def, _) = peeled_ty.kind() {
+            let def_span = self
+                .cx
+                .tcx
+                .hir()
+                .get_if_local(def.did())
+                .and_then(|node| node.ident())
+                .map(|ident| ident.span)
+                .unwrap_or_else(|| self.cx.tcx.def_span(def.did()));
+
+            // workaround to make test pass
+            let mut span: MultiSpan = def_span.into();
+            span.push_span_label(def_span, "");
+
+            diag.span_note(span, rustc_errors::fluent::def_note);
+        }
+
+        let is_variant_list_non_exhaustive = match self.ty.kind() {
+            ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local() => {
+                true
+            }
+            _ => false,
+        };
+
+        if is_variant_list_non_exhaustive {
+            diag.note(rustc_errors::fluent::non_exhaustive_type_note);
+        } else {
+            diag.note(rustc_errors::fluent::type_note);
+        }
+
+        if let ty::Ref(_, sub_ty, _) = self.ty.kind() {
+            if !sub_ty.is_inhabited_from(self.cx.tcx, self.cx.module, self.cx.param_env) {
+                diag.note(rustc_errors::fluent::reference_note);
+            }
+        }
+
+        let mut suggestion = None;
+        let sm = self.cx.tcx.sess.source_map();
+        if self.span.eq_ctxt(self.expr_span) {
+            // Get the span for the empty match body `{}`.
+            let (indentation, more) = if let Some(snippet) = sm.indentation_before(self.span) {
+                (format!("\n{}", snippet), "    ")
+            } else {
+                (" ".to_string(), "")
+            };
+            suggestion = Some((
+                self.span.shrink_to_hi().with_hi(self.expr_span.hi()),
+                format!(
+                    " {{{indentation}{more}_ => todo!(),{indentation}}}",
+                    indentation = indentation,
+                    more = more,
+                ),
+            ));
+        }
+
+        if let Some((span, sugg)) = suggestion {
+            diag.span_suggestion_verbose(
+                span,
+                rustc_errors::fluent::suggestion,
+                sugg,
+                Applicability::HasPlaceholders,
+            );
+        } else {
+            diag.help(rustc_errors::fluent::help);
+        }
+
+        diag
+    }
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_static_in_pattern, code = "E0158")]
+pub struct StaticInPattern {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_assoc_const_in_pattern, code = "E0158")]
+pub struct AssocConstInPattern {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_const_param_in_pattern, code = "E0158")]
+pub struct ConstParamInPattern {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_non_const_path, code = "E0080")]
+pub struct NonConstPath {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_unreachable_pattern)]
+pub struct UnreachablePattern {
+    #[label]
+    pub span: Option<Span>,
+    #[label(catchall_label)]
+    pub catchall: Option<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_const_pattern_depends_on_generic_parameter)]
+pub struct ConstPatternDependsOnGenericParameter {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_could_not_eval_const_pattern)]
+pub struct CouldNotEvalConstPattern {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper, code = "E0030")]
+pub struct LowerRangeBoundMustBeLessThanOrEqualToUpper {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[note(teach_note)]
+    pub teach: Option<()>,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_lower_range_bound_must_be_less_than_upper, code = "E0579")]
+pub struct LowerRangeBoundMustBeLessThanUpper {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_leading_irrefutable_let_patterns)]
+#[note]
+#[help]
+pub struct LeadingIrrefutableLetPatterns {
+    pub count: usize,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_trailing_irrefutable_let_patterns)]
+#[note]
+#[help]
+pub struct TrailingIrrefutableLetPatterns {
+    pub count: usize,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_bindings_with_variant_name, code = "E0170")]
+pub struct BindingsWithVariantName {
+    #[suggestion(code = "{ty_path}::{ident}", applicability = "machine-applicable")]
+    pub suggestion: Option<Span>,
+    pub ty_path: String,
+    pub ident: Ident,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_irrefutable_let_patterns_generic_let)]
+#[note]
+#[help]
+pub struct IrrefutableLetPatternsGenericLet {
+    pub count: usize,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_irrefutable_let_patterns_if_let)]
+#[note]
+#[help]
+pub struct IrrefutableLetPatternsIfLet {
+    pub count: usize,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_irrefutable_let_patterns_if_let_guard)]
+#[note]
+#[help]
+pub struct IrrefutableLetPatternsIfLetGuard {
+    pub count: usize,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_irrefutable_let_patterns_let_else)]
+#[note]
+#[help]
+pub struct IrrefutableLetPatternsLetElse {
+    pub count: usize,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_irrefutable_let_patterns_while_let)]
+#[note]
+#[help]
+pub struct IrrefutableLetPatternsWhileLet {
+    pub count: usize,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_borrow_of_moved_value)]
+pub struct BorrowOfMovedValue<'tcx> {
+    #[primary_span]
+    pub span: Span,
+    #[label]
+    #[label(occurs_because_label)]
+    pub binding_span: Span,
+    #[label(value_borrowed_label)]
+    pub conflicts_ref: Vec<Span>,
+    pub name: Ident,
+    pub ty: Ty<'tcx>,
+    #[suggestion(code = "ref ", applicability = "machine-applicable")]
+    pub suggest_borrowing: Option<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_multiple_mut_borrows)]
+pub struct MultipleMutBorrows {
+    #[primary_span]
+    pub span: Span,
+    #[label]
+    pub binding_span: Span,
+    #[subdiagnostic]
+    pub occurences: Vec<MultipleMutBorrowOccurence>,
+    pub name: Ident,
+}
+
+#[derive(Subdiagnostic)]
+pub enum MultipleMutBorrowOccurence {
+    #[label(mutable_borrow)]
+    Mutable {
+        #[primary_span]
+        span: Span,
+        name_mut: Ident,
+    },
+    #[label(immutable_borrow)]
+    Immutable {
+        #[primary_span]
+        span: Span,
+        name_immut: Ident,
+    },
+    #[label(moved)]
+    Moved {
+        #[primary_span]
+        span: Span,
+        name_moved: Ident,
+    },
+}
diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs
index 87975294595..2b05e92fdcf 100644
--- a/compiler/rustc_mir_build/src/lib.rs
+++ b/compiler/rustc_mir_build/src/lib.rs
@@ -19,6 +19,7 @@ extern crate rustc_middle;
 
 mod build;
 mod check_unsafety;
+mod errors;
 mod lints;
 pub mod thir;
 
diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs
index b21f30efce8..8529c64cd5c 100644
--- a/compiler/rustc_mir_build/src/lints.rs
+++ b/compiler/rustc_mir_build/src/lints.rs
@@ -1,3 +1,4 @@
+use crate::errors::UnconditionalRecursion;
 use rustc_data_structures::graph::iterate::{
     NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
 };
@@ -36,19 +37,11 @@ pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
 
         let sp = tcx.def_span(def_id);
         let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-        tcx.struct_span_lint_hir(
+        tcx.emit_spanned_lint(
             UNCONDITIONAL_RECURSION,
             hir_id,
             sp,
-            "function cannot return without recursing",
-            |lint| {
-                lint.span_label(sp, "cannot return without recursing");
-                // offer some help to the programmer.
-                for call_span in vis.reachable_recursive_calls {
-                    lint.span_label(call_span, "recursive call site");
-                }
-                lint.help("a `loop` may express intention better if this is on purpose")
-            },
+            UnconditionalRecursion { span: sp, call_sites: vis.reachable_recursive_calls },
         );
     }
 }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index e369dba5524..a94d8d6c643 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -4,18 +4,22 @@ use super::usefulness::{
 };
 use super::{PatCtxt, PatternError};
 
+use crate::errors::*;
+
 use rustc_arena::TypedArena;
 use rustc_ast::Mutability;
 use rustc_errors::{
-    error_code, pluralize, struct_span_err, Applicability, DelayDm, Diagnostic, DiagnosticBuilder,
-    ErrorGuaranteed, MultiSpan,
+    pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
+    MultiSpan,
 };
 use rustc_hir as hir;
 use rustc_hir::def::*;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{HirId, Pat};
+use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
+
 use rustc_session::lint::builtin::{
     BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS,
 };
@@ -107,28 +111,20 @@ impl PatCtxt<'_, '_> {
         for error in &self.errors {
             match *error {
                 PatternError::StaticInPattern(span) => {
-                    self.span_e0158(span, "statics cannot be referenced in patterns")
+                    self.tcx.sess.emit_err(StaticInPattern { span });
                 }
                 PatternError::AssocConstInPattern(span) => {
-                    self.span_e0158(span, "associated consts cannot be referenced in patterns")
+                    self.tcx.sess.emit_err(AssocConstInPattern { span });
                 }
                 PatternError::ConstParamInPattern(span) => {
-                    self.span_e0158(span, "const parameters cannot be referenced in patterns")
+                    self.tcx.sess.emit_err(ConstParamInPattern { span });
                 }
                 PatternError::NonConstPath(span) => {
-                    rustc_middle::mir::interpret::struct_error(
-                        self.tcx.at(span),
-                        "runtime values cannot be referenced in patterns",
-                    )
-                    .emit();
+                    self.tcx.sess.emit_err(NonConstPath { span });
                 }
             }
         }
     }
-
-    fn span_e0158(&self, span: Span, text: &str) {
-        struct_span_err!(self.tcx.sess, span, E0158, "{}", text).emit();
-    }
 }
 
 impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
@@ -345,29 +341,6 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
             );
             return true;
         }
-        let lint_affix = |affix: &[Option<(Span, bool)>], kind, suggestion| {
-            let span_start = affix[0].unwrap().0;
-            let span_end = affix.last().unwrap().unwrap().0;
-            let span = span_start.to(span_end);
-            let cnt = affix.len();
-            let s = pluralize!(cnt);
-            cx.tcx.struct_span_lint_hir(
-                IRREFUTABLE_LET_PATTERNS,
-                top,
-                span,
-                format!("{kind} irrefutable pattern{s} in let chain"),
-                |lint| {
-                    lint.note(format!(
-                        "{these} pattern{s} will always match",
-                        these = pluralize!("this", cnt),
-                    ))
-                    .help(format!(
-                        "consider moving {} {suggestion}",
-                        if cnt > 1 { "them" } else { "it" }
-                    ))
-                },
-            );
-        };
         if let Some(until) = chain_refutabilities.iter().position(|r| !matches!(*r, Some((_, false)))) && until > 0 {
             // The chain has a non-zero prefix of irrefutable `let` statements.
 
@@ -381,13 +354,21 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
             if !matches!(let_source, LetSource::WhileLet | LetSource::IfLetGuard) {
                 // Emit the lint
                 let prefix = &chain_refutabilities[..until];
-                lint_affix(prefix, "leading", "outside of the construct");
+                let span_start = prefix[0].unwrap().0;
+                let span_end = prefix.last().unwrap().unwrap().0;
+                let span = span_start.to(span_end);
+                let count = prefix.len();
+                cx.tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, top, span, LeadingIrrefutableLetPatterns { count });
             }
         }
         if let Some(from) = chain_refutabilities.iter().rposition(|r| !matches!(*r, Some((_, false)))) && from != (chain_refutabilities.len() - 1) {
             // The chain has a non-empty suffix of irrefutable `let` statements
             let suffix = &chain_refutabilities[from + 1..];
-            lint_affix(suffix, "trailing", "into the body");
+            let span_start = suffix[0].unwrap().0;
+            let span_end = suffix.last().unwrap().unwrap().0;
+            let span = span_start.to(span_end);
+            let count = suffix.len();
+            cx.tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, top, span, TrailingIrrefutableLetPatterns { count });
         }
         true
     }
@@ -568,32 +549,22 @@ fn check_for_bindings_named_same_as_variants(
             })
         {
             let variant_count = edef.variants().len();
-            cx.tcx.struct_span_lint_hir(
+            let ty_path = with_no_trimmed_paths!({
+                cx.tcx.def_path_str(edef.did())
+            });
+            cx.tcx.emit_spanned_lint(
                 BINDINGS_WITH_VARIANT_NAME,
                 p.hir_id,
                 p.span,
-                DelayDm(|| format!(
-                    "pattern binding `{}` is named the same as one \
-                        of the variants of the type `{}`",
-                    ident, cx.tcx.def_path_str(edef.did())
-                )),
-                |lint| {
-                    let ty_path = cx.tcx.def_path_str(edef.did());
-                    lint.code(error_code!(E0170));
-
+                BindingsWithVariantName {
                     // If this is an irrefutable pattern, and there's > 1 variant,
                     // then we can't actually match on this. Applying the below
                     // suggestion would produce code that breaks on `check_irrefutable`.
-                    if rf == Refutable || variant_count == 1 {
-                        lint.span_suggestion(
-                            p.span,
-                            "to match on the variant, qualify the path",
-                            format!("{}::{}", ty_path, ident),
-                            Applicability::MachineApplicable,
-                        );
-                    }
-
-                    lint
+                    suggestion: if rf == Refutable || variant_count == 1 {
+                        Some(p.span)
+                    } else { None },
+                    ty_path,
+                    ident,
                 },
             )
         }
@@ -611,14 +582,12 @@ fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool {
 }
 
 fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option<Span>) {
-    tcx.struct_span_lint_hir(UNREACHABLE_PATTERNS, id, span, "unreachable pattern", |lint| {
-        if let Some(catchall) = catchall {
-            // We had a catchall pattern, hint at that.
-            lint.span_label(span, "unreachable pattern");
-            lint.span_label(catchall, "matches any value");
-        }
-        lint
-    });
+    tcx.emit_spanned_lint(
+        UNREACHABLE_PATTERNS,
+        id,
+        span,
+        UnreachablePattern { span: if catchall.is_some() { Some(span) } else { None }, catchall },
+    );
 }
 
 fn irrefutable_let_pattern(tcx: TyCtxt<'_>, id: HirId, span: Span) {
@@ -634,67 +603,18 @@ fn irrefutable_let_patterns(
     span: Span,
 ) {
     macro_rules! emit_diag {
-        (
-            $lint:expr,
-            $source_name:expr,
-            $note_sufix:expr,
-            $help_sufix:expr
-        ) => {{
-            let s = pluralize!(count);
-            let these = pluralize!("this", count);
-            tcx.struct_span_lint_hir(
-                IRREFUTABLE_LET_PATTERNS,
-                id,
-                span,
-                format!("irrefutable {} pattern{s}", $source_name),
-                |lint| {
-                    lint.note(&format!(
-                        "{these} pattern{s} will always match, so the {}",
-                        $note_sufix
-                    ))
-                    .help(concat!("consider ", $help_sufix))
-                },
-            )
+        ($lint:tt) => {{
+            tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, id, span, $lint { count });
         }};
     }
 
     match source {
-        LetSource::GenericLet => {
-            emit_diag!(lint, "`let`", "`let` is useless", "removing `let`");
-        }
-        LetSource::IfLet => {
-            emit_diag!(
-                lint,
-                "`if let`",
-                "`if let` is useless",
-                "replacing the `if let` with a `let`"
-            );
-        }
-        LetSource::IfLetGuard => {
-            emit_diag!(
-                lint,
-                "`if let` guard",
-                "guard is useless",
-                "removing the guard and adding a `let` inside the match arm"
-            );
-        }
-        LetSource::LetElse => {
-            emit_diag!(
-                lint,
-                "`let...else`",
-                "`else` clause is useless",
-                "removing the `else` clause"
-            );
-        }
-        LetSource::WhileLet => {
-            emit_diag!(
-                lint,
-                "`while let`",
-                "loop will never exit",
-                "instead using a `loop { ... }` with a `let` inside it"
-            );
-        }
-    };
+        LetSource::GenericLet => emit_diag!(IrrefutableLetPatternsGenericLet),
+        LetSource::IfLet => emit_diag!(IrrefutableLetPatternsIfLet),
+        LetSource::IfLetGuard => emit_diag!(IrrefutableLetPatternsIfLetGuard),
+        LetSource::LetElse => emit_diag!(IrrefutableLetPatternsLetElse),
+        LetSource::WhileLet => emit_diag!(IrrefutableLetPatternsWhileLet),
+    }
 }
 
 fn is_let_irrefutable<'p, 'tcx>(
@@ -760,15 +680,17 @@ fn non_exhaustive_match<'p, 'tcx>(
     // informative.
     let mut err;
     let pattern;
-    let mut patterns_len = 0;
+    let patterns_len;
     if is_empty_match && !non_empty_enum {
-        err = create_e0004(
-            cx.tcx.sess,
-            sp,
-            format!("non-exhaustive patterns: type `{}` is non-empty", scrut_ty),
-        );
-        pattern = "_".to_string();
+        cx.tcx.sess.emit_err(NonExhaustivePatternsTypeNotEmpty {
+            cx,
+            expr_span,
+            span: sp,
+            ty: scrut_ty,
+        });
+        return;
     } else {
+        // FIXME: migration of this diagnostic will require list support
         let joined_patterns = joined_uncovered_patterns(cx, &witnesses);
         err = create_e0004(
             cx.tcx.sess,
@@ -1039,24 +961,17 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa
                 }
             });
             if !conflicts_ref.is_empty() {
-                let occurs_because = format!(
-                    "move occurs because `{}` has type `{}` which does not implement the `Copy` trait",
+                sess.emit_err(BorrowOfMovedValue {
+                    span: pat.span,
+                    binding_span,
+                    conflicts_ref,
                     name,
-                    typeck_results.node_type(pat.hir_id),
-                );
-                let mut err = sess.struct_span_err(pat.span, "borrow of moved value");
-                err.span_label(binding_span, format!("value moved into `{}` here", name))
-                    .span_label(binding_span, occurs_because)
-                    .span_labels(conflicts_ref, "value borrowed here after move");
-                if pat.span.contains(binding_span) {
-                    err.span_suggestion_verbose(
-                        binding_span.shrink_to_lo(),
-                        "borrow this binding in the pattern to avoid moving the value",
-                        "ref ".to_string(),
-                        Applicability::MachineApplicable,
-                    );
-                }
-                err.emit();
+                    ty: typeck_results.node_type(pat.hir_id),
+                    suggest_borrowing: pat
+                        .span
+                        .contains(binding_span)
+                        .then(|| binding_span.shrink_to_lo()),
+                });
             }
             return;
         }
@@ -1086,19 +1001,18 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa
     // Report errors if any.
     if !conflicts_mut_mut.is_empty() {
         // Report mutability conflicts for e.g. `ref mut x @ Some(ref mut y)`.
-        let mut err = sess
-            .struct_span_err(pat.span, "cannot borrow value as mutable more than once at a time");
-        err.span_label(binding_span, format!("first mutable borrow, by `{}`, occurs here", name));
-        for (span, name) in conflicts_mut_mut {
-            err.span_label(span, format!("another mutable borrow, by `{}`, occurs here", name));
+        let mut occurences = vec![];
+
+        for (span, name_mut) in conflicts_mut_mut {
+            occurences.push(MultipleMutBorrowOccurence::Mutable { span, name_mut });
         }
-        for (span, name) in conflicts_mut_ref {
-            err.span_label(span, format!("also borrowed as immutable, by `{}`, here", name));
+        for (span, name_immut) in conflicts_mut_ref {
+            occurences.push(MultipleMutBorrowOccurence::Immutable { span, name_immut });
         }
-        for (span, name) in conflicts_move {
-            err.span_label(span, format!("also moved into `{}` here", name));
+        for (span, name_moved) in conflicts_move {
+            occurences.push(MultipleMutBorrowOccurence::Moved { span, name_moved });
         }
-        err.emit();
+        sess.emit_err(MultipleMutBorrows { span: pat.span, binding_span, occurences, name });
     } else if !conflicts_mut_ref.is_empty() {
         // Report mutability conflicts for e.g. `ref x @ Some(ref mut y)` or the converse.
         let (primary, also) = match mut_outer {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 48a231a6cd6..2c775b39718 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -6,10 +6,12 @@ mod deconstruct_pat;
 mod usefulness;
 
 pub(crate) use self::check_match::check_match;
+pub(crate) use self::usefulness::MatchCheckCtxt;
 
+use crate::errors::*;
 use crate::thir::util::UserAnnotatedTyHelpers;
 
-use rustc_errors::struct_span_err;
+use rustc_errors::error_code;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::pat_util::EnumerateAndAdjustIterator;
@@ -139,13 +141,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             }
             // `x..y` where `x >= y`. The range is empty => error.
             (RangeEnd::Excluded, _) => {
-                struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0579,
-                    "lower range bound must be less than upper"
-                )
-                .emit();
+                self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanUpper { span });
                 PatKind::Wild
             }
             // `x..=y` where `x == y`.
@@ -156,23 +152,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             }
             // `x..=y` where `x > y` hence the range is empty => error.
             (RangeEnd::Included, _) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
+                self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanOrEqualToUpper {
                     span,
-                    E0030,
-                    "lower range bound must be less than or equal to upper"
-                );
-                err.span_label(span, "lower bound larger than upper bound");
-                if self.tcx.sess.teach(&err.get_code().unwrap()) {
-                    err.note(
-                        "When matching against a range, the compiler \
-                              verifies that the range is non-empty. Range \
-                              patterns include both end-points, so this is \
-                              equivalent to requiring the start of the range \
-                              to be less than or equal to the end of the range.",
-                    );
-                }
-                err.emit();
+                    teach: if self.tcx.sess.teach(&error_code!(E0030)) { Some(()) } else { None },
+                });
                 PatKind::Wild
             }
         }
@@ -501,7 +484,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             }
 
             Err(_) => {
-                self.tcx.sess.span_err(span, "could not evaluate constant pattern");
+                self.tcx.sess.emit_err(CouldNotEvalConstPattern { span });
                 return pat_from_kind(PatKind::Wild);
             }
         };
@@ -548,11 +531,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             Err(ErrorHandled::TooGeneric) => {
                 // While `Reported | Linted` cases will have diagnostics emitted already
                 // it is not true for TooGeneric case, so we need to give user more information.
-                self.tcx.sess.span_err(span, "constant pattern depends on a generic parameter");
+                self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
                 pat_from_kind(PatKind::Wild)
             }
             Err(_) => {
-                self.tcx.sess.span_err(span, "could not evaluate constant pattern");
+                self.tcx.sess.emit_err(CouldNotEvalConstPattern { span });
                 pat_from_kind(PatKind::Wild)
             }
         }
@@ -584,7 +567,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             mir::ConstantKind::Val(_, _) => self.const_to_pat(value, id, span, false).kind,
             mir::ConstantKind::Unevaluated(..) => {
                 // If we land here it means the const can't be evaluated because it's `TooGeneric`.
-                self.tcx.sess.span_err(span, "constant pattern depends on a generic parameter");
+                self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
                 return PatKind::Wild;
             }
         }
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index 044b7ce65bd..e384cfe1659 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -701,8 +701,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                     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().into(),
-                                Scalar::from_bool(false).into(),
+                                const_arg.to_scalar(),
+                                Scalar::from_bool(false),
                             );
                             this.ecx.write_immediate(val, &dest)
                         } else {
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index 3e45319431c..74d8337653f 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -129,6 +129,7 @@
 
 use std::collections::hash_map::{Entry, OccupiedEntry};
 
+use crate::simplify::remove_dead_blocks;
 use crate::MirPass;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_index::bit_set::BitSet;
@@ -235,6 +236,12 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
             apply_merges(body, tcx, &merges, &merged_locals);
         }
 
+        if round_count != 0 {
+            // Merging can introduce overlap between moved arguments and/or call destination in an
+            // unreachable code, which validator considers to be ill-formed.
+            remove_dead_blocks(tcx, body);
+        }
+
         trace!(round_count);
     }
 }
diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs
index 558a372fb1e..3a2bf051516 100644
--- a/compiler/rustc_mir_transform/src/sroa.rs
+++ b/compiler/rustc_mir_transform/src/sroa.rs
@@ -182,7 +182,7 @@ fn replace_flattened_locals<'tcx>(
     let mut fragments = IndexVec::new();
     for (k, v) in &replacements.fields {
         fragments.ensure_contains_elem(k.local, || Vec::new());
-        fragments[k.local].push((&k.projection[..], *v));
+        fragments[k.local].push((k.projection, *v));
     }
     debug!(?fragments);
 
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 10ea4d29cfe..deeeb9af4eb 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -595,8 +595,8 @@ fn check_recursion_limit<'tcx>(
         let def_path_str = tcx.def_path_str(def_id);
         let (shrunk, written_to_path) = shrunk_instance_name(tcx, &instance);
         let mut path = PathBuf::new();
-        let was_written = if written_to_path.is_some() {
-            path = written_to_path.unwrap();
+        let was_written = if let Some(written_to_path) = written_to_path {
+            path = written_to_path;
             Some(())
         } else {
             None
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index bebb012660a..40b88788caa 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -25,7 +25,7 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_ast::util::case::Case;
 use rustc_ast::AttrId;
 use rustc_ast::DUMMY_NODE_ID;
-use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, DelimArgs, Extern};
+use rustc_ast::{self as ast, AnonConst, AttrStyle, Const, DelimArgs, Extern};
 use rustc_ast::{Async, AttrArgs, AttrArgsEq, Expr, ExprKind, MacDelimiter, Mutability, StrLit};
 use rustc_ast::{HasAttrs, HasTokens, Unsafe, Visibility, VisibilityKind};
 use rustc_ast_pretty::pprust;
@@ -1217,11 +1217,7 @@ impl<'a> Parser<'a> {
             value: self.mk_expr(blk.span, ExprKind::Block(blk, None)),
         };
         let blk_span = anon_const.value.span;
-        Ok(self.mk_expr_with_attrs(
-            span.to(blk_span),
-            ExprKind::ConstBlock(anon_const),
-            AttrVec::from(attrs),
-        ))
+        Ok(self.mk_expr_with_attrs(span.to(blk_span), ExprKind::ConstBlock(anon_const), attrs))
     }
 
     /// Parses mutability (`mut` or nothing).
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 2d432e3f5bd..5333d3b8587 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -277,8 +277,7 @@ impl<'a> Parser<'a> {
                         if let Some(arg) = args
                             .iter()
                             .rev()
-                            .skip_while(|arg| matches!(arg, AngleBracketedArg::Constraint(_)))
-                            .next()
+                            .find(|arg| !matches!(arg, AngleBracketedArg::Constraint(_)))
                         {
                             err.span_suggestion_verbose(
                                 arg.span().shrink_to_hi(),
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index a71ae717a50..f5556738bff 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -787,7 +787,6 @@ impl<'tcx> DeadVisitor<'tcx> {
         let mut dead_codes = dead_codes
             .iter()
             .filter(|v| !v.name.as_str().starts_with('_'))
-            .map(|v| v)
             .collect::<Vec<&DeadVariant>>();
         if dead_codes.is_empty() {
             return;
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index a7854cd4998..272386f313e 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -121,7 +121,7 @@ impl<'k> StatCollector<'k> {
 
     fn print(&self, title: &str, prefix: &str) {
         let mut nodes: Vec<_> = self.nodes.iter().collect();
-        nodes.sort_by_key(|&(_, ref node)| node.stats.count * node.stats.size);
+        nodes.sort_by_key(|(_, node)| node.stats.count * node.stats.size);
 
         let total_size = nodes.iter().map(|(_, node)| node.stats.count * node.stats.size).sum();
 
@@ -147,7 +147,7 @@ impl<'k> StatCollector<'k> {
             );
             if !node.subnodes.is_empty() {
                 let mut subnodes: Vec<_> = node.subnodes.iter().collect();
-                subnodes.sort_by_key(|&(_, ref subnode)| subnode.count * subnode.size);
+                subnodes.sort_by_key(|(_, subnode)| subnode.count * subnode.size);
 
                 for (label, subnode) in subnodes {
                     let size = subnode.count * subnode.size;
diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs
index 99efed0b7fb..9a40b847d85 100644
--- a/compiler/rustc_passes/src/lang_items.rs
+++ b/compiler/rustc_passes/src/lang_items.rs
@@ -83,7 +83,6 @@ impl<'tcx> LanguageItemCollector<'tcx> {
                         .map(|p| p.display().to_string())
                         .collect::<Vec<_>>()
                         .join(", ")
-                        .into()
                 };
                 let first_defined_span = self.tcx.hir().span_if_local(original_def_id);
                 let mut orig_crate_name = Empty;
@@ -98,7 +97,6 @@ impl<'tcx> LanguageItemCollector<'tcx> {
                         .map(|p| p.display().to_string())
                         .collect::<Vec<_>>()
                         .join(", ")
-                        .into()
                 };
                 if first_defined_span.is_none() {
                     orig_crate_name = self.tcx.crate_name(original_def_id.krate);
diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs
index ac9653b9007..c4e605c1852 100644
--- a/compiler/rustc_query_impl/src/on_disk_cache.rs
+++ b/compiler/rustc_query_impl/src/on_disk_cache.rs
@@ -965,7 +965,7 @@ impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for Symbol {
                     s.emit_str(self.as_str());
                 }
                 Entry::Occupied(o) => {
-                    let x = o.get().clone();
+                    let x = *o.get();
                     s.emit_u8(SYMBOL_OFFSET);
                     s.emit_usize(x);
                 }
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index f4a6a08df1c..cf635996268 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -576,7 +576,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                 // Ensure there is at most one `self` in the list
                 let self_spans = items
                     .iter()
-                    .filter_map(|&(ref use_tree, _)| {
+                    .filter_map(|(use_tree, _)| {
                         if let ast::UseTreeKind::Simple(..) = use_tree.kind {
                             if use_tree.ident().name == kw::SelfLower {
                                 return Some(use_tree.span);
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 49bbe37ee43..600308b6508 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -277,11 +277,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                 let override_suggestion =
                     if ["true", "false"].contains(&item_str.to_string().to_lowercase().as_str()) {
                         let item_typo = item_str.to_string().to_lowercase();
-                        Some((
-                            item_span,
-                            "you may want to use a bool value instead",
-                            format!("{}", item_typo),
-                        ))
+                        Some((item_span, "you may want to use a bool value instead", item_typo))
                     // FIXME(vincenzopalazzo): make the check smarter,
                     // and maybe expand with levenshtein distance checks
                     } else if item_str.as_str() == "printf" {
@@ -2324,7 +2320,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                         let message = format!("consider introducing lifetime `{}` here", name);
                         should_continue = suggest(err, false, span, &message, sugg);
                     } else {
-                        let message = format!("consider introducing a named lifetime parameter");
+                        let message = "consider introducing a named lifetime parameter";
                         should_continue = suggest(err, false, span, &message, sugg);
                     }
                 }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 24e4b5bdd3f..4861ee746aa 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -1491,7 +1491,7 @@ impl<'a> Resolver<'a> {
             label_res_map: self.label_res_map.clone(),
             lifetimes_res_map: self.lifetimes_res_map.clone(),
             extra_lifetime_params_map: self.extra_lifetime_params_map.clone(),
-            next_node_id: self.next_node_id.clone(),
+            next_node_id: self.next_node_id,
             node_id_to_def_id: self.node_id_to_def_id.clone(),
             def_id_to_node_id: self.def_id_to_node_id.clone(),
             trait_map: self.trait_map.clone(),
diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs
index 1855a49c1ec..6f1b31ff9c3 100644
--- a/compiler/rustc_session/src/filesearch.rs
+++ b/compiler/rustc_session/src/filesearch.rs
@@ -122,7 +122,7 @@ pub fn sysroot_candidates() -> SmallVec<[PathBuf; 2]> {
     let target = crate::config::host_triple();
     let mut sysroot_candidates: SmallVec<[PathBuf; 2]> =
         smallvec![get_or_default_sysroot().expect("Failed finding sysroot")];
-    let path = current_dll_path().and_then(|s| Ok(s.canonicalize().map_err(|e| e.to_string())?));
+    let path = current_dll_path().and_then(|s| s.canonicalize().map_err(|e| e.to_string()));
     if let Ok(dll) = path {
         // use `parent` twice to chop off the file name and then also the
         // directory containing the dll which should be either `lib` or `bin`.
@@ -165,7 +165,7 @@ pub fn get_or_default_sysroot() -> Result<PathBuf, String> {
     }
 
     fn default_from_rustc_driver_dll() -> Result<PathBuf, String> {
-        let dll = current_dll_path().and_then(|s| Ok(canonicalize(s)))?;
+        let dll = current_dll_path().map(|s| canonicalize(s))?;
 
         // `dll` will be in one of the following two:
         // - compiler's libdir: $sysroot/lib/*.dll
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index fdd883fbeed..01a9b100088 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1323,7 +1323,7 @@ pub fn build_session(
     let warnings_allow = sopts
         .lint_opts
         .iter()
-        .rfind(|&&(ref key, _)| *key == "warnings")
+        .rfind(|&(key, _)| *key == "warnings")
         .map_or(false, |&(_, level)| level == lint::Allow);
     let cap_lints_allow = sopts.lint_cap.map_or(false, |cap| cap == lint::Allow);
     let can_emit_warnings = !(warnings_allow || cap_lints_allow);
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 c9ddb084d63..0845b1b6b09 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
@@ -99,13 +99,8 @@ fn is_c_void_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
         ty::Adt(adt_def, ..) => {
             let def_id = adt_def.0.did;
             let crate_name = tcx.crate_name(def_id.krate);
-            if tcx.item_name(def_id).as_str() == "c_void"
+            tcx.item_name(def_id).as_str() == "c_void"
                 && (crate_name == sym::core || crate_name == sym::std || crate_name == sym::libc)
-            {
-                true
-            } else {
-                false
-            }
         }
         _ => false,
     }
@@ -267,8 +262,7 @@ fn encode_predicates<'tcx>(
 ) -> String {
     // <predicate1[..predicateN]>E as part of vendor extended type
     let mut s = String::new();
-    let predicates: Vec<ty::PolyExistentialPredicate<'tcx>> =
-        predicates.iter().map(|predicate| predicate).collect();
+    let predicates: Vec<ty::PolyExistentialPredicate<'tcx>> = predicates.iter().collect();
     for predicate in predicates {
         s.push_str(&encode_predicate(tcx, predicate, dict, options));
     }
@@ -322,7 +316,7 @@ fn encode_substs<'tcx>(
 ) -> String {
     // [I<subst1..substN>E] as part of vendor extended type
     let mut s = String::new();
-    let substs: Vec<GenericArg<'_>> = substs.iter().map(|subst| subst).collect();
+    let substs: Vec<GenericArg<'_>> = substs.iter().collect();
     if !substs.is_empty() {
         s.push('I');
         for subst in substs {
@@ -703,11 +697,8 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
                         tcx.layout_of(param_env.and(ty)).map_or(false, |layout| layout.is_zst());
                     !is_zst
                 });
-                if field.is_none() {
-                    // Transform repr(transparent) types without non-ZST field into ()
-                    ty = tcx.mk_unit();
-                } else {
-                    let ty0 = tcx.type_of(field.unwrap().did);
+                if let Some(field) = field {
+                    let ty0 = tcx.type_of(field.did);
                     // Generalize any repr(transparent) user-defined type that is either a pointer
                     // or reference, and either references itself or any other type that contains or
                     // references itself, to avoid a reference cycle.
@@ -720,6 +711,9 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
                     } else {
                         ty = transform_ty(tcx, ty0, options);
                     }
+                } else {
+                    // Transform repr(transparent) types without non-ZST field into ()
+                    ty = tcx.mk_unit();
                 }
             } else {
                 ty = tcx.mk_adt(*adt_def, transform_substs(tcx, substs, options));
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index aef2f8ff991..948632ccc6c 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -159,13 +159,12 @@ impl<'tcx> AutoTraitFinder<'tcx> {
             orig_env,
             orig_env,
             &mut fresh_preds,
-            false,
         ) else {
             return AutoTraitResult::NegativeImpl;
         };
 
         let (full_env, full_user_env) = self
-            .evaluate_predicates(&infcx, trait_did, ty, new_env, user_env, &mut fresh_preds, true)
+            .evaluate_predicates(&infcx, trait_did, ty, new_env, user_env, &mut fresh_preds)
             .unwrap_or_else(|| {
                 panic!("Failed to fully process: {:?} {:?} {:?}", ty, trait_did, orig_env)
             });
@@ -247,7 +246,6 @@ impl<'tcx> AutoTraitFinder<'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         user_env: ty::ParamEnv<'tcx>,
         fresh_preds: &mut FxHashSet<ty::Predicate<'tcx>>,
-        only_projections: bool,
     ) -> Option<(ty::ParamEnv<'tcx>, ty::ParamEnv<'tcx>)> {
         let tcx = infcx.tcx;
 
@@ -322,7 +320,6 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                         fresh_preds,
                         &mut predicates,
                         &mut select,
-                        only_projections,
                     ) {
                         return None;
                     }
@@ -600,7 +597,6 @@ impl<'tcx> AutoTraitFinder<'tcx> {
         fresh_preds: &mut FxHashSet<ty::Predicate<'tcx>>,
         predicates: &mut VecDeque<ty::PolyTraitPredicate<'tcx>>,
         selcx: &mut SelectionContext<'_, 'tcx>,
-        only_projections: bool,
     ) -> bool {
         let dummy_cause = ObligationCause::dummy();
 
@@ -744,7 +740,6 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                                     fresh_preds,
                                     predicates,
                                     selcx,
-                                    only_projections,
                                 ) {
                                     return false;
                                 }
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 7c9fde27420..f8efe9bfa9f 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -138,10 +138,10 @@ pub fn is_const_evaluatable<'tcx>(
                 } else if uv.has_non_region_param() {
                     NotConstEvaluatable::MentionsParam
                 } else {
-                    let guar = infcx.tcx.sess.delay_span_bug(
-                        span,
-                        format!("Missing value for constant, but no error reported?"),
-                    );
+                    let guar = infcx
+                        .tcx
+                        .sess
+                        .delay_span_bug(span, "Missing value for constant, but no error reported?");
                     NotConstEvaluatable::Error(guar)
                 };
 
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 2dd2c568bab..8f317beaa77 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -226,7 +226,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
             let arg_length = arguments.len();
             let distinct = matches!(other, &[ArgKind::Tuple(..)]);
             match (arg_length, arguments.get(0)) {
-                (1, Some(&ArgKind::Tuple(_, ref fields))) => {
+                (1, Some(ArgKind::Tuple(_, fields))) => {
                     format!("a single {}-tuple as argument", fields.len())
                 }
                 _ => format!(
@@ -1574,7 +1574,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     &error.obligation.cause,
                     expected_found.expected,
                     expected_found.found,
-                    err.clone(),
+                    *err,
                 )
                 .emit();
             }
@@ -1583,7 +1583,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     &error.obligation.cause,
                     expected_found.expected,
                     expected_found.found,
-                    err.clone(),
+                    *err,
                 );
                 let code = error.obligation.cause.code().peel_derives().peel_match_impls();
                 if let ObligationCauseCode::BindingObligation(..)
@@ -1735,8 +1735,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 values.map(|(_, is_normalized_ty_expected, normalized_ty, expected_ty)| {
                     infer::ValuePairs::Terms(ExpectedFound::new(
                         is_normalized_ty_expected,
-                        normalized_ty.into(),
-                        expected_ty.into(),
+                        normalized_ty,
+                        expected_ty,
                     ))
                 }),
                 err,
@@ -2332,9 +2332,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                                 // get rid of :: between Trait and <type>
                                 // must be '::' between them, otherwise the parser won't accept the code
                                 suggestions.push((between_span, "".to_string(),));
-                                suggestions.push((generic_arg.span_ext.shrink_to_hi(), format!(">")));
+                                suggestions.push((generic_arg.span_ext.shrink_to_hi(), ">".to_string()));
                             } else {
-                                suggestions.push((trait_path_segment.ident.span.shrink_to_hi(), format!(">")));
+                                suggestions.push((trait_path_segment.ident.span.shrink_to_hi(), ">".to_string()));
                             }
                             err.multipart_suggestion(
                                 message,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 6cab2db3e80..036e8f6d47b 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -2344,28 +2344,33 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 }
             }
             GeneratorInteriorOrUpvar::Upvar(upvar_span) => {
-                // `Some(ref_ty)` if `target_ty` is `&T` and `T` fails to impl `Sync`
-                let refers_to_non_sync = match target_ty.kind() {
-                    ty::Ref(_, ref_ty, _) => match self.evaluate_obligation(&obligation) {
-                        Ok(eval) if !eval.may_apply() => Some(ref_ty),
+                // `Some((ref_ty, is_mut))` if `target_ty` is `&T` or `&mut T` and fails to impl `Send`
+                let non_send = match target_ty.kind() {
+                    ty::Ref(_, ref_ty, mutability) => match self.evaluate_obligation(&obligation) {
+                        Ok(eval) if !eval.may_apply() => Some((ref_ty, mutability.is_mut())),
                         _ => None,
                     },
                     _ => None,
                 };
 
-                let (span_label, span_note) = match refers_to_non_sync {
-                    // if `target_ty` is `&T` and `T` fails to impl `Sync`,
-                    // include suggestions to make `T: Sync` so that `&T: Send`
-                    Some(ref_ty) => (
-                        format!(
-                            "has type `{}` which {}, because `{}` is not `Sync`",
-                            target_ty, trait_explanation, ref_ty
-                        ),
-                        format!(
-                            "captured value {} because `&` references cannot be sent unless their referent is `Sync`",
-                            trait_explanation
-                        ),
-                    ),
+                let (span_label, span_note) = match non_send {
+                    // if `target_ty` is `&T` or `&mut T` and fails to impl `Send`,
+                    // include suggestions to make `T: Sync` so that `&T: Send`,
+                    // or to make `T: Send` so that `&mut T: Send`
+                    Some((ref_ty, is_mut)) => {
+                        let ref_ty_trait = if is_mut { "Send" } else { "Sync" };
+                        let ref_kind = if is_mut { "&mut" } else { "&" };
+                        (
+                            format!(
+                                "has type `{}` which {}, because `{}` is not `{}`",
+                                target_ty, trait_explanation, ref_ty, ref_ty_trait
+                            ),
+                            format!(
+                                "captured value {} because `{}` references cannot be sent unless their referent is `{}`",
+                                trait_explanation, ref_kind, ref_ty_trait
+                            ),
+                        )
+                    }
                     None => (
                         format!("has type `{}` which {}", target_ty, trait_explanation),
                         format!("captured value {}", trait_explanation),
@@ -2740,7 +2745,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             }
                             ty::Closure(def_id, _) => err.span_note(
                                 self.tcx.def_span(def_id),
-                                &format!("required because it's used within this closure"),
+                                "required because it's used within this closure",
                             ),
                             _ => err.note(&msg),
                         };
@@ -3386,7 +3391,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             }
             err.span_note(
                 multi_span,
-                format!("the method call chain might not have had the expected associated types"),
+                "the method call chain might not have had the expected associated types",
             );
         }
     }
diff --git a/compiler/rustc_transmute/src/layout/nfa.rs b/compiler/rustc_transmute/src/layout/nfa.rs
index c2bc47bc043..78fcceb5f2c 100644
--- a/compiler/rustc_transmute/src/layout/nfa.rs
+++ b/compiler/rustc_transmute/src/layout/nfa.rs
@@ -123,7 +123,7 @@ where
             let fix_state = |state| if state == other.start { self.accepting } else { state };
             let entry = transitions.entry(fix_state(source)).or_default();
             for (edge, destinations) in transition {
-                let entry = entry.entry(edge.clone()).or_default();
+                let entry = entry.entry(edge).or_default();
                 for destination in destinations {
                     entry.insert(fix_state(destination));
                 }
@@ -147,7 +147,7 @@ where
             }
             let entry = transitions.entry(source).or_default();
             for (edge, destinations) in transition {
-                let entry = entry.entry(edge.clone()).or_default();
+                let entry = entry.entry(*edge).or_default();
                 for &(mut destination) in destinations {
                     // if dest is accepting state of `other`, replace with accepting state of `self`
                     if destination == other.accepting {
diff --git a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs
index adab343ac98..e4f3e7928da 100644
--- a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs
+++ b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs
@@ -76,11 +76,7 @@ mod rustc {
                 }
             };
 
-            let ret = if self.visibility(def_id).is_accessible_from(parent, *self) {
-                true
-            } else {
-                false
-            };
+            let ret: bool = self.visibility(def_id).is_accessible_from(parent, *self);
 
             trace!(?ret, "ret");
             ret
diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs
index 799ce9d5daa..eadb35cb96d 100644
--- a/library/alloc/src/fmt.rs
+++ b/library/alloc/src/fmt.rs
@@ -419,7 +419,7 @@
 //!         // documentation for details, and the function `pad` can be used
 //!         // to pad strings.
 //!         let decimals = f.precision().unwrap_or(3);
-//!         let string = format!("{:.*}", decimals, magnitude);
+//!         let string = format!("{magnitude:.decimals$}");
 //!         f.pad_integral(true, "", &string)
 //!     }
 //! }
@@ -518,7 +518,7 @@
 //! write!(&mut some_writer, "{}", format_args!("print with a {}", "macro"));
 //!
 //! fn my_fmt_fn(args: fmt::Arguments) {
-//!     write!(&mut io::stdout(), "{}", args);
+//!     write!(&mut io::stdout(), "{args}");
 //! }
 //! my_fmt_fn(format_args!(", or a {} too", "function"));
 //! ```
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 122da675f7e..5f4a666de92 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -2471,8 +2471,8 @@ impl Display for char {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> Pointer for *const T {
     fn fmt(&self, f: &mut Formatter<'_>) -> Result {
-        // Cast is needed here because `.addr()` requires `T: Sized`.
-        pointer_fmt_inner((*self as *const ()).addr(), f)
+        // Cast is needed here because `.expose_addr()` requires `T: Sized`.
+        pointer_fmt_inner((*self as *const ()).expose_addr(), f)
     }
 }
 
diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs
index 0910ce599b7..e08a15571fc 100644
--- a/library/core/src/intrinsics/mir.rs
+++ b/library/core/src/intrinsics/mir.rs
@@ -44,7 +44,8 @@
 //! if you want your MIR to be modified by the full MIR pipeline, or `#![custom_mir(dialect =
 //! "runtime", phase = "optimized")] if you don't.
 //!
-//! [dialect docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/enum.MirPhase.html
+//! [dialect docs]:
+//!     https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/enum.MirPhase.html
 //!
 //! The input to the [`mir!`] macro is:
 //!
@@ -99,6 +100,30 @@
 //!         Return()
 //!     })
 //! }
+//!
+//! #[custom_mir(dialect = "runtime", phase = "optimized")]
+//! fn push_and_pop<T>(v: &mut Vec<T>, value: T) {
+//!     mir!(
+//!         let unused;
+//!         let popped;
+//!
+//!         {
+//!             Call(unused, pop, Vec::push(v, value))
+//!         }
+//!
+//!         pop = {
+//!             Call(popped, drop, Vec::pop(v))
+//!         }
+//!
+//!         drop = {
+//!             Drop(popped, ret)
+//!         }
+//!
+//!         ret = {
+//!             Return()
+//!         }
+//!     )
+//! }
 //! ```
 //!
 //! We can also set off compilation failures that happen in sufficiently late stages of the
@@ -195,10 +220,16 @@
 //!
 //! #### Terminators
 //!
-//!  - [`Goto`] and [`Return`] have associated functions.
+//! Custom MIR does not currently support cleanup blocks or non-trivial unwind paths. As such, there
+//! are no resume and abort terminators, and terminators that might unwind do not have any way to
+//! indicate the unwind block.
+//!
+//!  - [`Goto`], [`Return`], [`Unreachable`], [`Drop`](Drop()), and [`DropAndReplace`] have associated functions.
 //!  - `match some_int_operand` becomes a `SwitchInt`. Each arm should be `literal => basic_block`
 //!     - The exception is the last arm, which must be `_ => basic_block` and corresponds to the
 //!       otherwise branch.
+//!  - [`Call`] has an associated function as well. The third argument of this function is a normal
+//!    function call expresion, for example `my_other_function(a, 5)`.
 //!
 
 #![unstable(
@@ -223,6 +254,10 @@ macro_rules! define {
 
 define!("mir_return", fn Return() -> BasicBlock);
 define!("mir_goto", fn Goto(destination: BasicBlock) -> BasicBlock);
+define!("mir_unreachable", fn Unreachable() -> BasicBlock);
+define!("mir_drop", fn Drop<T>(place: T, goto: BasicBlock));
+define!("mir_drop_and_replace", fn DropAndReplace<T>(place: T, value: T, goto: BasicBlock));
+define!("mir_call", fn Call<T>(place: T, goto: BasicBlock, call: T));
 define!("mir_retag", fn Retag<T>(place: T));
 define!("mir_retag_raw", fn RetagRaw<T>(place: T));
 define!("mir_move", fn Move<T>(place: T) -> T);
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 8bd2ed45c0a..2c469f61854 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -1002,6 +1002,17 @@ impl<T> [T] {
     /// assert_eq!(chunks, &[['l', 'o'], ['r', 'e']]);
     /// assert_eq!(remainder, &['m']);
     /// ```
+    ///
+    /// If you expect the slice to be an exact multiple, you can combine
+    /// `let`-`else` with an empty slice pattern:
+    /// ```
+    /// #![feature(slice_as_chunks)]
+    /// let slice = ['R', 'u', 's', 't'];
+    /// let (chunks, []) = slice.as_chunks::<2>() else {
+    ///     panic!("slice didn't have even length")
+    /// };
+    /// assert_eq!(chunks, &[['R', 'u'], ['s', 't']]);
+    /// ```
     #[unstable(feature = "slice_as_chunks", issue = "74985")]
     #[inline]
     #[must_use]
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index 4748ac9d97e..b385ebde439 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -1567,3 +1567,31 @@ fn test_eq_direntry_metadata() {
         assert_eq!(ft1, ft2);
     }
 }
+
+/// Regression test for https://github.com/rust-lang/rust/issues/50619.
+#[test]
+#[cfg(target_os = "linux")]
+fn test_read_dir_infinite_loop() {
+    use crate::io::ErrorKind;
+    use crate::process::Command;
+
+    // Create a zombie child process
+    let Ok(mut child) = Command::new("echo").spawn() else { return };
+
+    // Make sure the process is (un)dead
+    match child.kill() {
+        // InvalidInput means the child already exited
+        Err(e) if e.kind() != ErrorKind::InvalidInput => return,
+        _ => {}
+    }
+
+    // open() on this path will succeed, but readdir() will fail
+    let id = child.id();
+    let path = format!("/proc/{id}/net");
+
+    // Skip the test if we can't open the directory in the first place
+    let Ok(dir) = fs::read_dir(path) else { return };
+
+    // Check for duplicate errors
+    assert!(dir.filter(|e| e.is_err()).take(2).count() < 2);
+}
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index 400d25beb26..17aff342c15 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -362,6 +362,10 @@ impl Read for ChildStdout {
     fn is_read_vectored(&self) -> bool {
         self.inner.is_read_vectored()
     }
+
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.inner.read_to_end(buf)
+    }
 }
 
 impl AsInner<AnonPipe> for ChildStdout {
@@ -907,10 +911,8 @@ impl Command {
     /// ```
     #[stable(feature = "process", since = "1.0.0")]
     pub fn output(&mut self) -> io::Result<Output> {
-        self.inner
-            .spawn(imp::Stdio::MakePipe, false)
-            .map(Child::from_inner)
-            .and_then(|p| p.wait_with_output())
+        let (status, stdout, stderr) = self.inner.output()?;
+        Ok(Output { status: ExitStatus(status), stdout, stderr })
     }
 
     /// Executes a command as a child process, waiting for it to finish and
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index 818914a2df0..d5f50d77911 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -243,17 +243,15 @@ struct InnerReadDir {
 
 pub struct ReadDir {
     inner: Arc<InnerReadDir>,
-    #[cfg(not(any(
-        target_os = "android",
-        target_os = "linux",
-        target_os = "solaris",
-        target_os = "illumos",
-        target_os = "fuchsia",
-        target_os = "redox",
-    )))]
     end_of_stream: bool,
 }
 
+impl ReadDir {
+    fn new(inner: InnerReadDir) -> Self {
+        Self { inner: Arc::new(inner), end_of_stream: false }
+    }
+}
+
 struct Dir(*mut libc::DIR);
 
 unsafe impl Send for Dir {}
@@ -594,6 +592,10 @@ impl Iterator for ReadDir {
         target_os = "illumos"
     ))]
     fn next(&mut self) -> Option<io::Result<DirEntry>> {
+        if self.end_of_stream {
+            return None;
+        }
+
         unsafe {
             loop {
                 // As of POSIX.1-2017, readdir() is not required to be thread safe; only
@@ -604,8 +606,12 @@ impl Iterator for ReadDir {
                 super::os::set_errno(0);
                 let entry_ptr = readdir64(self.inner.dirp.0);
                 if entry_ptr.is_null() {
-                    // null can mean either the end is reached or an error occurred.
-                    // So we had to clear errno beforehand to check for an error now.
+                    // We either encountered an error, or reached the end.  Either way,
+                    // the next call to next() should return None.
+                    self.end_of_stream = true;
+
+                    // To distinguish between errors and end-of-directory, we had to clear
+                    // errno beforehand to check for an error now.
                     return match super::os::errno() {
                         0 => None,
                         e => Some(Err(Error::from_raw_os_error(e))),
@@ -1363,18 +1369,7 @@ pub fn readdir(path: &Path) -> io::Result<ReadDir> {
     } else {
         let root = path.to_path_buf();
         let inner = InnerReadDir { dirp: Dir(ptr), root };
-        Ok(ReadDir {
-            inner: Arc::new(inner),
-            #[cfg(not(any(
-                target_os = "android",
-                target_os = "linux",
-                target_os = "solaris",
-                target_os = "illumos",
-                target_os = "fuchsia",
-                target_os = "redox",
-            )))]
-            end_of_stream: false,
-        })
+        Ok(ReadDir::new(inner))
     }
 }
 
@@ -1755,7 +1750,6 @@ mod remove_dir_impl {
     use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
     use crate::os::unix::prelude::{OwnedFd, RawFd};
     use crate::path::{Path, PathBuf};
-    use crate::sync::Arc;
     use crate::sys::common::small_c_string::run_path_with_cstr;
     use crate::sys::{cvt, cvt_r};
 
@@ -1832,21 +1826,8 @@ mod remove_dir_impl {
         // a valid root is not needed because we do not call any functions involving the full path
         // of the DirEntrys.
         let dummy_root = PathBuf::new();
-        Ok((
-            ReadDir {
-                inner: Arc::new(InnerReadDir { dirp, root: dummy_root }),
-                #[cfg(not(any(
-                    target_os = "android",
-                    target_os = "linux",
-                    target_os = "solaris",
-                    target_os = "illumos",
-                    target_os = "fuchsia",
-                    target_os = "redox",
-                )))]
-                end_of_stream: false,
-            },
-            new_parent_fd,
-        ))
+        let inner = InnerReadDir { dirp, root: dummy_root };
+        Ok((ReadDir::new(inner), new_parent_fd))
     }
 
     #[cfg(any(
diff --git a/library/std/src/sys/unix/pipe.rs b/library/std/src/sys/unix/pipe.rs
index a56c275c942..a744d0ab640 100644
--- a/library/std/src/sys/unix/pipe.rs
+++ b/library/std/src/sys/unix/pipe.rs
@@ -58,6 +58,10 @@ impl AnonPipe {
         self.0.is_read_vectored()
     }
 
+    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.0.read_to_end(buf)
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         self.0.write(buf)
     }
diff --git a/library/std/src/sys/unix/process/process_fuchsia.rs b/library/std/src/sys/unix/process/process_fuchsia.rs
index 66ea3db2015..4c99d758c93 100644
--- a/library/std/src/sys/unix/process/process_fuchsia.rs
+++ b/library/std/src/sys/unix/process/process_fuchsia.rs
@@ -35,6 +35,11 @@ impl Command {
         Ok((Process { handle: Handle::new(process_handle) }, ours))
     }
 
+    pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
+        let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?;
+        crate::sys_common::process::wait_with_output(proc, pipes)
+    }
+
     pub fn exec(&mut self, default: Stdio) -> io::Error {
         if self.saw_nul() {
             return io::const_io_error!(
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index c0716a089bc..39d1c8b1d8e 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -133,6 +133,11 @@ impl Command {
         }
     }
 
+    pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
+        let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?;
+        crate::sys_common::process::wait_with_output(proc, pipes)
+    }
+
     // Attempts to fork the process. If successful, returns Ok((0, -1))
     // in the child, and Ok((child_pid, -1)) in the parent.
     #[cfg(not(target_os = "linux"))]
diff --git a/library/std/src/sys/unix/process/process_unsupported.rs b/library/std/src/sys/unix/process/process_unsupported.rs
index 72f9f3f9ca7..f28ca58d020 100644
--- a/library/std/src/sys/unix/process/process_unsupported.rs
+++ b/library/std/src/sys/unix/process/process_unsupported.rs
@@ -20,6 +20,10 @@ impl Command {
         unsupported()
     }
 
+    pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
+        unsupported()
+    }
+
     pub fn exec(&mut self, _default: Stdio) -> io::Error {
         unsupported_err()
     }
diff --git a/library/std/src/sys/unix/process/process_vxworks.rs b/library/std/src/sys/unix/process/process_vxworks.rs
index 200ef671967..f549d37c301 100644
--- a/library/std/src/sys/unix/process/process_vxworks.rs
+++ b/library/std/src/sys/unix/process/process_vxworks.rs
@@ -108,6 +108,11 @@ impl Command {
         }
     }
 
+    pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
+        let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?;
+        crate::sys_common::process::wait_with_output(proc, pipes)
+    }
+
     pub fn exec(&mut self, default: Stdio) -> io::Error {
         let ret = Command::spawn(self, default, false);
         match ret {
diff --git a/library/std/src/sys/unsupported/pipe.rs b/library/std/src/sys/unsupported/pipe.rs
index 25514c2322f..0bba673b458 100644
--- a/library/std/src/sys/unsupported/pipe.rs
+++ b/library/std/src/sys/unsupported/pipe.rs
@@ -15,6 +15,10 @@ impl AnonPipe {
         self.0
     }
 
+    pub fn read_to_end(&self, _buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.0
+    }
+
     pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
         self.0
     }
diff --git a/library/std/src/sys/unsupported/process.rs b/library/std/src/sys/unsupported/process.rs
index 633f17c054b..a494f2d6b4c 100644
--- a/library/std/src/sys/unsupported/process.rs
+++ b/library/std/src/sys/unsupported/process.rs
@@ -75,6 +75,10 @@ impl Command {
     ) -> io::Result<(Process, StdioPipes)> {
         unsupported()
     }
+
+    pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
+        unsupported()
+    }
 }
 
 impl From<AnonPipe> for Stdio {
diff --git a/library/std/src/sys/windows/pipe.rs b/library/std/src/sys/windows/pipe.rs
index 9f26acc4520..7b25edaa556 100644
--- a/library/std/src/sys/windows/pipe.rs
+++ b/library/std/src/sys/windows/pipe.rs
@@ -1,7 +1,7 @@
 use crate::os::windows::prelude::*;
 
 use crate::ffi::OsStr;
-use crate::io::{self, IoSlice, IoSliceMut};
+use crate::io::{self, IoSlice, IoSliceMut, Read};
 use crate::mem;
 use crate::path::Path;
 use crate::ptr;
@@ -261,6 +261,10 @@ impl AnonPipe {
         self.inner.is_read_vectored()
     }
 
+    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        self.handle().read_to_end(buf)
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         unsafe {
             let len = crate::cmp::min(buf.len(), c::DWORD::MAX as usize) as c::DWORD;
diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs
index 31e9b34fb9e..10bc949e1f4 100644
--- a/library/std/src/sys/windows/process.rs
+++ b/library/std/src/sys/windows/process.rs
@@ -351,6 +351,11 @@ impl Command {
             ))
         }
     }
+
+    pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
+        let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?;
+        crate::sys_common::process::wait_with_output(proc, pipes)
+    }
 }
 
 impl fmt::Debug for Command {
diff --git a/library/std/src/sys_common/process.rs b/library/std/src/sys_common/process.rs
index 9f978789a62..ae11412067b 100644
--- a/library/std/src/sys_common/process.rs
+++ b/library/std/src/sys_common/process.rs
@@ -4,7 +4,9 @@
 use crate::collections::BTreeMap;
 use crate::env;
 use crate::ffi::{OsStr, OsString};
-use crate::sys::process::EnvKey;
+use crate::io;
+use crate::sys::pipe::read2;
+use crate::sys::process::{EnvKey, ExitStatus, Process, StdioPipes};
 
 // Stores a set of changes to an environment
 #[derive(Clone, Debug)]
@@ -117,3 +119,30 @@ impl<'a> ExactSizeIterator for CommandEnvs<'a> {
         self.iter.is_empty()
     }
 }
+
+pub fn wait_with_output(
+    mut process: Process,
+    mut pipes: StdioPipes,
+) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
+    drop(pipes.stdin.take());
+
+    let (mut stdout, mut stderr) = (Vec::new(), Vec::new());
+    match (pipes.stdout.take(), pipes.stderr.take()) {
+        (None, None) => {}
+        (Some(out), None) => {
+            let res = out.read_to_end(&mut stdout);
+            res.unwrap();
+        }
+        (None, Some(err)) => {
+            let res = err.read_to_end(&mut stderr);
+            res.unwrap();
+        }
+        (Some(out), Some(err)) => {
+            let res = read2(out, &mut stdout, err, &mut stderr);
+            res.unwrap();
+        }
+    }
+
+    let status = process.wait()?;
+    Ok((status, stdout, stderr))
+}
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 8ee6d49da8f..1d37d68c1d4 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -19,6 +19,7 @@ use crate::flags::{Color, Subcommand};
 use crate::install;
 use crate::native;
 use crate::run;
+use crate::setup;
 use crate::test;
 use crate::tool::{self, SourceType};
 use crate::util::{self, add_dylib_path, add_link_lib_path, exe, libdir, output, t};
@@ -433,8 +434,11 @@ impl<'a> ShouldRun<'a> {
 
     // single alias, which does not correspond to any on-disk path
     pub fn alias(mut self, alias: &str) -> Self {
+        // exceptional case for `Kind::Setup` because its `library`
+        // and `compiler` options would otherwise naively match with
+        // `compiler` and `library` folders respectively.
         assert!(
-            !self.builder.src.join(alias).exists(),
+            self.kind == Kind::Setup || !self.builder.src.join(alias).exists(),
             "use `builder.path()` for real paths: {}",
             alias
         );
@@ -744,6 +748,7 @@ impl<'a> Builder<'a> {
                 install::RustDemangler,
                 install::Clippy,
                 install::Miri,
+                install::LlvmTools,
                 install::Analysis,
                 install::Src,
                 install::Rustc
@@ -757,8 +762,9 @@ impl<'a> Builder<'a> {
                 run::CollectLicenseMetadata,
                 run::GenerateCopyright,
             ),
+            Kind::Setup => describe!(setup::Profile),
             // These commands either don't use paths, or they're special-cased in Build::build()
-            Kind::Clean | Kind::Format | Kind::Setup => vec![],
+            Kind::Clean | Kind::Format => vec![],
         }
     }
 
@@ -821,7 +827,11 @@ impl<'a> Builder<'a> {
             Subcommand::Install { ref paths } => (Kind::Install, &paths[..]),
             Subcommand::Run { ref paths, .. } => (Kind::Run, &paths[..]),
             Subcommand::Format { .. } => (Kind::Format, &[][..]),
-            Subcommand::Clean { .. } | Subcommand::Setup { .. } => {
+            Subcommand::Setup { profile: ref path } => (
+                Kind::Setup,
+                path.as_ref().map_or([].as_slice(), |path| std::slice::from_ref(path)),
+            ),
+            Subcommand::Clean { .. } => {
                 panic!()
             }
         };
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 960fbdf7538..2906616ffad 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -638,6 +638,7 @@ define_config! {
         dist_stage: Option<u32> = "dist-stage",
         bench_stage: Option<u32> = "bench-stage",
         patch_binaries_for_nix: Option<bool> = "patch-binaries-for-nix",
+        // NOTE: only parsed by bootstrap.py, `--feature build-metrics` enables metrics unconditionally
         metrics: Option<bool> = "metrics",
     }
 }
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index 37a8eb884ef..851cb5ecf4c 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -143,7 +143,7 @@ pub enum Subcommand {
         args: Vec<String>,
     },
     Setup {
-        profile: Option<Profile>,
+        profile: Option<PathBuf>,
     },
 }
 
@@ -351,7 +351,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
 
         // fn usage()
         let usage = |exit_code: i32, opts: &Options, verbose: bool, subcommand_help: &str| -> ! {
-            let config = Config::parse(&["build".to_string()]);
+            let config = Config::parse(&["setup".to_string()]);
             let build = Build::new(config);
             let paths = Builder::get_help(&build, subcommand);
 
@@ -621,7 +621,7 @@ Arguments:
             }
             Kind::Setup => {
                 let profile = if paths.len() > 1 {
-                    println!("\nat most one profile can be passed to setup\n");
+                    eprintln!("\nerror: At most one profile can be passed to setup\n");
                     usage(1, &opts, verbose, &subcommand_help)
                 } else if let Some(path) = paths.pop() {
                     let profile_string = t!(path.into_os_string().into_string().map_err(
diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs
index 5e7264fe765..b2f6afead79 100644
--- a/src/bootstrap/format.rs
+++ b/src/bootstrap/format.rs
@@ -8,7 +8,7 @@ use std::path::{Path, PathBuf};
 use std::process::{Command, Stdio};
 use std::sync::mpsc::SyncSender;
 
-fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl FnMut() {
+fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl FnMut(bool) -> bool {
     let mut cmd = Command::new(&rustfmt);
     // avoid the submodule config paths from coming into play,
     // we only allow a single global config for the workspace for now
@@ -23,7 +23,13 @@ fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl F
     let cmd_debug = format!("{:?}", cmd);
     let mut cmd = cmd.spawn().expect("running rustfmt");
     // poor man's async: return a closure that'll wait for rustfmt's completion
-    move || {
+    move |block: bool| -> bool {
+        if !block {
+            match cmd.try_wait() {
+                Ok(Some(_)) => {}
+                _ => return false,
+            }
+        }
         let status = cmd.wait().unwrap();
         if !status.success() {
             eprintln!(
@@ -34,6 +40,7 @@ fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl F
             );
             crate::detail_exit(1);
         }
+        true
     }
 }
 
@@ -146,15 +153,23 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
             let child = rustfmt(&src, &rustfmt_path, paths.as_slice(), check);
             children.push_back(child);
 
+            // poll completion before waiting
+            for i in (0..children.len()).rev() {
+                if children[i](false) {
+                    children.swap_remove_back(i);
+                    break;
+                }
+            }
+
             if children.len() >= max_processes {
                 // await oldest child
-                children.pop_front().unwrap()();
+                children.pop_front().unwrap()(true);
             }
         }
 
         // await remaining children
         for mut child in children {
-            child();
+            child(true);
         }
     });
 
diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs
index 7672b7c9135..c53d0d7e4cb 100644
--- a/src/bootstrap/install.rs
+++ b/src/bootstrap/install.rs
@@ -205,6 +205,12 @@ install!((self, builder, _config),
             .expect("missing miri");
         install_sh(builder, "miri", self.compiler.stage, Some(self.target), &tarball);
     };
+    LlvmTools, alias = "llvm-tools", Self::should_build(_config), only_hosts: true, {
+        let tarball = builder
+            .ensure(dist::LlvmTools { target: self.target })
+            .expect("missing llvm-tools");
+        install_sh(builder, "llvm-tools", self.compiler.stage, Some(self.target), &tarball);
+    };
     Rustfmt, alias = "rustfmt", Self::should_build(_config), only_hosts: true, {
         if let Some(tarball) = builder.ensure(dist::Rustfmt {
             compiler: self.compiler,
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 570fe6484e3..47fb4a38d05 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -108,6 +108,7 @@ use std::collections::{HashMap, HashSet};
 use std::env;
 use std::fs::{self, File};
 use std::io;
+use std::io::ErrorKind;
 use std::path::{Path, PathBuf};
 use std::process::Command;
 use std::str;
@@ -119,7 +120,9 @@ use once_cell::sync::OnceCell;
 
 use crate::builder::Kind;
 use crate::config::{LlvmLibunwind, TargetSelection};
-use crate::util::{exe, libdir, mtime, output, run, run_suppressed, try_run_suppressed, CiEnv};
+use crate::util::{
+    exe, libdir, mtime, output, run, run_suppressed, symlink_dir, try_run_suppressed, CiEnv,
+};
 
 mod bolt;
 mod builder;
@@ -586,6 +589,20 @@ impl Build {
             metadata::build(&mut build);
         }
 
+        // Make a symbolic link so we can use a consistent directory in the documentation.
+        let build_triple = build.out.join(&build.build.triple);
+        let host = build.out.join("host");
+        if let Err(e) = symlink_dir(&build.config, &build_triple, &host) {
+            if e.kind() != ErrorKind::AlreadyExists {
+                panic!(
+                    "symlink_dir({} => {}) failed with {}",
+                    host.display(),
+                    build_triple.display(),
+                    e
+                );
+            }
+        }
+
         build
     }
 
@@ -713,10 +730,6 @@ impl Build {
             return clean::clean(self, all);
         }
 
-        if let Subcommand::Setup { profile } = &self.config.cmd {
-            return setup::setup(&self.config, *profile);
-        }
-
         // Download rustfmt early so that it can be used in rust-analyzer configs.
         let _ = &builder::Builder::new(&self).initial_rustfmt();
 
diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs
index c7f98a7d0d1..57426ce3d51 100644
--- a/src/bootstrap/setup.rs
+++ b/src/bootstrap/setup.rs
@@ -1,3 +1,4 @@
+use crate::builder::{Builder, RunConfig, ShouldRun, Step};
 use crate::Config;
 use crate::{t, VERSION};
 use std::env::consts::EXE_SUFFIX;
@@ -9,7 +10,7 @@ use std::process::Command;
 use std::str::FromStr;
 use std::{fmt, fs, io};
 
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
 pub enum Profile {
     Compiler,
     Codegen,
@@ -48,6 +49,16 @@ impl Profile {
         }
         out
     }
+
+    pub fn as_str(&self) -> &'static str {
+        match self {
+            Profile::Compiler => "compiler",
+            Profile::Codegen => "codegen",
+            Profile::Library => "library",
+            Profile::Tools => "tools",
+            Profile::User => "user",
+        }
+    }
 }
 
 impl FromStr for Profile {
@@ -69,24 +80,58 @@ impl FromStr for Profile {
 
 impl fmt::Display for Profile {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            Profile::Compiler => write!(f, "compiler"),
-            Profile::Codegen => write!(f, "codegen"),
-            Profile::Library => write!(f, "library"),
-            Profile::User => write!(f, "user"),
-            Profile::Tools => write!(f, "tools"),
+        f.write_str(self.as_str())
+    }
+}
+
+impl Step for Profile {
+    type Output = ();
+    const DEFAULT: bool = true;
+
+    fn should_run(mut run: ShouldRun<'_>) -> ShouldRun<'_> {
+        for choice in Profile::all() {
+            run = run.alias(choice.as_str());
         }
+        run
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        // for Profile, `run.paths` will have 1 and only 1 element
+        // this is because we only accept at most 1 path from user input.
+        // If user calls `x.py setup` without arguments, the interactive TUI
+        // will guide user to provide one.
+        let profile = if run.paths.len() > 1 {
+            // HACK: `builder` runs this step with all paths if no path was passed.
+            t!(interactive_path())
+        } else {
+            run.paths
+                .first()
+                .unwrap()
+                .assert_single_path()
+                .path
+                .as_path()
+                .as_os_str()
+                .to_str()
+                .unwrap()
+                .parse()
+                .unwrap()
+        };
+
+        run.builder.ensure(profile);
+    }
+
+    fn run(self, builder: &Builder<'_>) {
+        setup(&builder.build.config, self)
     }
 }
 
-pub fn setup(config: &Config, profile: Option<Profile>) {
-    let profile = profile.unwrap_or_else(|| t!(interactive_path()));
+pub fn setup(config: &Config, profile: Profile) {
     let stage_path =
         ["build", config.build.rustc_target_arg(), "stage1"].join(&MAIN_SEPARATOR.to_string());
 
     if !rustup_installed() && profile != Profile::User {
         eprintln!("`rustup` is not installed; cannot link `stage1` toolchain");
-    } else if stage_dir_exists(&stage_path[..]) {
+    } else if stage_dir_exists(&stage_path[..]) && !config.dry_run() {
         attempt_toolchain_link(&stage_path[..]);
     }
 
@@ -104,7 +149,9 @@ pub fn setup(config: &Config, profile: Option<Profile>) {
         Profile::User => &["dist", "build"],
     };
 
-    t!(install_git_hook_maybe(&config));
+    if !config.dry_run() {
+        t!(install_git_hook_maybe(&config));
+    }
 
     println!();
 
@@ -144,6 +191,7 @@ fn setup_config_toml(path: &PathBuf, profile: Profile, config: &Config) {
     changelog-seen = {}\n",
         profile, VERSION
     );
+
     t!(fs::write(path, settings));
 
     let include_path = profile.include_path(&config.src);
diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
index 076a427c988..9e2568af13f 100644
--- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile
+++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
@@ -40,10 +40,10 @@ COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/
 
 ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1
 ENV SCRIPT python3 ../x.py --stage 2 test src/tools/expand-yaml-anchors && \
+           python3 ../x.py test --stage 0 src/tools/tidy && \
            python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu --all-targets && \
            python3 ../x.py build --stage 0 src/tools/build-manifest && \
            python3 ../x.py test --stage 0 src/tools/compiletest && \
-           python3 ../x.py test --stage 2 src/tools/tidy && \
            python3 ../x.py test --stage 0 core alloc std test proc_macro && \
            # Build both public and internal documentation.
            RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 0 library/test && \
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
index 3f8dcd03d2d..475434e5aef 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
@@ -1 +1 @@
-0.13.2
\ No newline at end of file
+0.13.4
\ No newline at end of file
diff --git a/src/ci/run.sh b/src/ci/run.sh
index 7de06ec35c3..f05bb81d4a1 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -56,6 +56,7 @@ fi
 if ! isCI || isCiBranch auto || isCiBranch beta || isCiBranch try || isCiBranch try-perf; then
     RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.print-step-timings --enable-verbose-tests"
     RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.metrics"
+    HAS_METRICS=1
 fi
 
 RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-sccache"
@@ -157,13 +158,6 @@ trap datecheck EXIT
 # sccache server at the start of the build, but no need to worry if this fails.
 SCCACHE_IDLE_TIMEOUT=10800 sccache --start-server || true
 
-if [ "$RUN_CHECK_WITH_PARALLEL_QUERIES" != "" ]; then
-  $SRC/configure --set rust.parallel-compiler
-  CARGO_INCREMENTAL=0 $PYTHON ../x.py check
-  rm -f config.toml
-  rm -rf build
-fi
-
 $SRC/configure $RUST_CONFIGURE_ARGS
 
 retry make prepare
@@ -193,4 +187,21 @@ else
   do_make "$RUST_CHECK_TARGET"
 fi
 
+if [ "$RUN_CHECK_WITH_PARALLEL_QUERIES" != "" ]; then
+  rm -f config.toml
+  $SRC/configure --set rust.parallel-compiler
+
+  # Save the build metrics before we wipe the directory
+  if [ $HAS_METRICS = 1 ]; then
+    mv build/metrics.json .
+  fi
+  rm -rf build
+  if [ $HAS_METRICS = 1 ]; then
+    mkdir build
+    mv metrics.json build
+  fi
+
+  CARGO_INCREMENTAL=0 $PYTHON ../x.py check
+fi
+
 sccache --show-stats || true
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index a65bec37e1d..022ed606cc3 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -2003,7 +2003,6 @@ in storage.js
 
 .more-examples-toggle .hide-more {
 	margin-left: 25px;
-	margin-bottom: 5px;
 	cursor: pointer;
 }
 
@@ -2031,16 +2030,12 @@ in storage.js
 	height: 100%;
 }
 
-.more-scraped-examples .scraped-example {
-	margin-bottom: 20px;
-}
-
-.more-scraped-examples .scraped-example:last-child {
-	margin-bottom: 0;
+.more-scraped-examples .scraped-example, .example-links {
+	margin-top: 20px;
 }
 
-.example-links a {
-	margin-top: 20px;
+.more-scraped-examples .scraped-example:first-child {
+	margin-top: 5px;
 }
 
 .example-links ul {
diff --git a/src/test/codegen/dst-vtable-align-nonzero.rs b/src/test/codegen/dst-vtable-align-nonzero.rs
index 14c4c3f30f9..54f6e7f992f 100644
--- a/src/test/codegen/dst-vtable-align-nonzero.rs
+++ b/src/test/codegen/dst-vtable-align-nonzero.rs
@@ -1,6 +1,7 @@
-// compile-flags: -O
+// compile-flags: -O -Z merge-functions=disabled
 
 #![crate_type = "lib"]
+#![feature(core_intrinsics)]
 
 // This test checks that we annotate alignment loads from vtables with nonzero range metadata,
 // and that this allows LLVM to eliminate redundant `align >= 1` checks.
@@ -42,4 +43,19 @@ pub fn does_not_eliminate_runtime_check_when_align_2(
     &x.dst
 }
 
+// CHECK-LABEL: @align_load_from_align_of_val
+#[no_mangle]
+pub fn align_load_from_align_of_val(x: &dyn Trait) -> usize {
+    // CHECK: {{%[0-9]+}} = load [[USIZE]], {{.+}} !range [[RANGE_META]]
+    core::mem::align_of_val(x)
+}
+
+// CHECK-LABEL: @align_load_from_vtable_align_intrinsic
+#[no_mangle]
+pub unsafe fn align_load_from_vtable_align_intrinsic(x: &dyn Trait) -> usize {
+    let (data, vtable): (*const (), *const ()) = core::mem::transmute(x);
+    // CHECK: {{%[0-9]+}} = load [[USIZE]], {{.+}} !range [[RANGE_META]]
+    core::intrinsics::vtable_align(vtable)
+}
+
 // CHECK: [[RANGE_META]] = !{[[USIZE]] 1, [[USIZE]] 0}
diff --git a/src/test/codegen/dst-vtable-size-range.rs b/src/test/codegen/dst-vtable-size-range.rs
new file mode 100644
index 00000000000..671c8abdebd
--- /dev/null
+++ b/src/test/codegen/dst-vtable-size-range.rs
@@ -0,0 +1,35 @@
+// compile-flags: -O -Z merge-functions=disabled
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+// Check that we annotate size loads from vtables with 0..(isize::MAX + 1) range metadata.
+
+pub trait Trait {
+    fn f(&self);
+}
+
+// Note that rustc uses inclusive bounds, but LLVM uses exclusive bounds for range metadata.
+// CHECK-LABEL: @generate_exclusive_bound
+#[no_mangle]
+pub fn generate_exclusive_bound() -> usize {
+    // CHECK: ret [[USIZE:i[0-9]+]] [[EXCLUSIVE_BOUND:[-0-9]+]]
+    isize::MAX as usize + 1
+}
+
+// CHECK-LABEL: @size_load_from_size_of_val
+#[no_mangle]
+pub fn size_load_from_size_of_val(x: &dyn Trait) -> usize {
+    // CHECK: {{%[0-9]+}} = load [[USIZE]], {{.+}} !range [[RANGE_META:![0-9]+]]
+    core::mem::size_of_val(x)
+}
+
+// CHECK-LABEL: @size_load_from_vtable_size_intrinsic
+#[no_mangle]
+pub unsafe fn size_load_from_vtable_size_intrinsic(x: &dyn Trait) -> usize {
+    let (data, vtable): (*const (), *const ()) = core::mem::transmute(x);
+    // CHECK: {{%[0-9]+}} = load [[USIZE]], {{.+}} !range [[RANGE_META]]
+    core::intrinsics::vtable_size(vtable)
+}
+
+// CHECK: [[RANGE_META]] = !{[[USIZE]] 0, [[USIZE]] [[EXCLUSIVE_BOUND]]}
diff --git a/src/test/mir-opt/building/custom/terminators.assert_nonzero.built.after.mir b/src/test/mir-opt/building/custom/terminators.assert_nonzero.built.after.mir
new file mode 100644
index 00000000000..a1a27226b4e
--- /dev/null
+++ b/src/test/mir-opt/building/custom/terminators.assert_nonzero.built.after.mir
@@ -0,0 +1,17 @@
+// MIR for `assert_nonzero` after built
+
+fn assert_nonzero(_1: i32) -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/terminators.rs:+0:27: +0:27
+
+    bb0: {
+        switchInt(_1) -> [0: bb1, otherwise: bb2]; // scope 0 at $DIR/terminators.rs:+3:13: +6:14
+    }
+
+    bb1: {
+        unreachable;                     // scope 0 at $DIR/terminators.rs:+10:13: +10:26
+    }
+
+    bb2: {
+        return;                          // scope 0 at $DIR/terminators.rs:+14:13: +14:21
+    }
+}
diff --git a/src/test/mir-opt/building/custom/terminators.direct_call.built.after.mir b/src/test/mir-opt/building/custom/terminators.direct_call.built.after.mir
new file mode 100644
index 00000000000..1b2345a965e
--- /dev/null
+++ b/src/test/mir-opt/building/custom/terminators.direct_call.built.after.mir
@@ -0,0 +1,16 @@
+// MIR for `direct_call` after built
+
+fn direct_call(_1: i32) -> i32 {
+    let mut _0: i32;                     // return place in scope 0 at $DIR/terminators.rs:+0:27: +0:30
+
+    bb0: {
+        _0 = ident::<i32>(_1) -> bb1;    // scope 0 at $DIR/terminators.rs:+3:13: +3:42
+                                         // mir::Constant
+                                         // + span: $DIR/terminators.rs:15:33: 15:38
+                                         // + literal: Const { ty: fn(i32) -> i32 {ident::<i32>}, val: Value(<ZST>) }
+    }
+
+    bb1: {
+        return;                          // scope 0 at $DIR/terminators.rs:+7:13: +7:21
+    }
+}
diff --git a/src/test/mir-opt/building/custom/terminators.drop_first.built.after.mir b/src/test/mir-opt/building/custom/terminators.drop_first.built.after.mir
new file mode 100644
index 00000000000..c903e594696
--- /dev/null
+++ b/src/test/mir-opt/building/custom/terminators.drop_first.built.after.mir
@@ -0,0 +1,13 @@
+// MIR for `drop_first` after built
+
+fn drop_first(_1: WriteOnDrop<'_>, _2: WriteOnDrop<'_>) -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/terminators.rs:+0:59: +0:59
+
+    bb0: {
+        replace(_1 <- move _2) -> bb1;   // scope 0 at $DIR/terminators.rs:+3:13: +3:49
+    }
+
+    bb1: {
+        return;                          // scope 0 at $DIR/terminators.rs:+7:13: +7:21
+    }
+}
diff --git a/src/test/mir-opt/building/custom/terminators.drop_second.built.after.mir b/src/test/mir-opt/building/custom/terminators.drop_second.built.after.mir
new file mode 100644
index 00000000000..f14246f2d12
--- /dev/null
+++ b/src/test/mir-opt/building/custom/terminators.drop_second.built.after.mir
@@ -0,0 +1,13 @@
+// MIR for `drop_second` after built
+
+fn drop_second(_1: WriteOnDrop<'_>, _2: WriteOnDrop<'_>) -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/terminators.rs:+0:60: +0:60
+
+    bb0: {
+        drop(_2) -> bb1;                 // scope 0 at $DIR/terminators.rs:+3:13: +3:30
+    }
+
+    bb1: {
+        return;                          // scope 0 at $DIR/terminators.rs:+7:13: +7:21
+    }
+}
diff --git a/src/test/mir-opt/building/custom/terminators.indirect_call.built.after.mir b/src/test/mir-opt/building/custom/terminators.indirect_call.built.after.mir
new file mode 100644
index 00000000000..2f1b14069ab
--- /dev/null
+++ b/src/test/mir-opt/building/custom/terminators.indirect_call.built.after.mir
@@ -0,0 +1,13 @@
+// MIR for `indirect_call` after built
+
+fn indirect_call(_1: i32, _2: fn(i32) -> i32) -> i32 {
+    let mut _0: i32;                     // return place in scope 0 at $DIR/terminators.rs:+0:48: +0:51
+
+    bb0: {
+        _0 = _2(_1) -> bb1;              // scope 0 at $DIR/terminators.rs:+3:13: +3:38
+    }
+
+    bb1: {
+        return;                          // scope 0 at $DIR/terminators.rs:+7:13: +7:21
+    }
+}
diff --git a/src/test/mir-opt/building/custom/terminators.rs b/src/test/mir-opt/building/custom/terminators.rs
new file mode 100644
index 00000000000..c23233fcf9a
--- /dev/null
+++ b/src/test/mir-opt/building/custom/terminators.rs
@@ -0,0 +1,108 @@
+#![feature(custom_mir, core_intrinsics)]
+
+extern crate core;
+use core::intrinsics::mir::*;
+
+fn ident<T>(t: T) -> T {
+    t
+}
+
+// EMIT_MIR terminators.direct_call.built.after.mir
+#[custom_mir(dialect = "built")]
+fn direct_call(x: i32) -> i32 {
+    mir!(
+        {
+            Call(RET, retblock, ident(x))
+        }
+
+        retblock = {
+            Return()
+        }
+    )
+}
+
+// EMIT_MIR terminators.indirect_call.built.after.mir
+#[custom_mir(dialect = "built")]
+fn indirect_call(x: i32, f: fn(i32) -> i32) -> i32 {
+    mir!(
+        {
+            Call(RET, retblock, f(x))
+        }
+
+        retblock = {
+            Return()
+        }
+    )
+}
+
+struct WriteOnDrop<'a>(&'a mut i32, i32);
+
+impl<'a> Drop for WriteOnDrop<'a> {
+    fn drop(&mut self) {
+        *self.0 = self.1;
+    }
+}
+
+// EMIT_MIR terminators.drop_first.built.after.mir
+#[custom_mir(dialect = "built")]
+fn drop_first<'a>(a: WriteOnDrop<'a>, b: WriteOnDrop<'a>) {
+    mir!(
+        {
+            DropAndReplace(a, Move(b), retblock)
+        }
+
+        retblock = {
+            Return()
+        }
+    )
+}
+
+// EMIT_MIR terminators.drop_second.built.after.mir
+#[custom_mir(dialect = "built")]
+fn drop_second<'a>(a: WriteOnDrop<'a>, b: WriteOnDrop<'a>) {
+    mir!(
+        {
+            Drop(b, retblock)
+        }
+
+        retblock = {
+            Return()
+        }
+    )
+}
+
+// EMIT_MIR terminators.assert_nonzero.built.after.mir
+#[custom_mir(dialect = "built")]
+fn assert_nonzero(a: i32) {
+    mir!(
+        {
+            match a {
+                0 => unreachable,
+                _ => retblock
+            }
+        }
+
+        unreachable = {
+            Unreachable()
+        }
+
+        retblock = {
+            Return()
+        }
+    )
+}
+
+fn main() {
+    assert_eq!(direct_call(5), 5);
+    assert_eq!(indirect_call(5, ident), 5);
+
+    let mut a = 0;
+    let mut b = 0;
+    drop_first(WriteOnDrop(&mut a, 1), WriteOnDrop(&mut b, 1));
+    assert_eq!((a, b), (1, 0));
+
+    let mut a = 0;
+    let mut b = 0;
+    drop_second(WriteOnDrop(&mut a, 1), WriteOnDrop(&mut b, 1));
+    assert_eq!((a, b), (0, 1));
+}
diff --git a/src/test/mir-opt/dest-prop/unreachable.f.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/unreachable.f.DestinationPropagation.diff
new file mode 100644
index 00000000000..9ea756c2712
--- /dev/null
+++ b/src/test/mir-opt/dest-prop/unreachable.f.DestinationPropagation.diff
@@ -0,0 +1,86 @@
+- // MIR for `f` before DestinationPropagation
++ // MIR for `f` after DestinationPropagation
+  
+  fn f(_1: T) -> () {
+      debug a => _1;                       // in scope 0 at $DIR/unreachable.rs:+0:19: +0:20
+      let mut _0: ();                      // return place in scope 0 at $DIR/unreachable.rs:+0:25: +0:25
+      let _2: T;                           // in scope 0 at $DIR/unreachable.rs:+1:9: +1:10
+      let mut _3: bool;                    // in scope 0 at $DIR/unreachable.rs:+2:8: +2:13
+      let _4: ();                          // in scope 0 at $DIR/unreachable.rs:+3:9: +3:16
+      let mut _5: T;                       // in scope 0 at $DIR/unreachable.rs:+3:11: +3:12
+      let mut _6: T;                       // in scope 0 at $DIR/unreachable.rs:+3:14: +3:15
+      let _7: ();                          // in scope 0 at $DIR/unreachable.rs:+5:9: +5:16
+      let mut _8: T;                       // in scope 0 at $DIR/unreachable.rs:+5:11: +5:12
+      let mut _9: T;                       // in scope 0 at $DIR/unreachable.rs:+5:14: +5:15
+      scope 1 {
+-         debug b => _2;                   // in scope 1 at $DIR/unreachable.rs:+1:9: +1:10
++         debug b => _1;                   // in scope 1 at $DIR/unreachable.rs:+1:9: +1:10
+      }
+  
+      bb0: {
+-         StorageLive(_2);                 // scope 0 at $DIR/unreachable.rs:+1:9: +1:10
+-         _2 = _1;                         // scope 0 at $DIR/unreachable.rs:+1:13: +1:14
++         nop;                             // scope 0 at $DIR/unreachable.rs:+1:9: +1:10
++         nop;                             // scope 0 at $DIR/unreachable.rs:+1:13: +1:14
+          StorageLive(_3);                 // scope 1 at $DIR/unreachable.rs:+2:8: +2:13
+          _3 = const false;                // scope 1 at $DIR/unreachable.rs:+2:8: +2:13
+-         goto -> bb3;                     // scope 1 at $DIR/unreachable.rs:+2:8: +2:13
++         goto -> bb1;                     // scope 1 at $DIR/unreachable.rs:+2:8: +2:13
+      }
+  
+      bb1: {
+-         StorageLive(_4);                 // scope 1 at $DIR/unreachable.rs:+3:9: +3:16
+-         StorageLive(_5);                 // scope 1 at $DIR/unreachable.rs:+3:11: +3:12
+-         _5 = _1;                         // scope 1 at $DIR/unreachable.rs:+3:11: +3:12
+-         StorageLive(_6);                 // scope 1 at $DIR/unreachable.rs:+3:14: +3:15
+-         _6 = _2;                         // scope 1 at $DIR/unreachable.rs:+3:14: +3:15
+-         _4 = g::<T>(move _5, move _6) -> bb2; // scope 1 at $DIR/unreachable.rs:+3:9: +3:16
+-                                          // mir::Constant
+-                                          // + span: $DIR/unreachable.rs:11:9: 11:10
+-                                          // + literal: Const { ty: fn(T, T) {g::<T>}, val: Value(<ZST>) }
+-     }
+- 
+-     bb2: {
+-         StorageDead(_6);                 // scope 1 at $DIR/unreachable.rs:+3:15: +3:16
+-         StorageDead(_5);                 // scope 1 at $DIR/unreachable.rs:+3:15: +3:16
+-         StorageDead(_4);                 // scope 1 at $DIR/unreachable.rs:+3:16: +3:17
+-         _0 = const ();                   // scope 1 at $DIR/unreachable.rs:+2:14: +4:6
+-         goto -> bb5;                     // scope 1 at $DIR/unreachable.rs:+2:5: +6:6
+-     }
+- 
+-     bb3: {
+          StorageLive(_7);                 // scope 1 at $DIR/unreachable.rs:+5:9: +5:16
+-         StorageLive(_8);                 // scope 1 at $DIR/unreachable.rs:+5:11: +5:12
+-         _8 = _2;                         // scope 1 at $DIR/unreachable.rs:+5:11: +5:12
++         nop;                             // scope 1 at $DIR/unreachable.rs:+5:11: +5:12
++         nop;                             // scope 1 at $DIR/unreachable.rs:+5:11: +5:12
+          StorageLive(_9);                 // scope 1 at $DIR/unreachable.rs:+5:14: +5:15
+-         _9 = _2;                         // scope 1 at $DIR/unreachable.rs:+5:14: +5:15
+-         _7 = g::<T>(move _8, move _9) -> bb4; // scope 1 at $DIR/unreachable.rs:+5:9: +5:16
++         _9 = _1;                         // scope 1 at $DIR/unreachable.rs:+5:14: +5:15
++         _7 = g::<T>(move _1, move _9) -> bb2; // scope 1 at $DIR/unreachable.rs:+5:9: +5:16
+                                           // mir::Constant
+                                           // + span: $DIR/unreachable.rs:13:9: 13:10
+                                           // + literal: Const { ty: fn(T, T) {g::<T>}, val: Value(<ZST>) }
+      }
+  
+-     bb4: {
++     bb2: {
+          StorageDead(_9);                 // scope 1 at $DIR/unreachable.rs:+5:15: +5:16
+-         StorageDead(_8);                 // scope 1 at $DIR/unreachable.rs:+5:15: +5:16
++         nop;                             // scope 1 at $DIR/unreachable.rs:+5:15: +5:16
+          StorageDead(_7);                 // scope 1 at $DIR/unreachable.rs:+5:16: +5:17
+          _0 = const ();                   // scope 1 at $DIR/unreachable.rs:+4:12: +6:6
+-         goto -> bb5;                     // scope 1 at $DIR/unreachable.rs:+2:5: +6:6
++         goto -> bb3;                     // scope 1 at $DIR/unreachable.rs:+2:5: +6:6
+      }
+  
+-     bb5: {
++     bb3: {
+          StorageDead(_3);                 // scope 1 at $DIR/unreachable.rs:+6:5: +6:6
+-         StorageDead(_2);                 // scope 0 at $DIR/unreachable.rs:+7:1: +7:2
++         nop;                             // scope 0 at $DIR/unreachable.rs:+7:1: +7:2
+          return;                          // scope 0 at $DIR/unreachable.rs:+7:2: +7:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/dest-prop/unreachable.rs b/src/test/mir-opt/dest-prop/unreachable.rs
new file mode 100644
index 00000000000..32b5def984a
--- /dev/null
+++ b/src/test/mir-opt/dest-prop/unreachable.rs
@@ -0,0 +1,18 @@
+// Check that unreachable code is removed after the destination propagation.
+// 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
+
+// EMIT_MIR unreachable.f.DestinationPropagation.diff
+pub fn f<T: Copy>(a: T) {
+    let b = a;
+    if false {
+        g(a, b);
+    } else {
+        g(b, b);
+    }
+}
+
+#[inline(never)]
+pub fn g<T: Copy>(_: T, _: T) {}
diff --git a/src/test/ui/argument-suggestions/basic.stderr b/src/test/ui/argument-suggestions/basic.stderr
index b118ce1bd0e..062b3768858 100644
--- a/src/test/ui/argument-suggestions/basic.stderr
+++ b/src/test/ui/argument-suggestions/basic.stderr
@@ -94,8 +94,8 @@ LL |     let closure = |x| x;
    |                   ^^^
 help: provide the argument
    |
-LL |     closure(/* value */);
-   |            ~~~~~~~~~~~~~
+LL |     closure(/* x */);
+   |            ~~~~~~~~~
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/borrowck/issue-103095.rs b/src/test/ui/borrowck/issue-103095.rs
new file mode 100644
index 00000000000..0340f39243f
--- /dev/null
+++ b/src/test/ui/borrowck/issue-103095.rs
@@ -0,0 +1,30 @@
+// check-pass
+
+trait FnOnceForGenericRef<T>: FnOnce(&T) -> Self::FnOutput {
+    type FnOutput;
+}
+
+impl<T, R, F: FnOnce(&T) -> R> FnOnceForGenericRef<T> for F {
+    type FnOutput = R;
+}
+
+struct Data<T, D: FnOnceForGenericRef<T>> {
+    value: Option<T>,
+    output: Option<D::FnOutput>,
+}
+
+impl<T, D: FnOnceForGenericRef<T>> Data<T, D> {
+    fn new(value: T, f: D) -> Self {
+        let output = f(&value);
+        Self {
+            value: Some(value),
+            output: Some(output),
+        }
+    }
+}
+
+fn test() {
+    Data::new(String::new(), |_| {});
+}
+
+fn main() {}
diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr
index c447e2f7987..3e39d15f9b0 100644
--- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr
+++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr
@@ -8,3 +8,4 @@ LL |     let ft =
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0320`.
diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr
index cd4706dd903..dbb74354471 100644
--- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr
+++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr
@@ -8,3 +8,4 @@ LL |     let ft =
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0320`.
diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr
index 18cd1b6cd41..deaf116b647 100644
--- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr
+++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr
@@ -16,3 +16,4 @@ LL |         Some(Wrapper::Simple::<u32>);
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0320`.
diff --git a/src/test/ui/error-codes/E0057.stderr b/src/test/ui/error-codes/E0057.stderr
index bea226f09dc..163737895fe 100644
--- a/src/test/ui/error-codes/E0057.stderr
+++ b/src/test/ui/error-codes/E0057.stderr
@@ -11,8 +11,8 @@ LL |     let f = |x| x * 3;
    |             ^^^
 help: provide the argument
    |
-LL |     let a = f(/* value */);
-   |              ~~~~~~~~~~~~~
+LL |     let a = f(/* x */);
+   |              ~~~~~~~~~
 
 error[E0057]: this function takes 1 argument but 2 arguments were supplied
   --> $DIR/E0057.rs:5:13
diff --git a/src/test/ui/generator/ref-upvar-not-send.rs b/src/test/ui/generator/ref-upvar-not-send.rs
new file mode 100644
index 00000000000..eb9ef63ecfc
--- /dev/null
+++ b/src/test/ui/generator/ref-upvar-not-send.rs
@@ -0,0 +1,31 @@
+// For `Send` generators, suggest a `T: Sync` requirement for `&T` upvars,
+// and suggest a `T: Send` requirement for `&mut T` upvars.
+
+#![feature(generators)]
+
+fn assert_send<T: Send>(_: T) {}
+//~^ NOTE required by a bound in `assert_send`
+//~| NOTE required by this bound in `assert_send`
+//~| NOTE required by a bound in `assert_send`
+//~| NOTE required by this bound in `assert_send`
+
+fn main() {
+    let x: &*mut () = &std::ptr::null_mut();
+    let y: &mut *mut () = &mut std::ptr::null_mut();
+    assert_send(move || {
+        //~^ ERROR generator cannot be sent between threads safely
+        //~| NOTE generator is not `Send`
+        yield;
+        let _x = x;
+    });
+    //~^^ NOTE captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync`
+    //~| NOTE has type `&*mut ()` which is not `Send`, because `*mut ()` is not `Sync`
+    assert_send(move || {
+        //~^ ERROR generator cannot be sent between threads safely
+        //~| NOTE generator is not `Send`
+        yield;
+        let _y = y;
+    });
+    //~^^ NOTE captured value is not `Send` because `&mut` references cannot be sent unless their referent is `Send`
+    //~| NOTE has type `&mut *mut ()` which is not `Send`, because `*mut ()` is not `Send`
+}
diff --git a/src/test/ui/generator/ref-upvar-not-send.stderr b/src/test/ui/generator/ref-upvar-not-send.stderr
new file mode 100644
index 00000000000..689ace67e34
--- /dev/null
+++ b/src/test/ui/generator/ref-upvar-not-send.stderr
@@ -0,0 +1,50 @@
+error: generator cannot be sent between threads safely
+  --> $DIR/ref-upvar-not-send.rs:15:17
+   |
+LL |       assert_send(move || {
+   |  _________________^
+LL | |
+LL | |
+LL | |         yield;
+LL | |         let _x = x;
+LL | |     });
+   | |_____^ generator is not `Send`
+   |
+   = help: the trait `Sync` is not implemented for `*mut ()`
+note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync`
+  --> $DIR/ref-upvar-not-send.rs:19:18
+   |
+LL |         let _x = x;
+   |                  ^ has type `&*mut ()` which is not `Send`, because `*mut ()` is not `Sync`
+note: required by a bound in `assert_send`
+  --> $DIR/ref-upvar-not-send.rs:6:19
+   |
+LL | fn assert_send<T: Send>(_: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error: generator cannot be sent between threads safely
+  --> $DIR/ref-upvar-not-send.rs:23:17
+   |
+LL |       assert_send(move || {
+   |  _________________^
+LL | |
+LL | |
+LL | |         yield;
+LL | |         let _y = y;
+LL | |     });
+   | |_____^ generator is not `Send`
+   |
+   = help: within `[generator@$DIR/ref-upvar-not-send.rs:23:17: 23:24]`, the trait `Send` is not implemented for `*mut ()`
+note: captured value is not `Send` because `&mut` references cannot be sent unless their referent is `Send`
+  --> $DIR/ref-upvar-not-send.rs:27:18
+   |
+LL |         let _y = y;
+   |                  ^ has type `&mut *mut ()` which is not `Send`, because `*mut ()` is not `Send`
+note: required by a bound in `assert_send`
+  --> $DIR/ref-upvar-not-send.rs:6:19
+   |
+LL | fn assert_send<T: Send>(_: T) {}
+   |                   ^^^^ required by this bound in `assert_send`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/higher-rank-trait-bounds/issue-58451.stderr b/src/test/ui/higher-rank-trait-bounds/issue-58451.stderr
index 09e25f4dc96..0f051be2128 100644
--- a/src/test/ui/higher-rank-trait-bounds/issue-58451.stderr
+++ b/src/test/ui/higher-rank-trait-bounds/issue-58451.stderr
@@ -11,8 +11,8 @@ LL | fn f<I>(i: I)
    |    ^    ----
 help: provide the argument
    |
-LL |     f(&[f(/* value */)]);
-   |          ~~~~~~~~~~~~~
+LL |     f(&[f(/* i */)]);
+   |          ~~~~~~~~~
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/infinite/issue-41731-infinite-macro-print.rs b/src/test/ui/infinite/issue-41731-infinite-macro-print.rs
new file mode 100644
index 00000000000..d52e6e7e9eb
--- /dev/null
+++ b/src/test/ui/infinite/issue-41731-infinite-macro-print.rs
@@ -0,0 +1,15 @@
+// compile-flags: -Z trace-macros
+
+#![recursion_limit = "5"]
+
+fn main() {
+    macro_rules! stack {
+        ($overflow:expr) => {
+            print!(stack!($overflow));
+            //~^ ERROR recursion limit reached while expanding
+            //~| ERROR format argument must be a string literal
+        };
+    }
+
+    stack!("overflow");
+}
diff --git a/src/test/ui/infinite/issue-41731-infinite-macro-print.stderr b/src/test/ui/infinite/issue-41731-infinite-macro-print.stderr
new file mode 100644
index 00000000000..e30b2039d69
--- /dev/null
+++ b/src/test/ui/infinite/issue-41731-infinite-macro-print.stderr
@@ -0,0 +1,38 @@
+error: recursion limit reached while expanding `$crate::format_args!`
+  --> $DIR/issue-41731-infinite-macro-print.rs:14:5
+   |
+LL |     stack!("overflow");
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "10"]` attribute to your crate (`issue_41731_infinite_macro_print`)
+   = note: this error originates in the macro `print` which comes from the expansion of the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: trace_macro
+  --> $DIR/issue-41731-infinite-macro-print.rs:14:5
+   |
+LL |     stack!("overflow");
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: expanding `stack! { "overflow" }`
+   = note: to `print! (stack! ("overflow")) ;`
+   = note: expanding `print! { stack! ("overflow") }`
+   = note: to `{ $crate :: io :: _print($crate :: format_args! (stack! ("overflow"))) ; }`
+   = note: expanding `stack! { "overflow" }`
+   = note: to `print! (stack! ("overflow")) ;`
+   = note: expanding `print! { stack! ("overflow") }`
+   = note: to `{ $crate :: io :: _print($crate :: format_args! (stack! ("overflow"))) ; }`
+
+error: format argument must be a string literal
+  --> $DIR/issue-41731-infinite-macro-print.rs:14:5
+   |
+LL |     stack!("overflow");
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in the macro `print` which comes from the expansion of the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: you might be missing a string literal to format with
+   |
+LL |             print!("{}", stack!($overflow));
+   |                    +++++
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/infinite/issue-41731-infinite-macro-println.rs b/src/test/ui/infinite/issue-41731-infinite-macro-println.rs
new file mode 100644
index 00000000000..3c2b7ee023b
--- /dev/null
+++ b/src/test/ui/infinite/issue-41731-infinite-macro-println.rs
@@ -0,0 +1,15 @@
+// compile-flags: -Z trace-macros
+
+#![recursion_limit = "5"]
+
+fn main() {
+    macro_rules! stack {
+        ($overflow:expr) => {
+            println!(stack!($overflow));
+            //~^ ERROR recursion limit reached while expanding
+            //~| ERROR format argument must be a string literal
+        };
+    }
+
+    stack!("overflow");
+}
diff --git a/src/test/ui/infinite/issue-41731-infinite-macro-println.stderr b/src/test/ui/infinite/issue-41731-infinite-macro-println.stderr
new file mode 100644
index 00000000000..66b466dafa0
--- /dev/null
+++ b/src/test/ui/infinite/issue-41731-infinite-macro-println.stderr
@@ -0,0 +1,38 @@
+error: recursion limit reached while expanding `$crate::format_args_nl!`
+  --> $DIR/issue-41731-infinite-macro-println.rs:14:5
+   |
+LL |     stack!("overflow");
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "10"]` attribute to your crate (`issue_41731_infinite_macro_println`)
+   = note: this error originates in the macro `println` which comes from the expansion of the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: trace_macro
+  --> $DIR/issue-41731-infinite-macro-println.rs:14:5
+   |
+LL |     stack!("overflow");
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: expanding `stack! { "overflow" }`
+   = note: to `println! (stack! ("overflow")) ;`
+   = note: expanding `println! { stack! ("overflow") }`
+   = note: to `{ $crate :: io :: _print($crate :: format_args_nl! (stack! ("overflow"))) ; }`
+   = note: expanding `stack! { "overflow" }`
+   = note: to `println! (stack! ("overflow")) ;`
+   = note: expanding `println! { stack! ("overflow") }`
+   = note: to `{ $crate :: io :: _print($crate :: format_args_nl! (stack! ("overflow"))) ; }`
+
+error: format argument must be a string literal
+  --> $DIR/issue-41731-infinite-macro-println.rs:14:5
+   |
+LL |     stack!("overflow");
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in the macro `println` which comes from the expansion of the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: you might be missing a string literal to format with
+   |
+LL |             println!("{}", stack!($overflow));
+   |                      +++++
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/issues/issue-3044.stderr b/src/test/ui/issues/issue-3044.stderr
index 2b142f688ec..1232b83c391 100644
--- a/src/test/ui/issues/issue-3044.stderr
+++ b/src/test/ui/issues/issue-3044.stderr
@@ -13,7 +13,7 @@ help: provide the argument
    |
 LL ~     needlesArr.iter().fold(|x, y| {
 LL +
-LL ~     }, /* value */);
+LL ~     }, /* f */);
    |
 
 error: aborting due to previous error
diff --git a/src/test/ui/lint/lint-uppercase-variables.rs b/src/test/ui/lint/lint-uppercase-variables.rs
index b590fa697ad..d4e88aa2643 100644
--- a/src/test/ui/lint/lint-uppercase-variables.rs
+++ b/src/test/ui/lint/lint-uppercase-variables.rs
@@ -20,19 +20,19 @@ fn main() {
 
     match foo::Foo::Foo {
         Foo => {}
-//~^ ERROR variable `Foo` should have a snake case name
-//~^^ WARN `Foo` is named the same as one of the variants of the type `Foo`
-//~^^^ WARN unused variable: `Foo`
+    //~^ ERROR variable `Foo` should have a snake case name
+    //~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo`
+    //~^^^ WARN unused variable: `Foo`
     }
 
     let Foo = foo::Foo::Foo;
     //~^ ERROR variable `Foo` should have a snake case name
-    //~^^ WARN `Foo` is named the same as one of the variants of the type `Foo`
+    //~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo`
     //~^^^ WARN unused variable: `Foo`
 
     fn in_param(Foo: foo::Foo) {}
     //~^ ERROR variable `Foo` should have a snake case name
-    //~^^ WARN `Foo` is named the same as one of the variants of the type `Foo`
+    //~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo`
     //~^^^ WARN unused variable: `Foo`
 
     test(1);
diff --git a/src/test/ui/lint/lint-uppercase-variables.stderr b/src/test/ui/lint/lint-uppercase-variables.stderr
index 71b24a835bc..d476d856e24 100644
--- a/src/test/ui/lint/lint-uppercase-variables.stderr
+++ b/src/test/ui/lint/lint-uppercase-variables.stderr
@@ -1,22 +1,22 @@
-warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `Foo`
+warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo`
   --> $DIR/lint-uppercase-variables.rs:22:9
    |
 LL |         Foo => {}
-   |         ^^^ help: to match on the variant, qualify the path: `Foo::Foo`
+   |         ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo`
    |
    = note: `#[warn(bindings_with_variant_name)]` on by default
 
-warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `Foo`
+warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo`
   --> $DIR/lint-uppercase-variables.rs:28:9
    |
 LL |     let Foo = foo::Foo::Foo;
-   |         ^^^ help: to match on the variant, qualify the path: `Foo::Foo`
+   |         ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo`
 
-warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `Foo`
+warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo`
   --> $DIR/lint-uppercase-variables.rs:33:17
    |
 LL |     fn in_param(Foo: foo::Foo) {}
-   |                 ^^^ help: to match on the variant, qualify the path: `Foo::Foo`
+   |                 ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo`
 
 warning: unused variable: `Foo`
   --> $DIR/lint-uppercase-variables.rs:22:9
diff --git a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr
index 1da29be43db..002dfe115b0 100644
--- a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr
+++ b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr
@@ -8,3 +8,4 @@ LL | fn f(x: S<u32>) {}
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0320`.
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject cc0a320879c17207bbfb96b5d778e28a2c62030
+Subproject c994a4a638370bc7e0ffcbb0e2865afdfa7d441
diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml
index 6448b2d4068..1bc457a9479 100644
--- a/src/tools/clippy/.github/workflows/clippy_bors.yml
+++ b/src/tools/clippy/.github/workflows/clippy_bors.yml
@@ -82,13 +82,6 @@ jobs:
       with:
         github_token: "${{ secrets.github_token }}"
 
-    - name: Install dependencies (Linux-i686)
-      run: |
-        sudo dpkg --add-architecture i386
-        sudo apt-get update
-        sudo apt-get install gcc-multilib libssl-dev:i386 libgit2-dev:i386
-      if: matrix.host == 'i686-unknown-linux-gnu'
-
     - name: Checkout
       uses: actions/checkout@v3.0.2
 
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 23912bb3ed6..903ee938d9d 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6,11 +6,181 @@ document.
 
 ## Unreleased / Beta / In Rust Nightly
 
-[b52fb523...master](https://github.com/rust-lang/rust-clippy/compare/b52fb523...master)
+[4f142aa1...master](https://github.com/rust-lang/rust-clippy/compare/4f142aa1...master)
+
+## Rust 1.66
+
+Current stable, released 2022-12-15
+
+[b52fb523...4f142aa1](https://github.com/rust-lang/rust-clippy/compare/b52fb523...4f142aa1)
+
+### New Lints
+
+* [`manual_clamp`]
+  [#9484](https://github.com/rust-lang/rust-clippy/pull/9484)
+* [`missing_trait_methods`]
+  [#9670](https://github.com/rust-lang/rust-clippy/pull/9670)
+* [`unused_format_specs`]
+  [#9637](https://github.com/rust-lang/rust-clippy/pull/9637)
+* [`iter_kv_map`]
+  [#9409](https://github.com/rust-lang/rust-clippy/pull/9409)
+* [`manual_filter`]
+  [#9451](https://github.com/rust-lang/rust-clippy/pull/9451)
+* [`box_default`]
+  [#9511](https://github.com/rust-lang/rust-clippy/pull/9511)
+* [`implicit_saturating_add`]
+  [#9549](https://github.com/rust-lang/rust-clippy/pull/9549)
+* [`as_ptr_cast_mut`]
+  [#9572](https://github.com/rust-lang/rust-clippy/pull/9572)
+* [`disallowed_macros`]
+  [#9495](https://github.com/rust-lang/rust-clippy/pull/9495)
+* [`partial_pub_fields`]
+  [#9658](https://github.com/rust-lang/rust-clippy/pull/9658)
+* [`uninlined_format_args`]
+  [#9233](https://github.com/rust-lang/rust-clippy/pull/9233)
+* [`cast_nan_to_int`]
+  [#9617](https://github.com/rust-lang/rust-clippy/pull/9617)
+
+### Moves and Deprecations
+
+* `positional_named_format_parameters` was uplifted to rustc under the new name
+  `named_arguments_used_positionally`
+  [#8518](https://github.com/rust-lang/rust-clippy/pull/8518)
+* Moved [`implicit_saturating_sub`] to `style` (Now warn-by-default)
+  [#9584](https://github.com/rust-lang/rust-clippy/pull/9584)
+* Moved `derive_partial_eq_without_eq` to `nursery` (now allow-by-default)
+  [#9536](https://github.com/rust-lang/rust-clippy/pull/9536)
+
+### Enhancements
+
+* [`nonstandard_macro_braces`]: Now includes `matches!()` in the default lint config
+  [#9471](https://github.com/rust-lang/rust-clippy/pull/9471)
+* [`suboptimal_flops`]: Now supports multiplication and subtraction operations
+  [#9581](https://github.com/rust-lang/rust-clippy/pull/9581)
+* [`arithmetic_side_effects`]: Now detects cases with literals behind references
+  [#9587](https://github.com/rust-lang/rust-clippy/pull/9587)
+* [`upper_case_acronyms`]: Now also checks enum names
+  [#9580](https://github.com/rust-lang/rust-clippy/pull/9580)
+* [`needless_borrowed_reference`]: Now lints nested patterns
+  [#9573](https://github.com/rust-lang/rust-clippy/pull/9573)
+* [`unnecessary_cast`]: Now works for non-trivial non-literal expressions
+  [#9576](https://github.com/rust-lang/rust-clippy/pull/9576)
+* [`arithmetic_side_effects`]: Now detects operations with custom types
+  [#9559](https://github.com/rust-lang/rust-clippy/pull/9559)
+* [`disallowed_methods`], [`disallowed_types`]: Not correctly lints types, functions and macros
+  with the same path
+  [#9495](https://github.com/rust-lang/rust-clippy/pull/9495)
+* [`self_named_module_files`], [`mod_module_files`]: Now take remapped path prefixes into account
+  [#9475](https://github.com/rust-lang/rust-clippy/pull/9475)
+* [`bool_to_int_with_if`]: Now detects the inverse if case
+  [#9476](https://github.com/rust-lang/rust-clippy/pull/9476)
+
+### False Positive Fixes
+
+* [`arithmetic_side_effects`]: Now allows operations that can't overflow
+  [#9474](https://github.com/rust-lang/rust-clippy/pull/9474)
+* [`unnecessary_lazy_evaluations`]: No longer lints in external macros
+  [#9486](https://github.com/rust-lang/rust-clippy/pull/9486)
+* [`needless_borrow`], [`explicit_auto_deref`]: No longer lint on unions that require the reference
+  [#9490](https://github.com/rust-lang/rust-clippy/pull/9490)
+* [`almost_complete_letter_range`]: No longer lints in external macros
+  [#9467](https://github.com/rust-lang/rust-clippy/pull/9467)
+* [`drop_copy`]: No longer lints on idiomatic cases in match arms 
+  [#9491](https://github.com/rust-lang/rust-clippy/pull/9491)
+* [`question_mark`]: No longer lints in const context
+  [#9487](https://github.com/rust-lang/rust-clippy/pull/9487)
+* [`collapsible_if`]: Suggestion now work in macros
+  [#9410](https://github.com/rust-lang/rust-clippy/pull/9410)
+* [`std_instead_of_core`]: No longer triggers on unstable modules
+  [#9545](https://github.com/rust-lang/rust-clippy/pull/9545)
+* [`unused_peekable`]: No longer lints, if the peak is done in a closure or function
+  [#9465](https://github.com/rust-lang/rust-clippy/pull/9465)
+* [`useless_attribute`]: No longer lints on `#[allow]` attributes for [`unsafe_removed_from_name`]
+  [#9593](https://github.com/rust-lang/rust-clippy/pull/9593)
+* [`unnecessary_lazy_evaluations`]: No longer suggest switching to early evaluation when type has
+  custom `Drop` implementation
+  [#9551](https://github.com/rust-lang/rust-clippy/pull/9551)
+* [`unnecessary_cast`]: No longer lints on negative hexadecimal literals when cast as floats
+  [#9609](https://github.com/rust-lang/rust-clippy/pull/9609)
+* [`use_self`]: No longer lints in proc macros
+  [#9454](https://github.com/rust-lang/rust-clippy/pull/9454)
+* [`never_loop`]: Now takes `let ... else` statements into consideration.
+  [#9496](https://github.com/rust-lang/rust-clippy/pull/9496)
+* [`default_numeric_fallback`]: Now ignores constants
+  [#9636](https://github.com/rust-lang/rust-clippy/pull/9636)
+* [`uninit_vec`]: No longer lints `Vec::set_len(0)`
+  [#9519](https://github.com/rust-lang/rust-clippy/pull/9519)
+* [`arithmetic_side_effects`]: Now ignores references to integer types
+  [#9507](https://github.com/rust-lang/rust-clippy/pull/9507)
+* [`large_stack_arrays`]: No longer lints inside static items
+  [#9466](https://github.com/rust-lang/rust-clippy/pull/9466)
+* [`ref_option_ref`]: No longer lints if the inner reference is mutable
+  [#9684](https://github.com/rust-lang/rust-clippy/pull/9684)
+* [`ptr_arg`]: No longer lints if the argument is used as an incomplete trait object
+  [#9645](https://github.com/rust-lang/rust-clippy/pull/9645)
+* [`should_implement_trait`]: Now also works for `default` methods
+  [#9546](https://github.com/rust-lang/rust-clippy/pull/9546)
+
+### Suggestion Fixes/Improvements
+
+* [`derivable_impls`]: The suggestion is now machine applicable
+  [#9429](https://github.com/rust-lang/rust-clippy/pull/9429)
+* [`match_single_binding`]: The suggestion now handles scrutinies with side effects better
+  [#9601](https://github.com/rust-lang/rust-clippy/pull/9601)
+* [`zero_prefixed_literal`]: Only suggests using octal numbers, if this is possible
+  [#9652](https://github.com/rust-lang/rust-clippy/pull/9652)
+* [`rc_buffer`]: The suggestion is no longer machine applicable to avoid semantic changes
+  [#9633](https://github.com/rust-lang/rust-clippy/pull/9633)
+* [`print_literal`], [`write_literal`], [`uninlined_format_args`]: The suggestion now ignores
+  comments after the macro call.
+  [#9586](https://github.com/rust-lang/rust-clippy/pull/9586)
+* [`expect_fun_call`]:Improved the suggestion for `format!` calls with captured variables
+  [#9586](https://github.com/rust-lang/rust-clippy/pull/9586)
+* [`nonstandard_macro_braces`]: The suggestion is now machine applicable and will no longer
+  replace brackets inside the macro argument.
+  [#9499](https://github.com/rust-lang/rust-clippy/pull/9499)
+* [`from_over_into`]: The suggestion is now a machine applicable and contains explanations
+  [#9649](https://github.com/rust-lang/rust-clippy/pull/9649)
+* [`needless_return`]: The automatic suggestion now removes all required semicolons
+  [#9497](https://github.com/rust-lang/rust-clippy/pull/9497)
+* [`to_string_in_format_args`]: The suggestion now keeps parenthesis around values
+  [#9590](https://github.com/rust-lang/rust-clippy/pull/9590)
+* [`manual_assert`]: The suggestion now preserves comments
+  [#9479](https://github.com/rust-lang/rust-clippy/pull/9479)
+* [`redundant_allocation`]: The suggestion applicability is now marked `MaybeIncorrect` to
+  avoid semantic changes
+  [#9634](https://github.com/rust-lang/rust-clippy/pull/9634)
+* [`assertions_on_result_states`]: The suggestion has been corrected, for cases where the
+  `assert!` is not in a statement.
+  [#9453](https://github.com/rust-lang/rust-clippy/pull/9453)
+* [`nonminimal_bool`]: The suggestion no longer expands macros
+  [#9457](https://github.com/rust-lang/rust-clippy/pull/9457)
+* [`collapsible_match`]: Now specifies field names, when a struct is destructed
+  [#9685](https://github.com/rust-lang/rust-clippy/pull/9685)
+* [`unnecessary_cast`]: The suggestion now adds parenthesis for negative numbers
+  [#9577](https://github.com/rust-lang/rust-clippy/pull/9577)
+* [`redundant_closure`]: The suggestion now works for `impl FnMut` arguments
+  [#9556](https://github.com/rust-lang/rust-clippy/pull/9556)
+
+### ICE Fixes
+
+* [`unnecessary_to_owned`]: Avoid ICEs in favor of false negatives if information is missing
+  [#9505](https://github.com/rust-lang/rust-clippy/pull/9505)
+* [`manual_range_contains`]: No longer ICEs on values behind references
+  [#9627](https://github.com/rust-lang/rust-clippy/pull/9627)
+* [`needless_pass_by_value`]: No longer ICEs on unsized `dyn Fn` arguments
+  [#9531](https://github.com/rust-lang/rust-clippy/pull/9531)
+* `*_interior_mutable_const` lints: no longer ICE on const unions containing `!Freeze` types
+  [#9539](https://github.com/rust-lang/rust-clippy/pull/9539)
+
+### Others
+
+* Released `rustc_tools_util` for version information on `Crates.io`. (Further adjustments will
+  not be published as part of this changelog)
 
 ## Rust 1.65
 
-Current stable, released 2022-11-03
+Released 2022-11-03
 
 [3c7e7dbc...b52fb523](https://github.com/rust-lang/rust-clippy/compare/3c7e7dbc...b52fb523)
 
@@ -3875,6 +4045,7 @@ Released 2018-09-13
 [`alloc_instead_of_core`]: https://rust-lang.github.io/rust-clippy/master/index.html#alloc_instead_of_core
 [`allow_attributes_without_reason`]: https://rust-lang.github.io/rust-clippy/master/index.html#allow_attributes_without_reason
 [`almost_complete_letter_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_letter_range
+[`almost_complete_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_range
 [`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped
 [`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant
 [`arithmetic_side_effects`]: https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects
@@ -4353,6 +4524,8 @@ Released 2018-09-13
 [`self_named_constructors`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_constructors
 [`self_named_module_files`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_module_files
 [`semicolon_if_nothing_returned`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned
+[`semicolon_inside_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_inside_block
+[`semicolon_outside_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_outside_block
 [`separated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#separated_literal_suffix
 [`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse
 [`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index fe425a2fb99..f8cb4b7219c 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy"
-version = "0.1.67"
+version = "0.1.68"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
@@ -23,7 +23,7 @@ path = "src/driver.rs"
 [dependencies]
 clippy_lints = { path = "clippy_lints" }
 semver = "1.0"
-rustc_tools_util = "0.2.1"
+rustc_tools_util = "0.3.0"
 tempfile = { version = "3.2", optional = true }
 termize = "0.1"
 
@@ -55,7 +55,7 @@ tokio = { version = "1", features = ["io-util"] }
 rustc-semver = "1.1"
 
 [build-dependencies]
-rustc_tools_util = "0.2.1"
+rustc_tools_util = "0.3.0"
 
 [features]
 deny-warnings = ["clippy_lints/deny-warnings"]
diff --git a/src/tools/clippy/book/src/README.md b/src/tools/clippy/book/src/README.md
index 6248d588a89..23867df8efe 100644
--- a/src/tools/clippy/book/src/README.md
+++ b/src/tools/clippy/book/src/README.md
@@ -1,6 +1,6 @@
 # Clippy
 
-[![Clippy Test](https://github.com/rust-lang/rust-clippy/workflows/Clippy%20Test/badge.svg?branch=auto&event=push)](https://github.com/rust-lang/rust-clippy/actions?query=workflow%3A%22Clippy+Test%22+event%3Apush+branch%3Aauto)
+[![Clippy Test](https://github.com/rust-lang/rust-clippy/workflows/Clippy%20Test%20(bors)/badge.svg?branch=auto&event=push)](https://github.com/rust-lang/rust-clippy/actions?query=workflow%3A%22Clippy+Test+(bors)%22+event%3Apush+branch%3Aauto)
 [![License: MIT OR Apache-2.0](https://img.shields.io/crates/l/clippy.svg)](https://github.com/rust-lang/rust-clippy#license)
 
 A collection of lints to catch common mistakes and improve your
diff --git a/src/tools/clippy/build.rs b/src/tools/clippy/build.rs
index b5484bec3c8..b79d09b0dd2 100644
--- a/src/tools/clippy/build.rs
+++ b/src/tools/clippy/build.rs
@@ -3,17 +3,5 @@ fn main() {
     println!("cargo:rustc-env=PROFILE={}", std::env::var("PROFILE").unwrap());
     // Don't rebuild even if nothing changed
     println!("cargo:rerun-if-changed=build.rs");
-    // forward git repo hashes we build at
-    println!(
-        "cargo:rustc-env=GIT_HASH={}",
-        rustc_tools_util::get_commit_hash().unwrap_or_default()
-    );
-    println!(
-        "cargo:rustc-env=COMMIT_DATE={}",
-        rustc_tools_util::get_commit_date().unwrap_or_default()
-    );
-    println!(
-        "cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}",
-        rustc_tools_util::get_channel()
-    );
+    rustc_tools_util::setup_version_info!();
 }
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index aedff24c12c..a9f69b1ba63 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.67"
+version = "0.1.68"
 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/almost_complete_letter_range.rs b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs
index 52beaf504a4..42e14b5cd94 100644
--- a/src/tools/clippy/clippy_lints/src/almost_complete_letter_range.rs
+++ b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs
@@ -10,8 +10,8 @@ use rustc_span::Span;
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for ranges which almost include the entire range of letters from 'a' to 'z', but
-    /// don't because they're a half open range.
+    /// Checks for ranges which almost include the entire range of letters from 'a' to 'z'
+    /// or digits from '0' to '9', but don't because they're a half open range.
     ///
     /// ### Why is this bad?
     /// This (`'a'..'z'`) is almost certainly a typo meant to include all letters.
@@ -25,21 +25,21 @@ declare_clippy_lint! {
     /// let _ = 'a'..='z';
     /// ```
     #[clippy::version = "1.63.0"]
-    pub ALMOST_COMPLETE_LETTER_RANGE,
+    pub ALMOST_COMPLETE_RANGE,
     suspicious,
-    "almost complete letter range"
+    "almost complete range"
 }
-impl_lint_pass!(AlmostCompleteLetterRange => [ALMOST_COMPLETE_LETTER_RANGE]);
+impl_lint_pass!(AlmostCompleteRange => [ALMOST_COMPLETE_RANGE]);
 
-pub struct AlmostCompleteLetterRange {
+pub struct AlmostCompleteRange {
     msrv: Msrv,
 }
-impl AlmostCompleteLetterRange {
+impl AlmostCompleteRange {
     pub fn new(msrv: Msrv) -> Self {
         Self { msrv }
     }
 }
-impl EarlyLintPass for AlmostCompleteLetterRange {
+impl EarlyLintPass for AlmostCompleteRange {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) {
         if let ExprKind::Range(Some(start), Some(end), RangeLimits::HalfOpen) = &e.kind {
             let ctxt = e.span.ctxt();
@@ -87,14 +87,18 @@ fn check_range(cx: &EarlyContext<'_>, span: Span, start: &Expr, end: &Expr, sugg
                 Ok(LitKind::Byte(b'A') | LitKind::Char('A')),
                 Ok(LitKind::Byte(b'Z') | LitKind::Char('Z')),
             )
+            | (
+                Ok(LitKind::Byte(b'0') | LitKind::Char('0')),
+                Ok(LitKind::Byte(b'9') | LitKind::Char('9')),
+            )
         )
         && !in_external_macro(cx.sess(), span)
     {
         span_lint_and_then(
             cx,
-            ALMOST_COMPLETE_LETTER_RANGE,
+            ALMOST_COMPLETE_RANGE,
             span,
-            "almost complete ascii letter range",
+            "almost complete ascii range",
             |diag| {
                 if let Some((span, sugg)) = sugg {
                     diag.span_suggestion(
diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs
index 36daceabe0b..91900542af8 100644
--- a/src/tools/clippy/clippy_lints/src/box_default.rs
+++ b/src/tools/clippy/clippy_lints/src/box_default.rs
@@ -30,7 +30,7 @@ declare_clippy_lint! {
     /// ```rust
     /// let x: Box<String> = Box::default();
     /// ```
-    #[clippy::version = "1.65.0"]
+    #[clippy::version = "1.66.0"]
     pub BOX_DEFAULT,
     perf,
     "Using Box::new(T::default()) instead of Box::default()"
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index c6d505c4a18..161e3a698e9 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -641,7 +641,7 @@ declare_clippy_lint! {
     /// ```rust,ignore
     /// let _: = 0_u64;
     /// ```
-    #[clippy::version = "1.64.0"]
+    #[clippy::version = "1.66.0"]
     pub CAST_NAN_TO_INT,
     suspicious,
     "casting a known floating-point NaN into an integer"
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index e4d76f07d6b..3cd7d1d7e72 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -35,7 +35,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::utils::internal_lints::produce_ice::PRODUCE_ICE_INFO,
     #[cfg(feature = "internal")]
     crate::utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH_INFO,
-    crate::almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE_INFO,
+    crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO,
     crate::approx_const::APPROX_CONSTANT_INFO,
     crate::as_conversions::AS_CONVERSIONS_INFO,
     crate::asm_syntax::INLINE_ASM_X86_ATT_SYNTAX_INFO,
@@ -525,6 +525,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::returns::NEEDLESS_RETURN_INFO,
     crate::same_name_method::SAME_NAME_METHOD_INFO,
     crate::self_named_constructors::SELF_NAMED_CONSTRUCTORS_INFO,
+    crate::semicolon_block::SEMICOLON_INSIDE_BLOCK_INFO,
+    crate::semicolon_block::SEMICOLON_OUTSIDE_BLOCK_INFO,
     crate::semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED_INFO,
     crate::serde_api::SERDE_API_MISUSE_INFO,
     crate::shadow::SHADOW_REUSE_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 31183266acf..7b43d8ccc67 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -1390,10 +1390,15 @@ fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedenc
                 continue;
             },
             ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty),
-            ty::Alias(ty::Projection, _) if ty.has_non_region_param() => TyPosition::new_deref_stable_for_result(precedence, ty),
-            ty::Infer(_) | ty::Error(_) | ty::Bound(..) | ty::Alias(ty::Opaque, ..) | ty::Placeholder(_) | ty::Dynamic(..) => {
-                Position::ReborrowStable(precedence).into()
+            ty::Alias(ty::Projection, _) if ty.has_non_region_param() => {
+                TyPosition::new_deref_stable_for_result(precedence, ty)
             },
+            ty::Infer(_)
+            | ty::Error(_)
+            | ty::Bound(..)
+            | ty::Alias(ty::Opaque, ..)
+            | ty::Placeholder(_)
+            | ty::Dynamic(..) => Position::ReborrowStable(precedence).into(),
             ty::Adt(..) if ty.has_placeholders() || ty.has_opaque_types() => {
                 Position::ReborrowStable(precedence).into()
             },
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 3f0b165f2b6..cf3483d4c00 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -513,10 +513,7 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) ->
         tcx.mk_predicates(ty_predicates.iter().map(|&(p, _)| p).chain(
             params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| {
                 tcx.mk_predicate(Binder::dummy(PredicateKind::Clause(Clause::Trait(TraitPredicate {
-                    trait_ref: tcx.mk_trait_ref(
-                        eq_trait_id,
-                        [tcx.mk_param_from_def(param)],
-                    ),
+                    trait_ref: tcx.mk_trait_ref(eq_trait_id, [tcx.mk_param_from_def(param)]),
                     constness: BoundConstness::NotConst,
                     polarity: ImplPolarity::Positive,
                 }))))
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
index 68122b4cef5..1971cab64ef 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
@@ -47,7 +47,7 @@ declare_clippy_lint! {
     ///     value: usize,
     /// }
     /// ```
-    #[clippy::version = "1.65.0"]
+    #[clippy::version = "1.66.0"]
     pub DISALLOWED_MACROS,
     style,
     "use of a disallowed macro"
diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs
index 111b624f529..69f7c152fc4 100644
--- a/src/tools/clippy/clippy_lints/src/format_args.rs
+++ b/src/tools/clippy/clippy_lints/src/format_args.rs
@@ -2,7 +2,8 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::is_diag_trait_item;
 use clippy_utils::macros::FormatParamKind::{Implicit, Named, NamedInline, Numbered, Starred};
 use clippy_utils::macros::{
-    is_format_macro, is_panic, root_macro_call, Count, FormatArg, FormatArgsExpn, FormatParam, FormatParamUsage,
+    is_assert_macro, is_format_macro, is_panic, root_macro_call, Count, FormatArg, FormatArgsExpn, FormatParam,
+    FormatParamUsage,
 };
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_opt;
@@ -122,7 +123,7 @@ declare_clippy_lint! {
     ///
     /// If a format string contains a numbered argument that cannot be inlined
     /// nothing will be suggested, e.g. `println!("{0}={1}", var, 1+2)`.
-    #[clippy::version = "1.65.0"]
+    #[clippy::version = "1.66.0"]
     pub UNINLINED_FORMAT_ARGS,
     style,
     "using non-inlined variables in `format!` calls"
@@ -290,8 +291,9 @@ fn check_uninlined_args(
     if args.format_string.span.from_expansion() {
         return;
     }
-    if call_site.edition() < Edition2021 && is_panic(cx, def_id) {
-        // panic! before 2021 edition considers a single string argument as non-format
+    if call_site.edition() < Edition2021 && (is_panic(cx, def_id) || is_assert_macro(cx, def_id)) {
+        // panic!, assert!, and debug_assert! before 2021 edition considers a single string argument as
+        // non-format
         return;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs
index 0634b2798fe..a92f7548ff2 100644
--- a/src/tools/clippy/clippy_lints/src/from_over_into.rs
+++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs
@@ -10,7 +10,7 @@ use rustc_hir::{
     TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::hir::nested_filter::OnlyBodies;
+use rustc_middle::{hir::nested_filter::OnlyBodies, ty};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::{kw, sym};
 use rustc_span::{Span, Symbol};
@@ -78,6 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto {
             && let Some(GenericArgs { args: [GenericArg::Type(target_ty)], .. }) = into_trait_seg.args
             && let Some(middle_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
             && cx.tcx.is_diagnostic_item(sym::Into, middle_trait_ref.def_id)
+            && !matches!(middle_trait_ref.substs.type_at(1).kind(), ty::Alias(ty::Opaque, _))
         {
             span_lint_and_then(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
index bf1351829c6..6e19343931e 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
@@ -31,7 +31,7 @@ declare_clippy_lint! {
     ///
     /// u = u.saturating_add(1);
     /// ```
-    #[clippy::version = "1.65.0"]
+    #[clippy::version = "1.66.0"]
     pub IMPLICIT_SATURATING_ADD,
     style,
     "Perform saturating addition instead of implicitly checking max bound of data type"
diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
index 4cd7dff4cfd..eebfb753a0c 100644
--- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
@@ -1,13 +1,13 @@
 //! lint on indexing and slicing operations
 
 use clippy_utils::consts::{constant, Constant};
-use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
+use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::higher;
 use rustc_ast::ast::RangeLimits;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -82,15 +82,29 @@ declare_clippy_lint! {
     "indexing/slicing usage"
 }
 
-declare_lint_pass!(IndexingSlicing => [INDEXING_SLICING, OUT_OF_BOUNDS_INDEXING]);
+impl_lint_pass!(IndexingSlicing => [INDEXING_SLICING, OUT_OF_BOUNDS_INDEXING]);
+
+#[derive(Copy, Clone)]
+pub struct IndexingSlicing {
+    suppress_restriction_lint_in_const: bool,
+}
+
+impl IndexingSlicing {
+    pub fn new(suppress_restriction_lint_in_const: bool) -> Self {
+        Self {
+            suppress_restriction_lint_in_const,
+        }
+    }
+}
 
 impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if cx.tcx.hir().is_inside_const_context(expr.hir_id) {
+        if self.suppress_restriction_lint_in_const && cx.tcx.hir().is_inside_const_context(expr.hir_id) {
             return;
         }
 
         if let ExprKind::Index(array, index) = &expr.kind {
+            let note = "the suggestion might not be applicable in constant blocks";
             let ty = cx.typeck_results().expr_ty(array).peel_refs();
             if let Some(range) = higher::Range::hir(index) {
                 // Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..]
@@ -141,7 +155,13 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
                     (None, None) => return, // [..] is ok.
                 };
 
-                span_lint_and_help(cx, INDEXING_SLICING, expr.span, "slicing may panic", None, help_msg);
+                span_lint_and_then(cx, INDEXING_SLICING, expr.span, "slicing may panic", |diag| {
+                    diag.help(help_msg);
+
+                    if cx.tcx.hir().is_inside_const_context(expr.hir_id) {
+                        diag.note(note);
+                    }
+                });
             } else {
                 // Catchall non-range index, i.e., [n] or [n << m]
                 if let ty::Array(..) = ty.kind() {
@@ -156,14 +176,13 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
                     }
                 }
 
-                span_lint_and_help(
-                    cx,
-                    INDEXING_SLICING,
-                    expr.span,
-                    "indexing may panic",
-                    None,
-                    "consider using `.get(n)` or `.get_mut(n)` instead",
-                );
+                span_lint_and_then(cx, INDEXING_SLICING, expr.span, "indexing may panic", |diag| {
+                    diag.help("consider using `.get(n)` or `.get_mut(n)` instead");
+
+                    if cx.tcx.hir().is_inside_const_context(expr.hir_id) {
+                        diag.note(note);
+                    }
+                });
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 73841f9aa9a..e88d1764a24 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -1,13 +1,13 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed};
+use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators};
 use if_chain::if_chain;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefIdSet;
 use rustc_hir::{
     def_id::DefId, AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, ImplItem, ImplItemKind, ImplicitSelfKind, Item,
-    ItemKind, Mutability, Node, TraitItemRef, TyKind,
+    ItemKind, Mutability, Node, TraitItemRef, TyKind, UnOp,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
@@ -16,6 +16,7 @@ use rustc_span::{
     source_map::{Span, Spanned, Symbol},
     symbol::sym,
 };
+use std::borrow::Cow;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -428,16 +429,23 @@ fn check_len(
 fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Expr<'_>, op: &str) {
     if (is_empty_array(lit2) || is_empty_string(lit2)) && has_is_empty(cx, lit1) {
         let mut applicability = Applicability::MachineApplicable;
+
+        let lit1 = peel_ref_operators(cx, lit1);
+        let mut lit_str = snippet_with_applicability(cx, lit1.span, "_", &mut applicability);
+
+        // Wrap the expression in parentheses if it's a deref expression. Otherwise operator precedence will
+        // cause the code to dereference boolean(won't compile).
+        if let ExprKind::Unary(UnOp::Deref, _) = lit1.kind {
+            lit_str = Cow::from(format!("({lit_str})"));
+        }
+
         span_lint_and_sugg(
             cx,
             COMPARISON_TO_EMPTY,
             span,
             "comparison to empty slice",
             &format!("using `{op}is_empty` is clearer and more explicit"),
-            format!(
-                "{op}{}.is_empty()",
-                snippet_with_applicability(cx, lit1.span, "_", &mut applicability)
-            ),
+            format!("{op}{lit_str}.is_empty()"),
             applicability,
         );
     }
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 7b17d8a156d..39850d59803 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -66,7 +66,7 @@ mod declared_lints;
 mod renamed_lints;
 
 // begin lints modules, do not remove this comment, it’s used in `update_lints`
-mod almost_complete_letter_range;
+mod almost_complete_range;
 mod approx_const;
 mod as_conversions;
 mod asm_syntax;
@@ -256,6 +256,7 @@ mod return_self_not_must_use;
 mod returns;
 mod same_name_method;
 mod self_named_constructors;
+mod semicolon_block;
 mod semicolon_if_nothing_returned;
 mod serde_api;
 mod shadow;
@@ -507,9 +508,20 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     }
 
     let arithmetic_side_effects_allowed = conf.arithmetic_side_effects_allowed.clone();
+    let arithmetic_side_effects_allowed_binary = conf.arithmetic_side_effects_allowed_binary.clone();
+    let arithmetic_side_effects_allowed_unary = conf.arithmetic_side_effects_allowed_unary.clone();
     store.register_late_pass(move |_| {
         Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new(
-            arithmetic_side_effects_allowed.clone(),
+            arithmetic_side_effects_allowed
+                .iter()
+                .flat_map(|el| [[el.clone(), "*".to_string()], ["*".to_string(), el.clone()]])
+                .chain(arithmetic_side_effects_allowed_binary.clone())
+                .collect(),
+            arithmetic_side_effects_allowed
+                .iter()
+                .chain(arithmetic_side_effects_allowed_unary.iter())
+                .cloned()
+                .collect(),
         ))
     });
     store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir));
@@ -538,7 +550,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(needless_bool::NeedlessBool));
     store.register_late_pass(|_| Box::new(needless_bool::BoolComparison));
     store.register_late_pass(|_| Box::new(needless_for_each::NeedlessForEach));
-    store.register_late_pass(|_| Box::new(misc::MiscLints));
+    store.register_late_pass(|_| Box::<misc::LintPass>::default());
     store.register_late_pass(|_| Box::new(eta_reduction::EtaReduction));
     store.register_late_pass(|_| Box::new(mut_mut::MutMut));
     store.register_late_pass(|_| Box::new(mut_reference::UnnecessaryMutPassed));
@@ -561,6 +573,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
     let allow_expect_in_tests = conf.allow_expect_in_tests;
     let allow_unwrap_in_tests = conf.allow_unwrap_in_tests;
+    let suppress_restriction_lint_in_const = conf.suppress_restriction_lint_in_const;
     store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(msrv())));
     store.register_late_pass(move |_| {
         Box::new(methods::Methods::new(
@@ -682,7 +695,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(inherent_impl::MultipleInherentImpl));
     store.register_late_pass(|_| Box::new(neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd));
     store.register_late_pass(|_| Box::new(unwrap::Unwrap));
-    store.register_late_pass(|_| Box::new(indexing_slicing::IndexingSlicing));
+    store.register_late_pass(move |_| {
+        Box::new(indexing_slicing::IndexingSlicing::new(
+            suppress_restriction_lint_in_const,
+        ))
+    });
     store.register_late_pass(|_| Box::new(non_copy_const::NonCopyConst));
     store.register_late_pass(|_| Box::new(ptr_offset_with_cast::PtrOffsetWithCast));
     store.register_late_pass(|_| Box::new(redundant_clone::RedundantClone));
@@ -859,7 +876,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(rc_clone_in_vec_init::RcCloneInVecInit));
     store.register_early_pass(|| Box::<duplicate_mod::DuplicateMod>::default());
     store.register_early_pass(|| Box::new(unused_rounding::UnusedRounding));
-    store.register_early_pass(move || Box::new(almost_complete_letter_range::AlmostCompleteLetterRange::new(msrv())));
+    store.register_early_pass(move || Box::new(almost_complete_range::AlmostCompleteRange::new(msrv())));
     store.register_late_pass(|_| Box::new(swap_ptr_to_ref::SwapPtrToRef));
     store.register_late_pass(|_| Box::new(mismatching_type_param_order::TypeParamMismatch));
     store.register_late_pass(|_| Box::new(read_zero_byte_vec::ReadZeroByteVec));
@@ -884,6 +901,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr));
     store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow));
     store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv())));
+    store.register_late_pass(|_| Box::new(semicolon_block::SemicolonBlock));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs
index b6f4cf7bbb3..28ee24309cc 100644
--- a/src/tools/clippy/clippy_lints/src/loops/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs
@@ -25,7 +25,6 @@ pub(super) struct IncrementVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,                  // context reference
     states: HirIdMap<IncrementVisitorVarState>, // incremented variables
     depth: u32,                                 // depth of conditional expressions
-    done: bool,
 }
 
 impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> {
@@ -34,7 +33,6 @@ impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> {
             cx,
             states: HirIdMap::default(),
             depth: 0,
-            done: false,
         }
     }
 
@@ -51,10 +49,6 @@ impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> {
 
 impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
-        if self.done {
-            return;
-        }
-
         // If node is a variable
         if let Some(def_id) = path_to_local(expr) {
             if let Some(parent) = get_parent_expr(self.cx, expr) {
@@ -95,7 +89,9 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
             walk_expr(self, expr);
             self.depth -= 1;
         } else if let ExprKind::Continue(_) = expr.kind {
-            self.done = true;
+            // If we see a `continue` block, then we increment depth so that the IncrementVisitor
+            // state will be set to DontWarn if we see the variable being modified anywhere afterwards.
+            self.depth += 1;
         } else {
             walk_expr(self, expr);
         }
diff --git a/src/tools/clippy/clippy_lints/src/manual_assert.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs
index b8ed9b9ec18..4277455a3a2 100644
--- a/src/tools/clippy/clippy_lints/src/manual_assert.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_assert.rs
@@ -2,7 +2,7 @@ use crate::rustc_lint::LintContext;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::{root_macro_call, FormatArgsExpn};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{peel_blocks_with_stmt, span_extract_comment, sugg};
+use clippy_utils::{is_else_clause, peel_blocks_with_stmt, span_extract_comment, sugg};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
@@ -47,6 +47,10 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert {
             if cx.tcx.item_name(macro_call.def_id) == sym::panic;
             if !cx.tcx.sess.source_map().is_multiline(cond.span);
             if let Some(format_args) = FormatArgsExpn::find_nested(cx, then, macro_call.expn);
+            // Don't change `else if foo { panic!(..) }` to `else { assert!(foo, ..) }` as it just
+            // shuffles the condition around.
+            // Should this have a config value?
+            if !is_else_clause(cx.tcx, expr);
             then {
                 let mut applicability = Applicability::MachineApplicable;
                 let format_args_snip = snippet_with_applicability(cx, format_args.inputs_span(), "..", &mut applicability);
diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
index 5ab049d8d13..d9ef7dffa02 100644
--- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
@@ -1,11 +1,12 @@
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::{diagnostics::span_lint_and_sugg, in_constant, macros::root_macro_call, source::snippet};
+use clippy_utils::{diagnostics::span_lint_and_sugg, higher, in_constant, macros::root_macro_call, source::snippet};
+use rustc_ast::ast::RangeLimits;
 use rustc_ast::LitKind::{Byte, Char};
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd};
+use rustc_hir::{BorrowKind, Expr, ExprKind, PatKind, RangeEnd};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::{def_id::DefId, sym};
+use rustc_span::{def_id::DefId, sym, Span};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -23,6 +24,10 @@ declare_clippy_lint! {
     ///     assert!(matches!(b'X', b'A'..=b'Z'));
     ///     assert!(matches!('2', '0'..='9'));
     ///     assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
+    ///
+    ///     ('0'..='9').contains(&'0');
+    ///     ('a'..='z').contains(&'a');
+    ///     ('A'..='Z').contains(&'A');
     /// }
     /// ```
     /// Use instead:
@@ -32,6 +37,10 @@ declare_clippy_lint! {
     ///     assert!(b'X'.is_ascii_uppercase());
     ///     assert!('2'.is_ascii_digit());
     ///     assert!('x'.is_ascii_alphabetic());
+    ///
+    ///     '0'.is_ascii_digit();
+    ///     'a'.is_ascii_lowercase();
+    ///     'A'.is_ascii_uppercase();
     /// }
     /// ```
     #[clippy::version = "1.66.0"]
@@ -75,40 +84,21 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
             return;
         }
 
-        let Some(macro_call) = root_macro_call(expr.span) else { return };
-
-        if is_matches_macro(cx, macro_call.def_id) {
+        if let Some(macro_call) = root_macro_call(expr.span)
+            && is_matches_macro(cx, macro_call.def_id) {
             if let ExprKind::Match(recv, [arm, ..], _) = expr.kind {
                 let range = check_pat(&arm.pat.kind);
-
-                if let Some(sugg) = match range {
-                    CharRange::UpperChar => Some("is_ascii_uppercase"),
-                    CharRange::LowerChar => Some("is_ascii_lowercase"),
-                    CharRange::FullChar => Some("is_ascii_alphabetic"),
-                    CharRange::Digit => Some("is_ascii_digit"),
-                    CharRange::Otherwise => None,
-                } {
-                    let default_snip = "..";
-                    // `snippet_with_applicability` may set applicability to `MaybeIncorrect` for
-                    // macro span, so we check applicability manually by comparing `recv` is not default.
-                    let recv = snippet(cx, recv.span, default_snip);
-
-                    let applicability = if recv == default_snip {
-                        Applicability::HasPlaceholders
-                    } else {
-                        Applicability::MachineApplicable
-                    };
-
-                    span_lint_and_sugg(
-                        cx,
-                        MANUAL_IS_ASCII_CHECK,
-                        macro_call.span,
-                        "manual check for common ascii range",
-                        "try",
-                        format!("{recv}.{sugg}()"),
-                        applicability,
-                    );
-                }
+                check_is_ascii(cx, macro_call.span, recv, &range);
+            }
+        } else if let ExprKind::MethodCall(path, receiver, [arg], ..) = expr.kind
+            && path.ident.name == sym!(contains)
+            && let Some(higher::Range { start: Some(start), end: Some(end), limits: RangeLimits::Closed })
+            = higher::Range::hir(receiver) {
+            let range = check_range(start, end);
+            if let ExprKind::AddrOf(BorrowKind::Ref, _, e) = arg.kind {
+                check_is_ascii(cx, expr.span, e, &range);
+            } else {
+                check_is_ascii(cx, expr.span, arg, &range);
             }
         }
     }
@@ -116,6 +106,37 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
     extract_msrv_attr!(LateContext);
 }
 
+fn check_is_ascii(cx: &LateContext<'_>, span: Span, recv: &Expr<'_>, range: &CharRange) {
+    if let Some(sugg) = match range {
+        CharRange::UpperChar => Some("is_ascii_uppercase"),
+        CharRange::LowerChar => Some("is_ascii_lowercase"),
+        CharRange::FullChar => Some("is_ascii_alphabetic"),
+        CharRange::Digit => Some("is_ascii_digit"),
+        CharRange::Otherwise => None,
+    } {
+        let default_snip = "..";
+        // `snippet_with_applicability` may set applicability to `MaybeIncorrect` for
+        // macro span, so we check applicability manually by comparing `recv` is not default.
+        let recv = snippet(cx, recv.span, default_snip);
+
+        let applicability = if recv == default_snip {
+            Applicability::HasPlaceholders
+        } else {
+            Applicability::MachineApplicable
+        };
+
+        span_lint_and_sugg(
+            cx,
+            MANUAL_IS_ASCII_CHECK,
+            span,
+            "manual check for common ascii range",
+            "try",
+            format!("{recv}.{sugg}()"),
+            applicability,
+        );
+    }
+}
+
 fn check_pat(pat_kind: &PatKind<'_>) -> CharRange {
     match pat_kind {
         PatKind::Or(pats) => {
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 874d36ca9f4..9c6f8b43c07 100644
--- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
@@ -151,7 +151,12 @@ fn emit_manual_let_else(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, pat:
             } else {
                 format!("{{ {sn_else} }}")
             };
-            let sugg = format!("let {sn_pat} = {sn_expr} else {else_bl};");
+            let sn_bl = if matches!(pat.kind, PatKind::Or(..)) {
+                format!("({sn_pat})")
+            } else {
+                sn_pat.into_owned()
+            };
+            let sugg = format!("let {sn_bl} = {sn_expr} else {else_bl};");
             diag.span_suggestion(span, "consider writing", sugg, app);
         },
     );
diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs
index c1e6c82487d..72cdb9c1736 100644
--- a/src/tools/clippy/clippy_lints/src/manual_retain.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs
@@ -70,7 +70,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualRetain {
             && seg.args.is_none()
             && let hir::ExprKind::MethodCall(_, target_expr, [], _) = &collect_expr.kind
             && let Some(collect_def_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id)
-            && match_def_path(cx, collect_def_id, &paths::CORE_ITER_COLLECT) {
+            && cx.tcx.is_diagnostic_item(sym::iterator_collect_fn, collect_def_id)
+        {
             check_into_iter(cx, parent_expr, left_expr, target_expr, &self.msrv);
             check_iter(cx, parent_expr, left_expr, target_expr, &self.msrv);
             check_to_owned(cx, parent_expr, left_expr, target_expr, &self.msrv);
diff --git a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
index 429cdc1918d..06ecbce4e70 100644
--- a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::peel_mid_ty_refs;
+use clippy_utils::ty::{implements_trait, peel_mid_ty_refs};
 use clippy_utils::{is_diag_item_method, is_diag_trait_item};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
@@ -19,6 +19,8 @@ pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv
         let (input_type, ref_count) = peel_mid_ty_refs(input_type);
         if let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did()));
         if return_type == input_type;
+        if let Some(clone_trait) = cx.tcx.lang_items().clone_trait();
+        if implements_trait(cx, return_type, clone_trait, &[]);
         then {
             let mut app = Applicability::MachineApplicable;
             let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0;
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index d2913680cbb..561e4336593 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -3059,7 +3059,7 @@ declare_clippy_lint! {
     /// let map: HashMap<u32, u32> = HashMap::new();
     /// let values = map.values().collect::<Vec<_>>();
     /// ```
-    #[clippy::version = "1.65.0"]
+    #[clippy::version = "1.66.0"]
     pub ITER_KV_MAP,
     complexity,
     "iterating on map using `iter` when `keys` or `values` would do"
@@ -3672,7 +3672,10 @@ impl Methods {
                     no_effect_replace::check(cx, expr, arg1, arg2);
 
                     // Check for repeated `str::replace` calls to perform `collapsible_str_replace` lint
-                    if name == "replace" && let Some(("replace", ..)) = method_call(recv) {
+                    if self.msrv.meets(msrvs::PATTERN_TRAIT_CHAR_ARRAY)
+                        && name == "replace"
+                        && let Some(("replace", ..)) = method_call(recv)
+                    {
                         collapsible_str_replace::check(cx, expr, arg1, arg2);
                     }
                 },
diff --git a/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs b/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
index 7e3bed1e41a..660b7049cce 100644
--- a/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::ty::implements_trait;
-use clippy_utils::{get_trait_def_id, match_def_path, paths};
+use clippy_utils::{get_trait_def_id, is_expr_used_or_unified, match_def_path, paths};
 use rustc_ast::ast::{LitIntType, LitKind};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
@@ -19,6 +19,10 @@ pub(super) fn check<'tcx>(
     // Get receiver type
     let ty = cx.typeck_results().expr_ty(recv).peel_refs();
 
+    if is_expr_used_or_unified(cx.tcx, expr) {
+        return;
+    }
+
     if let Some(seek_trait_id) = get_trait_def_id(cx, &paths::STD_IO_SEEK) &&
         implements_trait(cx, ty, seek_trait_id, &[]) &&
         let ExprKind::Call(func, args1) = arg.kind &&
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index 516dee20f8b..9f4beb92b9d 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -9,12 +9,14 @@ use rustc_hir::{
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::source_map::{ExpnKind, Span};
 
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{get_parent_expr, in_constant, is_integer_literal, iter_input_pats, last_path_segment, SpanlessEq};
+use clippy_utils::{
+    get_parent_expr, in_constant, is_integer_literal, is_no_std_crate, iter_input_pats, last_path_segment, SpanlessEq,
+};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -120,14 +122,28 @@ declare_clippy_lint! {
     "using `0 as *{const, mut} T`"
 }
 
-declare_lint_pass!(MiscLints => [
+pub struct LintPass {
+    std_or_core: &'static str,
+}
+impl Default for LintPass {
+    fn default() -> Self {
+        Self { std_or_core: "std" }
+    }
+}
+impl_lint_pass!(LintPass => [
     TOPLEVEL_REF_ARG,
     USED_UNDERSCORE_BINDING,
     SHORT_CIRCUIT_STATEMENT,
     ZERO_PTR,
 ]);
 
-impl<'tcx> LateLintPass<'tcx> for MiscLints {
+impl<'tcx> LateLintPass<'tcx> for LintPass {
+    fn check_crate(&mut self, cx: &LateContext<'_>) {
+        if is_no_std_crate(cx) {
+            self.std_or_core = "core";
+        }
+    }
+
     fn check_fn(
         &mut self,
         cx: &LateContext<'tcx>,
@@ -231,7 +247,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
 
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let ExprKind::Cast(e, ty) = expr.kind {
-            check_cast(cx, expr.span, e, ty);
+            self.check_cast(cx, expr.span, e, ty);
             return;
         }
         if in_attributes_expansion(expr) || expr.span.is_desugaring(DesugaringKind::Await) {
@@ -310,26 +326,28 @@ fn non_macro_local(cx: &LateContext<'_>, res: def::Res) -> bool {
     }
 }
 
-fn check_cast(cx: &LateContext<'_>, span: Span, e: &Expr<'_>, ty: &hir::Ty<'_>) {
-    if_chain! {
-        if let TyKind::Ptr(ref mut_ty) = ty.kind;
-        if is_integer_literal(e, 0);
-        if !in_constant(cx, e.hir_id);
-        then {
-            let (msg, sugg_fn) = match mut_ty.mutbl {
-                Mutability::Mut => ("`0 as *mut _` detected", "std::ptr::null_mut"),
-                Mutability::Not => ("`0 as *const _` detected", "std::ptr::null"),
-            };
+impl LintPass {
+    fn check_cast(&self, cx: &LateContext<'_>, span: Span, e: &Expr<'_>, ty: &hir::Ty<'_>) {
+        if_chain! {
+            if let TyKind::Ptr(ref mut_ty) = ty.kind;
+            if is_integer_literal(e, 0);
+            if !in_constant(cx, e.hir_id);
+            then {
+                let (msg, sugg_fn) = match mut_ty.mutbl {
+                    Mutability::Mut => ("`0 as *mut _` detected", "ptr::null_mut"),
+                    Mutability::Not => ("`0 as *const _` detected", "ptr::null"),
+                };
 
-            let (sugg, appl) = if let TyKind::Infer = mut_ty.ty.kind {
-                (format!("{sugg_fn}()"), Applicability::MachineApplicable)
-            } else if let Some(mut_ty_snip) = snippet_opt(cx, mut_ty.ty.span) {
-                (format!("{sugg_fn}::<{mut_ty_snip}>()"), Applicability::MachineApplicable)
-            } else {
-                // `MaybeIncorrect` as type inference may not work with the suggested code
-                (format!("{sugg_fn}()"), Applicability::MaybeIncorrect)
-            };
-            span_lint_and_sugg(cx, ZERO_PTR, span, msg, "try", sugg, appl);
+                let (sugg, appl) = if let TyKind::Infer = mut_ty.ty.kind {
+                    (format!("{}::{sugg_fn}()", self.std_or_core), Applicability::MachineApplicable)
+                } else if let Some(mut_ty_snip) = snippet_opt(cx, mut_ty.ty.span) {
+                    (format!("{}::{sugg_fn}::<{mut_ty_snip}>()", self.std_or_core), Applicability::MachineApplicable)
+                } else {
+                    // `MaybeIncorrect` as type inference may not work with the suggested code
+                    (format!("{}::{sugg_fn}()", self.std_or_core), Applicability::MaybeIncorrect)
+                };
+                span_lint_and_sugg(cx, ZERO_PTR, span, msg, "try", sugg, appl);
+            }
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
index 20b82d81a2a..4fbc8398e37 100644
--- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -5,25 +5,26 @@ use clippy_utils::{
     peel_hir_expr_refs,
 };
 use rustc_ast as ast;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::Ty;
 use rustc_session::impl_lint_pass;
 use rustc_span::source_map::{Span, Spanned};
 
-const HARD_CODED_ALLOWED: &[&str] = &[
-    "&str",
-    "f32",
-    "f64",
-    "std::num::Saturating",
-    "std::num::Wrapping",
-    "std::string::String",
+const HARD_CODED_ALLOWED_BINARY: &[[&str; 2]] = &[
+    ["f32", "f32"],
+    ["f64", "f64"],
+    ["std::num::Saturating", "std::num::Saturating"],
+    ["std::num::Wrapping", "std::num::Wrapping"],
+    ["std::string::String", "&str"],
 ];
+const HARD_CODED_ALLOWED_UNARY: &[&str] = &["f32", "f64", "std::num::Saturating", "std::num::Wrapping"];
 
 #[derive(Debug)]
 pub struct ArithmeticSideEffects {
-    allowed: FxHashSet<String>,
+    allowed_binary: FxHashMap<String, FxHashSet<String>>,
+    allowed_unary: FxHashSet<String>,
     // Used to check whether expressions are constants, such as in enum discriminants and consts
     const_span: Option<Span>,
     expr_span: Option<Span>,
@@ -33,19 +34,55 @@ impl_lint_pass!(ArithmeticSideEffects => [ARITHMETIC_SIDE_EFFECTS]);
 
 impl ArithmeticSideEffects {
     #[must_use]
-    pub fn new(mut allowed: FxHashSet<String>) -> Self {
-        allowed.extend(HARD_CODED_ALLOWED.iter().copied().map(String::from));
+    pub fn new(user_allowed_binary: Vec<[String; 2]>, user_allowed_unary: Vec<String>) -> Self {
+        let mut allowed_binary: FxHashMap<String, FxHashSet<String>> = <_>::default();
+        for [lhs, rhs] in user_allowed_binary.into_iter().chain(
+            HARD_CODED_ALLOWED_BINARY
+                .iter()
+                .copied()
+                .map(|[lhs, rhs]| [lhs.to_string(), rhs.to_string()]),
+        ) {
+            allowed_binary.entry(lhs).or_default().insert(rhs);
+        }
+        let allowed_unary = user_allowed_unary
+            .into_iter()
+            .chain(HARD_CODED_ALLOWED_UNARY.iter().copied().map(String::from))
+            .collect();
         Self {
-            allowed,
+            allowed_binary,
+            allowed_unary,
             const_span: None,
             expr_span: None,
         }
     }
 
-    /// Checks if the given `expr` has any of the inner `allowed` elements.
-    fn is_allowed_ty(&self, ty: Ty<'_>) -> bool {
-        self.allowed
-            .contains(ty.to_string().split('<').next().unwrap_or_default())
+    /// Checks if the lhs and the rhs types of a binary operation like "addition" or
+    /// "multiplication" are present in the inner set of allowed types.
+    fn has_allowed_binary(&self, lhs_ty: Ty<'_>, rhs_ty: Ty<'_>) -> bool {
+        let lhs_ty_string = lhs_ty.to_string();
+        let lhs_ty_string_elem = lhs_ty_string.split('<').next().unwrap_or_default();
+        let rhs_ty_string = rhs_ty.to_string();
+        let rhs_ty_string_elem = rhs_ty_string.split('<').next().unwrap_or_default();
+        if let Some(rhs_from_specific) = self.allowed_binary.get(lhs_ty_string_elem)
+            && {
+                let rhs_has_allowed_ty = rhs_from_specific.contains(rhs_ty_string_elem);
+                rhs_has_allowed_ty || rhs_from_specific.contains("*")
+            }
+        {
+           true
+        } else if let Some(rhs_from_glob) = self.allowed_binary.get("*") {
+            rhs_from_glob.contains(rhs_ty_string_elem)
+        } else {
+            false
+        }
+    }
+
+    /// Checks if the type of an unary operation like "negation" is present in the inner set of
+    /// allowed types.
+    fn has_allowed_unary(&self, ty: Ty<'_>) -> bool {
+        let ty_string = ty.to_string();
+        let ty_string_elem = ty_string.split('<').next().unwrap_or_default();
+        self.allowed_unary.contains(ty_string_elem)
     }
 
     // For example, 8i32 or &i64::MAX.
@@ -97,8 +134,7 @@ impl ArithmeticSideEffects {
         };
         let lhs_ty = cx.typeck_results().expr_ty(lhs);
         let rhs_ty = cx.typeck_results().expr_ty(rhs);
-        let lhs_and_rhs_have_the_same_ty = lhs_ty == rhs_ty;
-        if lhs_and_rhs_have_the_same_ty && self.is_allowed_ty(lhs_ty) && self.is_allowed_ty(rhs_ty) {
+        if self.has_allowed_binary(lhs_ty, rhs_ty) {
             return;
         }
         let has_valid_op = if Self::is_integral(lhs_ty) && Self::is_integral(rhs_ty) {
@@ -137,7 +173,7 @@ impl ArithmeticSideEffects {
             return;
         }
         let ty = cx.typeck_results().expr_ty(expr).peel_refs();
-        if self.is_allowed_ty(ty) {
+        if self.has_allowed_unary(ty) {
             return;
         }
         let actual_un_expr = peel_hir_expr_refs(un_expr).0;
diff --git a/src/tools/clippy/clippy_lints/src/operators/identity_op.rs b/src/tools/clippy/clippy_lints/src/operators/identity_op.rs
index b48d6c4e2e2..14a12da862e 100644
--- a/src/tools/clippy/clippy_lints/src/operators/identity_op.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/identity_op.rs
@@ -1,7 +1,7 @@
 use clippy_utils::consts::{constant_full_int, constant_simple, Constant, FullInt};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{clip, unsext};
+use clippy_utils::{clip, peel_hir_expr_refs, unsext};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, Node};
 use rustc_lint::LateContext;
@@ -20,20 +20,76 @@ pub(crate) fn check<'tcx>(
     if !is_allowed(cx, op, left, right) {
         match op {
             BinOpKind::Add | BinOpKind::BitOr | BinOpKind::BitXor => {
-                check_op(cx, left, 0, expr.span, right.span, needs_parenthesis(cx, expr, right));
-                check_op(cx, right, 0, expr.span, left.span, Parens::Unneeded);
+                check_op(
+                    cx,
+                    left,
+                    0,
+                    expr.span,
+                    peel_hir_expr_refs(right).0.span,
+                    needs_parenthesis(cx, expr, right),
+                );
+                check_op(
+                    cx,
+                    right,
+                    0,
+                    expr.span,
+                    peel_hir_expr_refs(left).0.span,
+                    Parens::Unneeded,
+                );
             },
             BinOpKind::Shl | BinOpKind::Shr | BinOpKind::Sub => {
-                check_op(cx, right, 0, expr.span, left.span, Parens::Unneeded);
+                check_op(
+                    cx,
+                    right,
+                    0,
+                    expr.span,
+                    peel_hir_expr_refs(left).0.span,
+                    Parens::Unneeded,
+                );
             },
             BinOpKind::Mul => {
-                check_op(cx, left, 1, expr.span, right.span, needs_parenthesis(cx, expr, right));
-                check_op(cx, right, 1, expr.span, left.span, Parens::Unneeded);
+                check_op(
+                    cx,
+                    left,
+                    1,
+                    expr.span,
+                    peel_hir_expr_refs(right).0.span,
+                    needs_parenthesis(cx, expr, right),
+                );
+                check_op(
+                    cx,
+                    right,
+                    1,
+                    expr.span,
+                    peel_hir_expr_refs(left).0.span,
+                    Parens::Unneeded,
+                );
             },
-            BinOpKind::Div => check_op(cx, right, 1, expr.span, left.span, Parens::Unneeded),
+            BinOpKind::Div => check_op(
+                cx,
+                right,
+                1,
+                expr.span,
+                peel_hir_expr_refs(left).0.span,
+                Parens::Unneeded,
+            ),
             BinOpKind::BitAnd => {
-                check_op(cx, left, -1, expr.span, right.span, needs_parenthesis(cx, expr, right));
-                check_op(cx, right, -1, expr.span, left.span, Parens::Unneeded);
+                check_op(
+                    cx,
+                    left,
+                    -1,
+                    expr.span,
+                    peel_hir_expr_refs(right).0.span,
+                    needs_parenthesis(cx, expr, right),
+                );
+                check_op(
+                    cx,
+                    right,
+                    -1,
+                    expr.span,
+                    peel_hir_expr_refs(left).0.span,
+                    Parens::Unneeded,
+                );
             },
             BinOpKind::Rem => check_remainder(cx, left, right, expr.span, left.span),
             _ => (),
diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs
index b8a20d5ebe9..eba230da6c3 100644
--- a/src/tools/clippy/clippy_lints/src/operators/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs
@@ -90,9 +90,6 @@ declare_clippy_lint! {
     /// use rust_decimal::Decimal;
     /// let _n = Decimal::MAX + Decimal::MAX;
     /// ```
-    ///
-    /// ### Allowed types
-    /// Custom allowed types can be specified through the "arithmetic-side-effects-allowed" filter.
     #[clippy::version = "1.64.0"]
     pub ARITHMETIC_SIDE_EFFECTS,
     restriction,
diff --git a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
index d612d249c2f..c2a8db7df03 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
@@ -84,7 +84,11 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
 
 fn is_not_macro_export<'tcx>(item: &'tcx Item<'tcx>) -> bool {
     if let ItemKind::Use(path, _) = item.kind {
-        if path.res.iter().all(|res| matches!(res, Res::Def(DefKind::Macro(MacroKind::Bang), _))) {
+        if path
+            .res
+            .iter()
+            .all(|res| matches!(res, Res::Def(DefKind::Macro(MacroKind::Bang), _)))
+        {
             return false;
         }
     } else if let ItemKind::Macro(..) = item.kind {
diff --git a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
index 3aa2490bc44..41f991a967b 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
@@ -66,7 +66,7 @@ impl RedundantStaticLifetimes {
                         TyKind::Path(..) | TyKind::Slice(..) | TyKind::Array(..) | TyKind::Tup(..) => {
                             if lifetime.ident.name == rustc_span::symbol::kw::StaticLifetime {
                                 let snip = snippet(cx, borrow_type.ty.span, "<type>");
-                                let sugg = format!("&{snip}");
+                                let sugg = format!("&{}{snip}", borrow_type.mutbl.prefix_str());
                                 span_lint_and_then(
                                     cx,
                                     REDUNDANT_STATIC_LIFETIMES,
diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
index 8e214218f23..72c25592609 100644
--- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
@@ -2,6 +2,7 @@
 
 #[rustfmt::skip]
 pub static RENAMED_LINTS: &[(&str, &str)] = &[
+    ("clippy::almost_complete_letter_range", "clippy::almost_complete_range"),
     ("clippy::blacklisted_name", "clippy::disallowed_names"),
     ("clippy::block_in_if_condition_expr", "clippy::blocks_in_if_conditions"),
     ("clippy::block_in_if_condition_stmt", "clippy::blocks_in_if_conditions"),
diff --git a/src/tools/clippy/clippy_lints/src/semicolon_block.rs b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
new file mode 100644
index 00000000000..8f1d1490e1f
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
@@ -0,0 +1,137 @@
+use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_then};
+use rustc_errors::Applicability;
+use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::Span;
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Suggests moving the semicolon after a block to the inside of the block, after its last
+    /// expression.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// For consistency it's best to have the semicolon inside/outside the block. Either way is fine
+    /// and this lint suggests inside the block.
+    /// Take a look at `semicolon_outside_block` for the other alternative.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// # fn f(_: u32) {}
+    /// # let x = 0;
+    /// unsafe { f(x) };
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # fn f(_: u32) {}
+    /// # let x = 0;
+    /// unsafe { f(x); }
+    /// ```
+    #[clippy::version = "1.66.0"]
+    pub SEMICOLON_INSIDE_BLOCK,
+    restriction,
+    "add a semicolon inside the block"
+}
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Suggests moving the semicolon from a block's final expression outside of the block.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// For consistency it's best to have the semicolon inside/outside the block. Either way is fine
+    /// and this lint suggests outside the block.
+    /// Take a look at `semicolon_inside_block` for the other alternative.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// # fn f(_: u32) {}
+    /// # let x = 0;
+    /// unsafe { f(x); }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # fn f(_: u32) {}
+    /// # let x = 0;
+    /// unsafe { f(x) };
+    /// ```
+    #[clippy::version = "1.66.0"]
+    pub SEMICOLON_OUTSIDE_BLOCK,
+    restriction,
+    "add a semicolon outside the block"
+}
+declare_lint_pass!(SemicolonBlock => [SEMICOLON_INSIDE_BLOCK, SEMICOLON_OUTSIDE_BLOCK]);
+
+impl LateLintPass<'_> for SemicolonBlock {
+    fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) {
+        match stmt.kind {
+            StmtKind::Expr(Expr {
+                kind: ExprKind::Block(block, _),
+                ..
+            }) if !block.span.from_expansion() => {
+                let Block {
+                    expr: None,
+                    stmts: [.., stmt],
+                    ..
+                } = block else { return };
+                let &Stmt {
+                    kind: StmtKind::Semi(expr),
+                    span,
+                    ..
+                } = stmt else { return };
+                semicolon_outside_block(cx, block, expr, span);
+            },
+            StmtKind::Semi(Expr {
+                kind: ExprKind::Block(block @ Block { expr: Some(tail), .. }, _),
+                ..
+            }) if !block.span.from_expansion() => semicolon_inside_block(cx, block, tail, stmt.span),
+            _ => (),
+        }
+    }
+}
+
+fn semicolon_inside_block(cx: &LateContext<'_>, block: &Block<'_>, tail: &Expr<'_>, semi_span: Span) {
+    let insert_span = tail.span.source_callsite().shrink_to_hi();
+    let remove_span = semi_span.with_lo(block.span.hi());
+
+    span_lint_and_then(
+        cx,
+        SEMICOLON_INSIDE_BLOCK,
+        semi_span,
+        "consider moving the `;` inside the block for consistent formatting",
+        |diag| {
+            multispan_sugg_with_applicability(
+                diag,
+                "put the `;` here",
+                Applicability::MachineApplicable,
+                [(remove_span, String::new()), (insert_span, ";".to_owned())],
+            );
+        },
+    );
+}
+
+fn semicolon_outside_block(cx: &LateContext<'_>, block: &Block<'_>, tail_stmt_expr: &Expr<'_>, semi_span: Span) {
+    let insert_span = block.span.with_lo(block.span.hi());
+    // account for macro calls
+    let semi_span = cx.sess().source_map().stmt_span(semi_span, block.span);
+    let remove_span = semi_span.with_lo(tail_stmt_expr.span.source_callsite().hi());
+
+    span_lint_and_then(
+        cx,
+        SEMICOLON_OUTSIDE_BLOCK,
+        block.span,
+        "consider moving the `;` outside the block for consistent formatting",
+        |diag| {
+            multispan_sugg_with_applicability(
+                diag,
+                "put the `;` here",
+                Applicability::MachineApplicable,
+                [(remove_span, String::new()), (insert_span, ";".to_owned())],
+            );
+        },
+    );
+}
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index f4705481d4e..bc18cad6d38 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -1,12 +1,12 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg};
 use clippy_utils::source::{snippet, snippet_with_applicability};
 use clippy_utils::ty::is_type_lang_item;
+use clippy_utils::{get_expr_use_or_unification_node, peel_blocks, SpanlessEq};
 use clippy_utils::{get_parent_expr, is_lint_allowed, match_function_call, method_calls, paths};
-use clippy_utils::{peel_blocks, SpanlessEq};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, QPath};
+use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, Node, QPath};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
@@ -249,6 +249,7 @@ const MAX_LENGTH_BYTE_STRING_LIT: usize = 32;
 declare_lint_pass!(StringLitAsBytes => [STRING_LIT_AS_BYTES, STRING_FROM_UTF8_AS_BYTES]);
 
 impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
+    #[expect(clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
         use rustc_ast::LitKind;
 
@@ -316,18 +317,27 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
                     && lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT
                     && !receiver.span.from_expansion()
                 {
-                    span_lint_and_sugg(
-                        cx,
-                        STRING_LIT_AS_BYTES,
-                        e.span,
-                        "calling `as_bytes()` on a string literal",
-                        "consider using a byte string literal instead",
-                        format!(
-                            "b{}",
-                            snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability)
-                        ),
-                        applicability,
-                    );
+                    if let Some((parent, id)) = get_expr_use_or_unification_node(cx.tcx, e)
+                        && let Node::Expr(parent) = parent
+                        && let ExprKind::Match(scrutinee, ..) = parent.kind
+                        && scrutinee.hir_id == id
+                    {
+                        // Don't lint. Byte strings produce `&[u8; N]` whereas `as_bytes()` produces
+                        // `&[u8]`. This change would prevent matching with different sized slices.
+                    } else {
+                        span_lint_and_sugg(
+                            cx,
+                            STRING_LIT_AS_BYTES,
+                            e.span,
+                            "calling `as_bytes()` on a string literal",
+                            "consider using a byte string literal instead",
+                            format!(
+                                "b{}",
+                                snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability)
+                            ),
+                            applicability,
+                        );
+                    }
                 }
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index b6dc8cd7ab1..3e7d0028c0f 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -205,10 +205,49 @@ macro_rules! define_Conf {
 }
 
 define_Conf! {
-    /// Lint: Arithmetic.
+    /// Lint: ARITHMETIC_SIDE_EFFECTS.
     ///
-    /// Suppress checking of the passed type names.
+    /// Suppress checking of the passed type names in all types of operations.
+    ///
+    /// If a specific operation is desired, consider using `arithmetic_side_effects_allowed_binary` or `arithmetic_side_effects_allowed_unary` instead.
+    ///
+    /// #### Example
+    ///
+    /// ```toml
+    /// arithmetic-side-effects-allowed = ["SomeType", "AnotherType"]
+    /// ```
+    ///
+    /// #### Noteworthy
+    ///
+    /// A type, say `SomeType`, listed in this configuration has the same behavior of `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`.
     (arithmetic_side_effects_allowed: rustc_data_structures::fx::FxHashSet<String> = <_>::default()),
+    /// Lint: ARITHMETIC_SIDE_EFFECTS.
+    ///
+    /// Suppress checking of the passed type pair names in binary operations like addition or
+    /// multiplication.
+    ///
+    /// Supports the "*" wildcard to indicate that a certain type won't trigger the lint regardless
+    /// of the involved counterpart. For example, `["SomeType", "*"]` or `["*", "AnotherType"]`.
+    ///
+    /// Pairs are asymmetric, which means that `["SomeType", "AnotherType"]` is not the same as
+    /// `["AnotherType", "SomeType"]`.
+    ///
+    /// #### Example
+    ///
+    /// ```toml
+    /// arithmetic-side-effects-allowed-binary = [["SomeType" , "f32"], ["AnotherType", "*"]]
+    /// ```
+    (arithmetic_side_effects_allowed_binary: Vec<[String; 2]> = <_>::default()),
+    /// Lint: ARITHMETIC_SIDE_EFFECTS.
+    ///
+    /// Suppress checking of the passed type names in unary operations like "negation" (`-`).
+    ///
+    /// #### Example
+    ///
+    /// ```toml
+    /// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"]
+    /// ```
+    (arithmetic_side_effects_allowed_unary: rustc_data_structures::fx::FxHashSet<String> = <_>::default()),
     /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX.
     ///
     /// Suppress lints whenever the suggested change would cause breakage for other crates.
@@ -406,6 +445,14 @@ define_Conf! {
     ///
     /// Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)`
     (allow_mixed_uninlined_format_args: bool = true),
+    /// Lint: INDEXING_SLICING
+    ///
+    /// Whether to suppress a restriction lint in constant code. In same
+    /// cases the restructured operation might not be unavoidable, as the
+    /// suggested counterparts are unavailable in constant code. This
+    /// configuration will cause restriction lints to trigger even
+    /// if no suggestion can be made.
+    (suppress_restriction_lint_in_const: bool = false),
 }
 
 /// Search for the configuration file.
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
index 680935f2329..9afe02c1e47 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
@@ -7,7 +7,7 @@ use rustc_hir::def::DefKind;
 use rustc_hir::Item;
 use rustc_hir_analysis::hir_ty_to_ty;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self, fast_reject::SimplifiedTypeGen, FloatTy};
+use rustc_middle::ty::{self, fast_reject::SimplifiedType, FloatTy};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::Symbol;
 
@@ -73,10 +73,10 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
     let lang_items = cx.tcx.lang_items();
     // This list isn't complete, but good enough for our current list of paths.
     let incoherent_impls = [
-        SimplifiedTypeGen::FloatSimplifiedType(FloatTy::F32),
-        SimplifiedTypeGen::FloatSimplifiedType(FloatTy::F64),
-        SimplifiedTypeGen::SliceSimplifiedType,
-        SimplifiedTypeGen::StrSimplifiedType,
+        SimplifiedType::FloatSimplifiedType(FloatTy::F32),
+        SimplifiedType::FloatSimplifiedType(FloatTy::F64),
+        SimplifiedType::SliceSimplifiedType,
+        SimplifiedType::StrSimplifiedType,
     ]
     .iter()
     .flat_map(|&ty| cx.tcx.incoherent_impls(ty).iter().copied());
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index fb9f4740ecc..ac6a566b9cd 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.67"
+version = "0.1.68"
 edition = "2021"
 publish = false
 
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 652f8b4d3c5..43e2d1ec826 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -196,7 +196,7 @@ pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool {
     let parent_id = cx.tcx.hir().get_parent_item(id).def_id;
     match cx.tcx.hir().get_by_def_id(parent_id) {
         Node::Item(&Item {
-            kind: ItemKind::Const(..) | ItemKind::Static(..),
+            kind: ItemKind::Const(..) | ItemKind::Static(..) | ItemKind::Enum(..),
             ..
         })
         | Node::TraitItem(&TraitItem {
diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs
index d13b34a66cc..77c5f115542 100644
--- a/src/tools/clippy/clippy_utils/src/macros.rs
+++ b/src/tools/clippy/clippy_utils/src/macros.rs
@@ -208,6 +208,12 @@ pub fn is_panic(cx: &LateContext<'_>, def_id: DefId) -> bool {
     )
 }
 
+/// Is `def_id` of `assert!` or `debug_assert!`
+pub fn is_assert_macro(cx: &LateContext<'_>, def_id: DefId) -> bool {
+    let Some(name) = cx.tcx.get_diagnostic_name(def_id) else { return false };
+    matches!(name, sym::assert_macro | sym::debug_assert_macro)
+}
+
 pub enum PanicExpn<'a> {
     /// No arguments - `panic!()`
     Empty,
diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs
index 12a512f78a6..ba5bc9c3135 100644
--- a/src/tools/clippy/clippy_utils/src/msrvs.rs
+++ b/src/tools/clippy/clippy_utils/src/msrvs.rs
@@ -21,7 +21,7 @@ macro_rules! msrv_aliases {
 msrv_aliases! {
     1,65,0 { LET_ELSE }
     1,62,0 { BOOL_THEN_SOME }
-    1,58,0 { FORMAT_ARGS_CAPTURE }
+    1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY }
     1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR }
     1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST }
     1,51,0 { BORROW_AS_PTR, SEEK_FROM_CURRENT, UNSIGNED_ABS }
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index 6417f0f3c71..9ca50105ae5 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -20,7 +20,6 @@ pub const BTREEMAP_CONTAINS_KEY: [&str; 6] = ["alloc", "collections", "btree", "
 pub const BTREEMAP_INSERT: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "insert"];
 pub const BTREESET_ITER: [&str; 6] = ["alloc", "collections", "btree", "set", "BTreeSet", "iter"];
 pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"];
-pub const CORE_ITER_COLLECT: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "collect"];
 pub const CORE_ITER_CLONED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "cloned"];
 pub const CORE_ITER_COPIED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "copied"];
 pub const CORE_ITER_FILTER: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "filter"];
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 8bf542ada04..e5d7da68281 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -301,10 +301,7 @@ fn check_terminator<'tcx>(
             check_operand(tcx, value, span, body)
         },
 
-        TerminatorKind::SwitchInt {
-            discr,
-            targets: _,
-        } => check_operand(tcx, discr, span, body),
+        TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(tcx, discr, span, body),
 
         TerminatorKind::Abort => Err((span, "abort is not stable in const fn".into())),
         TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => {
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index a6bcb134d40..2773da70d78 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -16,8 +16,8 @@ use rustc_infer::infer::{
 use rustc_lint::LateContext;
 use rustc_middle::mir::interpret::{ConstValue, Scalar};
 use rustc_middle::ty::{
-    self, AdtDef, AssocKind, Binder, BoundRegion, DefIdTree, FnSig, IntTy, List, ParamEnv, Predicate, PredicateKind,
-    AliasTy, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy,
+    self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, DefIdTree, FnSig, IntTy, List, ParamEnv, Predicate,
+    PredicateKind, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy,
     VariantDef, VariantDiscr,
 };
 use rustc_middle::ty::{GenericArg, GenericArgKind};
@@ -30,7 +30,7 @@ use std::iter;
 
 use crate::{match_def_path, path_res, paths};
 
-// Checks if the given type implements copy.
+/// Checks if the given type implements copy.
 pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
     ty.is_copy_modulo_regions(cx.tcx, cx.param_env)
 }
@@ -69,50 +69,66 @@ pub fn contains_adt_constructor<'tcx>(ty: Ty<'tcx>, adt: AdtDef<'tcx>) -> bool {
 /// This method also recurses into opaque type predicates, so call it with `impl Trait<U>` and `U`
 /// will also return `true`.
 pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, needle: Ty<'tcx>) -> bool {
-    ty.walk().any(|inner| match inner.unpack() {
-        GenericArgKind::Type(inner_ty) => {
-            if inner_ty == needle {
-                return true;
-            }
+    fn contains_ty_adt_constructor_opaque_inner<'tcx>(
+        cx: &LateContext<'tcx>,
+        ty: Ty<'tcx>,
+        needle: Ty<'tcx>,
+        seen: &mut FxHashSet<DefId>,
+    ) -> bool {
+        ty.walk().any(|inner| match inner.unpack() {
+            GenericArgKind::Type(inner_ty) => {
+                if inner_ty == needle {
+                    return true;
+                }
 
-            if inner_ty.ty_adt_def() == needle.ty_adt_def() {
-                return true;
-            }
+                if inner_ty.ty_adt_def() == needle.ty_adt_def() {
+                    return true;
+                }
 
-            if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *inner_ty.kind() {
-                for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
-                    match predicate.kind().skip_binder() {
-                        // For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
-                        // and check substituions to find `U`.
-                        ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => {
-                            if trait_predicate
-                                .trait_ref
-                                .substs
-                                .types()
-                                .skip(1) // Skip the implicit `Self` generic parameter
-                                .any(|ty| contains_ty_adt_constructor_opaque(cx, ty, needle))
-                            {
-                                return true;
-                            }
-                        },
-                        // For `impl Trait<Assoc=U>`, it will register a predicate of `<T as Trait>::Assoc = U`,
-                        // so we check the term for `U`.
-                        ty::PredicateKind::Clause(ty::Clause::Projection(projection_predicate)) => {
-                            if let ty::TermKind::Ty(ty) = projection_predicate.term.unpack() {
-                                if contains_ty_adt_constructor_opaque(cx, ty, needle) {
+                if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *inner_ty.kind() {
+                    if !seen.insert(def_id) {
+                        return false;
+                    }
+
+                    for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
+                        match predicate.kind().skip_binder() {
+                            // For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
+                            // and check substituions to find `U`.
+                            ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => {
+                                if trait_predicate
+                                    .trait_ref
+                                    .substs
+                                    .types()
+                                    .skip(1) // Skip the implicit `Self` generic parameter
+                                    .any(|ty| contains_ty_adt_constructor_opaque_inner(cx, ty, needle, seen))
+                                {
                                     return true;
                                 }
-                            };
-                        },
-                        _ => (),
+                            },
+                            // For `impl Trait<Assoc=U>`, it will register a predicate of `<T as Trait>::Assoc = U`,
+                            // so we check the term for `U`.
+                            ty::PredicateKind::Clause(ty::Clause::Projection(projection_predicate)) => {
+                                if let ty::TermKind::Ty(ty) = projection_predicate.term.unpack() {
+                                    if contains_ty_adt_constructor_opaque_inner(cx, ty, needle, seen) {
+                                        return true;
+                                    }
+                                };
+                            },
+                            _ => (),
+                        }
                     }
                 }
-            }
 
-            false
-        },
-        GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
-    })
+                false
+            },
+            GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
+        })
+    }
+
+    // A hash set to ensure that the same opaque type (`impl Trait` in RPIT or TAIT) is not
+    // visited twice.
+    let mut seen = FxHashSet::default();
+    contains_ty_adt_constructor_opaque_inner(cx, ty, needle, &mut seen)
 }
 
 /// Resolves `<T as Iterator>::Item` for `T`
@@ -631,7 +647,9 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
             Some(ExprFnSig::Closure(decl, subs.as_closure().sig()))
         },
         ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))),
-        ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => sig_from_bounds(cx, ty, cx.tcx.item_bounds(def_id), cx.tcx.opt_parent(def_id)),
+        ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
+            sig_from_bounds(cx, ty, cx.tcx.item_bounds(def_id), cx.tcx.opt_parent(def_id))
+        },
         ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)),
         ty::Dynamic(bounds, _, _) => {
             let lang_items = cx.tcx.lang_items();
@@ -685,8 +703,7 @@ fn sig_from_bounds<'tcx>(
                 inputs = Some(i);
             },
             PredicateKind::Clause(ty::Clause::Projection(p))
-                if Some(p.projection_ty.def_id) == lang_items.fn_once_output()
-                    && p.projection_ty.self_ty() == ty =>
+                if Some(p.projection_ty.def_id) == lang_items.fn_once_output() && p.projection_ty.self_ty() == ty =>
             {
                 if output.is_some() {
                     // Multiple different fn trait impls. Is this even allowed?
@@ -1039,10 +1056,7 @@ pub fn make_projection<'tcx>(
             }
         }
 
-        Some(tcx.mk_alias_ty(
-            assoc_item.def_id,
-            substs,
-        ))
+        Some(tcx.mk_alias_ty(assoc_item.def_id, substs))
     }
     helper(
         tcx,
diff --git a/src/tools/clippy/declare_clippy_lint/Cargo.toml b/src/tools/clippy/declare_clippy_lint/Cargo.toml
index 082570f1fe5..c01e1062cb5 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.67"
+version = "0.1.68"
 edition = "2021"
 publish = false
 
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 19fee38db46..8e21cef32ab 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2022-12-01"
+channel = "nightly-2022-12-17"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/rustc_tools_util/CHANGELOG.md b/src/tools/clippy/rustc_tools_util/CHANGELOG.md
new file mode 100644
index 00000000000..1b351da2e7b
--- /dev/null
+++ b/src/tools/clippy/rustc_tools_util/CHANGELOG.md
@@ -0,0 +1,6 @@
+# Changelog
+
+## Version 0.3.0
+
+* Added `setup_version_info!();` macro for automated scripts.
+* `get_version_info!()` no longer requires the user to import `rustc_tools_util::VersionInfo` and `std::env`
diff --git a/src/tools/clippy/rustc_tools_util/Cargo.toml b/src/tools/clippy/rustc_tools_util/Cargo.toml
index 89c3d6aaa89..877049ae7d0 100644
--- a/src/tools/clippy/rustc_tools_util/Cargo.toml
+++ b/src/tools/clippy/rustc_tools_util/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "rustc_tools_util"
-version = "0.2.1"
+version = "0.3.0"
 description = "small helper to generate version information for git packages"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
diff --git a/src/tools/clippy/rustc_tools_util/README.md b/src/tools/clippy/rustc_tools_util/README.md
index e947f9c7e66..eefc661f963 100644
--- a/src/tools/clippy/rustc_tools_util/README.md
+++ b/src/tools/clippy/rustc_tools_util/README.md
@@ -13,43 +13,39 @@ build = "build.rs"
 List rustc_tools_util as regular AND build dependency.
 ````toml
 [dependencies]
-rustc_tools_util = "0.2.1"
+rustc_tools_util = "0.3.0"
 
 [build-dependencies]
-rustc_tools_util = "0.2.1"
+rustc_tools_util = "0.3.0"
 ````
 
 In `build.rs`, generate the data in your `main()`
-````rust
+
+```rust
 fn main() {
-    println!(
-        "cargo:rustc-env=GIT_HASH={}",
-        rustc_tools_util::get_commit_hash().unwrap_or_default()
-    );
-    println!(
-        "cargo:rustc-env=COMMIT_DATE={}",
-        rustc_tools_util::get_commit_date().unwrap_or_default()
-    );
-    println!(
-        "cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}",
-        rustc_tools_util::get_channel().unwrap_or_default()
-    );
+    rustc_tools_util::setup_version_info!();
 }
-
-````
+```
 
 Use the version information in your main.rs
-````rust
-use rustc_tools_util::*;
 
+```rust
 fn show_version() {
     let version_info = rustc_tools_util::get_version_info!();
     println!("{}", version_info);
 }
-````
+```
+
 This gives the following output in clippy:
-`clippy 0.0.212 (a416c5e 2018-12-14)`
+`clippy 0.1.66 (a28f3c8 2022-11-20)`
+
+## Repository
+
+This project is part of the rust-lang/rust-clippy repository. The source code
+can be found under `./rustc_tools_util/`.
 
+The changelog for `rustc_tools_util` is available under:
+[`rustc_tools_util/CHANGELOG.md`](https://github.com/rust-lang/rust-clippy/blob/master/rustc_tools_util/CHANGELOG.md)
 
 ## License
 
diff --git a/src/tools/clippy/rustc_tools_util/src/lib.rs b/src/tools/clippy/rustc_tools_util/src/lib.rs
index 01d25c53126..4c1d8c3733d 100644
--- a/src/tools/clippy/rustc_tools_util/src/lib.rs
+++ b/src/tools/clippy/rustc_tools_util/src/lib.rs
@@ -1,20 +1,20 @@
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
 
-use std::env;
-
+/// This macro creates the version string during compilation from the
+/// current environment
 #[macro_export]
 macro_rules! get_version_info {
     () => {{
-        let major = env!("CARGO_PKG_VERSION_MAJOR").parse::<u8>().unwrap();
-        let minor = env!("CARGO_PKG_VERSION_MINOR").parse::<u8>().unwrap();
-        let patch = env!("CARGO_PKG_VERSION_PATCH").parse::<u16>().unwrap();
-        let crate_name = String::from(env!("CARGO_PKG_NAME"));
+        let major = std::env!("CARGO_PKG_VERSION_MAJOR").parse::<u8>().unwrap();
+        let minor = std::env!("CARGO_PKG_VERSION_MINOR").parse::<u8>().unwrap();
+        let patch = std::env!("CARGO_PKG_VERSION_PATCH").parse::<u16>().unwrap();
+        let crate_name = String::from(std::env!("CARGO_PKG_NAME"));
 
-        let host_compiler = option_env!("RUSTC_RELEASE_CHANNEL").map(str::to_string);
-        let commit_hash = option_env!("GIT_HASH").map(str::to_string);
-        let commit_date = option_env!("COMMIT_DATE").map(str::to_string);
+        let host_compiler = std::option_env!("RUSTC_RELEASE_CHANNEL").map(str::to_string);
+        let commit_hash = std::option_env!("GIT_HASH").map(str::to_string);
+        let commit_date = std::option_env!("COMMIT_DATE").map(str::to_string);
 
-        VersionInfo {
+        $crate::VersionInfo {
             major,
             minor,
             patch,
@@ -26,6 +26,24 @@ macro_rules! get_version_info {
     }};
 }
 
+/// This macro can be used in `build.rs` to automatically set the needed
+/// environment values, namely `GIT_HASH`, `COMMIT_DATE` and
+/// `RUSTC_RELEASE_CHANNEL`
+#[macro_export]
+macro_rules! setup_version_info {
+    () => {{
+        println!(
+            "cargo:rustc-env=GIT_HASH={}",
+            $crate::get_commit_hash().unwrap_or_default()
+        );
+        println!(
+            "cargo:rustc-env=COMMIT_DATE={}",
+            $crate::get_commit_date().unwrap_or_default()
+        );
+        println!("cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}", $crate::get_channel());
+    }};
+}
+
 // some code taken and adapted from RLS and cargo
 pub struct VersionInfo {
     pub major: u8,
@@ -101,7 +119,7 @@ pub fn get_commit_date() -> Option<String> {
 
 #[must_use]
 pub fn get_channel() -> String {
-    match env::var("CFG_RELEASE_CHANNEL") {
+    match std::env::var("CFG_RELEASE_CHANNEL") {
         Ok(channel) => channel,
         Err(_) => {
             // if that failed, try to ask rustc -V, do some parsing and find out
@@ -136,8 +154,8 @@ mod test {
     fn test_struct_local() {
         let vi = get_version_info!();
         assert_eq!(vi.major, 0);
-        assert_eq!(vi.minor, 2);
-        assert_eq!(vi.patch, 1);
+        assert_eq!(vi.minor, 3);
+        assert_eq!(vi.patch, 0);
         assert_eq!(vi.crate_name, "rustc_tools_util");
         // hard to make positive tests for these since they will always change
         assert!(vi.commit_hash.is_none());
@@ -147,7 +165,7 @@ mod test {
     #[test]
     fn test_display_local() {
         let vi = get_version_info!();
-        assert_eq!(vi.to_string(), "rustc_tools_util 0.2.1");
+        assert_eq!(vi.to_string(), "rustc_tools_util 0.3.0");
     }
 
     #[test]
@@ -156,7 +174,7 @@ mod test {
         let s = format!("{vi:?}");
         assert_eq!(
             s,
-            "VersionInfo { crate_name: \"rustc_tools_util\", major: 0, minor: 2, patch: 1 }"
+            "VersionInfo { crate_name: \"rustc_tools_util\", major: 0, minor: 3, patch: 0 }"
         );
     }
 }
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index 9ec4df8e651..bcc096c570e 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -19,7 +19,6 @@ extern crate rustc_span;
 use rustc_interface::interface;
 use rustc_session::parse::ParseSess;
 use rustc_span::symbol::Symbol;
-use rustc_tools_util::VersionInfo;
 
 use std::borrow::Cow;
 use std::env;
diff --git a/src/tools/clippy/src/main.rs b/src/tools/clippy/src/main.rs
index d418d2daa31..7a78b32620d 100644
--- a/src/tools/clippy/src/main.rs
+++ b/src/tools/clippy/src/main.rs
@@ -2,7 +2,6 @@
 // warn on lints, that are included in `rust-lang/rust`s bootstrap
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
-use rustc_tools_util::VersionInfo;
 use std::env;
 use std::path::PathBuf;
 use std::process::{self, Command};
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
index 2a240cc249b..3ca45404e44 100644
--- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
@@ -7,14 +7,6 @@ LL |     const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"];
    = help: convert all references to use `sym::Deref`
    = note: `-D clippy::unnecessary-def-path` implied by `-D warnings`
 
-error: hardcoded path to a diagnostic item
-  --> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43
-   |
-LL |     const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
-   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: convert all references to use `sym::deref_method`
-
 error: hardcoded path to a language item
   --> $DIR/unnecessary_def_path_hardcoded_path.rs:11:40
    |
@@ -23,5 +15,13 @@ LL |     const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"]
    |
    = help: convert all references to use `LangItem::DerefMut`
 
+error: hardcoded path to a diagnostic item
+  --> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43
+   |
+LL |     const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: convert all references to use `sym::deref_method`
+
 error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs b/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs
index e8a023ab176..36db9e54a22 100644
--- a/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs
+++ b/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs
@@ -2,32 +2,117 @@
 
 use core::ops::{Add, Neg};
 
-#[derive(Clone, Copy)]
-struct Point {
-    x: i32,
-    y: i32,
+macro_rules! create {
+    ($name:ident) => {
+        #[allow(clippy::arithmetic_side_effects)]
+        #[derive(Clone, Copy)]
+        struct $name;
+
+        impl Add<$name> for $name {
+            type Output = $name;
+            fn add(self, other: $name) -> Self::Output {
+                todo!()
+            }
+        }
+
+        impl Add<i32> for $name {
+            type Output = $name;
+            fn add(self, other: i32) -> Self::Output {
+                todo!()
+            }
+        }
+
+        impl Add<$name> for i32 {
+            type Output = $name;
+            fn add(self, other: $name) -> Self::Output {
+                todo!()
+            }
+        }
+
+        impl Add<i64> for $name {
+            type Output = $name;
+            fn add(self, other: i64) -> Self::Output {
+                todo!()
+            }
+        }
+
+        impl Add<$name> for i64 {
+            type Output = $name;
+            fn add(self, other: $name) -> Self::Output {
+                todo!()
+            }
+        }
+
+        impl Neg for $name {
+            type Output = $name;
+            fn neg(self) -> Self::Output {
+                todo!()
+            }
+        }
+    };
 }
 
-impl Add for Point {
-    type Output = Self;
+create!(Foo);
+create!(Bar);
+create!(Baz);
+create!(OutOfNames);
 
-    fn add(self, other: Self) -> Self {
-        todo!()
-    }
+fn lhs_and_rhs_are_equal() {
+    // is explicitly on the list
+    let _ = OutOfNames + OutOfNames;
+    // is explicitly on the list
+    let _ = Foo + Foo;
+    // is implicitly on the list
+    let _ = Bar + Bar;
+    // not on the list
+    let _ = Baz + Baz;
 }
 
-impl Neg for Point {
-    type Output = Self;
+fn lhs_is_different() {
+    // is explicitly on the list
+    let _ = 1i32 + OutOfNames;
+    // is explicitly on the list
+    let _ = 1i32 + Foo;
+    // is implicitly on the list
+    let _ = 1i32 + Bar;
+    // not on the list
+    let _ = 1i32 + Baz;
 
-    fn neg(self) -> Self::Output {
-        todo!()
-    }
+    // not on the list
+    let _ = 1i64 + Foo;
+    // is implicitly on the list
+    let _ = 1i64 + Bar;
+    // not on the list
+    let _ = 1i64 + Baz;
 }
 
-fn main() {
-    let _ = Point { x: 1, y: 0 } + Point { x: 2, y: 3 };
+fn rhs_is_different() {
+    // is explicitly on the list
+    let _ = OutOfNames + 1i32;
+    // is explicitly on the list
+    let _ = Foo + 1i32;
+    // is implicitly on the list
+    let _ = Bar + 1i32;
+    // not on the list
+    let _ = Baz + 1i32;
+
+    // not on the list
+    let _ = Foo + 1i64;
+    // is implicitly on the list
+    let _ = Bar + 1i64;
+    // not on the list
+    let _ = Baz + 1i64;
+}
 
-    let point: Point = Point { x: 1, y: 0 };
-    let _ = point + point;
-    let _ = -point;
+fn unary() {
+    // is explicitly on the list
+    let _ = -OutOfNames;
+    // is specifically on the list
+    let _ = -Foo;
+    // not on the list
+    let _ = -Bar;
+    // not on the list
+    let _ = -Baz;
 }
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.stderr b/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.stderr
new file mode 100644
index 00000000000..ad89534aa1b
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.stderr
@@ -0,0 +1,58 @@
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects_allowed.rs:68:13
+   |
+LL |     let _ = Baz + Baz;
+   |             ^^^^^^^^^
+   |
+   = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings`
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects_allowed.rs:79:13
+   |
+LL |     let _ = 1i32 + Baz;
+   |             ^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects_allowed.rs:82:13
+   |
+LL |     let _ = 1i64 + Foo;
+   |             ^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects_allowed.rs:86:13
+   |
+LL |     let _ = 1i64 + Baz;
+   |             ^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects_allowed.rs:97:13
+   |
+LL |     let _ = Baz + 1i32;
+   |             ^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects_allowed.rs:100:13
+   |
+LL |     let _ = Foo + 1i64;
+   |             ^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects_allowed.rs:104:13
+   |
+LL |     let _ = Baz + 1i64;
+   |             ^^^^^^^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects_allowed.rs:113:13
+   |
+LL |     let _ = -Bar;
+   |             ^^^^
+
+error: arithmetic operation that can potentially result in unexpected side-effects
+  --> $DIR/arithmetic_side_effects_allowed.rs:115:13
+   |
+LL |     let _ = -Baz;
+   |             ^^^^
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml b/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml
index e736256f29a..89cbea7ecfe 100644
--- a/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml
+++ b/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml
@@ -1 +1,11 @@
-arithmetic-side-effects-allowed = ["Point"]
+arithmetic-side-effects-allowed = [
+    "OutOfNames"
+]
+arithmetic-side-effects-allowed-binary = [
+    ["Foo", "Foo"],
+    ["Foo", "i32"],
+    ["i32", "Foo"],
+    ["Bar", "*"],
+    ["*", "Bar"],
+]
+arithmetic-side-effects-allowed-unary = ["Foo"]
diff --git a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/clippy.toml b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/clippy.toml
new file mode 100644
index 00000000000..1b9384d7e3e
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/clippy.toml
@@ -0,0 +1 @@
+suppress-restriction-lint-in-const = true
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
new file mode 100644
index 00000000000..5a2df9f6c5d
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs
@@ -0,0 +1,60 @@
+#![feature(inline_const)]
+#![warn(clippy::indexing_slicing)]
+// We also check the out_of_bounds_indexing lint here, because it lints similar things and
+// we want to avoid false positives.
+#![warn(clippy::out_of_bounds_indexing)]
+#![allow(unconditional_panic, clippy::no_effect, clippy::unnecessary_operation)]
+
+const ARR: [i32; 2] = [1, 2];
+const REF: &i32 = &ARR[idx()]; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
+const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
+
+const fn idx() -> usize {
+    1
+}
+const fn idx4() -> usize {
+    4
+}
+
+fn main() {
+    let x = [1, 2, 3, 4];
+    let index: usize = 1;
+    x[index];
+    x[4]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
+    x[1 << 3]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
+
+    x[0]; // Ok, should not produce stderr.
+    x[3]; // Ok, should not produce stderr.
+    x[const { idx() }]; // Ok, should not produce stderr.
+    x[const { idx4() }]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
+    const { &ARR[idx()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
+    const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
+
+    let y = &x;
+    y[0]; // Ok, referencing shouldn't affect this lint. See the issue 6021
+    y[4]; // Ok, rustc will handle references too.
+
+    let v = vec![0; 5];
+    v[0];
+    v[10];
+    v[1 << 3];
+
+    const N: usize = 15; // Out of bounds
+    const M: usize = 3; // In bounds
+    x[N]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
+    x[M]; // Ok, should not produce stderr.
+    v[N];
+    v[M];
+}
+
+/// An opaque integer representation
+pub struct Integer<'a> {
+    /// The underlying data
+    value: &'a [u8],
+}
+impl<'a> Integer<'a> {
+    // Check whether `self` holds a negative number or not
+    pub const fn is_negative(&self) -> bool {
+        self.value[0] & 0b1000_0000 != 0
+    }
+}
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
new file mode 100644
index 00000000000..bc178b7e131
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr
@@ -0,0 +1,70 @@
+error[E0080]: evaluation of `main::{constant#3}` failed
+  --> $DIR/test.rs:31: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 used
+  --> $DIR/test.rs:31: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:22:5
+   |
+LL |     x[index];
+   |     ^^^^^^^^
+   |
+   = help: consider using `.get(n)` or `.get_mut(n)` instead
+   = note: `-D clippy::indexing-slicing` implied by `-D warnings`
+
+error: indexing may panic
+  --> $DIR/test.rs:38:5
+   |
+LL |     v[0];
+   |     ^^^^
+   |
+   = help: consider using `.get(n)` or `.get_mut(n)` instead
+
+error: indexing may panic
+  --> $DIR/test.rs:39:5
+   |
+LL |     v[10];
+   |     ^^^^^
+   |
+   = help: consider using `.get(n)` or `.get_mut(n)` instead
+
+error: indexing may panic
+  --> $DIR/test.rs:40:5
+   |
+LL |     v[1 << 3];
+   |     ^^^^^^^^^
+   |
+   = help: consider using `.get(n)` or `.get_mut(n)` instead
+
+error: indexing may panic
+  --> $DIR/test.rs:46:5
+   |
+LL |     v[N];
+   |     ^^^^
+   |
+   = help: consider using `.get(n)` or `.get_mut(n)` instead
+
+error: indexing may panic
+  --> $DIR/test.rs:47:5
+   |
+LL |     v[M];
+   |     ^^^^
+   |
+   = help: consider using `.get(n)` or `.get_mut(n)` instead
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/test.rs:10: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 8 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index 01a5e962c94..a22c6a5a060 100644
--- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -6,6 +6,8 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie
            allow-unwrap-in-tests
            allowed-scripts
            arithmetic-side-effects-allowed
+           arithmetic-side-effects-allowed-binary
+           arithmetic-side-effects-allowed-unary
            array-size-threshold
            avoid-breaking-exported-api
            await-holding-invalid-types
@@ -35,6 +37,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie
            pass-by-value-size-limit
            single-char-binding-names-threshold
            standard-macro-braces
+           suppress-restriction-lint-in-const
            third-party
            too-large-for-stack
            too-many-arguments-threshold
diff --git a/src/tools/clippy/tests/ui/almost_complete_letter_range.stderr b/src/tools/clippy/tests/ui/almost_complete_letter_range.stderr
deleted file mode 100644
index 9abf6d6c5e7..00000000000
--- a/src/tools/clippy/tests/ui/almost_complete_letter_range.stderr
+++ /dev/null
@@ -1,113 +0,0 @@
-error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:29:17
-   |
-LL |         let _ = ('a') ..'z';
-   |                 ^^^^^^--^^^
-   |                       |
-   |                       help: use an inclusive range: `..=`
-   |
-   = note: `-D clippy::almost-complete-letter-range` implied by `-D warnings`
-
-error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:30:17
-   |
-LL |         let _ = 'A' .. ('Z');
-   |                 ^^^^--^^^^^^
-   |                     |
-   |                     help: use an inclusive range: `..=`
-
-error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:36:13
-   |
-LL |     let _ = (b'a')..(b'z');
-   |             ^^^^^^--^^^^^^
-   |                   |
-   |                   help: use an inclusive range: `..=`
-
-error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:37:13
-   |
-LL |     let _ = b'A'..b'Z';
-   |             ^^^^--^^^^
-   |                 |
-   |                 help: use an inclusive range: `..=`
-
-error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:42:13
-   |
-LL |     let _ = a!()..'z';
-   |             ^^^^--^^^
-   |                 |
-   |                 help: use an inclusive range: `..=`
-
-error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:45:9
-   |
-LL |         b'a'..b'z' if true => 1,
-   |         ^^^^--^^^^
-   |             |
-   |             help: use an inclusive range: `..=`
-
-error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:46:9
-   |
-LL |         b'A'..b'Z' if true => 2,
-   |         ^^^^--^^^^
-   |             |
-   |             help: use an inclusive range: `..=`
-
-error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:53:9
-   |
-LL |         'a'..'z' if true => 1,
-   |         ^^^--^^^
-   |            |
-   |            help: use an inclusive range: `..=`
-
-error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:54:9
-   |
-LL |         'A'..'Z' if true => 2,
-   |         ^^^--^^^
-   |            |
-   |            help: use an inclusive range: `..=`
-
-error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:22:17
-   |
-LL |         let _ = 'a'..'z';
-   |                 ^^^--^^^
-   |                    |
-   |                    help: use an inclusive range: `..=`
-...
-LL |     b!();
-   |     ---- in this macro invocation
-   |
-   = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:67:9
-   |
-LL |         'a'..'z' => 1,
-   |         ^^^--^^^
-   |            |
-   |            help: use an inclusive range: `...`
-
-error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:74:13
-   |
-LL |     let _ = 'a'..'z';
-   |             ^^^--^^^
-   |                |
-   |                help: use an inclusive range: `..=`
-
-error: almost complete ascii letter range
-  --> $DIR/almost_complete_letter_range.rs:76:9
-   |
-LL |         'a'..'z' => 1,
-   |         ^^^--^^^
-   |            |
-   |            help: use an inclusive range: `..=`
-
-error: aborting due to 13 previous errors
-
diff --git a/src/tools/clippy/tests/ui/almost_complete_letter_range.fixed b/src/tools/clippy/tests/ui/almost_complete_range.fixed
index adcbd4d5134..6046addf719 100644
--- a/src/tools/clippy/tests/ui/almost_complete_letter_range.fixed
+++ b/src/tools/clippy/tests/ui/almost_complete_range.fixed
@@ -4,9 +4,10 @@
 
 #![feature(exclusive_range_pattern)]
 #![feature(stmt_expr_attributes)]
-#![warn(clippy::almost_complete_letter_range)]
+#![warn(clippy::almost_complete_range)]
 #![allow(ellipsis_inclusive_range_patterns)]
 #![allow(clippy::needless_parens_on_range_literals)]
+#![allow(clippy::double_parens)]
 
 #[macro_use]
 extern crate macro_rules;
@@ -16,10 +17,22 @@ macro_rules! a {
         'a'
     };
 }
+macro_rules! A {
+    () => {
+        'A'
+    };
+}
+macro_rules! zero {
+    () => {
+        '0'
+    };
+}
 
 macro_rules! b {
     () => {
         let _ = 'a'..='z';
+        let _ = 'A'..='Z';
+        let _ = '0'..='9';
     };
 }
 
@@ -28,36 +41,46 @@ fn main() {
     {
         let _ = ('a') ..='z';
         let _ = 'A' ..= ('Z');
+        let _ = ((('0'))) ..= ('9');
     }
 
     let _ = 'b'..'z';
     let _ = 'B'..'Z';
+    let _ = '1'..'9';
 
     let _ = (b'a')..=(b'z');
     let _ = b'A'..=b'Z';
+    let _ = b'0'..=b'9';
 
     let _ = b'b'..b'z';
     let _ = b'B'..b'Z';
+    let _ = b'1'..b'9';
 
     let _ = a!()..='z';
+    let _ = A!()..='Z';
+    let _ = zero!()..='9';
 
     let _ = match 0u8 {
         b'a'..=b'z' if true => 1,
         b'A'..=b'Z' if true => 2,
-        b'b'..b'z' => 3,
-        b'B'..b'Z' => 4,
-        _ => 5,
+        b'0'..=b'9' if true => 3,
+        b'b'..b'z' => 4,
+        b'B'..b'Z' => 5,
+        b'1'..b'9' => 6,
+        _ => 7,
     };
 
     let _ = match 'x' {
         'a'..='z' if true => 1,
         'A'..='Z' if true => 2,
-        'b'..'z' => 3,
-        'B'..'Z' => 4,
-        _ => 5,
+        '0'..='9' if true => 3,
+        'b'..'z' => 4,
+        'B'..'Z' => 5,
+        '1'..'9' => 6,
+        _ => 7,
     };
 
-    almost_complete_letter_range!();
+    almost_complete_range!();
     b!();
 }
 
@@ -65,15 +88,21 @@ fn main() {
 fn _under_msrv() {
     let _ = match 'a' {
         'a'...'z' => 1,
-        _ => 2,
+        'A'...'Z' => 2,
+        '0'...'9' => 3,
+        _ => 4,
     };
 }
 
 #[clippy::msrv = "1.26"]
 fn _meets_msrv() {
     let _ = 'a'..='z';
+    let _ = 'A'..='Z';
+    let _ = '0'..='9';
     let _ = match 'a' {
         'a'..='z' => 1,
-        _ => 2,
+        'A'..='Z' => 1,
+        '0'..='9' => 3,
+        _ => 4,
     };
 }
diff --git a/src/tools/clippy/tests/ui/almost_complete_letter_range.rs b/src/tools/clippy/tests/ui/almost_complete_range.rs
index 9979316eca4..ae7e07ab872 100644
--- a/src/tools/clippy/tests/ui/almost_complete_letter_range.rs
+++ b/src/tools/clippy/tests/ui/almost_complete_range.rs
@@ -4,9 +4,10 @@
 
 #![feature(exclusive_range_pattern)]
 #![feature(stmt_expr_attributes)]
-#![warn(clippy::almost_complete_letter_range)]
+#![warn(clippy::almost_complete_range)]
 #![allow(ellipsis_inclusive_range_patterns)]
 #![allow(clippy::needless_parens_on_range_literals)]
+#![allow(clippy::double_parens)]
 
 #[macro_use]
 extern crate macro_rules;
@@ -16,10 +17,22 @@ macro_rules! a {
         'a'
     };
 }
+macro_rules! A {
+    () => {
+        'A'
+    };
+}
+macro_rules! zero {
+    () => {
+        '0'
+    };
+}
 
 macro_rules! b {
     () => {
         let _ = 'a'..'z';
+        let _ = 'A'..'Z';
+        let _ = '0'..'9';
     };
 }
 
@@ -28,36 +41,46 @@ fn main() {
     {
         let _ = ('a') ..'z';
         let _ = 'A' .. ('Z');
+        let _ = ((('0'))) .. ('9');
     }
 
     let _ = 'b'..'z';
     let _ = 'B'..'Z';
+    let _ = '1'..'9';
 
     let _ = (b'a')..(b'z');
     let _ = b'A'..b'Z';
+    let _ = b'0'..b'9';
 
     let _ = b'b'..b'z';
     let _ = b'B'..b'Z';
+    let _ = b'1'..b'9';
 
     let _ = a!()..'z';
+    let _ = A!()..'Z';
+    let _ = zero!()..'9';
 
     let _ = match 0u8 {
         b'a'..b'z' if true => 1,
         b'A'..b'Z' if true => 2,
-        b'b'..b'z' => 3,
-        b'B'..b'Z' => 4,
-        _ => 5,
+        b'0'..b'9' if true => 3,
+        b'b'..b'z' => 4,
+        b'B'..b'Z' => 5,
+        b'1'..b'9' => 6,
+        _ => 7,
     };
 
     let _ = match 'x' {
         'a'..'z' if true => 1,
         'A'..'Z' if true => 2,
-        'b'..'z' => 3,
-        'B'..'Z' => 4,
-        _ => 5,
+        '0'..'9' if true => 3,
+        'b'..'z' => 4,
+        'B'..'Z' => 5,
+        '1'..'9' => 6,
+        _ => 7,
     };
 
-    almost_complete_letter_range!();
+    almost_complete_range!();
     b!();
 }
 
@@ -65,15 +88,21 @@ fn main() {
 fn _under_msrv() {
     let _ = match 'a' {
         'a'..'z' => 1,
-        _ => 2,
+        'A'..'Z' => 2,
+        '0'..'9' => 3,
+        _ => 4,
     };
 }
 
 #[clippy::msrv = "1.26"]
 fn _meets_msrv() {
     let _ = 'a'..'z';
+    let _ = 'A'..'Z';
+    let _ = '0'..'9';
     let _ = match 'a' {
         'a'..'z' => 1,
-        _ => 2,
+        'A'..'Z' => 1,
+        '0'..'9' => 3,
+        _ => 4,
     };
 }
diff --git a/src/tools/clippy/tests/ui/almost_complete_range.stderr b/src/tools/clippy/tests/ui/almost_complete_range.stderr
new file mode 100644
index 00000000000..a7a53287850
--- /dev/null
+++ b/src/tools/clippy/tests/ui/almost_complete_range.stderr
@@ -0,0 +1,235 @@
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:42:17
+   |
+LL |         let _ = ('a') ..'z';
+   |                 ^^^^^^--^^^
+   |                       |
+   |                       help: use an inclusive range: `..=`
+   |
+   = note: `-D clippy::almost-complete-range` implied by `-D warnings`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:43:17
+   |
+LL |         let _ = 'A' .. ('Z');
+   |                 ^^^^--^^^^^^
+   |                     |
+   |                     help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:44:17
+   |
+LL |         let _ = ((('0'))) .. ('9');
+   |                 ^^^^^^^^^^--^^^^^^
+   |                           |
+   |                           help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:51:13
+   |
+LL |     let _ = (b'a')..(b'z');
+   |             ^^^^^^--^^^^^^
+   |                   |
+   |                   help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:52:13
+   |
+LL |     let _ = b'A'..b'Z';
+   |             ^^^^--^^^^
+   |                 |
+   |                 help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:53:13
+   |
+LL |     let _ = b'0'..b'9';
+   |             ^^^^--^^^^
+   |                 |
+   |                 help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:59:13
+   |
+LL |     let _ = a!()..'z';
+   |             ^^^^--^^^
+   |                 |
+   |                 help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:60:13
+   |
+LL |     let _ = A!()..'Z';
+   |             ^^^^--^^^
+   |                 |
+   |                 help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:61:13
+   |
+LL |     let _ = zero!()..'9';
+   |             ^^^^^^^--^^^
+   |                    |
+   |                    help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:64:9
+   |
+LL |         b'a'..b'z' if true => 1,
+   |         ^^^^--^^^^
+   |             |
+   |             help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:65:9
+   |
+LL |         b'A'..b'Z' if true => 2,
+   |         ^^^^--^^^^
+   |             |
+   |             help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:66:9
+   |
+LL |         b'0'..b'9' if true => 3,
+   |         ^^^^--^^^^
+   |             |
+   |             help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:74:9
+   |
+LL |         'a'..'z' if true => 1,
+   |         ^^^--^^^
+   |            |
+   |            help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:75:9
+   |
+LL |         'A'..'Z' if true => 2,
+   |         ^^^--^^^
+   |            |
+   |            help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:76:9
+   |
+LL |         '0'..'9' if true => 3,
+   |         ^^^--^^^
+   |            |
+   |            help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:33:17
+   |
+LL |         let _ = 'a'..'z';
+   |                 ^^^--^^^
+   |                    |
+   |                    help: use an inclusive range: `..=`
+...
+LL |     b!();
+   |     ---- in this macro invocation
+   |
+   = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:34:17
+   |
+LL |         let _ = 'A'..'Z';
+   |                 ^^^--^^^
+   |                    |
+   |                    help: use an inclusive range: `..=`
+...
+LL |     b!();
+   |     ---- in this macro invocation
+   |
+   = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:35:17
+   |
+LL |         let _ = '0'..'9';
+   |                 ^^^--^^^
+   |                    |
+   |                    help: use an inclusive range: `..=`
+...
+LL |     b!();
+   |     ---- in this macro invocation
+   |
+   = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:90:9
+   |
+LL |         'a'..'z' => 1,
+   |         ^^^--^^^
+   |            |
+   |            help: use an inclusive range: `...`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:91:9
+   |
+LL |         'A'..'Z' => 2,
+   |         ^^^--^^^
+   |            |
+   |            help: use an inclusive range: `...`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:92:9
+   |
+LL |         '0'..'9' => 3,
+   |         ^^^--^^^
+   |            |
+   |            help: use an inclusive range: `...`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:99:13
+   |
+LL |     let _ = 'a'..'z';
+   |             ^^^--^^^
+   |                |
+   |                help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:100:13
+   |
+LL |     let _ = 'A'..'Z';
+   |             ^^^--^^^
+   |                |
+   |                help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:101:13
+   |
+LL |     let _ = '0'..'9';
+   |             ^^^--^^^
+   |                |
+   |                help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:103:9
+   |
+LL |         'a'..'z' => 1,
+   |         ^^^--^^^
+   |            |
+   |            help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:104:9
+   |
+LL |         'A'..'Z' => 1,
+   |         ^^^--^^^
+   |            |
+   |            help: use an inclusive range: `..=`
+
+error: almost complete ascii range
+  --> $DIR/almost_complete_range.rs:105:9
+   |
+LL |         '0'..'9' => 3,
+   |         ^^^--^^^
+   |            |
+   |            help: use an inclusive range: `..=`
+
+error: aborting due to 27 previous errors
+
diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr
index 0259a0824e7..9fe4b7cf28d 100644
--- a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr
+++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr
@@ -1,28 +1,10 @@
 error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:78:13
-   |
-LL |     let _ = String::new() + "";
-   |             ^^^^^^^^^^^^^^^^^^
-   |
-   = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings`
-
-error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:86:27
-   |
-LL |     let inferred_string = string + "";
-   |                           ^^^^^^^^^^^
-
-error: arithmetic operation that can potentially result in unexpected side-effects
-  --> $DIR/arithmetic_side_effects.rs:90:13
-   |
-LL |     let _ = inferred_string + "";
-   |             ^^^^^^^^^^^^^^^^^^^^
-
-error: arithmetic operation that can potentially result in unexpected side-effects
   --> $DIR/arithmetic_side_effects.rs:165:5
    |
 LL |     _n += 1;
    |     ^^^^^^^
+   |
+   = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings`
 
 error: arithmetic operation that can potentially result in unexpected side-effects
   --> $DIR/arithmetic_side_effects.rs:166:5
@@ -348,5 +330,5 @@ error: arithmetic operation that can potentially result in unexpected side-effec
 LL |     _n = -&_n;
    |          ^^^^
 
-error: aborting due to 58 previous errors
+error: aborting due to 55 previous errors
 
diff --git a/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs b/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
index ef3ca9aea38..1e5f20e8c39 100644
--- a/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
@@ -142,8 +142,10 @@ macro_rules! equatable_if_let {
 }
 
 #[macro_export]
-macro_rules! almost_complete_letter_range {
+macro_rules! almost_complete_range {
     () => {
         let _ = 'a'..'z';
+        let _ = 'A'..'Z';
+        let _ = '0'..'9';
     };
 }
diff --git a/src/tools/clippy/tests/ui/cast_lossless_integer.fixed b/src/tools/clippy/tests/ui/cast_lossless_integer.fixed
index 72a708b4073..925cbf25368 100644
--- a/src/tools/clippy/tests/ui/cast_lossless_integer.fixed
+++ b/src/tools/clippy/tests/ui/cast_lossless_integer.fixed
@@ -45,3 +45,9 @@ mod cast_lossless_in_impl {
         }
     }
 }
+
+#[derive(PartialEq, Debug)]
+#[repr(i64)]
+enum Test {
+    A = u32::MAX as i64 + 1,
+}
diff --git a/src/tools/clippy/tests/ui/cast_lossless_integer.rs b/src/tools/clippy/tests/ui/cast_lossless_integer.rs
index 34bb47181e6..c82bd9108d2 100644
--- a/src/tools/clippy/tests/ui/cast_lossless_integer.rs
+++ b/src/tools/clippy/tests/ui/cast_lossless_integer.rs
@@ -45,3 +45,9 @@ mod cast_lossless_in_impl {
         }
     }
 }
+
+#[derive(PartialEq, Debug)]
+#[repr(i64)]
+enum Test {
+    A = u32::MAX as i64 + 1,
+}
diff --git a/src/tools/clippy/tests/ui/collapsible_str_replace.fixed b/src/tools/clippy/tests/ui/collapsible_str_replace.fixed
index 49fc9a9629e..9792ae9ed6b 100644
--- a/src/tools/clippy/tests/ui/collapsible_str_replace.fixed
+++ b/src/tools/clippy/tests/ui/collapsible_str_replace.fixed
@@ -1,5 +1,6 @@
 // run-rustfix
 
+#![allow(unused)]
 #![warn(clippy::collapsible_str_replace)]
 
 fn get_filter() -> char {
@@ -71,3 +72,13 @@ fn main() {
         .replace('u', iter.next().unwrap())
         .replace('s', iter.next().unwrap());
 }
+
+#[clippy::msrv = "1.57"]
+fn msrv_1_57() {
+    let _ = "".replace('a', "1.57").replace('b', "1.57");
+}
+
+#[clippy::msrv = "1.58"]
+fn msrv_1_58() {
+    let _ = "".replace(['a', 'b'], "1.58");
+}
diff --git a/src/tools/clippy/tests/ui/collapsible_str_replace.rs b/src/tools/clippy/tests/ui/collapsible_str_replace.rs
index e3e25c4146f..baee185b79e 100644
--- a/src/tools/clippy/tests/ui/collapsible_str_replace.rs
+++ b/src/tools/clippy/tests/ui/collapsible_str_replace.rs
@@ -1,5 +1,6 @@
 // run-rustfix
 
+#![allow(unused)]
 #![warn(clippy::collapsible_str_replace)]
 
 fn get_filter() -> char {
@@ -74,3 +75,13 @@ fn main() {
         .replace('u', iter.next().unwrap())
         .replace('s', iter.next().unwrap());
 }
+
+#[clippy::msrv = "1.57"]
+fn msrv_1_57() {
+    let _ = "".replace('a', "1.57").replace('b', "1.57");
+}
+
+#[clippy::msrv = "1.58"]
+fn msrv_1_58() {
+    let _ = "".replace('a', "1.58").replace('b', "1.58");
+}
diff --git a/src/tools/clippy/tests/ui/collapsible_str_replace.stderr b/src/tools/clippy/tests/ui/collapsible_str_replace.stderr
index 8e3daf3b898..223358cf53f 100644
--- a/src/tools/clippy/tests/ui/collapsible_str_replace.stderr
+++ b/src/tools/clippy/tests/ui/collapsible_str_replace.stderr
@@ -1,5 +1,5 @@
 error: used consecutive `str::replace` call
-  --> $DIR/collapsible_str_replace.rs:19:27
+  --> $DIR/collapsible_str_replace.rs:20:27
    |
 LL |     let _ = "hesuo worpd".replace('s', "l").replace('u', "l");
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], "l")`
@@ -7,19 +7,19 @@ LL |     let _ = "hesuo worpd".replace('s', "l").replace('u', "l");
    = note: `-D clippy::collapsible-str-replace` implied by `-D warnings`
 
 error: used consecutive `str::replace` call
-  --> $DIR/collapsible_str_replace.rs:21:27
+  --> $DIR/collapsible_str_replace.rs:22:27
    |
 LL |     let _ = "hesuo worpd".replace('s', l).replace('u', l);
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], l)`
 
 error: used consecutive `str::replace` call
-  --> $DIR/collapsible_str_replace.rs:23:27
+  --> $DIR/collapsible_str_replace.rs:24:27
    |
 LL |     let _ = "hesuo worpd".replace('s', "l").replace('u', "l").replace('p', "l");
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u', 'p'], "l")`
 
 error: used consecutive `str::replace` call
-  --> $DIR/collapsible_str_replace.rs:26:10
+  --> $DIR/collapsible_str_replace.rs:27:10
    |
 LL |           .replace('s', "l")
    |  __________^
@@ -29,58 +29,64 @@ LL | |         .replace('d', "l");
    | |__________________________^ help: replace with: `replace(['s', 'u', 'p', 'd'], "l")`
 
 error: used consecutive `str::replace` call
-  --> $DIR/collapsible_str_replace.rs:31:27
+  --> $DIR/collapsible_str_replace.rs:32:27
    |
 LL |     let _ = "hesuo world".replace(s, "l").replace('u', "l");
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, 'u'], "l")`
 
 error: used consecutive `str::replace` call
-  --> $DIR/collapsible_str_replace.rs:33:27
+  --> $DIR/collapsible_str_replace.rs:34:27
    |
 LL |     let _ = "hesuo worpd".replace(s, "l").replace('u', "l").replace('p', "l");
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, 'u', 'p'], "l")`
 
 error: used consecutive `str::replace` call
-  --> $DIR/collapsible_str_replace.rs:35:27
+  --> $DIR/collapsible_str_replace.rs:36:27
    |
 LL |     let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace('p', "l");
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, u, 'p'], "l")`
 
 error: used consecutive `str::replace` call
-  --> $DIR/collapsible_str_replace.rs:37:27
+  --> $DIR/collapsible_str_replace.rs:38:27
    |
 LL |     let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace(p, "l");
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, u, p], "l")`
 
 error: used consecutive `str::replace` call
-  --> $DIR/collapsible_str_replace.rs:39:27
+  --> $DIR/collapsible_str_replace.rs:40:27
    |
 LL |     let _ = "hesuo worlp".replace('s', "l").replace('u', "l").replace('p', "d");
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], "l")`
 
 error: used consecutive `str::replace` call
-  --> $DIR/collapsible_str_replace.rs:41:45
+  --> $DIR/collapsible_str_replace.rs:42:45
    |
 LL |     let _ = "hesuo worpd".replace('s', "x").replace('u', "l").replace('p', "l");
    |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['u', 'p'], "l")`
 
 error: used consecutive `str::replace` call
-  --> $DIR/collapsible_str_replace.rs:44:47
+  --> $DIR/collapsible_str_replace.rs:45:47
    |
 LL |     let _ = "hesudo worpd".replace("su", "l").replace('d', "l").replace('p', "l");
    |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['d', 'p'], "l")`
 
 error: used consecutive `str::replace` call
-  --> $DIR/collapsible_str_replace.rs:46:28
+  --> $DIR/collapsible_str_replace.rs:47:28
    |
 LL |     let _ = "hesudo worpd".replace(d, "l").replace('p', "l").replace("su", "l");
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([d, 'p'], "l")`
 
 error: used consecutive `str::replace` call
-  --> $DIR/collapsible_str_replace.rs:48:27
+  --> $DIR/collapsible_str_replace.rs:49:27
    |
 LL |     let _ = "hesuo world".replace(get_filter(), "l").replace('s', "l");
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([get_filter(), 's'], "l")`
 
-error: aborting due to 13 previous errors
+error: used consecutive `str::replace` call
+  --> $DIR/collapsible_str_replace.rs:86:16
+   |
+LL |     let _ = "".replace('a', "1.58").replace('b', "1.58");
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['a', 'b'], "1.58")`
+
+error: aborting due to 14 previous errors
 
diff --git a/src/tools/clippy/tests/ui/explicit_counter_loop.rs b/src/tools/clippy/tests/ui/explicit_counter_loop.rs
index 6eddc01e2c4..46565a97f00 100644
--- a/src/tools/clippy/tests/ui/explicit_counter_loop.rs
+++ b/src/tools/clippy/tests/ui/explicit_counter_loop.rs
@@ -189,3 +189,33 @@ mod issue_7920 {
         }
     }
 }
+
+mod issue_10058 {
+    pub fn test() {
+        // should not lint since we are increasing counter potentially more than once in the loop
+        let values = [0, 1, 0, 1, 1, 1, 0, 1, 0, 1];
+        let mut counter = 0;
+        for value in values {
+            counter += 1;
+
+            if value == 0 {
+                continue;
+            }
+
+            counter += 1;
+        }
+    }
+
+    pub fn test2() {
+        // should not lint since we are increasing counter potentially more than once in the loop
+        let values = [0, 1, 0, 1, 1, 1, 0, 1, 0, 1];
+        let mut counter = 0;
+        for value in values {
+            counter += 1;
+
+            if value != 0 {
+                counter += 1;
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/from_over_into.fixed b/src/tools/clippy/tests/ui/from_over_into.fixed
index 125c9a69cd3..72d635c2ccd 100644
--- a/src/tools/clippy/tests/ui/from_over_into.fixed
+++ b/src/tools/clippy/tests/ui/from_over_into.fixed
@@ -1,5 +1,6 @@
 // run-rustfix
 
+#![feature(type_alias_impl_trait)]
 #![warn(clippy::from_over_into)]
 #![allow(unused)]
 
@@ -81,4 +82,10 @@ fn msrv_1_41() {
     }
 }
 
+type Opaque = impl Sized;
+struct IntoOpaque;
+impl Into<Opaque> for IntoOpaque {
+    fn into(self) -> Opaque {}
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/from_over_into.rs b/src/tools/clippy/tests/ui/from_over_into.rs
index 5aa127bfabe..965f4d5d785 100644
--- a/src/tools/clippy/tests/ui/from_over_into.rs
+++ b/src/tools/clippy/tests/ui/from_over_into.rs
@@ -1,5 +1,6 @@
 // run-rustfix
 
+#![feature(type_alias_impl_trait)]
 #![warn(clippy::from_over_into)]
 #![allow(unused)]
 
@@ -81,4 +82,10 @@ fn msrv_1_41() {
     }
 }
 
+type Opaque = impl Sized;
+struct IntoOpaque;
+impl Into<Opaque> for IntoOpaque {
+    fn into(self) -> Opaque {}
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/from_over_into.stderr b/src/tools/clippy/tests/ui/from_over_into.stderr
index a1764a5ea12..3c4d011d6fb 100644
--- a/src/tools/clippy/tests/ui/from_over_into.stderr
+++ b/src/tools/clippy/tests/ui/from_over_into.stderr
@@ -1,5 +1,5 @@
 error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
-  --> $DIR/from_over_into.rs:9:1
+  --> $DIR/from_over_into.rs:10:1
    |
 LL | impl Into<StringWrapper> for String {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ LL ~         StringWrapper(val)
    |
 
 error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
-  --> $DIR/from_over_into.rs:17:1
+  --> $DIR/from_over_into.rs:18:1
    |
 LL | impl Into<SelfType> for String {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -26,7 +26,7 @@ LL ~         SelfType(String::new())
    |
 
 error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
-  --> $DIR/from_over_into.rs:32:1
+  --> $DIR/from_over_into.rs:33:1
    |
 LL | impl Into<SelfKeywords> for X {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -41,7 +41,7 @@ LL ~         let _: X = val;
    |
 
 error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
-  --> $DIR/from_over_into.rs:44:1
+  --> $DIR/from_over_into.rs:45:1
    |
 LL | impl core::convert::Into<bool> for crate::ExplicitPaths {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -59,7 +59,7 @@ LL ~         val.0
    |
 
 error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
-  --> $DIR/from_over_into.rs:77:5
+  --> $DIR/from_over_into.rs:78:5
    |
 LL |     impl<T> Into<FromOverInto<T>> for Vec<T> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/identity_op.fixed b/src/tools/clippy/tests/ui/identity_op.fixed
index e7b9a78c5db..cac69ef42c4 100644
--- a/src/tools/clippy/tests/ui/identity_op.fixed
+++ b/src/tools/clippy/tests/ui/identity_op.fixed
@@ -65,7 +65,7 @@ fn main() {
     42;
     1;
     42;
-    &x;
+    x;
     x;
 
     let mut a = A(String::new());
@@ -112,6 +112,10 @@ fn main() {
     2 * { a };
     (({ a } + 4));
     1;
+
+    // Issue #9904
+    let x = 0i32;
+    let _: i32 = x;
 }
 
 pub fn decide(a: bool, b: bool) -> u32 {
diff --git a/src/tools/clippy/tests/ui/identity_op.rs b/src/tools/clippy/tests/ui/identity_op.rs
index 9a435cdbb75..33201aad4f6 100644
--- a/src/tools/clippy/tests/ui/identity_op.rs
+++ b/src/tools/clippy/tests/ui/identity_op.rs
@@ -112,6 +112,10 @@ fn main() {
     2 * (0 + { a });
     1 * ({ a } + 4);
     1 * 1;
+
+    // Issue #9904
+    let x = 0i32;
+    let _: i32 = &x + 0;
 }
 
 pub fn decide(a: bool, b: bool) -> u32 {
diff --git a/src/tools/clippy/tests/ui/identity_op.stderr b/src/tools/clippy/tests/ui/identity_op.stderr
index 1a104a20b84..3ba557d18b2 100644
--- a/src/tools/clippy/tests/ui/identity_op.stderr
+++ b/src/tools/clippy/tests/ui/identity_op.stderr
@@ -70,7 +70,7 @@ error: this operation has no effect
   --> $DIR/identity_op.rs:68:5
    |
 LL |     &x >> 0;
-   |     ^^^^^^^ help: consider reducing it to: `&x`
+   |     ^^^^^^^ help: consider reducing it to: `x`
 
 error: this operation has no effect
   --> $DIR/identity_op.rs:69:5
@@ -229,10 +229,16 @@ LL |     1 * 1;
    |     ^^^^^ help: consider reducing it to: `1`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:118:5
+  --> $DIR/identity_op.rs:118:18
+   |
+LL |     let _: i32 = &x + 0;
+   |                  ^^^^^^ help: consider reducing it to: `x`
+
+error: this operation has no effect
+  --> $DIR/identity_op.rs:122:5
    |
 LL |     0 + if a { 1 } else { 2 } + if b { 3 } else { 5 }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(if a { 1 } else { 2 })`
 
-error: aborting due to 39 previous errors
+error: aborting due to 40 previous errors
 
diff --git a/src/tools/clippy/tests/ui/implicit_clone.fixed b/src/tools/clippy/tests/ui/implicit_clone.fixed
index 33770fc2a2c..51b1afbe5ac 100644
--- a/src/tools/clippy/tests/ui/implicit_clone.fixed
+++ b/src/tools/clippy/tests/ui/implicit_clone.fixed
@@ -115,4 +115,14 @@ fn main() {
     let pathbuf_ref = &pathbuf_ref;
     let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&&PathBuf`
     let _ = (**pathbuf_ref).clone();
+
+    struct NoClone;
+    impl ToOwned for NoClone {
+        type Owned = Self;
+        fn to_owned(&self) -> Self {
+            NoClone
+        }
+    }
+    let no_clone = &NoClone;
+    let _ = no_clone.to_owned();
 }
diff --git a/src/tools/clippy/tests/ui/implicit_clone.rs b/src/tools/clippy/tests/ui/implicit_clone.rs
index fc896525bd2..8a9027433d9 100644
--- a/src/tools/clippy/tests/ui/implicit_clone.rs
+++ b/src/tools/clippy/tests/ui/implicit_clone.rs
@@ -115,4 +115,14 @@ fn main() {
     let pathbuf_ref = &pathbuf_ref;
     let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&&PathBuf`
     let _ = pathbuf_ref.to_path_buf();
+
+    struct NoClone;
+    impl ToOwned for NoClone {
+        type Owned = Self;
+        fn to_owned(&self) -> Self {
+            NoClone
+        }
+    }
+    let no_clone = &NoClone;
+    let _ = no_clone.to_owned();
 }
diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.rs b/src/tools/clippy/tests/ui/indexing_slicing_index.rs
index 4476e0eb922..26abc9edb5e 100644
--- a/src/tools/clippy/tests/ui/indexing_slicing_index.rs
+++ b/src/tools/clippy/tests/ui/indexing_slicing_index.rs
@@ -6,7 +6,7 @@
 #![allow(unconditional_panic, clippy::no_effect, clippy::unnecessary_operation)]
 
 const ARR: [i32; 2] = [1, 2];
-const REF: &i32 = &ARR[idx()]; // Ok, should not produce stderr.
+const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
 const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
 
 const fn idx() -> usize {
@@ -27,8 +27,8 @@ fn main() {
     x[3]; // Ok, should not produce stderr.
     x[const { idx() }]; // Ok, should not produce stderr.
     x[const { idx4() }]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays.
-    const { &ARR[idx()] }; // Ok, should not produce stderr.
-    const { &ARR[idx4()] }; // Ok, let rustc handle const contexts.
+    const { &ARR[idx()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
+    const { &ARR[idx4()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
 
     let y = &x;
     y[0]; // Ok, referencing shouldn't affect this lint. See the issue 6021
diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr
index d8b6e3f1262..8fd77913a3f 100644
--- a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr
+++ b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr
@@ -1,13 +1,32 @@
+error: indexing may panic
+  --> $DIR/indexing_slicing_index.rs:9:20
+   |
+LL | const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
+   |                    ^^^^^^^^^^
+   |
+   = help: consider using `.get(n)` or `.get_mut(n)` instead
+   = note: the suggestion might not be applicable in constant blocks
+   = note: `-D clippy::indexing-slicing` implied by `-D warnings`
+
+error: indexing may panic
+  --> $DIR/indexing_slicing_index.rs:10:24
+   |
+LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
+   |                        ^^^^^^^^^^^
+   |
+   = help: consider using `.get(n)` or `.get_mut(n)` instead
+   = note: the suggestion might not be applicable in constant blocks
+
 error[E0080]: evaluation of `main::{constant#3}` failed
   --> $DIR/indexing_slicing_index.rs:31:14
    |
-LL |     const { &ARR[idx4()] }; // Ok, let rustc handle const contexts.
+LL |     const { &ARR[idx4()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
    |              ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
 
 note: erroneous constant used
   --> $DIR/indexing_slicing_index.rs:31:5
    |
-LL |     const { &ARR[idx4()] }; // Ok, let rustc handle const contexts.
+LL |     const { &ARR[idx4()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: indexing may panic
@@ -17,7 +36,24 @@ LL |     x[index];
    |     ^^^^^^^^
    |
    = help: consider using `.get(n)` or `.get_mut(n)` instead
-   = note: `-D clippy::indexing-slicing` implied by `-D warnings`
+
+error: indexing may panic
+  --> $DIR/indexing_slicing_index.rs:30:14
+   |
+LL |     const { &ARR[idx()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
+   |              ^^^^^^^^^^
+   |
+   = help: consider using `.get(n)` or `.get_mut(n)` instead
+   = note: the suggestion might not be applicable in constant blocks
+
+error: indexing may panic
+  --> $DIR/indexing_slicing_index.rs:31:14
+   |
+LL |     const { &ARR[idx4()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false.
+   |              ^^^^^^^^^^^
+   |
+   = help: consider using `.get(n)` or `.get_mut(n)` instead
+   = note: the suggestion might not be applicable in constant blocks
 
 error: indexing may panic
   --> $DIR/indexing_slicing_index.rs:38:5
@@ -65,6 +101,6 @@ error[E0080]: evaluation of constant value failed
 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 8 previous errors
+error: aborting due to 12 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/src/tools/clippy/tests/ui/len_zero.fixed b/src/tools/clippy/tests/ui/len_zero.fixed
index 1f3b8ac99b1..c1c0b5ae40f 100644
--- a/src/tools/clippy/tests/ui/len_zero.fixed
+++ b/src/tools/clippy/tests/ui/len_zero.fixed
@@ -3,6 +3,9 @@
 #![warn(clippy::len_zero)]
 #![allow(dead_code, unused, clippy::len_without_is_empty)]
 
+extern crate core;
+use core::ops::Deref;
+
 pub struct One;
 struct Wither;
 
@@ -56,6 +59,26 @@ impl WithIsEmpty for Wither {
     }
 }
 
+struct DerefToDerefToString;
+
+impl Deref for DerefToDerefToString {
+    type Target = DerefToString;
+
+    fn deref(&self) -> &Self::Target {
+        &DerefToString {}
+    }
+}
+
+struct DerefToString;
+
+impl Deref for DerefToString {
+    type Target = str;
+
+    fn deref(&self) -> &Self::Target {
+        "Hello, world!"
+    }
+}
+
 fn main() {
     let x = [1, 2];
     if x.is_empty() {
@@ -64,6 +87,23 @@ fn main() {
 
     if "".is_empty() {}
 
+    let s = "Hello, world!";
+    let s1 = &s;
+    let s2 = &s1;
+    let s3 = &s2;
+    let s4 = &s3;
+    let s5 = &s4;
+    let s6 = &s5;
+    println!("{}", s1.is_empty());
+    println!("{}", s2.is_empty());
+    println!("{}", s3.is_empty());
+    println!("{}", s4.is_empty());
+    println!("{}", s5.is_empty());
+    println!("{}", (s6).is_empty());
+
+    let d2s = DerefToDerefToString {};
+    println!("{}", (**d2s).is_empty());
+
     let y = One;
     if y.len() == 0 {
         // No error; `One` does not have `.is_empty()`.
diff --git a/src/tools/clippy/tests/ui/len_zero.rs b/src/tools/clippy/tests/ui/len_zero.rs
index dc21de0001b..cc2eb05b6bf 100644
--- a/src/tools/clippy/tests/ui/len_zero.rs
+++ b/src/tools/clippy/tests/ui/len_zero.rs
@@ -3,6 +3,9 @@
 #![warn(clippy::len_zero)]
 #![allow(dead_code, unused, clippy::len_without_is_empty)]
 
+extern crate core;
+use core::ops::Deref;
+
 pub struct One;
 struct Wither;
 
@@ -56,6 +59,26 @@ impl WithIsEmpty for Wither {
     }
 }
 
+struct DerefToDerefToString;
+
+impl Deref for DerefToDerefToString {
+    type Target = DerefToString;
+
+    fn deref(&self) -> &Self::Target {
+        &DerefToString {}
+    }
+}
+
+struct DerefToString;
+
+impl Deref for DerefToString {
+    type Target = str;
+
+    fn deref(&self) -> &Self::Target {
+        "Hello, world!"
+    }
+}
+
 fn main() {
     let x = [1, 2];
     if x.len() == 0 {
@@ -64,6 +87,23 @@ fn main() {
 
     if "".len() == 0 {}
 
+    let s = "Hello, world!";
+    let s1 = &s;
+    let s2 = &s1;
+    let s3 = &s2;
+    let s4 = &s3;
+    let s5 = &s4;
+    let s6 = &s5;
+    println!("{}", *s1 == "");
+    println!("{}", **s2 == "");
+    println!("{}", ***s3 == "");
+    println!("{}", ****s4 == "");
+    println!("{}", *****s5 == "");
+    println!("{}", ******(s6) == "");
+
+    let d2s = DerefToDerefToString {};
+    println!("{}", &**d2s == "");
+
     let y = One;
     if y.len() == 0 {
         // No error; `One` does not have `.is_empty()`.
diff --git a/src/tools/clippy/tests/ui/len_zero.stderr b/src/tools/clippy/tests/ui/len_zero.stderr
index 6c71f1beeac..b6f13780253 100644
--- a/src/tools/clippy/tests/ui/len_zero.stderr
+++ b/src/tools/clippy/tests/ui/len_zero.stderr
@@ -1,5 +1,5 @@
 error: length comparison to zero
-  --> $DIR/len_zero.rs:61:8
+  --> $DIR/len_zero.rs:84:8
    |
 LL |     if x.len() == 0 {
    |        ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `x.is_empty()`
@@ -7,82 +7,126 @@ LL |     if x.len() == 0 {
    = note: `-D clippy::len-zero` implied by `-D warnings`
 
 error: length comparison to zero
-  --> $DIR/len_zero.rs:65:8
+  --> $DIR/len_zero.rs:88:8
    |
 LL |     if "".len() == 0 {}
    |        ^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `"".is_empty()`
 
+error: comparison to empty slice
+  --> $DIR/len_zero.rs:97:20
+   |
+LL |     println!("{}", *s1 == "");
+   |                    ^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s1.is_empty()`
+   |
+   = note: `-D clippy::comparison-to-empty` implied by `-D warnings`
+
+error: comparison to empty slice
+  --> $DIR/len_zero.rs:98:20
+   |
+LL |     println!("{}", **s2 == "");
+   |                    ^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s2.is_empty()`
+
+error: comparison to empty slice
+  --> $DIR/len_zero.rs:99:20
+   |
+LL |     println!("{}", ***s3 == "");
+   |                    ^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s3.is_empty()`
+
+error: comparison to empty slice
+  --> $DIR/len_zero.rs:100:20
+   |
+LL |     println!("{}", ****s4 == "");
+   |                    ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s4.is_empty()`
+
+error: comparison to empty slice
+  --> $DIR/len_zero.rs:101:20
+   |
+LL |     println!("{}", *****s5 == "");
+   |                    ^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s5.is_empty()`
+
+error: comparison to empty slice
+  --> $DIR/len_zero.rs:102:20
+   |
+LL |     println!("{}", ******(s6) == "");
+   |                    ^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(s6).is_empty()`
+
+error: comparison to empty slice
+  --> $DIR/len_zero.rs:105:20
+   |
+LL |     println!("{}", &**d2s == "");
+   |                    ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(**d2s).is_empty()`
+
 error: length comparison to zero
-  --> $DIR/len_zero.rs:80:8
+  --> $DIR/len_zero.rs:120:8
    |
 LL |     if has_is_empty.len() == 0 {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> $DIR/len_zero.rs:83:8
+  --> $DIR/len_zero.rs:123:8
    |
 LL |     if has_is_empty.len() != 0 {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> $DIR/len_zero.rs:86:8
+  --> $DIR/len_zero.rs:126:8
    |
 LL |     if has_is_empty.len() > 0 {
    |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to one
-  --> $DIR/len_zero.rs:89:8
+  --> $DIR/len_zero.rs:129:8
    |
 LL |     if has_is_empty.len() < 1 {
    |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to one
-  --> $DIR/len_zero.rs:92:8
+  --> $DIR/len_zero.rs:132:8
    |
 LL |     if has_is_empty.len() >= 1 {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> $DIR/len_zero.rs:103:8
+  --> $DIR/len_zero.rs:143:8
    |
 LL |     if 0 == has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> $DIR/len_zero.rs:106:8
+  --> $DIR/len_zero.rs:146:8
    |
 LL |     if 0 != has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> $DIR/len_zero.rs:109:8
+  --> $DIR/len_zero.rs:149:8
    |
 LL |     if 0 < has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to one
-  --> $DIR/len_zero.rs:112:8
+  --> $DIR/len_zero.rs:152:8
    |
 LL |     if 1 <= has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to one
-  --> $DIR/len_zero.rs:115:8
+  --> $DIR/len_zero.rs:155:8
    |
 LL |     if 1 > has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> $DIR/len_zero.rs:129:8
+  --> $DIR/len_zero.rs:169:8
    |
 LL |     if with_is_empty.len() == 0 {
    |        ^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `with_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> $DIR/len_zero.rs:142:8
+  --> $DIR/len_zero.rs:182:8
    |
 LL |     if b.len() != 0 {}
    |        ^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!b.is_empty()`
 
-error: aborting due to 14 previous errors
+error: aborting due to 21 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed b/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
index c9a819ba535..638320dd6ee 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
@@ -62,6 +62,11 @@ fn main() {
         panic!("panic5");
     }
     assert!(!a.is_empty(), "with expansion {}", one!());
+    if a.is_empty() {
+        let _ = 0;
+    } else if a.len() == 1 {
+        panic!("panic6");
+    }
 }
 
 fn issue7730(a: u8) {
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed b/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed
index 2f62de51cad..8c7e919bf62 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed
@@ -50,6 +50,11 @@ fn main() {
     assert!(!(b.is_empty() || a.is_empty()), "panic4");
     assert!(!(a.is_empty() || !b.is_empty()), "panic5");
     assert!(!a.is_empty(), "with expansion {}", one!());
+    if a.is_empty() {
+        let _ = 0;
+    } else if a.len() == 1 {
+        panic!("panic6");
+    }
 }
 
 fn issue7730(a: u8) {
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr
index 237638ee134..3555ac29243 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr
@@ -65,7 +65,7 @@ LL | |     }
    | |_____^ help: try instead: `assert!(!a.is_empty(), "with expansion {}", one!());`
 
 error: only a `panic!` in `if`-then statement
-  --> $DIR/manual_assert.rs:73:5
+  --> $DIR/manual_assert.rs:78:5
    |
 LL | /     if a > 2 {
 LL | |         // comment
diff --git a/src/tools/clippy/tests/ui/manual_assert.rs b/src/tools/clippy/tests/ui/manual_assert.rs
index 6a4cc2468d4..f037c5b8405 100644
--- a/src/tools/clippy/tests/ui/manual_assert.rs
+++ b/src/tools/clippy/tests/ui/manual_assert.rs
@@ -66,6 +66,11 @@ fn main() {
     if a.is_empty() {
         panic!("with expansion {}", one!())
     }
+    if a.is_empty() {
+        let _ = 0;
+    } else if a.len() == 1 {
+        panic!("panic6");
+    }
 }
 
 fn issue7730(a: u8) {
diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed b/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed
index 231ba83b142..5b2b44c2fdb 100644
--- a/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed
+++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed
@@ -15,6 +15,19 @@ fn main() {
     assert!('x'.is_ascii_alphabetic());
 
     assert!(matches!('x', 'A'..='Z' | 'a'..='z' | '_'));
+
+    b'0'.is_ascii_digit();
+    b'a'.is_ascii_lowercase();
+    b'A'.is_ascii_uppercase();
+
+    '0'.is_ascii_digit();
+    'a'.is_ascii_lowercase();
+    'A'.is_ascii_uppercase();
+
+    let cool_letter = &'g';
+    cool_letter.is_ascii_digit();
+    cool_letter.is_ascii_lowercase();
+    cool_letter.is_ascii_uppercase();
 }
 
 #[clippy::msrv = "1.23"]
diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.rs b/src/tools/clippy/tests/ui/manual_is_ascii_check.rs
index 39ee6151c56..c9433f33a1b 100644
--- a/src/tools/clippy/tests/ui/manual_is_ascii_check.rs
+++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.rs
@@ -15,6 +15,19 @@ fn main() {
     assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
 
     assert!(matches!('x', 'A'..='Z' | 'a'..='z' | '_'));
+
+    (b'0'..=b'9').contains(&b'0');
+    (b'a'..=b'z').contains(&b'a');
+    (b'A'..=b'Z').contains(&b'A');
+
+    ('0'..='9').contains(&'0');
+    ('a'..='z').contains(&'a');
+    ('A'..='Z').contains(&'A');
+
+    let cool_letter = &'g';
+    ('0'..='9').contains(cool_letter);
+    ('a'..='z').contains(cool_letter);
+    ('A'..='Z').contains(cool_letter);
 }
 
 #[clippy::msrv = "1.23"]
diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr b/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr
index 397cbe05c82..ee60188506d 100644
--- a/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr
+++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr
@@ -43,28 +43,82 @@ LL |     assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_alphabetic()`
 
 error: manual check for common ascii range
-  --> $DIR/manual_is_ascii_check.rs:29:13
+  --> $DIR/manual_is_ascii_check.rs:19:5
+   |
+LL |     (b'0'..=b'9').contains(&b'0');
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'0'.is_ascii_digit()`
+
+error: manual check for common ascii range
+  --> $DIR/manual_is_ascii_check.rs:20:5
+   |
+LL |     (b'a'..=b'z').contains(&b'a');
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'a'.is_ascii_lowercase()`
+
+error: manual check for common ascii range
+  --> $DIR/manual_is_ascii_check.rs:21:5
+   |
+LL |     (b'A'..=b'Z').contains(&b'A');
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'A'.is_ascii_uppercase()`
+
+error: manual check for common ascii range
+  --> $DIR/manual_is_ascii_check.rs:23:5
+   |
+LL |     ('0'..='9').contains(&'0');
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'0'.is_ascii_digit()`
+
+error: manual check for common ascii range
+  --> $DIR/manual_is_ascii_check.rs:24:5
+   |
+LL |     ('a'..='z').contains(&'a');
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'a'.is_ascii_lowercase()`
+
+error: manual check for common ascii range
+  --> $DIR/manual_is_ascii_check.rs:25:5
+   |
+LL |     ('A'..='Z').contains(&'A');
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'A'.is_ascii_uppercase()`
+
+error: manual check for common ascii range
+  --> $DIR/manual_is_ascii_check.rs:28:5
+   |
+LL |     ('0'..='9').contains(cool_letter);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_digit()`
+
+error: manual check for common ascii range
+  --> $DIR/manual_is_ascii_check.rs:29:5
+   |
+LL |     ('a'..='z').contains(cool_letter);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_lowercase()`
+
+error: manual check for common ascii range
+  --> $DIR/manual_is_ascii_check.rs:30:5
+   |
+LL |     ('A'..='Z').contains(cool_letter);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_uppercase()`
+
+error: manual check for common ascii range
+  --> $DIR/manual_is_ascii_check.rs:42:13
    |
 LL |     assert!(matches!(b'1', b'0'..=b'9'));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'1'.is_ascii_digit()`
 
 error: manual check for common ascii range
-  --> $DIR/manual_is_ascii_check.rs:30:13
+  --> $DIR/manual_is_ascii_check.rs:43:13
    |
 LL |     assert!(matches!('X', 'A'..='Z'));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'X'.is_ascii_uppercase()`
 
 error: manual check for common ascii range
-  --> $DIR/manual_is_ascii_check.rs:31:13
+  --> $DIR/manual_is_ascii_check.rs:44:13
    |
 LL |     assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_alphabetic()`
 
 error: manual check for common ascii range
-  --> $DIR/manual_is_ascii_check.rs:41:23
+  --> $DIR/manual_is_ascii_check.rs:54:23
    |
 LL |     const FOO: bool = matches!('x', '0'..='9');
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_digit()`
 
-error: aborting due to 11 previous errors
+error: aborting due to 20 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_let_else_match.rs b/src/tools/clippy/tests/ui/manual_let_else_match.rs
index 93c86ca24fe..28caed9d79d 100644
--- a/src/tools/clippy/tests/ui/manual_let_else_match.rs
+++ b/src/tools/clippy/tests/ui/manual_let_else_match.rs
@@ -64,6 +64,13 @@ fn fire() {
         Ok(v) => v,
         Err(()) => return,
     };
+
+    let f = Variant::Bar(1);
+
+    let _value = match f {
+        Variant::Bar(_) | Variant::Baz(_) => (),
+        _ => return,
+    };
 }
 
 fn not_fire() {
diff --git a/src/tools/clippy/tests/ui/manual_let_else_match.stderr b/src/tools/clippy/tests/ui/manual_let_else_match.stderr
index 38be5ac5454..cd5e9a9ac39 100644
--- a/src/tools/clippy/tests/ui/manual_let_else_match.stderr
+++ b/src/tools/clippy/tests/ui/manual_let_else_match.stderr
@@ -25,7 +25,7 @@ LL | /         let v = match h() {
 LL | |             (Some(_), Some(_)) | (None, None) => continue,
 LL | |             (Some(v), None) | (None, Some(v)) => v,
 LL | |         };
-   | |__________^ help: consider writing: `let (Some(v), None) | (None, Some(v)) = h() else { continue };`
+   | |__________^ help: consider writing: `let ((Some(v), None) | (None, Some(v))) = h() else { continue };`
 
 error: this could be rewritten as `let...else`
   --> $DIR/manual_let_else_match.rs:49:9
@@ -34,7 +34,7 @@ LL | /         let v = match build_enum() {
 LL | |             _ => continue,
 LL | |             Variant::Bar(v) | Variant::Baz(v) => v,
 LL | |         };
-   | |__________^ help: consider writing: `let Variant::Bar(v) | Variant::Baz(v) = build_enum() else { continue };`
+   | |__________^ help: consider writing: `let (Variant::Bar(v) | Variant::Baz(v)) = build_enum() else { continue };`
 
 error: this could be rewritten as `let...else`
   --> $DIR/manual_let_else_match.rs:57:5
@@ -54,5 +54,14 @@ LL | |         Err(()) => return,
 LL | |     };
    | |______^ help: consider writing: `let Ok(v) = f().map_err(|_| ()) else { return };`
 
-error: aborting due to 6 previous errors
+error: this could be rewritten as `let...else`
+  --> $DIR/manual_let_else_match.rs:70:5
+   |
+LL | /     let _value = match f {
+LL | |         Variant::Bar(_) | Variant::Baz(_) => (),
+LL | |         _ => return,
+LL | |     };
+   | |______^ help: consider writing: `let (Variant::Bar(_) | Variant::Baz(_)) = f else { return };`
+
+error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_parens_on_range_literals.fixed b/src/tools/clippy/tests/ui/needless_parens_on_range_literals.fixed
index 1bd75c806bc..f11330a8916 100644
--- a/src/tools/clippy/tests/ui/needless_parens_on_range_literals.fixed
+++ b/src/tools/clippy/tests/ui/needless_parens_on_range_literals.fixed
@@ -2,7 +2,7 @@
 // edition:2018
 
 #![warn(clippy::needless_parens_on_range_literals)]
-#![allow(clippy::almost_complete_letter_range)]
+#![allow(clippy::almost_complete_range)]
 
 fn main() {
     let _ = 'a'..='z';
diff --git a/src/tools/clippy/tests/ui/needless_parens_on_range_literals.rs b/src/tools/clippy/tests/ui/needless_parens_on_range_literals.rs
index 7abb8a1adc1..671c0009e23 100644
--- a/src/tools/clippy/tests/ui/needless_parens_on_range_literals.rs
+++ b/src/tools/clippy/tests/ui/needless_parens_on_range_literals.rs
@@ -2,7 +2,7 @@
 // edition:2018
 
 #![warn(clippy::needless_parens_on_range_literals)]
-#![allow(clippy::almost_complete_letter_range)]
+#![allow(clippy::almost_complete_range)]
 
 fn main() {
     let _ = ('a')..=('z');
diff --git a/src/tools/clippy/tests/ui/new_ret_no_self.rs b/src/tools/clippy/tests/ui/new_ret_no_self.rs
index f69982d63a8..beec42f08bb 100644
--- a/src/tools/clippy/tests/ui/new_ret_no_self.rs
+++ b/src/tools/clippy/tests/ui/new_ret_no_self.rs
@@ -1,3 +1,4 @@
+#![feature(type_alias_impl_trait)]
 #![warn(clippy::new_ret_no_self)]
 #![allow(dead_code)]
 
@@ -400,3 +401,25 @@ mod issue7344 {
         }
     }
 }
+
+mod issue10041 {
+    struct Bomb;
+
+    impl Bomb {
+        // Hidden <Rhs = Self> default generic paramter.
+        pub fn new() -> impl PartialOrd {
+            0i32
+        }
+    }
+
+    // TAIT with self-referencing bounds
+    type X = impl std::ops::Add<Output = X>;
+
+    struct Bomb2;
+
+    impl Bomb2 {
+        pub fn new() -> X {
+            0i32
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/new_ret_no_self.stderr b/src/tools/clippy/tests/ui/new_ret_no_self.stderr
index bc13be47927..2eaebfb5cac 100644
--- a/src/tools/clippy/tests/ui/new_ret_no_self.stderr
+++ b/src/tools/clippy/tests/ui/new_ret_no_self.stderr
@@ -1,5 +1,5 @@
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:49:5
+  --> $DIR/new_ret_no_self.rs:50:5
    |
 LL | /     pub fn new(_: String) -> impl R<Item = u32> {
 LL | |         S3
@@ -9,7 +9,7 @@ LL | |     }
    = note: `-D clippy::new-ret-no-self` implied by `-D warnings`
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:81:5
+  --> $DIR/new_ret_no_self.rs:82:5
    |
 LL | /     pub fn new() -> u32 {
 LL | |         unimplemented!();
@@ -17,7 +17,7 @@ LL | |     }
    | |_____^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:90:5
+  --> $DIR/new_ret_no_self.rs:91:5
    |
 LL | /     pub fn new(_: String) -> u32 {
 LL | |         unimplemented!();
@@ -25,7 +25,7 @@ LL | |     }
    | |_____^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:126:5
+  --> $DIR/new_ret_no_self.rs:127:5
    |
 LL | /     pub fn new() -> (u32, u32) {
 LL | |         unimplemented!();
@@ -33,7 +33,7 @@ LL | |     }
    | |_____^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:153:5
+  --> $DIR/new_ret_no_self.rs:154:5
    |
 LL | /     pub fn new() -> *mut V {
 LL | |         unimplemented!();
@@ -41,7 +41,7 @@ LL | |     }
    | |_____^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:171:5
+  --> $DIR/new_ret_no_self.rs:172:5
    |
 LL | /     pub fn new() -> Option<u32> {
 LL | |         unimplemented!();
@@ -49,19 +49,19 @@ LL | |     }
    | |_____^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:224:9
+  --> $DIR/new_ret_no_self.rs:225:9
    |
 LL |         fn new() -> String;
    |         ^^^^^^^^^^^^^^^^^^^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:236:9
+  --> $DIR/new_ret_no_self.rs:237:9
    |
 LL |         fn new(_: String) -> String;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:271:9
+  --> $DIR/new_ret_no_self.rs:272:9
    |
 LL | /         fn new() -> (u32, u32) {
 LL | |             unimplemented!();
@@ -69,7 +69,7 @@ LL | |         }
    | |_________^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:298:9
+  --> $DIR/new_ret_no_self.rs:299:9
    |
 LL | /         fn new() -> *mut V {
 LL | |             unimplemented!();
@@ -77,7 +77,7 @@ LL | |         }
    | |_________^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:368:9
+  --> $DIR/new_ret_no_self.rs:369:9
    |
 LL | /         fn new(t: T) -> impl Into<i32> {
 LL | |             1
@@ -85,12 +85,28 @@ LL | |         }
    | |_________^
 
 error: methods called `new` usually return `Self`
-  --> $DIR/new_ret_no_self.rs:389:9
+  --> $DIR/new_ret_no_self.rs:390:9
    |
 LL | /         fn new(t: T) -> impl Trait2<(), i32> {
 LL | |             unimplemented!()
 LL | |         }
    | |_________^
 
-error: aborting due to 12 previous errors
+error: methods called `new` usually return `Self`
+  --> $DIR/new_ret_no_self.rs:410:9
+   |
+LL | /         pub fn new() -> impl PartialOrd {
+LL | |             0i32
+LL | |         }
+   | |_________^
+
+error: methods called `new` usually return `Self`
+  --> $DIR/new_ret_no_self.rs:421:9
+   |
+LL | /         pub fn new() -> X {
+LL | |             0i32
+LL | |         }
+   | |_________^
+
+error: aborting due to 14 previous errors
 
diff --git a/src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed b/src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed
index 4c5846fe837..bca777a890c 100644
--- a/src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed
+++ b/src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed
@@ -39,8 +39,14 @@ static STATIC_VAR_TUPLE: &(u8, u8) = &(1, 2); // ERROR Consider removing 'static
 
 static STATIC_VAR_ARRAY: &[u8; 1] = b"T"; // ERROR Consider removing 'static.
 
+static mut STATIC_MUT_SLICE: &mut [u32] = &mut [0];
+
 fn main() {
     let false_positive: &'static str = "test";
+
+    unsafe {
+        STATIC_MUT_SLICE[0] = 0;
+    }
 }
 
 trait Bar {
diff --git a/src/tools/clippy/tests/ui/redundant_static_lifetimes.rs b/src/tools/clippy/tests/ui/redundant_static_lifetimes.rs
index 64a66be1a83..afe7644816d 100644
--- a/src/tools/clippy/tests/ui/redundant_static_lifetimes.rs
+++ b/src/tools/clippy/tests/ui/redundant_static_lifetimes.rs
@@ -39,8 +39,14 @@ static STATIC_VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing
 
 static STATIC_VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static.
 
+static mut STATIC_MUT_SLICE: &'static mut [u32] = &mut [0];
+
 fn main() {
     let false_positive: &'static str = "test";
+
+    unsafe {
+        STATIC_MUT_SLICE[0] = 0;
+    }
 }
 
 trait Bar {
diff --git a/src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr b/src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr
index 0938ebf783f..b2cbd2d9d01 100644
--- a/src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr
+++ b/src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr
@@ -97,10 +97,16 @@ LL | static STATIC_VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removin
    |                          -^^^^^^^-------- help: consider removing `'static`: `&[u8; 1]`
 
 error: statics have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:65:16
+  --> $DIR/redundant_static_lifetimes.rs:42:31
+   |
+LL | static mut STATIC_MUT_SLICE: &'static mut [u32] = &mut [0];
+   |                              -^^^^^^^---------- help: consider removing `'static`: `&mut [u32]`
+
+error: statics have by default a `'static` lifetime
+  --> $DIR/redundant_static_lifetimes.rs:71:16
    |
 LL |     static V: &'static u8 = &17;
    |               -^^^^^^^--- help: consider removing `'static`: `&u8`
 
-error: aborting due to 17 previous errors
+error: aborting due to 18 previous errors
 
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index 689928f0479..2f76b575296 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -4,6 +4,7 @@
 
 // run-rustfix
 
+#![allow(clippy::almost_complete_range)]
 #![allow(clippy::disallowed_names)]
 #![allow(clippy::blocks_in_if_conditions)]
 #![allow(clippy::box_collection)]
@@ -37,6 +38,7 @@
 #![allow(temporary_cstring_as_ptr)]
 #![allow(unknown_lints)]
 #![allow(unused_labels)]
+#![warn(clippy::almost_complete_range)]
 #![warn(clippy::disallowed_names)]
 #![warn(clippy::blocks_in_if_conditions)]
 #![warn(clippy::blocks_in_if_conditions)]
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index b74aa650ffd..699c0ff464e 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -4,6 +4,7 @@
 
 // run-rustfix
 
+#![allow(clippy::almost_complete_range)]
 #![allow(clippy::disallowed_names)]
 #![allow(clippy::blocks_in_if_conditions)]
 #![allow(clippy::box_collection)]
@@ -37,6 +38,7 @@
 #![allow(temporary_cstring_as_ptr)]
 #![allow(unknown_lints)]
 #![allow(unused_labels)]
+#![warn(clippy::almost_complete_letter_range)]
 #![warn(clippy::blacklisted_name)]
 #![warn(clippy::block_in_if_condition_expr)]
 #![warn(clippy::block_in_if_condition_stmt)]
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index 622a32c5908..9af58dc75a6 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -1,244 +1,250 @@
+error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
+  --> $DIR/rename.rs:41:9
+   |
+LL | #![warn(clippy::almost_complete_letter_range)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
+   |
+   = note: `-D renamed-and-removed-lints` implied by `-D warnings`
+
 error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
-  --> $DIR/rename.rs:40:9
+  --> $DIR/rename.rs:42:9
    |
 LL | #![warn(clippy::blacklisted_name)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
-   |
-   = note: `-D renamed-and-removed-lints` implied by `-D warnings`
 
 error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:41:9
+  --> $DIR/rename.rs:43:9
    |
 LL | #![warn(clippy::block_in_if_condition_expr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
 error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:42:9
+  --> $DIR/rename.rs:44:9
    |
 LL | #![warn(clippy::block_in_if_condition_stmt)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
 error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
-  --> $DIR/rename.rs:43:9
+  --> $DIR/rename.rs:45:9
    |
 LL | #![warn(clippy::box_vec)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
 
 error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
-  --> $DIR/rename.rs:44:9
+  --> $DIR/rename.rs:46:9
    |
 LL | #![warn(clippy::const_static_lifetime)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
 
 error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
-  --> $DIR/rename.rs:45:9
+  --> $DIR/rename.rs:47:9
    |
 LL | #![warn(clippy::cyclomatic_complexity)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
 
 error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
-  --> $DIR/rename.rs:46:9
+  --> $DIR/rename.rs:48:9
    |
 LL | #![warn(clippy::disallowed_method)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
 
 error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
-  --> $DIR/rename.rs:47:9
+  --> $DIR/rename.rs:49:9
    |
 LL | #![warn(clippy::disallowed_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
 
 error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
-  --> $DIR/rename.rs:48:9
+  --> $DIR/rename.rs:50:9
    |
 LL | #![warn(clippy::eval_order_dependence)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
 
 error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
-  --> $DIR/rename.rs:49:9
+  --> $DIR/rename.rs:51:9
    |
 LL | #![warn(clippy::identity_conversion)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
 
 error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
-  --> $DIR/rename.rs:50:9
+  --> $DIR/rename.rs:52:9
    |
 LL | #![warn(clippy::if_let_some_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
 
 error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
-  --> $DIR/rename.rs:51:9
+  --> $DIR/rename.rs:53:9
    |
 LL | #![warn(clippy::logic_bug)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
 
 error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
-  --> $DIR/rename.rs:52:9
+  --> $DIR/rename.rs:54:9
    |
 LL | #![warn(clippy::new_without_default_derive)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
 
 error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
-  --> $DIR/rename.rs:53:9
+  --> $DIR/rename.rs:55:9
    |
 LL | #![warn(clippy::option_and_then_some)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
 
 error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:54:9
+  --> $DIR/rename.rs:56:9
    |
 LL | #![warn(clippy::option_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:55:9
+  --> $DIR/rename.rs:57:9
    |
 LL | #![warn(clippy::option_map_unwrap_or)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:56:9
+  --> $DIR/rename.rs:58:9
    |
 LL | #![warn(clippy::option_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:57:9
+  --> $DIR/rename.rs:59:9
    |
 LL | #![warn(clippy::option_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
-  --> $DIR/rename.rs:58:9
+  --> $DIR/rename.rs:60:9
    |
 LL | #![warn(clippy::ref_in_deref)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
 
 error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:59:9
+  --> $DIR/rename.rs:61:9
    |
 LL | #![warn(clippy::result_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:60:9
+  --> $DIR/rename.rs:62:9
    |
 LL | #![warn(clippy::result_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:61:9
+  --> $DIR/rename.rs:63:9
    |
 LL | #![warn(clippy::result_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
-  --> $DIR/rename.rs:62:9
+  --> $DIR/rename.rs:64:9
    |
 LL | #![warn(clippy::single_char_push_str)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
 
 error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
-  --> $DIR/rename.rs:63:9
+  --> $DIR/rename.rs:65:9
    |
 LL | #![warn(clippy::stutter)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
 
 error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
-  --> $DIR/rename.rs:64:9
+  --> $DIR/rename.rs:66:9
    |
 LL | #![warn(clippy::to_string_in_display)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
 
 error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
-  --> $DIR/rename.rs:65:9
+  --> $DIR/rename.rs:67:9
    |
 LL | #![warn(clippy::zero_width_space)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
 
 error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
-  --> $DIR/rename.rs:66:9
+  --> $DIR/rename.rs:68:9
    |
 LL | #![warn(clippy::drop_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
 error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:67:9
+  --> $DIR/rename.rs:69:9
    |
 LL | #![warn(clippy::for_loop_over_option)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:68:9
+  --> $DIR/rename.rs:70:9
    |
 LL | #![warn(clippy::for_loop_over_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:69:9
+  --> $DIR/rename.rs:71:9
    |
 LL | #![warn(clippy::for_loops_over_fallibles)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> $DIR/rename.rs:70:9
+  --> $DIR/rename.rs:72:9
    |
 LL | #![warn(clippy::into_iter_on_array)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
 
 error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
-  --> $DIR/rename.rs:71:9
+  --> $DIR/rename.rs:73:9
    |
 LL | #![warn(clippy::invalid_atomic_ordering)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
 
 error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
-  --> $DIR/rename.rs:72:9
+  --> $DIR/rename.rs:74:9
    |
 LL | #![warn(clippy::invalid_ref)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
 error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
-  --> $DIR/rename.rs:73:9
+  --> $DIR/rename.rs:75:9
    |
 LL | #![warn(clippy::let_underscore_drop)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
 
 error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> $DIR/rename.rs:74:9
+  --> $DIR/rename.rs:76:9
    |
 LL | #![warn(clippy::mem_discriminant_non_enum)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
 error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
-  --> $DIR/rename.rs:75:9
+  --> $DIR/rename.rs:77:9
    |
 LL | #![warn(clippy::panic_params)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
 error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
-  --> $DIR/rename.rs:76:9
+  --> $DIR/rename.rs:78:9
    |
 LL | #![warn(clippy::positional_named_format_parameters)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
 
 error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
-  --> $DIR/rename.rs:77:9
+  --> $DIR/rename.rs:79:9
    |
 LL | #![warn(clippy::temporary_cstring_as_ptr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
 
 error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-  --> $DIR/rename.rs:78:9
+  --> $DIR/rename.rs:80:9
    |
 LL | #![warn(clippy::unknown_clippy_lints)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
 
 error: lint `clippy::unused_label` has been renamed to `unused_labels`
-  --> $DIR/rename.rs:79:9
+  --> $DIR/rename.rs:81:9
    |
 LL | #![warn(clippy::unused_label)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
 
-error: aborting due to 40 previous errors
+error: aborting due to 41 previous errors
 
diff --git a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.fixed b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.fixed
index 9d0d1124c46..713cff604a1 100644
--- a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.fixed
+++ b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.fixed
@@ -70,6 +70,12 @@ fn seek_to_end<T: Seek>(t: &mut T) {
     t.seek(SeekFrom::End(0));
 }
 
+// This should NOT trigger clippy warning because
+// expr is used here
+fn seek_to_start_in_let<T: Seek>(t: &mut T) {
+    let a = t.seek(SeekFrom::Start(0)).unwrap();
+}
+
 fn main() {
     let mut f = OpenOptions::new()
         .write(true)
diff --git a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs
index c5bc57cc3a7..467003a1a66 100644
--- a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs
+++ b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs
@@ -70,6 +70,12 @@ fn seek_to_end<T: Seek>(t: &mut T) {
     t.seek(SeekFrom::End(0));
 }
 
+// This should NOT trigger clippy warning because
+// expr is used here
+fn seek_to_start_in_let<T: Seek>(t: &mut T) {
+    let a = t.seek(SeekFrom::Start(0)).unwrap();
+}
+
 fn main() {
     let mut f = OpenOptions::new()
         .write(true)
diff --git a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.stderr b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.stderr
index 6cce025359f..342ec00fe72 100644
--- a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.stderr
+++ b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.stderr
@@ -13,7 +13,7 @@ LL |     t.seek(SeekFrom::Start(0));
    |       ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()`
 
 error: used `seek` to go to the start of the stream
-  --> $DIR/seek_to_start_instead_of_rewind.rs:128:7
+  --> $DIR/seek_to_start_instead_of_rewind.rs:134:7
    |
 LL |     f.seek(SeekFrom::Start(0));
    |       ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()`
diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block.fixed b/src/tools/clippy/tests/ui/semicolon_inside_block.fixed
new file mode 100644
index 00000000000..42e97e1ca35
--- /dev/null
+++ b/src/tools/clippy/tests/ui/semicolon_inside_block.fixed
@@ -0,0 +1,85 @@
+// run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_inside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block(); }
+    unsafe { unit_fn_block(); }
+
+    { unit_fn_block(); }
+    unsafe { unit_fn_block(); }
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()); }
+    { m!(()); }
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block.rs b/src/tools/clippy/tests/ui/semicolon_inside_block.rs
new file mode 100644
index 00000000000..f40848f702e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/semicolon_inside_block.rs
@@ -0,0 +1,85 @@
+// run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_inside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); }
+    unsafe { unit_fn_block(); }
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block()
+    };
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()); }
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block.stderr b/src/tools/clippy/tests/ui/semicolon_inside_block.stderr
new file mode 100644
index 00000000000..48d3690e2bd
--- /dev/null
+++ b/src/tools/clippy/tests/ui/semicolon_inside_block.stderr
@@ -0,0 +1,54 @@
+error: consider moving the `;` inside the block for consistent formatting
+  --> $DIR/semicolon_inside_block.rs:39:5
+   |
+LL |     { unit_fn_block() };
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::semicolon-inside-block` implied by `-D warnings`
+help: put the `;` here
+   |
+LL -     { unit_fn_block() };
+LL +     { unit_fn_block(); }
+   |
+
+error: consider moving the `;` inside the block for consistent formatting
+  --> $DIR/semicolon_inside_block.rs:40:5
+   |
+LL |     unsafe { unit_fn_block() };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: put the `;` here
+   |
+LL -     unsafe { unit_fn_block() };
+LL +     unsafe { unit_fn_block(); }
+   |
+
+error: consider moving the `;` inside the block for consistent formatting
+  --> $DIR/semicolon_inside_block.rs:48:5
+   |
+LL | /     {
+LL | |         unit_fn_block();
+LL | |         unit_fn_block()
+LL | |     };
+   | |______^
+   |
+help: put the `;` here
+   |
+LL ~         unit_fn_block();
+LL ~     }
+   |
+
+error: consider moving the `;` inside the block for consistent formatting
+  --> $DIR/semicolon_inside_block.rs:61:5
+   |
+LL |     { m!(()) };
+   |     ^^^^^^^^^^^
+   |
+help: put the `;` here
+   |
+LL -     { m!(()) };
+LL +     { m!(()); }
+   |
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/semicolon_outside_block.fixed b/src/tools/clippy/tests/ui/semicolon_outside_block.fixed
new file mode 100644
index 00000000000..091eaa7518e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/semicolon_outside_block.fixed
@@ -0,0 +1,85 @@
+// run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_outside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block()
+    };
+    {
+        unit_fn_block();
+        unit_fn_block()
+    };
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()) };
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/src/tools/clippy/tests/ui/semicolon_outside_block.rs b/src/tools/clippy/tests/ui/semicolon_outside_block.rs
new file mode 100644
index 00000000000..7ce46431fac
--- /dev/null
+++ b/src/tools/clippy/tests/ui/semicolon_outside_block.rs
@@ -0,0 +1,85 @@
+// run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_outside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); }
+    unsafe { unit_fn_block(); }
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block()
+    };
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()); }
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/src/tools/clippy/tests/ui/semicolon_outside_block.stderr b/src/tools/clippy/tests/ui/semicolon_outside_block.stderr
new file mode 100644
index 00000000000..dcc102e6099
--- /dev/null
+++ b/src/tools/clippy/tests/ui/semicolon_outside_block.stderr
@@ -0,0 +1,54 @@
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/semicolon_outside_block.rs:42:5
+   |
+LL |     { unit_fn_block(); }
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::semicolon-outside-block` implied by `-D warnings`
+help: put the `;` here
+   |
+LL -     { unit_fn_block(); }
+LL +     { unit_fn_block() };
+   |
+
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/semicolon_outside_block.rs:43:5
+   |
+LL |     unsafe { unit_fn_block(); }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: put the `;` here
+   |
+LL -     unsafe { unit_fn_block(); }
+LL +     unsafe { unit_fn_block() };
+   |
+
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/semicolon_outside_block.rs:52:5
+   |
+LL | /     {
+LL | |         unit_fn_block();
+LL | |         unit_fn_block();
+LL | |     }
+   | |_____^
+   |
+help: put the `;` here
+   |
+LL ~         unit_fn_block()
+LL ~     };
+   |
+
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/semicolon_outside_block.rs:62:5
+   |
+LL |     { m!(()); }
+   |     ^^^^^^^^^^^
+   |
+help: put the `;` here
+   |
+LL -     { m!(()); }
+LL +     { m!(()) };
+   |
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed b/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed
index df2256e4f97..506187fc125 100644
--- a/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed
+++ b/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed
@@ -25,6 +25,12 @@ fn str_lit_as_bytes() {
     let includestr = include_bytes!("string_lit_as_bytes.rs");
 
     let _ = b"string with newline\t\n";
+
+    let _ = match "x".as_bytes() {
+        b"xx" => 0,
+        [b'x', ..] => 1,
+        _ => 2,
+    };
 }
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/string_lit_as_bytes.rs b/src/tools/clippy/tests/ui/string_lit_as_bytes.rs
index c6bf8f732ed..2c339f1ddb8 100644
--- a/src/tools/clippy/tests/ui/string_lit_as_bytes.rs
+++ b/src/tools/clippy/tests/ui/string_lit_as_bytes.rs
@@ -25,6 +25,12 @@ fn str_lit_as_bytes() {
     let includestr = include_str!("string_lit_as_bytes.rs").as_bytes();
 
     let _ = "string with newline\t\n".as_bytes();
+
+    let _ = match "x".as_bytes() {
+        b"xx" => 0,
+        [b'x', ..] => 1,
+        _ => 2,
+    };
 }
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.fixed b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.fixed
index 96cc0877960..52b5343c351 100644
--- a/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.fixed
+++ b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.fixed
@@ -26,4 +26,7 @@ fn main() {
             panic!("p4 {var}");
         }
     }
+
+    assert!(var == 1, "p5 {}", var);
+    debug_assert!(var == 1, "p6 {}", var);
 }
diff --git a/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.fixed b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.fixed
index faf8ca4d3a7..ee72065e28a 100644
--- a/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.fixed
+++ b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.fixed
@@ -26,4 +26,7 @@ fn main() {
             panic!("p4 {var}");
         }
     }
+
+    assert!(var == 1, "p5 {var}");
+    debug_assert!(var == 1, "p6 {var}");
 }
diff --git a/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.stderr b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.stderr
index 0f09c45f413..fc7b125080e 100644
--- a/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.stderr
+++ b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.stderr
@@ -47,5 +47,29 @@ LL -         panic!("p3 {var}", var = var);
 LL +         panic!("p3 {var}");
    |
 
-error: aborting due to 4 previous errors
+error: variables can be used directly in the `format!` string
+  --> $DIR/uninlined_format_args_panic.rs:30:5
+   |
+LL |     assert!(var == 1, "p5 {}", var);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: change this to
+   |
+LL -     assert!(var == 1, "p5 {}", var);
+LL +     assert!(var == 1, "p5 {var}");
+   |
+
+error: variables can be used directly in the `format!` string
+  --> $DIR/uninlined_format_args_panic.rs:31:5
+   |
+LL |     debug_assert!(var == 1, "p6 {}", var);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: change this to
+   |
+LL -     debug_assert!(var == 1, "p6 {}", var);
+LL +     debug_assert!(var == 1, "p6 {var}");
+   |
+
+error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui/uninlined_format_args_panic.rs b/src/tools/clippy/tests/ui/uninlined_format_args_panic.rs
index 6421c5bbed2..b4a0a0f496e 100644
--- a/src/tools/clippy/tests/ui/uninlined_format_args_panic.rs
+++ b/src/tools/clippy/tests/ui/uninlined_format_args_panic.rs
@@ -26,4 +26,7 @@ fn main() {
             panic!("p4 {var}");
         }
     }
+
+    assert!(var == 1, "p5 {}", var);
+    debug_assert!(var == 1, "p6 {}", var);
 }
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
index ddeda795f81..345f6d604c4 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
@@ -454,3 +454,23 @@ mod issue_9771b {
         Key(v.to_vec())
     }
 }
+
+// This is a watered down version of the code in: https://github.com/oxigraph/rio
+// The ICE is triggered by the call to `to_owned` on this line:
+// https://github.com/oxigraph/rio/blob/66635b9ff8e5423e58932353fa40d6e64e4820f7/testsuite/src/parser_evaluator.rs#L116
+mod issue_10021 {
+    #![allow(unused)]
+
+    pub struct Iri<T>(T);
+
+    impl<T: AsRef<str>> Iri<T> {
+        pub fn parse(iri: T) -> Result<Self, ()> {
+            unimplemented!()
+        }
+    }
+
+    pub fn parse_w3c_rdf_test_file(url: &str) -> Result<(), ()> {
+        let base_iri = Iri::parse(url.to_owned())?;
+        Ok(())
+    }
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
index 95d2576733c..7eb53df39e5 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
@@ -454,3 +454,23 @@ mod issue_9771b {
         Key(v.to_vec())
     }
 }
+
+// This is a watered down version of the code in: https://github.com/oxigraph/rio
+// The ICE is triggered by the call to `to_owned` on this line:
+// https://github.com/oxigraph/rio/blob/66635b9ff8e5423e58932353fa40d6e64e4820f7/testsuite/src/parser_evaluator.rs#L116
+mod issue_10021 {
+    #![allow(unused)]
+
+    pub struct Iri<T>(T);
+
+    impl<T: AsRef<str>> Iri<T> {
+        pub fn parse(iri: T) -> Result<Self, ()> {
+            unimplemented!()
+        }
+    }
+
+    pub fn parse_w3c_rdf_test_file(url: &str) -> Result<(), ()> {
+        let base_iri = Iri::parse(url.to_owned())?;
+        Ok(())
+    }
+}
diff --git a/src/tools/clippy/tests/ui/zero_ptr_no_std.fixed b/src/tools/clippy/tests/ui/zero_ptr_no_std.fixed
new file mode 100644
index 00000000000..8906c776977
--- /dev/null
+++ b/src/tools/clippy/tests/ui/zero_ptr_no_std.fixed
@@ -0,0 +1,21 @@
+// run-rustfix
+
+#![feature(lang_items, start, libc)]
+#![no_std]
+#![deny(clippy::zero_ptr)]
+
+#[start]
+fn main(_argc: isize, _argv: *const *const u8) -> isize {
+    let _ = core::ptr::null::<usize>();
+    let _ = core::ptr::null_mut::<f64>();
+    let _: *const u8 = core::ptr::null();
+    0
+}
+
+#[panic_handler]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+    loop {}
+}
+
+#[lang = "eh_personality"]
+extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/zero_ptr_no_std.rs b/src/tools/clippy/tests/ui/zero_ptr_no_std.rs
new file mode 100644
index 00000000000..379c1b18d29
--- /dev/null
+++ b/src/tools/clippy/tests/ui/zero_ptr_no_std.rs
@@ -0,0 +1,21 @@
+// run-rustfix
+
+#![feature(lang_items, start, libc)]
+#![no_std]
+#![deny(clippy::zero_ptr)]
+
+#[start]
+fn main(_argc: isize, _argv: *const *const u8) -> isize {
+    let _ = 0 as *const usize;
+    let _ = 0 as *mut f64;
+    let _: *const u8 = 0 as *const _;
+    0
+}
+
+#[panic_handler]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+    loop {}
+}
+
+#[lang = "eh_personality"]
+extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/zero_ptr_no_std.stderr b/src/tools/clippy/tests/ui/zero_ptr_no_std.stderr
new file mode 100644
index 00000000000..d92bb4a6528
--- /dev/null
+++ b/src/tools/clippy/tests/ui/zero_ptr_no_std.stderr
@@ -0,0 +1,26 @@
+error: `0 as *const _` detected
+  --> $DIR/zero_ptr_no_std.rs:9:13
+   |
+LL |     let _ = 0 as *const usize;
+   |             ^^^^^^^^^^^^^^^^^ help: try: `core::ptr::null::<usize>()`
+   |
+note: the lint level is defined here
+  --> $DIR/zero_ptr_no_std.rs:5:9
+   |
+LL | #![deny(clippy::zero_ptr)]
+   |         ^^^^^^^^^^^^^^^^
+
+error: `0 as *mut _` detected
+  --> $DIR/zero_ptr_no_std.rs:10:13
+   |
+LL |     let _ = 0 as *mut f64;
+   |             ^^^^^^^^^^^^^ help: try: `core::ptr::null_mut::<f64>()`
+
+error: `0 as *const _` detected
+  --> $DIR/zero_ptr_no_std.rs:11:24
+   |
+LL |     let _: *const u8 = 0 as *const _;
+   |                        ^^^^^^^^^^^^^ help: try: `core::ptr::null()`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/versioncheck.rs b/src/tools/clippy/tests/versioncheck.rs
index 7a85386a3df..c721e9969c9 100644
--- a/src/tools/clippy/tests/versioncheck.rs
+++ b/src/tools/clippy/tests/versioncheck.rs
@@ -2,7 +2,6 @@
 #![warn(rust_2018_idioms, unused_lifetimes)]
 #![allow(clippy::single_match_else)]
 
-use rustc_tools_util::VersionInfo;
 use std::fs;
 
 #[test]
diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml
index acb476ee696..6f50ef932e1 100644
--- a/src/tools/clippy/triagebot.toml
+++ b/src/tools/clippy/triagebot.toml
@@ -1,7 +1,7 @@
 [relabel]
 allow-unauthenticated = [
     "A-*", "C-*", "E-*", "I-*", "L-*", "P-*", "S-*", "T-*",
-    "good-first-issue"
+    "good-first-issue", "beta-nominated"
 ]
 
 # Allows shortcuts like `@rustbot ready`
diff --git a/src/tools/remote-test-server/src/main.rs b/src/tools/remote-test-server/src/main.rs
index 8e7c39e72b6..c1450aedc31 100644
--- a/src/tools/remote-test-server/src/main.rs
+++ b/src/tools/remote-test-server/src/main.rs
@@ -46,6 +46,7 @@ const NUMBER_OF_RETRIES: usize = 5;
 struct Config {
     verbose: bool,
     sequential: bool,
+    batch: bool,
     bind: SocketAddr,
 }
 
@@ -54,6 +55,7 @@ impl Config {
         Config {
             verbose: false,
             sequential: false,
+            batch: false,
             bind: if cfg!(target_os = "android") || cfg!(windows) {
                 ([0, 0, 0, 0], 12345).into()
             } else {
@@ -75,6 +77,7 @@ impl Config {
                 }
                 "--bind" => next_is_bind = true,
                 "--sequential" => config.sequential = true,
+                "--batch" => config.batch = true,
                 "--verbose" | "-v" => config.verbose = true,
                 "--help" | "-h" => {
                     show_help();
@@ -100,6 +103,7 @@ fn show_help() {
 OPTIONS:
     --bind <IP>:<PORT>   Specify IP address and port to listen for requests, e.g. "0.0.0.0:12345"
     --sequential         Run only one test at a time
+    --batch              Send stdout and stderr in batch instead of streaming
     -v, --verbose        Show status messages
     -h, --help           Show this help screen
 "#,
@@ -280,22 +284,30 @@ fn handle_run(socket: TcpStream, work: &Path, tmp: &Path, lock: &Mutex<()>, conf
     // Some tests assume RUST_TEST_TMPDIR exists
     cmd.env("RUST_TEST_TMPDIR", tmp.to_owned());
 
-    // Spawn the child and ferry over stdout/stderr to the socket in a framed
-    // fashion (poor man's style)
-    let mut child =
-        t!(cmd.stdin(Stdio::null()).stdout(Stdio::piped()).stderr(Stdio::piped()).spawn());
-    drop(lock);
-    let mut stdout = child.stdout.take().unwrap();
-    let mut stderr = child.stderr.take().unwrap();
     let socket = Arc::new(Mutex::new(reader.into_inner()));
-    let socket2 = socket.clone();
-    let thread = thread::spawn(move || my_copy(&mut stdout, 0, &*socket2));
-    my_copy(&mut stderr, 1, &*socket);
-    thread.join().unwrap();
 
-    // Finally send over the exit status.
-    let status = t!(child.wait());
+    let status = if config.batch {
+        let child =
+            t!(cmd.stdin(Stdio::null()).stdout(Stdio::piped()).stderr(Stdio::piped()).output());
+        batch_copy(&child.stdout, 0, &*socket);
+        batch_copy(&child.stderr, 1, &*socket);
+        child.status
+    } else {
+        // Spawn the child and ferry over stdout/stderr to the socket in a framed
+        // fashion (poor man's style)
+        let mut child =
+            t!(cmd.stdin(Stdio::null()).stdout(Stdio::piped()).stderr(Stdio::piped()).spawn());
+        drop(lock);
+        let mut stdout = child.stdout.take().unwrap();
+        let mut stderr = child.stderr.take().unwrap();
+        let socket2 = socket.clone();
+        let thread = thread::spawn(move || my_copy(&mut stdout, 0, &*socket2));
+        my_copy(&mut stderr, 1, &*socket);
+        thread.join().unwrap();
+        t!(child.wait())
+    };
 
+    // Finally send over the exit status.
     let (which, code) = get_status_code(&status);
 
     t!(socket.lock().unwrap().write_all(&[
@@ -368,6 +380,17 @@ fn my_copy(src: &mut dyn Read, which: u8, dst: &Mutex<dyn Write>) {
     }
 }
 
+fn batch_copy(buf: &[u8], which: u8, dst: &Mutex<dyn Write>) {
+    let n = buf.len();
+    let mut dst = dst.lock().unwrap();
+    t!(dst.write_all(&[which, (n >> 24) as u8, (n >> 16) as u8, (n >> 8) as u8, (n >> 0) as u8,]));
+    if n > 0 {
+        t!(dst.write_all(buf));
+        // Marking buf finished
+        t!(dst.write_all(&[which, 0, 0, 0, 0,]));
+    }
+}
+
 fn read_u32(r: &mut dyn Read) -> u32 {
     let mut len = [0; 4];
     t!(r.read_exact(&mut len));
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index b0b11cafca5..6714c63ee62 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -35,15 +35,26 @@ fn main() {
 
     let bad = std::sync::Arc::new(AtomicBool::new(false));
 
+    let drain_handles = |handles: &mut VecDeque<ScopedJoinHandle<'_, ()>>| {
+        // poll all threads for completion before awaiting the oldest one
+        for i in (0..handles.len()).rev() {
+            if handles[i].is_finished() {
+                handles.swap_remove_back(i).unwrap().join().unwrap();
+            }
+        }
+
+        while handles.len() >= concurrency.get() {
+            handles.pop_front().unwrap().join().unwrap();
+        }
+    };
+
     scope(|s| {
         let mut handles: VecDeque<ScopedJoinHandle<'_, ()>> =
             VecDeque::with_capacity(concurrency.get());
 
         macro_rules! check {
             ($p:ident $(, $args:expr)* ) => {
-                while handles.len() >= concurrency.get() {
-                    handles.pop_front().unwrap().join().unwrap();
-                }
+                drain_handles(&mut handles);
 
                 let handle = s.spawn(|| {
                     let mut flag = false;
@@ -97,9 +108,8 @@ fn main() {
         check!(alphabetical, &library_path);
 
         let collected = {
-            while handles.len() >= concurrency.get() {
-                handles.pop_front().unwrap().join().unwrap();
-            }
+            drain_handles(&mut handles);
+
             let mut flag = false;
             let r = features::check(&src_path, &compiler_path, &library_path, &mut flag, verbose);
             if flag {
diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs
index e3a094caf91..f91e38262f6 100644
--- a/src/tools/tidy/src/style.rs
+++ b/src/tools/tidy/src/style.rs
@@ -17,7 +17,7 @@
 //! `// ignore-tidy-CHECK-NAME`.
 
 use crate::walk::{filter_dirs, walk};
-use regex::Regex;
+use regex::{Regex, RegexSet};
 use std::path::Path;
 
 /// Error code markdown is restricted to 80 columns because they can be
@@ -225,6 +225,7 @@ pub fn check(path: &Path, bad: &mut bool) {
         .chain(PROBLEMATIC_CONSTS.iter().map(|v| format!("{:x}", v)))
         .chain(PROBLEMATIC_CONSTS.iter().map(|v| format!("{:X}", v)))
         .collect();
+    let problematic_regex = RegexSet::new(problematic_consts_strings.as_slice()).unwrap();
     walk(path, &mut skip, &mut |entry, contents| {
         let file = entry.path();
         let filename = file.file_name().unwrap().to_string_lossy();
@@ -281,7 +282,27 @@ pub fn check(path: &Path, bad: &mut bool) {
         let mut trailing_new_lines = 0;
         let mut lines = 0;
         let mut last_safety_comment = false;
+        let is_test = file.components().any(|c| c.as_os_str() == "tests");
+        // scanning the whole file for multiple needles at once is more efficient than
+        // executing lines times needles separate searches.
+        let any_problematic_line = problematic_regex.is_match(contents);
         for (i, line) in contents.split('\n').enumerate() {
+            if line.is_empty() {
+                if i == 0 {
+                    leading_new_lines = true;
+                }
+                trailing_new_lines += 1;
+                continue;
+            } else {
+                trailing_new_lines = 0;
+            }
+
+            let trimmed = line.trim();
+
+            if !trimmed.starts_with("//") {
+                lines += 1;
+            }
+
             let mut err = |msg: &str| {
                 tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg);
             };
@@ -308,28 +329,29 @@ pub fn check(path: &Path, bad: &mut bool) {
                 suppressible_tidy_err!(err, skip_cr, "CR character");
             }
             if filename != "style.rs" {
-                if line.contains("TODO") {
+                if trimmed.contains("TODO") {
                     err("TODO is deprecated; use FIXME")
                 }
-                if line.contains("//") && line.contains(" XXX") {
+                if trimmed.contains("//") && trimmed.contains(" XXX") {
                     err("XXX is deprecated; use FIXME")
                 }
-                for s in problematic_consts_strings.iter() {
-                    if line.contains(s) {
-                        err("Don't use magic numbers that spell things (consider 0x12345678)");
+                if any_problematic_line {
+                    for s in problematic_consts_strings.iter() {
+                        if trimmed.contains(s) {
+                            err("Don't use magic numbers that spell things (consider 0x12345678)");
+                        }
                     }
                 }
             }
-            let is_test = || file.components().any(|c| c.as_os_str() == "tests");
             // for now we just check libcore
-            if line.contains("unsafe {") && !line.trim().starts_with("//") && !last_safety_comment {
-                if file.components().any(|c| c.as_os_str() == "core") && !is_test() {
+            if trimmed.contains("unsafe {") && !trimmed.starts_with("//") && !last_safety_comment {
+                if file.components().any(|c| c.as_os_str() == "core") && !is_test {
                     suppressible_tidy_err!(err, skip_undocumented_unsafe, "undocumented unsafe");
                 }
             }
-            if line.contains("// SAFETY:") {
+            if trimmed.contains("// SAFETY:") {
                 last_safety_comment = true;
-            } else if line.trim().starts_with("//") || line.trim().is_empty() {
+            } else if trimmed.starts_with("//") || trimmed.is_empty() {
                 // keep previous value
             } else {
                 last_safety_comment = false;
@@ -337,7 +359,8 @@ pub fn check(path: &Path, bad: &mut bool) {
             if (line.starts_with("// Copyright")
                 || line.starts_with("# Copyright")
                 || line.starts_with("Copyright"))
-                && (line.contains("Rust Developers") || line.contains("Rust Project Developers"))
+                && (trimmed.contains("Rust Developers")
+                    || trimmed.contains("Rust Project Developers"))
             {
                 suppressible_tidy_err!(
                     err,
@@ -351,18 +374,6 @@ pub fn check(path: &Path, bad: &mut bool) {
             if filename.ends_with(".cpp") && line.contains("llvm_unreachable") {
                 err(LLVM_UNREACHABLE_INFO);
             }
-            if line.is_empty() {
-                if i == 0 {
-                    leading_new_lines = true;
-                }
-                trailing_new_lines += 1;
-            } else {
-                trailing_new_lines = 0;
-            }
-
-            if !line.trim().starts_with("//") {
-                lines += 1;
-            }
         }
         if leading_new_lines {
             let mut err = |_| {
diff --git a/src/tools/x/src/main.rs b/src/tools/x/src/main.rs
index 02c364dabf9..f07ff43efe9 100644
--- a/src/tools/x/src/main.rs
+++ b/src/tools/x/src/main.rs
@@ -1,51 +1,43 @@
-//! Run `x.py` from any subdirectory of a rust compiler checkout.
+//! Run bootstrap from any subdirectory of a rust compiler checkout.
 //!
 //! We prefer `exec`, to avoid adding an extra process in the process tree.
 //! However, since `exec` isn't available on Windows, we indirect through
 //! `exec_or_status`, which will call `exec` on unix and `status` on Windows.
 //!
-//! We use `python`, `python3`, or `python2` as the python interpreter to run
-//! `x.py`, in that order of preference.
+//! We use `powershell.exe x.ps1` on Windows, and `sh -c x` on Unix, those are
+//! the ones that call `x.py`. We use `sh -c` on Unix, because it is a standard.
+//! We also don't use `pwsh` on Windows, because it is not installed by default;
 
 use std::{
-    env::{self, consts::EXE_EXTENSION},
-    io,
+    env, io,
+    path::Path,
     process::{self, Command, ExitStatus},
 };
 
-const PYTHON: &str = "python";
-const PYTHON2: &str = "python2";
-const PYTHON3: &str = "python3";
-
-fn python() -> &'static str {
-    let val = match env::var_os("PATH") {
-        Some(val) => val,
-        None => return PYTHON,
-    };
-
-    let mut python2 = false;
-    let mut python3 = false;
-
-    for dir in env::split_paths(&val) {
-        // `python` should always take precedence over python2 / python3 if it exists
-        if dir.join(PYTHON).with_extension(EXE_EXTENSION).exists() {
-            return PYTHON;
-        }
+#[cfg(windows)]
+fn x_command(dir: &Path) -> Command {
+    let mut cmd = Command::new("powershell.exe");
+    cmd.args([
+        "-NoLogo",
+        "-NoProfile",
+        "-NonInteractive",
+        "-ExecutionPolicy",
+        "RemoteSigned",
+        "-Command",
+        "./x.ps1",
+    ])
+    .current_dir(dir);
+    cmd
+}
 
-        python2 |= dir.join(PYTHON2).with_extension(EXE_EXTENSION).exists();
-        python3 |= dir.join(PYTHON3).with_extension(EXE_EXTENSION).exists();
-    }
+#[cfg(unix)]
+fn x_command(dir: &Path) -> Command {
+    Command::new(dir.join("x"))
+}
 
-    // try 3 before 2
-    if python3 {
-        PYTHON3
-    } else if python2 {
-        PYTHON2
-    } else {
-        // Python was not found on path, so exit
-        eprintln!("Unable to find python in your PATH. Please check it is installed.");
-        process::exit(1);
-    }
+#[cfg(not(any(windows, unix)))]
+fn x_command(_dir: &Path) -> Command {
+    compile_error!("Unsupported platform");
 }
 
 #[cfg(unix)]
@@ -72,15 +64,15 @@ fn main() {
         let candidate = dir.join("x.py");
 
         if candidate.exists() {
-            let mut python = Command::new(python());
+            let mut cmd = x_command(dir);
 
-            python.arg(&candidate).args(env::args().skip(1)).current_dir(dir);
+            cmd.args(env::args().skip(1)).current_dir(dir);
 
-            let result = exec_or_status(&mut python);
+            let result = exec_or_status(&mut cmd);
 
             match result {
                 Err(error) => {
-                    eprintln!("Failed to invoke `{}`: {}", candidate.display(), error);
+                    eprintln!("Failed to invoke `{:?}`: {}", cmd, error);
                 }
                 Ok(status) => {
                     process::exit(status.code().unwrap_or(1));