about summary refs log tree commit diff
path: root/src/tools
diff options
context:
space:
mode:
authorThe rustc-dev-guide Cronjob Bot <github-actions@github.com>2025-02-10 04:02:38 +0000
committerThe rustc-dev-guide Cronjob Bot <github-actions@github.com>2025-02-10 04:02:38 +0000
commit81f21f0cce8be1e4dd1c8f4b9c6d0434029a13be (patch)
tree2d6f32e88ad42b1ced7529c15488473bfe8b2abd /src/tools
parentc2ff52afbd2bbc53e5f83fbce034c805c2c1b3f6 (diff)
parent124cc92199ffa924f6b4c7cc819a85b65e0c3984 (diff)
downloadrust-81f21f0cce8be1e4dd1c8f4b9c6d0434029a13be.tar.gz
rust-81f21f0cce8be1e4dd1c8f4b9c6d0434029a13be.zip
Merge from rustc
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/build-manifest/src/main.rs13
-rw-r--r--src/tools/bump-stage0/src/main.rs2
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/CHANGELOG.md4
-rw-r--r--src/tools/clippy/book/src/attribs.md2
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md1
-rw-r--r--src/tools/clippy/book/src/lints.md13
-rw-r--r--src/tools/clippy/clippy_config/src/conf.rs1
-rw-r--r--src/tools/clippy/clippy_dev/src/new_lint.rs28
-rw-r--r--src/tools/clippy/clippy_dev/src/update_lints.rs28
-rw-r--r--src/tools/clippy/clippy_lints/src/approx_const.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs67
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/empty_line_after.rs342
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/mod.rs81
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/empty_line_after.rs492
-rw-r--r--src/tools/clippy/clippy_lints/src/endian_bytes.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/escape.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/excessive_bools.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/excessive_nesting.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/format_push_string.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_to_string.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/large_futures.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/large_stack_arrays.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_slice_fill.rs111
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mod.rs28
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_div_ceil.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs225
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs34
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs71
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_option_take.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/return_and_then.rs67
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs68
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/misc.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/mutex_atomic.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/mod.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/precedence.rs68
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs36
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_clone.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_else.rs46
-rw-r--r--src/tools/clippy/clippy_lints/src/same_name_method.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/to_digit_is_some.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/types/mod.rs64
-rw-r--r--src/tools/clippy/clippy_lints/src/types/type_complexity.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unconditional_recursion.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_semicolon.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/unneeded_struct_pattern.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/attr_collector.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs2
-rw-r--r--src/tools/clippy/clippy_utils/README.md2
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils/mod.rs20
-rw-r--r--src/tools/clippy/clippy_utils/src/check_proc_macro.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs9
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs20
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs13
-rw-r--r--src/tools/clippy/clippy_utils/src/macros.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/mod.rs12
-rw-r--r--src/tools/clippy/clippy_utils/src/msrvs.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/source.rs22
-rw-r--r--src/tools/clippy/clippy_utils/src/str_utils.rs10
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/mod.rs2
-rw-r--r--src/tools/clippy/lintcheck/src/config.rs9
-rw-r--r--src/tools/clippy/lintcheck/src/main.rs53
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/tests/ui/cmp_null.fixed32
-rw-r--r--src/tools/clippy/tests/ui/cmp_null.rs12
-rw-r--r--src/tools/clippy/tests/ui/cmp_null.stderr26
-rw-r--r--src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs16
-rw-r--r--src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr14
-rw-r--r--src/tools/clippy/tests/ui/empty_line_after/doc_comments.1.fixed9
-rw-r--r--src/tools/clippy/tests/ui/empty_line_after/doc_comments.2.fixed9
-rw-r--r--src/tools/clippy/tests/ui/empty_line_after/doc_comments.rs10
-rw-r--r--src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr51
-rw-r--r--src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr30
-rw-r--r--src/tools/clippy/tests/ui/eta.fixed5
-rw-r--r--src/tools/clippy/tests/ui/eta.rs5
-rw-r--r--src/tools/clippy/tests/ui/eta.stderr54
-rw-r--r--src/tools/clippy/tests/ui/ignored_unit_patterns.fixed15
-rw-r--r--src/tools/clippy/tests/ui/ignored_unit_patterns.rs15
-rw-r--r--src/tools/clippy/tests/ui/ignored_unit_patterns.stderr18
-rw-r--r--src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.rs7
-rw-r--r--src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.stderr36
-rw-r--r--src/tools/clippy/tests/ui/manual_option_as_slice.fixed62
-rw-r--r--src/tools/clippy/tests/ui/manual_option_as_slice.rs71
-rw-r--r--src/tools/clippy/tests/ui/manual_option_as_slice.stderr58
-rw-r--r--src/tools/clippy/tests/ui/manual_slice_fill.fixed101
-rw-r--r--src/tools/clippy/tests/ui/manual_slice_fill.rs110
-rw-r--r--src/tools/clippy/tests/ui/manual_slice_fill.stderr38
-rw-r--r--src/tools/clippy/tests/ui/manual_unwrap_or_default_unfixable.rs15
-rw-r--r--src/tools/clippy/tests/ui/manual_unwrap_or_default_unfixable.stderr34
-rw-r--r--src/tools/clippy/tests/ui/needless_option_take.fixed58
-rw-r--r--src/tools/clippy/tests/ui/needless_option_take.stderr36
-rw-r--r--src/tools/clippy/tests/ui/needless_range_loop.rs3
-rw-r--r--src/tools/clippy/tests/ui/needless_range_loop.stderr28
-rw-r--r--src/tools/clippy/tests/ui/precedence.fixed8
-rw-r--r--src/tools/clippy/tests/ui/precedence.stderr26
-rw-r--r--src/tools/clippy/tests/ui/precedence_bits.fixed35
-rw-r--r--src/tools/clippy/tests/ui/precedence_bits.rs35
-rw-r--r--src/tools/clippy/tests/ui/precedence_bits.stderr29
-rw-r--r--src/tools/clippy/tests/ui/print_literal.fixed14
-rw-r--r--src/tools/clippy/tests/ui/print_literal.rs15
-rw-r--r--src/tools/clippy/tests/ui/print_literal.stderr38
-rw-r--r--src/tools/clippy/tests/ui/redundant_else.fixed154
-rw-r--r--src/tools/clippy/tests/ui/redundant_else.stderr77
-rw-r--r--src/tools/clippy/tests/ui/return_and_then.fixed67
-rw-r--r--src/tools/clippy/tests/ui/return_and_then.rs63
-rw-r--r--src/tools/clippy/tests/ui/return_and_then.stderr101
-rw-r--r--src/tools/clippy/tests/ui/size_of_in_element_count/expressions.rs17
-rw-r--r--src/tools/clippy/tests/ui/size_of_in_element_count/expressions.stderr12
-rw-r--r--src/tools/clippy/tests/ui/size_of_in_element_count/functions.rs43
-rw-r--r--src/tools/clippy/tests/ui/size_of_in_element_count/functions.stderr110
-rw-r--r--src/tools/clippy/tests/ui/suspicious_doc_comments.fixed1
-rw-r--r--src/tools/clippy/tests/ui/suspicious_doc_comments.rs1
-rw-r--r--src/tools/clippy/tests/ui/suspicious_doc_comments.stderr18
-rw-r--r--src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr4
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.fixed6
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.fixed6
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_semicolon.rs6
-rw-r--r--src/tools/clippy/tests/ui/write_literal.fixed16
-rw-r--r--src/tools/clippy/tests/ui/write_literal.rs17
-rw-r--r--src/tools/clippy/tests/ui/write_literal.stderr38
-rw-r--r--src/tools/clippy/util/gh-pages/index_template.html23
-rw-r--r--src/tools/clippy/util/gh-pages/script.js87
-rw-r--r--src/tools/clippy/util/gh-pages/style.css8
-rw-r--r--src/tools/clippy/util/gh-pages/theme.js9
-rw-r--r--src/tools/compiletest/src/header.rs8
-rw-r--r--src/tools/compiletest/src/header/tests.rs7
-rw-r--r--src/tools/compiletest/src/runtest.rs4
-rw-r--r--src/tools/compiletest/src/runtest/rustdoc_json.rs3
-rw-r--r--src/tools/coverage-dump/src/covfun.rs11
-rw-r--r--src/tools/features-status-dump/Cargo.toml12
-rw-r--r--src/tools/features-status-dump/src/main.rs53
-rw-r--r--src/tools/generate-copyright/src/cargo_metadata.rs15
-rw-r--r--src/tools/generate-copyright/src/main.rs10
-rw-r--r--src/tools/jsondoclint/src/validator/tests.rs327
-rw-r--r--src/tools/lint-docs/src/lib.rs42
-rw-r--r--src/tools/miri/src/bin/miri.rs5
-rw-r--r--src/tools/miri/src/lib.rs2
-rw-r--r--src/tools/miri/src/machine.rs5
-rw-r--r--src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs3
-rw-r--r--src/tools/miri/tests/fail/intrinsics/disjoint_bitor.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/disjoint_bitor.stderr15
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.rs5
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.stderr15
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs2
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.rs7
-rw-r--r--src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.stderr15
-rw-r--r--src/tools/miri/tests/pass/binops.rs30
-rw-r--r--src/tools/miri/tests/pass/box-custom-alloc.rs3
-rw-r--r--src/tools/miri/tests/pass/dyn-upcast.rs3
-rwxr-xr-xsrc/tools/publish_toolstate.py19
-rw-r--r--src/tools/run-make-support/src/external_deps/rustc.rs12
-rw-r--r--src/tools/run-make-support/src/fs.rs4
-rw-r--r--src/tools/run-make-support/src/lib.rs4
-rw-r--r--src/tools/run-make-support/src/path_helpers.rs19
-rw-r--r--src/tools/rust-installer/src/compression.rs19
-rw-r--r--src/tools/rustc-perf-wrapper/Cargo.toml7
-rw-r--r--src/tools/rustc-perf-wrapper/README.md3
-rw-r--r--src/tools/rustc-perf-wrapper/src/config.rs45
-rw-r--r--src/tools/rustc-perf-wrapper/src/main.rs178
-rw-r--r--src/tools/rustdoc-gui/tester.js1
-rw-r--r--src/tools/rustfmt/src/config/file_lines.rs4
-rw-r--r--src/tools/rustfmt/src/parse/session.rs97
-rw-r--r--src/tools/rustfmt/src/source_file.rs7
-rw-r--r--src/tools/rustfmt/src/visitor.rs6
-rw-r--r--src/tools/tidy/Cargo.toml4
-rw-r--r--src/tools/tidy/src/allowed_run_make_makefiles.txt1
-rw-r--r--src/tools/tidy/src/ext_tool_checks.rs33
-rw-r--r--src/tools/tidy/src/features.rs2
-rw-r--r--src/tools/tidy/src/features/version.rs1
-rw-r--r--src/tools/tidy/src/issues.txt16
-rw-r--r--src/tools/tidy/src/known_bug.rs11
-rw-r--r--src/tools/tidy/src/pal.rs3
-rw-r--r--src/tools/tidy/src/ui_tests.rs2
-rw-r--r--src/tools/unicode-table-generator/src/raw_emitter.rs48
194 files changed, 3979 insertions, 1710 deletions
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index feec2a7444f..c21bf82b852 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -603,11 +603,14 @@ impl Builder {
             })
             .collect();
 
-        dst.insert(pkg.manifest_component_name(), Package {
-            version: version_info.version.unwrap_or_default(),
-            git_commit_hash: version_info.git_commit,
-            target: targets,
-        });
+        dst.insert(
+            pkg.manifest_component_name(),
+            Package {
+                version: version_info.version.unwrap_or_default(),
+                git_commit_hash: version_info.git_commit,
+                target: targets,
+            },
+        );
     }
 
     fn url(&self, path: &Path) -> String {
diff --git a/src/tools/bump-stage0/src/main.rs b/src/tools/bump-stage0/src/main.rs
index b2dc044ec66..f51072718a3 100644
--- a/src/tools/bump-stage0/src/main.rs
+++ b/src/tools/bump-stage0/src/main.rs
@@ -50,7 +50,7 @@ impl Tool {
 #
 # All changes below this comment will be overridden the next time the
 # tool is executed.
-            "#;
+"#;
 
         let mut file_content = String::new();
 
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 0e3d73849ab8cbbab3ec5c65cbd555586cb2133
+Subproject 2928e32734b04925ee51e1ae88bea9a83d2fd45
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index bc42c07224e..fa03c953aa5 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -5765,6 +5765,7 @@ Released 2018-09-13
 [`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive
 [`manual_ok_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_err
 [`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or
+[`manual_option_as_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_option_as_slice
 [`manual_pattern_char_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_pattern_char_comparison
 [`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains
 [`manual_range_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_patterns
@@ -5773,6 +5774,7 @@ Released 2018-09-13
 [`manual_retain`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain
 [`manual_rotate`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rotate
 [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic
+[`manual_slice_fill`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_slice_fill
 [`manual_slice_size_calculation`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_slice_size_calculation
 [`manual_split_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once
 [`manual_str_repeat`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat
@@ -5954,6 +5956,7 @@ Released 2018-09-13
 [`positional_named_format_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#positional_named_format_parameters
 [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma
 [`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence
+[`precedence_bits`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence_bits
 [`print_in_format_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_in_format_impl
 [`print_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_literal
 [`print_stderr`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_stderr
@@ -6026,6 +6029,7 @@ Released 2018-09-13
 [`result_map_unwrap_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unwrap_or_else
 [`result_unit_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unit_err
 [`result_unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unwrap_used
+[`return_and_then`]: https://rust-lang.github.io/rust-clippy/master/index.html#return_and_then
 [`return_self_not_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#return_self_not_must_use
 [`reverse_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#reverse_range_loop
 [`reversed_empty_ranges`]: https://rust-lang.github.io/rust-clippy/master/index.html#reversed_empty_ranges
diff --git a/src/tools/clippy/book/src/attribs.md b/src/tools/clippy/book/src/attribs.md
index cf99497bc0f..9b7f5970504 100644
--- a/src/tools/clippy/book/src/attribs.md
+++ b/src/tools/clippy/book/src/attribs.md
@@ -5,7 +5,7 @@ To do this, Clippy provides attributes that can be applied to items in the 3rd p
 
 ## `#[clippy::format_args]`
 
-_Available since Clippy v1.84_
+_Available since Clippy v1.85_
 
 This attribute can be added to a macro that supports `format!`, `println!`, or similar syntax.
 It tells Clippy that the macro is a formatting macro, and that the arguments to the macro
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index b8f9fff9c61..dab2630a56f 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -752,6 +752,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio
 * [`manual_rem_euclid`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid)
 * [`manual_repeat_n`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_repeat_n)
 * [`manual_retain`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain)
+* [`manual_slice_fill`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_slice_fill)
 * [`manual_split_once`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once)
 * [`manual_str_repeat`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat)
 * [`manual_strip`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip)
diff --git a/src/tools/clippy/book/src/lints.md b/src/tools/clippy/book/src/lints.md
index 442dc63914e..1dd51797660 100644
--- a/src/tools/clippy/book/src/lints.md
+++ b/src/tools/clippy/book/src/lints.md
@@ -101,5 +101,18 @@ The `clippy::cargo` group gives you suggestions on how to improve your
 your crate and are not sure if you have all useful information in your
 `Cargo.toml`.
 
+## Nursery
+
+The `clippy::nursery` group contains lints which are buggy or need more work. It is **not** 
+recommended to enable the whole group, but rather cherry-pick lints that are useful for your 
+code base and your use case. 
+
+## Deprecated
+
+The `clippy::deprecated` is empty lints that exist to ensure that `#[allow(lintname)]` still 
+compiles after the lint was deprecated. Deprecation "removes" lints by removing their 
+functionality and marking them as deprecated, which may cause further warnings but cannot 
+cause a compiler error.
+
 [Clippy lint documentation]: https://rust-lang.github.io/rust-clippy/
 [Clippy 1.0 RFC]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md#lint-audit-and-categories
diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs
index 552141476f3..a1591188bee 100644
--- a/src/tools/clippy/clippy_config/src/conf.rs
+++ b/src/tools/clippy/clippy_config/src/conf.rs
@@ -621,6 +621,7 @@ define_Conf! {
         manual_rem_euclid,
         manual_repeat_n,
         manual_retain,
+        manual_slice_fill,
         manual_split_once,
         manual_str_repeat,
         manual_strip,
diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs
index 35dd986ff61..cc4b26867a2 100644
--- a/src/tools/clippy/clippy_dev/src/new_lint.rs
+++ b/src/tools/clippy/clippy_dev/src/new_lint.rs
@@ -255,8 +255,9 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
     let name_camel = to_camel_case(lint.name);
     let name_upper = lint_name.to_uppercase();
 
-    result.push_str(&if enable_msrv {
-        formatdoc!(
+    if enable_msrv {
+        let _: fmt::Result = writedoc!(
+            result,
             r"
             use clippy_utils::msrvs::{{self, Msrv}};
             use clippy_config::Conf;
@@ -265,22 +266,24 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
             use rustc_session::impl_lint_pass;
 
         "
-        )
+        );
     } else {
-        formatdoc!(
+        let _: fmt::Result = writedoc!(
+            result,
             r"
             {pass_import}
             use rustc_lint::{{{context_import}, {pass_type}}};
             use rustc_session::declare_lint_pass;
 
         "
-        )
-    });
+        );
+    }
 
     let _: fmt::Result = writeln!(result, "{}", get_lint_declaration(&name_upper, category));
 
-    result.push_str(&if enable_msrv {
-        formatdoc!(
+    if enable_msrv {
+        let _: fmt::Result = writedoc!(
+            result,
             r"
             pub struct {name_camel} {{
                 msrv: Msrv,
@@ -301,16 +304,17 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
             // TODO: Add MSRV level to `clippy_config/src/msrvs.rs` if needed.
             // TODO: Update msrv config comment in `clippy_config/src/conf.rs`
         "
-        )
+        );
     } else {
-        formatdoc!(
+        let _: fmt::Result = writedoc!(
+            result,
             r"
             declare_lint_pass!({name_camel} => [{name_upper}]);
 
             impl {pass_type}{pass_lifetimes} for {name_camel} {{}}
         "
-        )
-    });
+        );
+    }
 
     result
 }
diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs
index fc0780f89a7..b80ee5aac7e 100644
--- a/src/tools/clippy/clippy_dev/src/update_lints.rs
+++ b/src/tools/clippy/clippy_dev/src/update_lints.rs
@@ -985,17 +985,23 @@ mod tests {
             Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()),
         ];
         let mut expected: HashMap<String, Vec<Lint>> = HashMap::new();
-        expected.insert("group1".to_string(), vec![
-            Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()),
-            Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()),
-        ]);
-        expected.insert("group2".to_string(), vec![Lint::new(
-            "should_assert_eq2",
-            "group2",
-            "\"abc\"",
-            "module_name",
-            Range::default(),
-        )]);
+        expected.insert(
+            "group1".to_string(),
+            vec![
+                Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()),
+                Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()),
+            ],
+        );
+        expected.insert(
+            "group2".to_string(),
+            vec![Lint::new(
+                "should_assert_eq2",
+                "group2",
+                "\"abc\"",
+                "module_name",
+                Range::default(),
+            )],
+        );
         assert_eq!(expected, Lint::by_lint_group(lints.into_iter()));
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs
index 95c85f250e9..95f64b74044 100644
--- a/src/tools/clippy/clippy_lints/src/approx_const.rs
+++ b/src/tools/clippy/clippy_lints/src/approx_const.rs
@@ -3,10 +3,10 @@ use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::msrvs::{self, Msrv};
 use rustc_ast::ast::{FloatTy, LitFloatType, LitKind};
 use rustc_attr_parsing::RustcVersion;
-use rustc_hir::{Expr, ExprKind};
+use rustc_hir::{HirId, Lit};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
-use rustc_span::symbol;
+use rustc_span::{Span, symbol};
 use std::f64::consts as f64;
 
 declare_clippy_lint! {
@@ -73,22 +73,28 @@ impl ApproxConstant {
             msrv: conf.msrv.clone(),
         }
     }
+}
 
-    fn check_lit(&self, cx: &LateContext<'_>, lit: &LitKind, e: &Expr<'_>) {
-        match *lit {
+impl<'tcx> LateLintPass<'tcx> for ApproxConstant {
+    fn check_lit(&mut self, cx: &LateContext<'_>, _hir_id: HirId, lit: &Lit, _negated: bool) {
+        match lit.node {
             LitKind::Float(s, LitFloatType::Suffixed(fty)) => match fty {
-                FloatTy::F16 => self.check_known_consts(cx, e, s, "f16"),
-                FloatTy::F32 => self.check_known_consts(cx, e, s, "f32"),
-                FloatTy::F64 => self.check_known_consts(cx, e, s, "f64"),
-                FloatTy::F128 => self.check_known_consts(cx, e, s, "f128"),
+                FloatTy::F16 => self.check_known_consts(cx, lit.span, s, "f16"),
+                FloatTy::F32 => self.check_known_consts(cx, lit.span, s, "f32"),
+                FloatTy::F64 => self.check_known_consts(cx, lit.span, s, "f64"),
+                FloatTy::F128 => self.check_known_consts(cx, lit.span, s, "f128"),
             },
             // FIXME(f16_f128): add `f16` and `f128` when these types become stable.
-            LitKind::Float(s, LitFloatType::Unsuffixed) => self.check_known_consts(cx, e, s, "f{32, 64}"),
+            LitKind::Float(s, LitFloatType::Unsuffixed) => self.check_known_consts(cx, lit.span, s, "f{32, 64}"),
             _ => (),
         }
     }
 
-    fn check_known_consts(&self, cx: &LateContext<'_>, e: &Expr<'_>, s: symbol::Symbol, module: &str) {
+    extract_msrv_attr!(LateContext);
+}
+
+impl ApproxConstant {
+    fn check_known_consts(&self, cx: &LateContext<'_>, span: Span, s: symbol::Symbol, module: &str) {
         let s = s.as_str();
         if s.parse::<f64>().is_ok() {
             for &(constant, name, min_digits, msrv) in &KNOWN_CONSTS {
@@ -96,7 +102,7 @@ impl ApproxConstant {
                     span_lint_and_help(
                         cx,
                         APPROX_CONSTANT,
-                        e.span,
+                        span,
                         format!("approximate value of `{module}::consts::{name}` found"),
                         None,
                         "consider using the constant directly",
@@ -110,16 +116,6 @@ impl ApproxConstant {
 
 impl_lint_pass!(ApproxConstant => [APPROX_CONSTANT]);
 
-impl<'tcx> LateLintPass<'tcx> for ApproxConstant {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
-        if let ExprKind::Lit(lit) = &e.kind {
-            self.check_lit(cx, &lit.node, e);
-        }
-    }
-
-    extract_msrv_attr!(LateContext);
-}
-
 /// Returns `false` if the number of significant figures in `value` are
 /// less than `min_digits`; otherwise, returns true if `value` is equal
 /// to `constant`, rounded to the number of digits present in `value`.
diff --git a/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs b/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs
index 3e4bcfbfc19..5a26ba8bf93 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs
@@ -1,8 +1,8 @@
+use std::sync::Arc;
 use super::MIXED_ATTRIBUTES_STYLE;
 use clippy_utils::diagnostics::span_lint;
 use rustc_ast::{AttrKind, AttrStyle, Attribute};
 use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::sync::Lrc;
 use rustc_lint::{EarlyContext, LintContext};
 use rustc_span::source_map::SourceMap;
 use rustc_span::{SourceFile, Span, Symbol};
@@ -79,7 +79,7 @@ fn lint_mixed_attrs(cx: &EarlyContext<'_>, attrs: &[Attribute]) {
     );
 }
 
-fn attr_in_same_src_as_item(source_map: &SourceMap, item_src: &Lrc<SourceFile>, attr_span: Span) -> bool {
+fn attr_in_same_src_as_item(source_map: &SourceMap, item_src: &Arc<SourceFile>, attr_span: Span) -> bool {
     let attr_src = source_map.lookup_source_file(attr_span.lo());
-    Lrc::ptr_eq(item_src, &attr_src)
+    Arc::ptr_eq(item_src, &attr_src)
 }
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
index 48e9f1d690e..ca973f4bb1a 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
@@ -4,13 +4,13 @@ use clippy_utils::expr_or_init;
 use clippy_utils::source::snippet;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::{get_discriminant_value, is_isize_or_usize};
+use rustc_abi::IntegerType;
 use rustc_errors::{Applicability, Diag};
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, FloatTy, Ty};
 use rustc_span::Span;
-use rustc_target::abi::IntegerType;
 
 use super::{CAST_ENUM_TRUNCATION, CAST_POSSIBLE_TRUNCATION, utils};
 
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 86bcf8edd57..5c5978b5559 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -144,8 +144,6 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::doc::DOC_NESTED_REFDEFS_INFO,
     crate::doc::DOC_OVERINDENTED_LIST_ITEMS_INFO,
     crate::doc::EMPTY_DOCS_INFO,
-    crate::doc::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO,
-    crate::doc::EMPTY_LINE_AFTER_OUTER_ATTR_INFO,
     crate::doc::MISSING_ERRORS_DOC_INFO,
     crate::doc::MISSING_PANICS_DOC_INFO,
     crate::doc::MISSING_SAFETY_DOC_INFO,
@@ -162,6 +160,8 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::else_if_without_else::ELSE_IF_WITHOUT_ELSE_INFO,
     crate::empty_drop::EMPTY_DROP_INFO,
     crate::empty_enum::EMPTY_ENUM_INFO,
+    crate::empty_line_after::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO,
+    crate::empty_line_after::EMPTY_LINE_AFTER_OUTER_ATTR_INFO,
     crate::empty_with_brackets::EMPTY_ENUM_VARIANTS_WITH_BRACKETS_INFO,
     crate::empty_with_brackets::EMPTY_STRUCTS_WITH_BRACKETS_INFO,
     crate::endian_bytes::BIG_ENDIAN_BYTES_INFO,
@@ -292,6 +292,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::loops::MANUAL_FIND_INFO,
     crate::loops::MANUAL_FLATTEN_INFO,
     crate::loops::MANUAL_MEMCPY_INFO,
+    crate::loops::MANUAL_SLICE_FILL_INFO,
     crate::loops::MANUAL_WHILE_LET_SOME_INFO,
     crate::loops::MISSING_SPIN_LOOP_INFO,
     crate::loops::MUT_RANGE_BOUND_INFO,
@@ -321,6 +322,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::manual_let_else::MANUAL_LET_ELSE_INFO,
     crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO,
     crate::manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE_INFO,
+    crate::manual_option_as_slice::MANUAL_OPTION_AS_SLICE_INFO,
     crate::manual_range_patterns::MANUAL_RANGE_PATTERNS_INFO,
     crate::manual_rem_euclid::MANUAL_REM_EUCLID_INFO,
     crate::manual_retain::MANUAL_RETAIN_INFO,
@@ -463,6 +465,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::methods::REPEAT_ONCE_INFO,
     crate::methods::RESULT_FILTER_MAP_INFO,
     crate::methods::RESULT_MAP_OR_INTO_OPTION_INFO,
+    crate::methods::RETURN_AND_THEN_INFO,
     crate::methods::SEARCH_IS_SOME_INFO,
     crate::methods::SEEK_FROM_CURRENT_INFO,
     crate::methods::SEEK_TO_START_INSTEAD_OF_REWIND_INFO,
@@ -626,6 +629,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::permissions_set_readonly_false::PERMISSIONS_SET_READONLY_FALSE_INFO,
     crate::pointers_in_nomem_asm_block::POINTERS_IN_NOMEM_ASM_BLOCK_INFO,
     crate::precedence::PRECEDENCE_INFO,
+    crate::precedence::PRECEDENCE_BITS_INFO,
     crate::ptr::CMP_NULL_INFO,
     crate::ptr::INVALID_NULL_PTR_USAGE_INFO,
     crate::ptr::MUT_FROM_REF_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 123e358d7c3..233ebe00d8e 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -291,10 +291,13 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                             && let Some(ty) = use_node.defined_ty(cx)
                             && TyCoercionStability::for_defined_ty(cx, ty, use_node.is_return()).is_deref_stable()
                         {
-                            self.state = Some((State::ExplicitDeref { mutability: None }, StateData {
-                                first_expr: expr,
-                                adjusted_ty,
-                            }));
+                            self.state = Some((
+                                State::ExplicitDeref { mutability: None },
+                                StateData {
+                                    first_expr: expr,
+                                    adjusted_ty,
+                                },
+                            ));
                         }
                     },
                     RefOp::Method { mutbl, is_ufcs }
@@ -456,10 +459,13 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                             && next_adjust.is_none_or(|a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
                             && iter.all(|a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
                         {
-                            self.state = Some((State::Borrow { mutability }, StateData {
-                                first_expr: expr,
-                                adjusted_ty,
-                            }));
+                            self.state = Some((
+                                State::Borrow { mutability },
+                                StateData {
+                                    first_expr: expr,
+                                    adjusted_ty,
+                                },
+                            ));
                         }
                     },
                     _ => {},
@@ -503,10 +509,13 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                 let stability = state.stability;
                 report(cx, expr, State::DerefedBorrow(state), data, typeck);
                 if stability.is_deref_stable() {
-                    self.state = Some((State::Borrow { mutability }, StateData {
-                        first_expr: expr,
-                        adjusted_ty,
-                    }));
+                    self.state = Some((
+                        State::Borrow { mutability },
+                        StateData {
+                            first_expr: expr,
+                            adjusted_ty,
+                        },
+                    ));
                 }
             },
             (Some((State::DerefedBorrow(state), data)), RefOp::Deref) => {
@@ -531,10 +540,13 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                 } else if stability.is_deref_stable()
                     && let Some(parent) = get_parent_expr(cx, expr)
                 {
-                    self.state = Some((State::ExplicitDeref { mutability: None }, StateData {
-                        first_expr: parent,
-                        adjusted_ty,
-                    }));
+                    self.state = Some((
+                        State::ExplicitDeref { mutability: None },
+                        StateData {
+                            first_expr: parent,
+                            adjusted_ty,
+                        },
+                    ));
                 }
             },
 
@@ -1124,17 +1136,20 @@ impl<'tcx> Dereferencing<'tcx> {
         if let Some(outer_pat) = self.ref_locals.get_mut(&local) {
             if let Some(pat) = outer_pat {
                 // Check for auto-deref
-                if !matches!(cx.typeck_results().expr_adjustments(e), [
-                    Adjustment {
-                        kind: Adjust::Deref(_),
-                        ..
-                    },
-                    Adjustment {
-                        kind: Adjust::Deref(_),
+                if !matches!(
+                    cx.typeck_results().expr_adjustments(e),
+                    [
+                        Adjustment {
+                            kind: Adjust::Deref(_),
+                            ..
+                        },
+                        Adjustment {
+                            kind: Adjust::Deref(_),
+                            ..
+                        },
                         ..
-                    },
-                    ..
-                ]) {
+                    ]
+                ) {
                     match get_parent_expr(cx, e) {
                         // Field accesses are the same no matter the number of references.
                         Some(Expr {
diff --git a/src/tools/clippy/clippy_lints/src/doc/empty_line_after.rs b/src/tools/clippy/clippy_lints/src/doc/empty_line_after.rs
deleted file mode 100644
index 099194d4e74..00000000000
--- a/src/tools/clippy/clippy_lints/src/doc/empty_line_after.rs
+++ /dev/null
@@ -1,342 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::source::{SpanRangeExt, snippet_indent};
-use clippy_utils::tokenize_with_text;
-use itertools::Itertools;
-use rustc_ast::AttrStyle;
-use rustc_ast::token::CommentKind;
-use rustc_errors::{Applicability, Diag, SuggestionStyle};
-use rustc_hir::{AttrKind, Attribute, ItemKind, Node};
-use rustc_lexer::TokenKind;
-use rustc_lint::LateContext;
-use rustc_span::{BytePos, ExpnKind, InnerSpan, Span, SpanData};
-
-use super::{EMPTY_LINE_AFTER_DOC_COMMENTS, EMPTY_LINE_AFTER_OUTER_ATTR};
-
-#[derive(Debug, PartialEq, Clone, Copy)]
-enum StopKind {
-    Attr,
-    Doc(CommentKind),
-}
-
-impl StopKind {
-    fn is_doc(self) -> bool {
-        matches!(self, StopKind::Doc(_))
-    }
-}
-
-#[derive(Debug)]
-struct Stop {
-    span: Span,
-    kind: StopKind,
-    first: usize,
-    last: usize,
-}
-
-impl Stop {
-    fn convert_to_inner(&self) -> (Span, String) {
-        let inner = match self.kind {
-            // #|[...]
-            StopKind::Attr => InnerSpan::new(1, 1),
-            // /// or /**
-            //   ^      ^
-            StopKind::Doc(_) => InnerSpan::new(2, 3),
-        };
-        (self.span.from_inner(inner), "!".into())
-    }
-
-    fn comment_out(&self, cx: &LateContext<'_>, suggestions: &mut Vec<(Span, String)>) {
-        match self.kind {
-            StopKind::Attr => {
-                if cx.tcx.sess.source_map().is_multiline(self.span) {
-                    suggestions.extend([
-                        (self.span.shrink_to_lo(), "/* ".into()),
-                        (self.span.shrink_to_hi(), " */".into()),
-                    ]);
-                } else {
-                    suggestions.push((self.span.shrink_to_lo(), "// ".into()));
-                }
-            },
-            StopKind::Doc(CommentKind::Line) => suggestions.push((self.span.shrink_to_lo(), "// ".into())),
-            StopKind::Doc(CommentKind::Block) => {
-                // /** outer */  /*! inner */
-                //  ^             ^
-                let asterisk = self.span.from_inner(InnerSpan::new(1, 2));
-                suggestions.push((asterisk, String::new()));
-            },
-        }
-    }
-
-    fn from_attr(cx: &LateContext<'_>, attr: &Attribute) -> Option<Self> {
-        let SpanData { lo, hi, .. } = attr.span.data();
-        let file = cx.tcx.sess.source_map().lookup_source_file(lo);
-
-        Some(Self {
-            span: attr.span,
-            kind: match attr.kind {
-                AttrKind::Normal(_) => StopKind::Attr,
-                AttrKind::DocComment(comment_kind, _) => StopKind::Doc(comment_kind),
-            },
-            first: file.lookup_line(file.relative_position(lo))?,
-            last: file.lookup_line(file.relative_position(hi))?,
-        })
-    }
-}
-
-/// Represents a set of attrs/doc comments separated by 1 or more empty lines
-///
-/// ```ignore
-/// /// chunk 1 docs
-/// // not an empty line so also part of chunk 1
-/// #[chunk_1_attrs] // <-- prev_stop
-///
-/// /* gap */
-///
-/// /// chunk 2 docs // <-- next_stop
-/// #[chunk_2_attrs]
-/// ```
-struct Gap<'a> {
-    /// The span of individual empty lines including the newline at the end of the line
-    empty_lines: Vec<Span>,
-    has_comment: bool,
-    next_stop: &'a Stop,
-    prev_stop: &'a Stop,
-    /// The chunk that includes [`prev_stop`](Self::prev_stop)
-    prev_chunk: &'a [Stop],
-}
-
-impl<'a> Gap<'a> {
-    fn new(cx: &LateContext<'_>, prev_chunk: &'a [Stop], next_chunk: &'a [Stop]) -> Option<Self> {
-        let prev_stop = prev_chunk.last()?;
-        let next_stop = next_chunk.first()?;
-        let gap_span = prev_stop.span.between(next_stop.span);
-        let gap_snippet = gap_span.get_source_text(cx)?;
-
-        let mut has_comment = false;
-        let mut empty_lines = Vec::new();
-
-        for (token, source, inner_span) in tokenize_with_text(&gap_snippet) {
-            match token {
-                TokenKind::BlockComment {
-                    doc_style: None,
-                    terminated: true,
-                }
-                | TokenKind::LineComment { doc_style: None } => has_comment = true,
-                TokenKind::Whitespace => {
-                    let newlines = source.bytes().positions(|b| b == b'\n');
-                    empty_lines.extend(
-                        newlines
-                            .tuple_windows()
-                            .map(|(a, b)| InnerSpan::new(inner_span.start + a + 1, inner_span.start + b))
-                            .map(|inner_span| gap_span.from_inner(inner_span)),
-                    );
-                },
-                // Ignore cfg_attr'd out attributes as they may contain empty lines, could also be from macro
-                // shenanigans
-                _ => return None,
-            }
-        }
-
-        (!empty_lines.is_empty()).then_some(Self {
-            empty_lines,
-            has_comment,
-            next_stop,
-            prev_stop,
-            prev_chunk,
-        })
-    }
-
-    fn contiguous_empty_lines(&self) -> impl Iterator<Item = Span> + '_ {
-        self.empty_lines
-            // The `+ BytePos(1)` means "next line", because each empty line span is "N:1-N:1".
-            .chunk_by(|a, b| a.hi() + BytePos(1) == b.lo())
-            .map(|chunk| {
-                let first = chunk.first().expect("at least one empty line");
-                let last = chunk.last().expect("at least one empty line");
-                // The BytePos subtraction here is safe, as before an empty line, there must be at least one
-                // attribute/comment. The span needs to start at the end of the previous line.
-                first.with_lo(first.lo() - BytePos(1)).with_hi(last.hi())
-            })
-    }
-}
-
-/// If the node the attributes/docs apply to is the first in the module/crate suggest converting
-/// them to inner attributes/docs
-fn suggest_inner(cx: &LateContext<'_>, diag: &mut Diag<'_, ()>, kind: StopKind, gaps: &[Gap<'_>]) {
-    let Some(owner) = cx.last_node_with_lint_attrs.as_owner() else {
-        return;
-    };
-    let parent_desc = match cx.tcx.parent_hir_node(owner.into()) {
-        Node::Item(item)
-            if let ItemKind::Mod(parent_mod) = item.kind
-                && let [first, ..] = parent_mod.item_ids
-                && first.owner_id == owner =>
-        {
-            "parent module"
-        },
-        Node::Crate(crate_mod)
-            if let Some(first) = crate_mod
-                .item_ids
-                .iter()
-                .map(|&id| cx.tcx.hir().item(id))
-                // skip prelude imports
-                .find(|item| !matches!(item.span.ctxt().outer_expn_data().kind, ExpnKind::AstPass(_)))
-                && first.owner_id == owner =>
-        {
-            "crate"
-        },
-        _ => return,
-    };
-
-    diag.multipart_suggestion_verbose(
-        match kind {
-            StopKind::Attr => format!("if the attribute should apply to the {parent_desc} use an inner attribute"),
-            StopKind::Doc(_) => format!("if the comment should document the {parent_desc} use an inner doc comment"),
-        },
-        gaps.iter()
-            .flat_map(|gap| gap.prev_chunk)
-            .map(Stop::convert_to_inner)
-            .collect(),
-        Applicability::MaybeIncorrect,
-    );
-}
-
-fn check_gaps(cx: &LateContext<'_>, gaps: &[Gap<'_>]) -> bool {
-    let Some(first_gap) = gaps.first() else {
-        return false;
-    };
-    let empty_lines = || gaps.iter().flat_map(|gap| gap.empty_lines.iter().copied());
-    let contiguous_empty_lines = || gaps.iter().flat_map(Gap::contiguous_empty_lines);
-    let mut has_comment = false;
-    let mut has_attr = false;
-    for gap in gaps {
-        has_comment |= gap.has_comment;
-        if !has_attr {
-            has_attr = gap.prev_chunk.iter().any(|stop| stop.kind == StopKind::Attr);
-        }
-    }
-    let kind = first_gap.prev_stop.kind;
-    let (lint, kind_desc) = match kind {
-        StopKind::Attr => (EMPTY_LINE_AFTER_OUTER_ATTR, "outer attribute"),
-        StopKind::Doc(_) => (EMPTY_LINE_AFTER_DOC_COMMENTS, "doc comment"),
-    };
-    let (lines, are, them) = if empty_lines().nth(1).is_some() {
-        ("lines", "are", "them")
-    } else {
-        ("line", "is", "it")
-    };
-    span_lint_and_then(
-        cx,
-        lint,
-        first_gap.prev_stop.span.to(empty_lines().last().unwrap()),
-        format!("empty {lines} after {kind_desc}"),
-        |diag| {
-            if let Some(owner) = cx.last_node_with_lint_attrs.as_owner() {
-                let def_id = owner.to_def_id();
-                let def_descr = cx.tcx.def_descr(def_id);
-                diag.span_label(cx.tcx.def_span(def_id), match kind {
-                    StopKind::Attr => format!("the attribute applies to this {def_descr}"),
-                    StopKind::Doc(_) => format!("the comment documents this {def_descr}"),
-                });
-            }
-
-            diag.multipart_suggestion_with_style(
-                format!("if the empty {lines} {are} unintentional remove {them}"),
-                contiguous_empty_lines()
-                    .map(|empty_lines| (empty_lines, String::new()))
-                    .collect(),
-                Applicability::MaybeIncorrect,
-                SuggestionStyle::HideCodeAlways,
-            );
-
-            if has_comment && kind.is_doc() {
-                // Likely doc comments that applied to some now commented out code
-                //
-                // /// Old docs for Foo
-                // // struct Foo;
-
-                let mut suggestions = Vec::new();
-                for stop in gaps.iter().flat_map(|gap| gap.prev_chunk) {
-                    stop.comment_out(cx, &mut suggestions);
-                }
-                let name = match cx.tcx.hir().opt_name(cx.last_node_with_lint_attrs) {
-                    Some(name) => format!("`{name}`"),
-                    None => "this".into(),
-                };
-                diag.multipart_suggestion_verbose(
-                    format!("if the doc comment should not document {name} comment it out"),
-                    suggestions,
-                    Applicability::MaybeIncorrect,
-                );
-            } else {
-                suggest_inner(cx, diag, kind, gaps);
-            }
-
-            if kind == StopKind::Doc(CommentKind::Line)
-                && gaps
-                    .iter()
-                    .all(|gap| !gap.has_comment && gap.next_stop.kind == StopKind::Doc(CommentKind::Line))
-            {
-                // Commentless empty gaps between line doc comments, possibly intended to be part of the markdown
-
-                let indent = snippet_indent(cx, first_gap.prev_stop.span).unwrap_or_default();
-                diag.multipart_suggestion_verbose(
-                    format!("if the documentation should include the empty {lines} include {them} in the comment"),
-                    empty_lines()
-                        .map(|empty_line| (empty_line, format!("{indent}///")))
-                        .collect(),
-                    Applicability::MaybeIncorrect,
-                );
-            }
-        },
-    );
-    kind.is_doc()
-}
-
-/// Returns `true` if [`EMPTY_LINE_AFTER_DOC_COMMENTS`] triggered, used to skip other doc comment
-/// lints where they would be confusing
-///
-/// [`EMPTY_LINE_AFTER_OUTER_ATTR`] is also here to share an implementation but does not return
-/// `true` if it triggers
-pub(super) fn check(cx: &LateContext<'_>, attrs: &[Attribute]) -> bool {
-    let mut outer = attrs
-        .iter()
-        .filter(|attr| attr.style == AttrStyle::Outer && !attr.span.from_expansion())
-        .map(|attr| Stop::from_attr(cx, attr))
-        .collect::<Option<Vec<_>>>()
-        .unwrap_or_default();
-
-    if outer.is_empty() {
-        return false;
-    }
-
-    // Push a fake attribute Stop for the item itself so we check for gaps between the last outer
-    // attr/doc comment and the item they apply to
-    let span = cx.tcx.hir().span(cx.last_node_with_lint_attrs);
-    if !span.from_expansion()
-        && let Ok(line) = cx.tcx.sess.source_map().lookup_line(span.lo())
-    {
-        outer.push(Stop {
-            span,
-            kind: StopKind::Attr,
-            first: line.line,
-            // last doesn't need to be accurate here, we don't compare it with anything
-            last: line.line,
-        });
-    }
-
-    let mut gaps = Vec::new();
-    let mut last = 0;
-    for pos in outer
-        .array_windows()
-        .positions(|[a, b]| b.first.saturating_sub(a.last) > 1)
-    {
-        // we want to be after the first stop in the window
-        let pos = pos + 1;
-        if let Some(gap) = Gap::new(cx, &outer[last..pos], &outer[pos..]) {
-            last = pos;
-            gaps.push(gap);
-        }
-    }
-
-    check_gaps(cx, &gaps)
-}
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index 3d8ce7becdb..42e1f7fd950 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -33,7 +33,6 @@ use rustc_span::{Span, sym};
 use std::ops::Range;
 use url::Url;
 
-mod empty_line_after;
 mod include_in_doc_without_cfg;
 mod link_with_quotes;
 mod markdown;
@@ -493,82 +492,6 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for empty lines after outer attributes
-    ///
-    /// ### Why is this bad?
-    /// The attribute may have meant to be an inner attribute (`#![attr]`). If
-    /// it was meant to be an outer attribute (`#[attr]`) then the empty line
-    /// should be removed
-    ///
-    /// ### Example
-    /// ```no_run
-    /// #[allow(dead_code)]
-    ///
-    /// fn not_quite_good_code() {}
-    /// ```
-    ///
-    /// Use instead:
-    /// ```no_run
-    /// // Good (as inner attribute)
-    /// #![allow(dead_code)]
-    ///
-    /// fn this_is_fine() {}
-    ///
-    /// // or
-    ///
-    /// // Good (as outer attribute)
-    /// #[allow(dead_code)]
-    /// fn this_is_fine_too() {}
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub EMPTY_LINE_AFTER_OUTER_ATTR,
-    suspicious,
-    "empty line after outer attribute"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for empty lines after doc comments.
-    ///
-    /// ### Why is this bad?
-    /// The doc comment may have meant to be an inner doc comment, regular
-    /// comment or applied to some old code that is now commented out. If it was
-    /// intended to be a doc comment, then the empty line should be removed.
-    ///
-    /// ### Example
-    /// ```no_run
-    /// /// Some doc comment with a blank line after it.
-    ///
-    /// fn f() {}
-    ///
-    /// /// Docs for `old_code`
-    /// // fn old_code() {}
-    ///
-    /// fn new_code() {}
-    /// ```
-    ///
-    /// Use instead:
-    /// ```no_run
-    /// //! Convert it to an inner doc comment
-    ///
-    /// // Or a regular comment
-    ///
-    /// /// Or remove the empty line
-    /// fn f() {}
-    ///
-    /// // /// Docs for `old_code`
-    /// // fn old_code() {}
-    ///
-    /// fn new_code() {}
-    /// ```
-    #[clippy::version = "1.70.0"]
-    pub EMPTY_LINE_AFTER_DOC_COMMENTS,
-    suspicious,
-    "empty line after doc comments"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
     /// Checks if included files in doc comments are included only for `cfg(doc)`.
     ///
     /// ### Why restrict this?
@@ -650,8 +573,6 @@ impl_lint_pass!(Documentation => [
     EMPTY_DOCS,
     DOC_LAZY_CONTINUATION,
     DOC_OVERINDENTED_LIST_ITEMS,
-    EMPTY_LINE_AFTER_OUTER_ATTR,
-    EMPTY_LINE_AFTER_DOC_COMMENTS,
     TOO_LONG_FIRST_DOC_PARAGRAPH,
     DOC_INCLUDE_WITHOUT_CFG,
 ]);
@@ -784,7 +705,7 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
     }
 
     include_in_doc_without_cfg::check(cx, attrs);
-    if suspicious_doc_comments::check(cx, attrs) || empty_line_after::check(cx, attrs) || is_doc_hidden(attrs) {
+    if suspicious_doc_comments::check(cx, attrs) || is_doc_hidden(attrs) {
         return None;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs
index 9ba2723157a..ce5beab24bf 100644
--- a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs
@@ -1,10 +1,10 @@
 use std::ops::Range;
 use std::{io, thread};
+use std::sync::Arc;
 
 use crate::doc::{NEEDLESS_DOCTEST_MAIN, TEST_ATTR_IN_DOCTEST};
 use clippy_utils::diagnostics::span_lint;
 use rustc_ast::{CoroutineKind, Fn, FnRetTy, Item, ItemKind};
-use rustc_data_structures::sync::Lrc;
 use rustc_errors::emitter::HumanEmitter;
 use rustc_errors::{Diag, DiagCtxt};
 use rustc_lint::LateContext;
@@ -46,8 +46,8 @@ pub fn check(
                     rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
                 let emitter = HumanEmitter::new(Box::new(io::sink()), fallback_bundle);
                 let dcx = DiagCtxt::new(Box::new(emitter)).disable_warnings();
-                #[expect(clippy::arc_with_non_send_sync)] // `Lrc` is expected by with_dcx
-                let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
+                #[expect(clippy::arc_with_non_send_sync)] // `Arc` is expected by with_dcx
+                let sm = Arc::new(SourceMap::new(FilePathMapping::empty()));
                 let psess = ParseSess::with_dcx(dcx, sm);
 
                 let mut parser = match new_parser_from_source_str(&psess, filename, code) {
diff --git a/src/tools/clippy/clippy_lints/src/empty_line_after.rs b/src/tools/clippy/clippy_lints/src/empty_line_after.rs
new file mode 100644
index 00000000000..578ff6e38a6
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/empty_line_after.rs
@@ -0,0 +1,492 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::{SpanRangeExt, snippet_indent};
+use clippy_utils::tokenize_with_text;
+use itertools::Itertools;
+use rustc_ast::token::CommentKind;
+use rustc_ast::{AssocItemKind, AttrKind, AttrStyle, Attribute, Crate, Item, ItemKind, ModKind, NodeId};
+use rustc_errors::{Applicability, Diag, SuggestionStyle};
+use rustc_lexer::TokenKind;
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_session::impl_lint_pass;
+use rustc_span::symbol::kw;
+use rustc_span::{BytePos, ExpnKind, Ident, InnerSpan, Span, SpanData, Symbol};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for empty lines after outer attributes
+    ///
+    /// ### Why is this bad?
+    /// The attribute may have meant to be an inner attribute (`#![attr]`). If
+    /// it was meant to be an outer attribute (`#[attr]`) then the empty line
+    /// should be removed
+    ///
+    /// ### Example
+    /// ```no_run
+    /// #[allow(dead_code)]
+    ///
+    /// fn not_quite_good_code() {}
+    /// ```
+    ///
+    /// Use instead:
+    /// ```no_run
+    /// // Good (as inner attribute)
+    /// #![allow(dead_code)]
+    ///
+    /// fn this_is_fine() {}
+    ///
+    /// // or
+    ///
+    /// // Good (as outer attribute)
+    /// #[allow(dead_code)]
+    /// fn this_is_fine_too() {}
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub EMPTY_LINE_AFTER_OUTER_ATTR,
+    suspicious,
+    "empty line after outer attribute"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for empty lines after doc comments.
+    ///
+    /// ### Why is this bad?
+    /// The doc comment may have meant to be an inner doc comment, regular
+    /// comment or applied to some old code that is now commented out. If it was
+    /// intended to be a doc comment, then the empty line should be removed.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// /// Some doc comment with a blank line after it.
+    ///
+    /// fn f() {}
+    ///
+    /// /// Docs for `old_code`
+    /// // fn old_code() {}
+    ///
+    /// fn new_code() {}
+    /// ```
+    ///
+    /// Use instead:
+    /// ```no_run
+    /// //! Convert it to an inner doc comment
+    ///
+    /// // Or a regular comment
+    ///
+    /// /// Or remove the empty line
+    /// fn f() {}
+    ///
+    /// // /// Docs for `old_code`
+    /// // fn old_code() {}
+    ///
+    /// fn new_code() {}
+    /// ```
+    #[clippy::version = "1.70.0"]
+    pub EMPTY_LINE_AFTER_DOC_COMMENTS,
+    suspicious,
+    "empty line after doc comments"
+}
+
+#[derive(Debug)]
+struct ItemInfo {
+    kind: &'static str,
+    name: Symbol,
+    span: Span,
+    mod_items: Option<NodeId>,
+}
+
+pub struct EmptyLineAfter {
+    items: Vec<ItemInfo>,
+}
+
+impl_lint_pass!(EmptyLineAfter => [
+    EMPTY_LINE_AFTER_OUTER_ATTR,
+    EMPTY_LINE_AFTER_DOC_COMMENTS,
+]);
+
+impl EmptyLineAfter {
+    pub fn new() -> Self {
+        Self { items: Vec::new() }
+    }
+}
+
+#[derive(Debug, PartialEq, Clone, Copy)]
+enum StopKind {
+    Attr,
+    Doc(CommentKind),
+}
+
+impl StopKind {
+    fn is_doc(self) -> bool {
+        matches!(self, StopKind::Doc(_))
+    }
+}
+
+#[derive(Debug)]
+struct Stop {
+    span: Span,
+    kind: StopKind,
+    first: usize,
+    last: usize,
+}
+
+impl Stop {
+    fn convert_to_inner(&self) -> (Span, String) {
+        let inner = match self.kind {
+            // #![...]
+            StopKind::Attr => InnerSpan::new(1, 1),
+            // /// or /**
+            //   ^      ^
+            StopKind::Doc(_) => InnerSpan::new(2, 3),
+        };
+        (self.span.from_inner(inner), "!".into())
+    }
+
+    fn comment_out(&self, cx: &EarlyContext<'_>, suggestions: &mut Vec<(Span, String)>) {
+        match self.kind {
+            StopKind::Attr => {
+                if cx.sess().source_map().is_multiline(self.span) {
+                    suggestions.extend([
+                        (self.span.shrink_to_lo(), "/* ".into()),
+                        (self.span.shrink_to_hi(), " */".into()),
+                    ]);
+                } else {
+                    suggestions.push((self.span.shrink_to_lo(), "// ".into()));
+                }
+            },
+            StopKind::Doc(CommentKind::Line) => suggestions.push((self.span.shrink_to_lo(), "// ".into())),
+            StopKind::Doc(CommentKind::Block) => {
+                // /** outer */  /*! inner */
+                //  ^             ^
+                let asterisk = self.span.from_inner(InnerSpan::new(1, 2));
+                suggestions.push((asterisk, String::new()));
+            },
+        }
+    }
+
+    fn from_attr(cx: &EarlyContext<'_>, attr: &Attribute) -> Option<Self> {
+        let SpanData { lo, hi, .. } = attr.span.data();
+        let file = cx.sess().source_map().lookup_source_file(lo);
+
+        Some(Self {
+            span: attr.span,
+            kind: match attr.kind {
+                AttrKind::Normal(_) => StopKind::Attr,
+                AttrKind::DocComment(comment_kind, _) => StopKind::Doc(comment_kind),
+            },
+            first: file.lookup_line(file.relative_position(lo))?,
+            last: file.lookup_line(file.relative_position(hi))?,
+        })
+    }
+}
+
+/// Represents a set of attrs/doc comments separated by 1 or more empty lines
+///
+/// ```ignore
+/// /// chunk 1 docs
+/// // not an empty line so also part of chunk 1
+/// #[chunk_1_attrs] // <-- prev_stop
+///
+/// /* gap */
+///
+/// /// chunk 2 docs // <-- next_stop
+/// #[chunk_2_attrs]
+/// ```
+struct Gap<'a> {
+    /// The span of individual empty lines including the newline at the end of the line
+    empty_lines: Vec<Span>,
+    has_comment: bool,
+    next_stop: &'a Stop,
+    prev_stop: &'a Stop,
+    /// The chunk that includes [`prev_stop`](Self::prev_stop)
+    prev_chunk: &'a [Stop],
+}
+
+impl<'a> Gap<'a> {
+    fn new(cx: &EarlyContext<'_>, prev_chunk: &'a [Stop], next_chunk: &'a [Stop]) -> Option<Self> {
+        let prev_stop = prev_chunk.last()?;
+        let next_stop = next_chunk.first()?;
+        let gap_span = prev_stop.span.between(next_stop.span);
+        let gap_snippet = gap_span.get_source_text(cx)?;
+
+        let mut has_comment = false;
+        let mut empty_lines = Vec::new();
+
+        for (token, source, inner_span) in tokenize_with_text(&gap_snippet) {
+            match token {
+                TokenKind::BlockComment {
+                    doc_style: None,
+                    terminated: true,
+                }
+                | TokenKind::LineComment { doc_style: None } => has_comment = true,
+                TokenKind::Whitespace => {
+                    let newlines = source.bytes().positions(|b| b == b'\n');
+                    empty_lines.extend(
+                        newlines
+                            .tuple_windows()
+                            .map(|(a, b)| InnerSpan::new(inner_span.start + a + 1, inner_span.start + b))
+                            .map(|inner_span| gap_span.from_inner(inner_span)),
+                    );
+                },
+                // Ignore cfg_attr'd out attributes as they may contain empty lines, could also be from macro
+                // shenanigans
+                _ => return None,
+            }
+        }
+
+        (!empty_lines.is_empty()).then_some(Self {
+            empty_lines,
+            has_comment,
+            next_stop,
+            prev_stop,
+            prev_chunk,
+        })
+    }
+
+    fn contiguous_empty_lines(&self) -> impl Iterator<Item = Span> + '_ {
+        self.empty_lines
+            // The `+ BytePos(1)` means "next line", because each empty line span is "N:1-N:1".
+            .chunk_by(|a, b| a.hi() + BytePos(1) == b.lo())
+            .map(|chunk| {
+                let first = chunk.first().expect("at least one empty line");
+                let last = chunk.last().expect("at least one empty line");
+                // The BytePos subtraction here is safe, as before an empty line, there must be at least one
+                // attribute/comment. The span needs to start at the end of the previous line.
+                first.with_lo(first.lo() - BytePos(1)).with_hi(last.hi())
+            })
+    }
+}
+
+impl EmptyLineAfter {
+    fn check_gaps(&self, cx: &EarlyContext<'_>, gaps: &[Gap<'_>], id: NodeId) {
+        let Some(first_gap) = gaps.first() else {
+            return;
+        };
+        let empty_lines = || gaps.iter().flat_map(|gap| gap.empty_lines.iter().copied());
+        let contiguous_empty_lines = || gaps.iter().flat_map(Gap::contiguous_empty_lines);
+        let mut has_comment = false;
+        let mut has_attr = false;
+        for gap in gaps {
+            has_comment |= gap.has_comment;
+            if !has_attr {
+                has_attr = gap.prev_chunk.iter().any(|stop| stop.kind == StopKind::Attr);
+            }
+        }
+        let kind = first_gap.prev_stop.kind;
+        let (lint, kind_desc) = match kind {
+            StopKind::Attr => (EMPTY_LINE_AFTER_OUTER_ATTR, "outer attribute"),
+            StopKind::Doc(_) => (EMPTY_LINE_AFTER_DOC_COMMENTS, "doc comment"),
+        };
+        let (lines, are, them) = if empty_lines().nth(1).is_some() {
+            ("lines", "are", "them")
+        } else {
+            ("line", "is", "it")
+        };
+        span_lint_and_then(
+            cx,
+            lint,
+            first_gap.prev_stop.span.to(empty_lines().last().unwrap()),
+            format!("empty {lines} after {kind_desc}"),
+            |diag| {
+                let info = self.items.last().unwrap();
+                diag.span_label(info.span, match kind {
+                    StopKind::Attr => format!("the attribute applies to this {}", info.kind),
+                    StopKind::Doc(_) => format!("the comment documents this {}", info.kind),
+                });
+
+                diag.multipart_suggestion_with_style(
+                    format!("if the empty {lines} {are} unintentional, remove {them}"),
+                    contiguous_empty_lines()
+                        .map(|empty_lines| (empty_lines, String::new()))
+                        .collect(),
+                    Applicability::MaybeIncorrect,
+                    SuggestionStyle::HideCodeAlways,
+                );
+
+                if has_comment && kind.is_doc() {
+                    // Likely doc comments that applied to some now commented out code
+                    //
+                    // /// Old docs for Foo
+                    // // struct Foo;
+
+                    let mut suggestions = Vec::new();
+                    for stop in gaps.iter().flat_map(|gap| gap.prev_chunk) {
+                        stop.comment_out(cx, &mut suggestions);
+                    }
+                    diag.multipart_suggestion_verbose(
+                        format!("if the doc comment should not document `{}` comment it out", info.name),
+                        suggestions,
+                        Applicability::MaybeIncorrect,
+                    );
+                } else {
+                    self.suggest_inner(diag, kind, gaps, id);
+                }
+
+                if kind == StopKind::Doc(CommentKind::Line)
+                    && gaps
+                        .iter()
+                        .all(|gap| !gap.has_comment && gap.next_stop.kind == StopKind::Doc(CommentKind::Line))
+                {
+                    // Commentless empty gaps between line doc comments, possibly intended to be part of the markdown
+
+                    let indent = snippet_indent(cx, first_gap.prev_stop.span).unwrap_or_default();
+                    diag.multipart_suggestion_verbose(
+                        format!("if the documentation should include the empty {lines} include {them} in the comment"),
+                        empty_lines()
+                            .map(|empty_line| (empty_line, format!("{indent}///")))
+                            .collect(),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+            },
+        );
+    }
+
+    /// If the node the attributes/docs apply to is the first in the module/crate suggest converting
+    /// them to inner attributes/docs
+    fn suggest_inner(&self, diag: &mut Diag<'_, ()>, kind: StopKind, gaps: &[Gap<'_>], id: NodeId) {
+        if let Some(parent) = self.items.iter().rev().nth(1)
+            && (parent.kind == "module" || parent.kind == "crate")
+            && parent.mod_items == Some(id)
+        {
+            let desc = if parent.kind == "module" {
+                "parent module"
+            } else {
+                parent.kind
+            };
+            diag.multipart_suggestion_verbose(
+                match kind {
+                    StopKind::Attr => format!("if the attribute should apply to the {desc} use an inner attribute"),
+                    StopKind::Doc(_) => format!("if the comment should document the {desc} use an inner doc comment"),
+                },
+                gaps.iter()
+                    .flat_map(|gap| gap.prev_chunk)
+                    .map(Stop::convert_to_inner)
+                    .collect(),
+                Applicability::MaybeIncorrect,
+            );
+        }
+    }
+
+    fn check_item_kind(
+        &mut self,
+        cx: &EarlyContext<'_>,
+        kind: &ItemKind,
+        ident: &Ident,
+        span: Span,
+        attrs: &[Attribute],
+        id: NodeId,
+    ) {
+        self.items.push(ItemInfo {
+            kind: kind.descr(),
+            name: ident.name,
+            span: if span.contains(ident.span) {
+                span.with_hi(ident.span.hi())
+            } else {
+                span.with_hi(span.lo())
+            },
+            mod_items: match kind {
+                ItemKind::Mod(_, ModKind::Loaded(items, _, _, _)) => items
+                    .iter()
+                    .filter(|i| !matches!(i.span.ctxt().outer_expn_data().kind, ExpnKind::AstPass(_)))
+                    .map(|i| i.id)
+                    .next(),
+                _ => None,
+            },
+        });
+
+        let mut outer = attrs
+            .iter()
+            .filter(|attr| attr.style == AttrStyle::Outer && !attr.span.from_expansion())
+            .map(|attr| Stop::from_attr(cx, attr))
+            .collect::<Option<Vec<_>>>()
+            .unwrap_or_default();
+
+        if outer.is_empty() {
+            return;
+        }
+
+        // Push a fake attribute Stop for the item itself so we check for gaps between the last outer
+        // attr/doc comment and the item they apply to
+        let span = self.items.last().unwrap().span;
+        if !span.from_expansion()
+            && let Ok(line) = cx.sess().source_map().lookup_line(span.lo())
+        {
+            outer.push(Stop {
+                span,
+                kind: StopKind::Attr,
+                first: line.line,
+                // last doesn't need to be accurate here, we don't compare it with anything
+                last: line.line,
+            });
+        }
+
+        let mut gaps = Vec::new();
+        let mut last = 0;
+        for pos in outer
+            .array_windows()
+            .positions(|[a, b]| b.first.saturating_sub(a.last) > 1)
+        {
+            // we want to be after the first stop in the window
+            let pos = pos + 1;
+            if let Some(gap) = Gap::new(cx, &outer[last..pos], &outer[pos..]) {
+                last = pos;
+                gaps.push(gap);
+            }
+        }
+
+        self.check_gaps(cx, &gaps, id);
+    }
+}
+
+impl EarlyLintPass for EmptyLineAfter {
+    fn check_crate(&mut self, _: &EarlyContext<'_>, krate: &Crate) {
+        self.items.push(ItemInfo {
+            kind: "crate",
+            name: kw::Crate,
+            span: krate.spans.inner_span.with_hi(krate.spans.inner_span.lo()),
+            mod_items: krate
+                .items
+                .iter()
+                .filter(|i| !matches!(i.span.ctxt().outer_expn_data().kind, ExpnKind::AstPass(_)))
+                .map(|i| i.id)
+                .next(),
+        });
+    }
+
+    fn check_item_post(&mut self, _: &EarlyContext<'_>, _: &Item) {
+        self.items.pop();
+    }
+    fn check_impl_item_post(&mut self, _: &EarlyContext<'_>, _: &Item<AssocItemKind>) {
+        self.items.pop();
+    }
+    fn check_trait_item_post(&mut self, _: &EarlyContext<'_>, _: &Item<AssocItemKind>) {
+        self.items.pop();
+    }
+
+    fn check_impl_item(&mut self, cx: &EarlyContext<'_>, item: &Item<AssocItemKind>) {
+        self.check_item_kind(
+            cx,
+            &item.kind.clone().into(),
+            &item.ident,
+            item.span,
+            &item.attrs,
+            item.id,
+        );
+    }
+
+    fn check_trait_item(&mut self, cx: &EarlyContext<'_>, item: &Item<AssocItemKind>) {
+        self.check_item_kind(
+            cx,
+            &item.kind.clone().into(),
+            &item.ident,
+            item.span,
+            &item.attrs,
+            item.id,
+        );
+    }
+
+    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
+        self.check_item_kind(cx, &item.kind, &item.ident, item.span, &item.attrs, item.id);
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/endian_bytes.rs b/src/tools/clippy/clippy_lints/src/endian_bytes.rs
index 29deaaf3bc7..a7670ffce88 100644
--- a/src/tools/clippy/clippy_lints/src/endian_bytes.rs
+++ b/src/tools/clippy/clippy_lints/src/endian_bytes.rs
@@ -6,6 +6,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty::Ty;
 use rustc_session::declare_lint_pass;
 use rustc_span::Symbol;
+use std::fmt::Write;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -183,7 +184,7 @@ fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix
                     help_str.push_str("either of ");
                 }
 
-                help_str.push_str(&format!("`{ty}::{}` ", lint.as_name(prefix)));
+                write!(help_str, "`{ty}::{}` ", lint.as_name(prefix)).unwrap();
 
                 if i != len && !only_one {
                     help_str.push_str("or ");
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index a89f0d9c432..c55d4387d69 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -10,7 +10,7 @@ use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::kw;
-use rustc_target::spec::abi::Abi;
+use rustc_abi::ExternAbi;
 
 pub struct BoxedLocal {
     too_large_for_stack: u64,
@@ -73,7 +73,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
         fn_def_id: LocalDefId,
     ) {
         if let Some(header) = fn_kind.header() {
-            if header.abi != Abi::Rust {
+            if header.abi != ExternAbi::Rust {
                 return;
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 52b699274bb..ae3acc1c4b1 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -1,13 +1,13 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::higher::VecArgs;
-use clippy_utils::source::snippet_opt;
+use clippy_utils::source::{snippet_opt, snippet_with_applicability};
 use clippy_utils::ty::get_type_diagnostic_name;
 use clippy_utils::usage::{local_used_after_expr, local_used_in};
 use clippy_utils::{
     get_path_from_caller_to_method_type, is_adjusted, is_no_std_crate, path_to_local, path_to_local_id,
 };
 use rustc_errors::Applicability;
-use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, Param, PatKind, QPath, Safety, TyKind};
+use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, GenericArgs, Param, PatKind, QPath, Safety, TyKind};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{
@@ -15,7 +15,7 @@ use rustc_middle::ty::{
 };
 use rustc_session::declare_lint_pass;
 use rustc_span::symbol::sym;
-use rustc_target::spec::abi::Abi;
+use rustc_abi::ExternAbi;
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt as _;
 
 declare_clippy_lint! {
@@ -172,7 +172,7 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
                         && let output = typeck.expr_ty(body.value)
                         && let ty::Tuple(tys) = *subs.type_at(1).kind()
                     {
-                        cx.tcx.mk_fn_sig(tys, output, false, Safety::Safe, Abi::Rust)
+                        cx.tcx.mk_fn_sig(tys, output, false, Safety::Safe, ExternAbi::Rust)
                     } else {
                         return;
                     }
@@ -239,6 +239,11 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
                 && !cx.tcx.has_attr(method_def_id, sym::track_caller)
                 && check_sig(closure_sig, cx.tcx.fn_sig(method_def_id).skip_binder().skip_binder())
             {
+                let mut app = Applicability::MachineApplicable;
+                let generic_args = match path.args.and_then(GenericArgs::span_ext) {
+                    Some(span) => format!("::{}", snippet_with_applicability(cx, span, "<..>", &mut app)),
+                    None => String::new(),
+                };
                 span_lint_and_then(
                     cx,
                     REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
@@ -251,8 +256,8 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
                         diag.span_suggestion(
                             expr.span,
                             "replace the closure with the method itself",
-                            format!("{}::{}", type_name, path.ident.name),
-                            Applicability::MachineApplicable,
+                            format!("{}::{}{}", type_name, path.ident.name, generic_args),
+                            app,
                         );
                     },
                 );
diff --git a/src/tools/clippy/clippy_lints/src/excessive_bools.rs b/src/tools/clippy/clippy_lints/src/excessive_bools.rs
index 0011da03dda..15afe3e8c14 100644
--- a/src/tools/clippy/clippy_lints/src/excessive_bools.rs
+++ b/src/tools/clippy/clippy_lints/src/excessive_bools.rs
@@ -7,7 +7,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 use rustc_span::def_id::LocalDefId;
-use rustc_target::spec::abi::Abi;
+use rustc_abi::ExternAbi;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -145,7 +145,7 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools {
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx TraitItem<'tcx>) {
         // functions with a body are already checked by `check_fn`
         if let TraitItemKind::Fn(fn_sig, TraitFn::Required(_)) = &trait_item.kind
-            && fn_sig.header.abi == Abi::Rust
+            && fn_sig.header.abi == ExternAbi::Rust
             && fn_sig.decl.inputs.len() as u64 > self.max_fn_params_bools
         {
             check_fn_decl(cx, fn_sig.decl, fn_sig.span, self.max_fn_params_bools);
@@ -162,7 +162,7 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools {
         def_id: LocalDefId,
     ) {
         if let Some(fn_header) = fn_kind.header()
-            && fn_header.abi == Abi::Rust
+            && fn_header.abi == ExternAbi::Rust
             && fn_decl.inputs.len() as u64 > self.max_fn_params_bools
             && get_parent_as_impl(cx.tcx, cx.tcx.local_def_id_to_hir_id(def_id))
                 .is_none_or(|impl_item| impl_item.of_trait.is_none())
diff --git a/src/tools/clippy/clippy_lints/src/excessive_nesting.rs b/src/tools/clippy/clippy_lints/src/excessive_nesting.rs
index 36567b3ded0..1d3ae894944 100644
--- a/src/tools/clippy/clippy_lints/src/excessive_nesting.rs
+++ b/src/tools/clippy/clippy_lints/src/excessive_nesting.rs
@@ -124,7 +124,9 @@ struct NestingVisitor<'conf, 'cx> {
 
 impl NestingVisitor<'_, '_> {
     fn check_indent(&mut self, span: Span, id: NodeId) -> bool {
-        if self.nest_level > self.conf.excessive_nesting_threshold && !span.in_external_macro(self.cx.sess().source_map()) {
+        if self.nest_level > self.conf.excessive_nesting_threshold
+            && !span.in_external_macro(self.cx.sess().source_map())
+        {
             self.conf.nodes.insert(id);
 
             return true;
diff --git a/src/tools/clippy/clippy_lints/src/format_push_string.rs b/src/tools/clippy/clippy_lints/src/format_push_string.rs
index 8b1f86cbb91..68cc50f3939 100644
--- a/src/tools/clippy/clippy_lints/src/format_push_string.rs
+++ b/src/tools/clippy/clippy_lints/src/format_push_string.rs
@@ -11,7 +11,7 @@ declare_clippy_lint! {
     /// Detects cases where the result of a `format!` call is
     /// appended to an existing `String`.
     ///
-    /// ### Why restrict this?
+    /// ### Why is this bad?
     /// Introduces an extra, avoidable heap allocation.
     ///
     /// ### Known problems
@@ -35,7 +35,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.62.0"]
     pub FORMAT_PUSH_STRING,
-    restriction,
+    pedantic,
     "`format!(..)` appended to existing `String`"
 }
 declare_lint_pass!(FormatPushString => [FORMAT_PUSH_STRING]);
diff --git a/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs b/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs
index e72a2ad49d8..f17f687719f 100644
--- a/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs
@@ -1,7 +1,7 @@
 use rustc_hir::{self as hir, intravisit};
 use rustc_lint::LateContext;
 use rustc_span::Span;
-use rustc_target::spec::abi::Abi;
+use rustc_abi::ExternAbi;
 
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::is_trait_impl_item;
@@ -23,11 +23,11 @@ pub(super) fn check_fn(
             intravisit::FnKind::Method(
                 _,
                 &hir::FnSig {
-                    header: hir::FnHeader { abi: Abi::Rust, .. },
+                    header: hir::FnHeader { abi: ExternAbi::Rust, .. },
                     ..
                 },
             )
-            | intravisit::FnKind::ItemFn(_, _, hir::FnHeader { abi: Abi::Rust, .. }) => check_arg_number(
+            | intravisit::FnKind::ItemFn(_, _, hir::FnHeader { abi: ExternAbi::Rust, .. }) => check_arg_number(
                 cx,
                 decl,
                 span.with_hi(decl.output.span().hi()),
@@ -41,7 +41,7 @@ pub(super) fn check_fn(
 pub(super) fn check_trait_item(cx: &LateContext<'_>, item: &hir::TraitItem<'_>, too_many_arguments_threshold: u64) {
     if let hir::TraitItemKind::Fn(ref sig, _) = item.kind {
         // don't lint extern functions decls, it's not their fault
-        if sig.header.abi == Abi::Rust {
+        if sig.header.abi == ExternAbi::Rust {
             check_arg_number(
                 cx,
                 sig.decl,
diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
index 415b47adac5..c58e8773e3a 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
@@ -5,7 +5,7 @@ use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind, LangItem};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
-use rustc_target::spec::abi::Abi;
+use rustc_abi::ExternAbi;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
             // #11201
             && let header = signature.header
             && header.is_safe()
-            && header.abi == Abi::Rust
+            && header.abi == ExternAbi::Rust
             && impl_item.ident.name == sym::to_string
             && let decl = signature.decl
             && decl.implicit_self.has_implicit_self()
diff --git a/src/tools/clippy/clippy_lints/src/large_futures.rs b/src/tools/clippy/clippy_lints/src/large_futures.rs
index 593704f206a..fd7965d564d 100644
--- a/src/tools/clippy/clippy_lints/src/large_futures.rs
+++ b/src/tools/clippy/clippy_lints/src/large_futures.rs
@@ -2,11 +2,11 @@ use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::implements_trait;
+use rustc_abi::Size;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, LangItem, MatchSource, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
-use rustc_target::abi::Size;
 
 declare_clippy_lint! {
     /// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
index 6f5c5d6b3ea..c68499ce9f7 100644
--- a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
+++ b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
@@ -7,8 +7,8 @@ use clippy_utils::macros::macro_backtrace;
 use clippy_utils::source::snippet;
 use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty;
+use rustc_middle::ty::layout::LayoutOf;
 use rustc_session::impl_lint_pass;
 use rustc_span::{Span, sym};
 
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 4b700673d0f..13218331a67 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -126,6 +126,7 @@ mod duplicate_mod;
 mod else_if_without_else;
 mod empty_drop;
 mod empty_enum;
+mod empty_line_after;
 mod empty_with_brackets;
 mod endian_bytes;
 mod entry;
@@ -217,6 +218,7 @@ mod manual_is_power_of_two;
 mod manual_let_else;
 mod manual_main_separator_str;
 mod manual_non_exhaustive;
+mod manual_option_as_slice;
 mod manual_range_patterns;
 mod manual_rem_euclid;
 mod manual_retain;
@@ -972,9 +974,11 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(move |_| Box::new(unused_trait_names::UnusedTraitNames::new(conf)));
     store.register_late_pass(|_| Box::new(manual_ignore_case_cmp::ManualIgnoreCaseCmp));
     store.register_late_pass(|_| Box::new(unnecessary_literal_bound::UnnecessaryLiteralBound));
+    store.register_early_pass(|| Box::new(empty_line_after::EmptyLineAfter::new()));
     store.register_late_pass(move |_| Box::new(arbitrary_source_item_ordering::ArbitrarySourceItemOrdering::new(conf)));
     store.register_late_pass(|_| Box::new(unneeded_struct_pattern::UnneededStructPattern));
     store.register_late_pass(|_| Box::<unnecessary_semicolon::UnnecessarySemicolon>::default());
     store.register_late_pass(move |_| Box::new(non_std_lazy_statics::NonStdLazyStatic::new(conf)));
+    store.register_late_pass(|_| Box::new(manual_option_as_slice::ManualOptionAsSlice::new(conf)));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_slice_fill.rs b/src/tools/clippy/clippy_lints/src/loops/manual_slice_fill.rs
new file mode 100644
index 00000000000..7c656423579
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_slice_fill.rs
@@ -0,0 +1,111 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::eager_or_lazy::switch_to_eager_eval;
+use clippy_utils::macros::span_is_local;
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::source::{HasSession, snippet_with_applicability};
+use clippy_utils::ty::implements_trait;
+use clippy_utils::{higher, peel_blocks_with_stmt, span_contains_comment};
+use rustc_ast::ast::LitKind;
+use rustc_ast::{RangeLimits, UnOp};
+use rustc_data_structures::packed::Pu128;
+use rustc_errors::Applicability;
+use rustc_hir::QPath::Resolved;
+use rustc_hir::def::Res;
+use rustc_hir::{Expr, ExprKind, Pat};
+use rustc_lint::LateContext;
+use rustc_span::source_map::Spanned;
+use rustc_span::sym;
+
+use super::MANUAL_SLICE_FILL;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    pat: &'tcx Pat<'_>,
+    arg: &'tcx Expr<'_>,
+    body: &'tcx Expr<'_>,
+    expr: &'tcx Expr<'_>,
+    msrv: &Msrv,
+) {
+    if !msrv.meets(msrvs::SLICE_FILL) {
+        return;
+    }
+
+    // `for _ in 0..slice.len() { slice[_] = value; }`
+    if let Some(higher::Range {
+        start: Some(start),
+        end: Some(end),
+        limits: RangeLimits::HalfOpen,
+    }) = higher::Range::hir(arg)
+        && let ExprKind::Lit(Spanned {
+            node: LitKind::Int(Pu128(0), _),
+            ..
+        }) = start.kind
+        && let ExprKind::Block(..) = body.kind
+        // Check if the body is an assignment to a slice element.
+        && let ExprKind::Assign(assignee, assignval, _) = peel_blocks_with_stmt(body).kind
+        && let ExprKind::Index(slice, _, _) = assignee.kind
+        // Check if `len()` is used for the range end.
+        && let ExprKind::MethodCall(path, recv,..) = end.kind
+        && path.ident.name == sym::len
+        // Check if the slice which is being assigned to is the same as the one being iterated over.
+        && let ExprKind::Path(Resolved(_, recv_path)) = recv.kind
+        && let ExprKind::Path(Resolved(_, slice_path)) = slice.kind
+        && recv_path.res == slice_path.res
+        && !assignval.span.from_expansion()
+        // It is generally not equivalent to use the `fill` method if `assignval` can have side effects
+        && switch_to_eager_eval(cx, assignval)
+        && span_is_local(assignval.span)
+        // The `fill` method requires that the slice's element type implements the `Clone` trait.
+        && let Some(clone_trait) = cx.tcx.lang_items().clone_trait()
+        && implements_trait(cx, cx.typeck_results().expr_ty(slice), clone_trait, &[])
+    {
+        sugg(cx, body, expr, slice.span, assignval.span);
+    }
+    // `for _ in &mut slice { *_ = value; }`
+    else if let ExprKind::AddrOf(_, _, recv) = arg.kind
+        // Check if the body is an assignment to a slice element.
+        && let ExprKind::Assign(assignee, assignval, _) = peel_blocks_with_stmt(body).kind
+        && let ExprKind::Unary(UnOp::Deref, slice_iter) = assignee.kind
+        && let ExprKind::Path(Resolved(_, recv_path)) = recv.kind
+        // Check if the slice which is being assigned to is the same as the one being iterated over.
+        && let ExprKind::Path(Resolved(_, slice_path)) = slice_iter.kind
+        && let Res::Local(local) = slice_path.res
+        && local == pat.hir_id
+        && !assignval.span.from_expansion()
+        && switch_to_eager_eval(cx, assignval)
+        && span_is_local(assignval.span)
+        // The `fill` method cannot be used if the slice's element type does not implement the `Clone` trait.
+        && let Some(clone_trait) = cx.tcx.lang_items().clone_trait()
+        && implements_trait(cx, cx.typeck_results().expr_ty(recv), clone_trait, &[])
+    {
+        sugg(cx, body, expr, recv_path.span, assignval.span);
+    }
+}
+
+fn sugg<'tcx>(
+    cx: &LateContext<'tcx>,
+    body: &'tcx Expr<'_>,
+    expr: &'tcx Expr<'_>,
+    slice_span: rustc_span::Span,
+    assignval_span: rustc_span::Span,
+) {
+    let mut app = if span_contains_comment(cx.sess().source_map(), body.span) {
+        Applicability::MaybeIncorrect // Comments may be informational.
+    } else {
+        Applicability::MachineApplicable
+    };
+
+    span_lint_and_sugg(
+        cx,
+        MANUAL_SLICE_FILL,
+        expr.span,
+        "manually filling a slice",
+        "try",
+        format!(
+            "{}.fill({});",
+            snippet_with_applicability(cx, slice_span, "..", &mut app),
+            snippet_with_applicability(cx, assignval_span, "..", &mut app),
+        ),
+        app,
+    );
+}
diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs
index c5e75af2303..cdc8c18c3b7 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs
@@ -8,6 +8,7 @@ mod iter_next_loop;
 mod manual_find;
 mod manual_flatten;
 mod manual_memcpy;
+mod manual_slice_fill;
 mod manual_while_let_some;
 mod missing_spin_loop;
 mod mut_range_bound;
@@ -714,6 +715,31 @@ declare_clippy_lint! {
     "possibly unintended infinite loop"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for manually filling a slice with a value.
+    ///
+    /// ### Why is this bad?
+    /// Using the `fill` method is more idiomatic and concise.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// let mut some_slice = [1, 2, 3, 4, 5];
+    /// for i in 0..some_slice.len() {
+    ///     some_slice[i] = 0;
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// let mut some_slice = [1, 2, 3, 4, 5];
+    /// some_slice.fill(0);
+    /// ```
+    #[clippy::version = "1.86.0"]
+    pub MANUAL_SLICE_FILL,
+    style,
+    "manually filling a slice with a value"
+}
+
 pub struct Loops {
     msrv: Msrv,
     enforce_iter_loop_reborrow: bool,
@@ -750,6 +776,7 @@ impl_lint_pass!(Loops => [
     MANUAL_WHILE_LET_SOME,
     UNUSED_ENUMERATE_INDEX,
     INFINITE_LOOP,
+    MANUAL_SLICE_FILL,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Loops {
@@ -823,6 +850,7 @@ impl Loops {
     ) {
         let is_manual_memcpy_triggered = manual_memcpy::check(cx, pat, arg, body, expr);
         if !is_manual_memcpy_triggered {
+            manual_slice_fill::check(cx, pat, arg, body, expr, &self.msrv);
             needless_range_loop::check(cx, pat, arg, body, expr);
             explicit_counter_loop::check(cx, pat, arg, body, expr, label);
         }
diff --git a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs
index 816ca17b3d2..04357cdd8f6 100644
--- a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs
@@ -181,13 +181,16 @@ fn build_suggestion(
             ExprKind::Lit(Spanned {
                 node: LitKind::Int(_, LitIntType::Unsuffixed),
                 ..
-            }) | ExprKind::Unary(UnOp::Neg, Expr {
-                kind: ExprKind::Lit(Spanned {
-                    node: LitKind::Int(_, LitIntType::Unsuffixed),
+            }) | ExprKind::Unary(
+                UnOp::Neg,
+                Expr {
+                    kind: ExprKind::Lit(Spanned {
+                        node: LitKind::Int(_, LitIntType::Unsuffixed),
+                        ..
+                    }),
                     ..
-                }),
-                ..
-            })
+                }
+            )
         ) {
         format!("_{}", cx.typeck_results().expr_ty(rhs))
     } else {
diff --git a/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs b/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs
new file mode 100644
index 00000000000..5c40c945c69
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs
@@ -0,0 +1,225 @@
+use clippy_config::Conf;
+use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
+use clippy_utils::{is_none_arm, msrvs, peel_hir_expr_refs};
+use rustc_errors::Applicability;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::{Arm, Expr, ExprKind, LangItem, Pat, PatKind, QPath, is_range_literal};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
+use rustc_session::impl_lint_pass;
+use rustc_span::{Span, Symbol, sym};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// This detects various manual reimplementations of `Option::as_slice`.
+    ///
+    /// ### Why is this bad?
+    /// Those implementations are both more complex than calling `as_slice`
+    /// and unlike that incur a branch, pessimizing performance and leading
+    /// to more generated code.
+    ///
+    /// ### Example
+    /// ```no_run
+    ///# let opt = Some(1);
+    /// _ = opt.as_ref().map_or(&[][..], std::slice::from_ref);
+    /// _ = match opt.as_ref() {
+    ///     Some(f) => std::slice::from_ref(f),
+    ///     None => &[],
+    /// };
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    ///# let opt = Some(1);
+    /// _ = opt.as_slice();
+    /// _ = opt.as_slice();
+    /// ```
+    #[clippy::version = "1.85.0"]
+    pub MANUAL_OPTION_AS_SLICE,
+    complexity,
+    "manual `Option::as_slice`"
+}
+
+pub struct ManualOptionAsSlice {
+    msrv: msrvs::Msrv,
+}
+
+impl ManualOptionAsSlice {
+    pub fn new(conf: &Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
+    }
+}
+
+impl_lint_pass!(ManualOptionAsSlice => [MANUAL_OPTION_AS_SLICE]);
+
+impl LateLintPass<'_> for ManualOptionAsSlice {
+    extract_msrv_attr!(LateContext);
+
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+        let span = expr.span;
+        if span.from_expansion()
+            || !self.msrv.meets(if clippy_utils::is_in_const_context(cx) {
+                msrvs::CONST_OPTION_AS_SLICE
+            } else {
+                msrvs::OPTION_AS_SLICE
+            })
+        {
+            return;
+        }
+        match expr.kind {
+            ExprKind::Match(scrutinee, [arm1, arm2], _) => {
+                if is_none_arm(cx, arm2) && check_arms(cx, arm2, arm1)
+                    || is_none_arm(cx, arm1) && check_arms(cx, arm1, arm2)
+                {
+                    check_as_ref(cx, scrutinee, span);
+                }
+            },
+            ExprKind::If(cond, then, Some(other)) => {
+                if let ExprKind::Let(let_expr) = cond.kind
+                    && let Some(binding) = extract_ident_from_some_pat(cx, let_expr.pat)
+                    && check_some_body(cx, binding, then)
+                    && is_empty_slice(cx, other.peel_blocks())
+                {
+                    check_as_ref(cx, let_expr.init, span);
+                }
+            },
+            ExprKind::MethodCall(seg, callee, [], _) => {
+                if seg.ident.name.as_str() == "unwrap_or_default" {
+                    check_map(cx, callee, span);
+                }
+            },
+            ExprKind::MethodCall(seg, callee, [or], _) => match seg.ident.name.as_str() {
+                "unwrap_or" => {
+                    if is_empty_slice(cx, or) {
+                        check_map(cx, callee, span);
+                    }
+                },
+                "unwrap_or_else" => {
+                    if returns_empty_slice(cx, or) {
+                        check_map(cx, callee, span);
+                    }
+                },
+                _ => {},
+            },
+            ExprKind::MethodCall(seg, callee, [or_else, map], _) => match seg.ident.name.as_str() {
+                "map_or" => {
+                    if is_empty_slice(cx, or_else) && is_slice_from_ref(cx, map) {
+                        check_as_ref(cx, callee, span);
+                    }
+                },
+                "map_or_else" => {
+                    if returns_empty_slice(cx, or_else) && is_slice_from_ref(cx, map) {
+                        check_as_ref(cx, callee, span);
+                    }
+                },
+                _ => {},
+            },
+            _ => {},
+        }
+    }
+}
+
+fn check_map(cx: &LateContext<'_>, map: &Expr<'_>, span: Span) {
+    if let ExprKind::MethodCall(seg, callee, [mapping], _) = map.kind
+        && seg.ident.name == sym::map
+        && is_slice_from_ref(cx, mapping)
+    {
+        check_as_ref(cx, callee, span);
+    }
+}
+
+fn check_as_ref(cx: &LateContext<'_>, expr: &Expr<'_>, span: Span) {
+    if let ExprKind::MethodCall(seg, callee, [], _) = expr.kind
+        && seg.ident.name == sym::as_ref
+        && let ty::Adt(adtdef, ..) = cx.typeck_results().expr_ty(callee).kind()
+        && cx.tcx.is_diagnostic_item(sym::Option, adtdef.did())
+    {
+        if let Some(snippet) = clippy_utils::source::snippet_opt(cx, callee.span) {
+            span_lint_and_sugg(
+                cx,
+                MANUAL_OPTION_AS_SLICE,
+                span,
+                "use `Option::as_slice`",
+                "use",
+                format!("{snippet}.as_slice()"),
+                Applicability::MachineApplicable,
+            );
+        } else {
+            span_lint(cx, MANUAL_OPTION_AS_SLICE, span, "use `Option_as_slice`");
+        }
+    }
+}
+
+fn extract_ident_from_some_pat(cx: &LateContext<'_>, pat: &Pat<'_>) -> Option<Symbol> {
+    if let PatKind::TupleStruct(QPath::Resolved(None, path), [binding], _) = pat.kind
+        && let Res::Def(DefKind::Ctor(..), def_id) = path.res
+        && let PatKind::Binding(_mode, _hir_id, ident, _inner_pat) = binding.kind
+        && clippy_utils::is_lang_item_or_ctor(cx, def_id, LangItem::OptionSome)
+    {
+        Some(ident.name)
+    } else {
+        None
+    }
+}
+
+/// Returns true if `expr` is `std::slice::from_ref(<name>)`. Used in `if let`s.
+fn check_some_body(cx: &LateContext<'_>, name: Symbol, expr: &Expr<'_>) -> bool {
+    if let ExprKind::Call(slice_from_ref, [arg]) = expr.peel_blocks().kind
+        && is_slice_from_ref(cx, slice_from_ref)
+        && let ExprKind::Path(QPath::Resolved(None, path)) = arg.kind
+        && let [seg] = path.segments
+    {
+        seg.ident.name == name
+    } else {
+        false
+    }
+}
+
+fn check_arms(cx: &LateContext<'_>, none_arm: &Arm<'_>, some_arm: &Arm<'_>) -> bool {
+    if none_arm.guard.is_none()
+        && some_arm.guard.is_none()
+        && is_empty_slice(cx, none_arm.body)
+        && let Some(name) = extract_ident_from_some_pat(cx, some_arm.pat)
+    {
+        check_some_body(cx, name, some_arm.body)
+    } else {
+        false
+    }
+}
+
+fn returns_empty_slice(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    match expr.kind {
+        ExprKind::Path(_) => clippy_utils::is_path_diagnostic_item(cx, expr, sym::default_fn),
+        ExprKind::Closure(cl) => is_empty_slice(cx, cx.tcx.hir().body(cl.body).value),
+        _ => false,
+    }
+}
+
+/// Returns if expr returns an empty slice. If:
+/// - An indexing operation to an empty array with a built-in range. `[][..]`
+/// - An indexing operation with a zero-ended range. `expr[..0]`
+/// - A reference to an empty array. `&[]`
+/// - Or a call to `Default::default`.
+fn is_empty_slice(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    let expr = peel_hir_expr_refs(expr.peel_blocks()).0;
+    match expr.kind {
+        ExprKind::Index(arr, range, _) => match arr.kind {
+            ExprKind::Array([]) => is_range_literal(range),
+            ExprKind::Array(_) => {
+                let Some(range) = clippy_utils::higher::Range::hir(range) else {
+                    return false;
+                };
+                range.end.is_some_and(|e| clippy_utils::is_integer_const(cx, e, 0))
+            },
+            _ => false,
+        },
+        ExprKind::Array([]) => true,
+        ExprKind::Call(def, []) => clippy_utils::is_path_diagnostic_item(cx, def, sym::default_fn),
+        _ => false,
+    }
+}
+
+fn is_slice_from_ref(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    clippy_utils::is_expr_path_def_path(cx, expr, &["core", "slice", "raw", "from_ref"])
+}
diff --git a/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs b/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs
index 7b95399c907..87d2faa225c 100644
--- a/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs
@@ -9,8 +9,8 @@ use rustc_span::sym;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::higher::IfLetOrMatch;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::implements_trait;
-use clippy_utils::{is_default_equivalent, is_in_const_context, peel_blocks, span_contains_comment};
+use clippy_utils::ty::{expr_type_is_certain, implements_trait};
+use clippy_utils::{is_default_equivalent, is_in_const_context, path_res, peel_blocks, span_contains_comment};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -158,6 +158,36 @@ fn handle<'tcx>(cx: &LateContext<'tcx>, if_let_or_match: IfLetOrMatch<'tcx>, exp
         } else {
             Applicability::MachineApplicable
         };
+
+        // We now check if the condition is a None variant, in which case we need to specify the type
+        if path_res(cx, condition)
+            .opt_def_id()
+            .is_some_and(|id| Some(cx.tcx.parent(id)) == cx.tcx.lang_items().option_none_variant())
+        {
+            return span_lint_and_sugg(
+                cx,
+                MANUAL_UNWRAP_OR_DEFAULT,
+                expr.span,
+                format!("{expr_name} can be simplified with `.unwrap_or_default()`"),
+                "replace it with",
+                format!("{receiver}::<{expr_type}>.unwrap_or_default()"),
+                applicability,
+            );
+        }
+
+        // We check if the expression type is still uncertain, in which case we ask the user to specify it
+        if !expr_type_is_certain(cx, condition) {
+            return span_lint_and_sugg(
+                cx,
+                MANUAL_UNWRAP_OR_DEFAULT,
+                expr.span,
+                format!("{expr_name} can be simplified with `.unwrap_or_default()`"),
+                format!("ascribe the type {expr_type} and replace your expression with"),
+                format!("{receiver}.unwrap_or_default()"),
+                Applicability::Unspecified,
+            );
+        }
+
         span_lint_and_sugg(
             cx,
             MANUAL_UNWRAP_OR_DEFAULT,
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
index b1889d26c93..1cb4b512a30 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
@@ -1,8 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{is_res_lang_ctor, path_res, peel_blocks};
+use clippy_utils::{is_none_arm, is_res_lang_ctor, path_res, peel_blocks};
 use rustc_errors::Applicability;
-use rustc_hir::{Arm, BindingMode, ByRef, Expr, ExprKind, LangItem, Mutability, PatExpr, PatExprKind, PatKind, QPath};
+use rustc_hir::{Arm, BindingMode, ByRef, Expr, ExprKind, LangItem, Mutability, PatKind, QPath};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
 
@@ -55,14 +55,6 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
     }
 }
 
-// Checks if arm has the form `None => None`
-fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
-    matches!(
-        arm.pat.kind,
-        PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), .. }) if is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), LangItem::OptionNone)
-    )
-}
-
 // Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`)
 fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<Mutability> {
     if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 2f447775fa5..0a8eafad0e8 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -95,6 +95,7 @@ mod readonly_write_lock;
 mod redundant_as_str;
 mod repeat_once;
 mod result_map_or_else_none;
+mod return_and_then;
 mod search_is_some;
 mod seek_from_current;
 mod seek_to_start_instead_of_rewind;
@@ -148,6 +149,7 @@ use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item};
 use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, peel_blocks, return_ty};
 pub use path_ends_with_ext::DEFAULT_ALLOWED_DOTFILES;
+use rustc_abi::ExternAbi;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::{Expr, ExprKind, Node, Stmt, StmtKind, TraitItem, TraitItemKind};
@@ -3517,7 +3519,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.73.0"]
     pub FORMAT_COLLECT,
-    perf,
+    pedantic,
     "`format!`ing every element in a collection, then collecting the strings into a new `String`"
 }
 
@@ -4365,7 +4367,7 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for string slices immediantly followed by `as_bytes`.
+    /// Checks for string slices immediately followed by `as_bytes`.
     ///
     /// ### Why is this bad?
     /// It involves doing an unnecessary UTF-8 alignment check which is less efficient, and can cause a panic.
@@ -4391,6 +4393,46 @@ declare_clippy_lint! {
      "slicing a string and immediately calling as_bytes is less efficient and can lead to panics"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Detect functions that end with `Option::and_then` or `Result::and_then`, and suggest using a question mark (`?`) instead.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// The `and_then` method is used to chain a computation that returns an `Option` or a `Result`.
+    /// This can be replaced with the `?` operator, which is more concise and idiomatic.
+    ///
+    /// ### Example
+    ///
+    /// ```no_run
+    /// fn test(opt: Option<i32>) -> Option<i32> {
+    ///     opt.and_then(|n| {
+    ///         if n > 1 {
+    ///             Some(n + 1)
+    ///         } else {
+    ///             None
+    ///        }
+    ///     })
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// fn test(opt: Option<i32>) -> Option<i32> {
+    ///     let n = opt?;
+    ///     if n > 1 {
+    ///         Some(n + 1)
+    ///     } else {
+    ///         None
+    ///     }
+    /// }
+    /// ```
+    #[clippy::version = "1.86.0"]
+    pub RETURN_AND_THEN,
+    restriction,
+    "using `Option::and_then` or `Result::and_then` to chain a computation that returns an `Option` or a `Result`"
+}
+
 pub struct Methods {
     avoid_breaking_exported_api: bool,
     msrv: Msrv,
@@ -4560,6 +4602,7 @@ impl_lint_pass!(Methods => [
     USELESS_NONZERO_NEW_UNCHECKED,
     MANUAL_REPEAT_N,
     SLICED_STRING_AS_BYTES,
+    RETURN_AND_THEN,
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -4789,7 +4832,10 @@ impl Methods {
                     let biom_option_linted = bind_instead_of_map::check_and_then_some(cx, expr, recv, arg);
                     let biom_result_linted = bind_instead_of_map::check_and_then_ok(cx, expr, recv, arg);
                     if !biom_option_linted && !biom_result_linted {
-                        unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
+                        let ule_and_linted = unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
+                        if !ule_and_linted {
+                            return_and_then::check(cx, expr, recv, arg);
+                        }
                     }
                 },
                 ("any", [arg]) => {
@@ -5003,7 +5049,9 @@ impl Methods {
                     get_first::check(cx, expr, recv, arg);
                     get_last_with_len::check(cx, expr, recv, arg);
                 },
-                ("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"),
+                ("get_or_insert_with", [arg]) => {
+                    unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert");
+                },
                 ("hash", [arg]) => {
                     unit_hash::check(cx, expr, recv, arg);
                 },
@@ -5144,7 +5192,9 @@ impl Methods {
                     },
                     _ => iter_nth_zero::check(cx, expr, recv, n_arg),
                 },
-                ("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
+                ("ok_or_else", [arg]) => {
+                    unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or");
+                },
                 ("open", [_]) => {
                     open_options::check(cx, expr, recv);
                 },
@@ -5398,7 +5448,7 @@ const FN_HEADER: hir::FnHeader = hir::FnHeader {
     safety: hir::HeaderSafety::Normal(hir::Safety::Safe),
     constness: hir::Constness::NotConst,
     asyncness: hir::IsAsync::NotAsync,
-    abi: rustc_target::spec::abi::Abi::Rust,
+    abi: ExternAbi::Rust,
 };
 
 struct ShouldImplTraitCase {
@@ -5437,9 +5487,12 @@ impl ShouldImplTraitCase {
     fn lifetime_param_cond(&self, impl_item: &hir::ImplItem<'_>) -> bool {
         self.lint_explicit_lifetime
             || !impl_item.generics.params.iter().any(|p| {
-                matches!(p.kind, hir::GenericParamKind::Lifetime {
-                    kind: hir::LifetimeParamKind::Explicit
-                })
+                matches!(
+                    p.kind,
+                    hir::GenericParamKind::Lifetime {
+                        kind: hir::LifetimeParamKind::Explicit
+                    }
+                )
             })
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_option_take.rs b/src/tools/clippy/clippy_lints/src/methods/needless_option_take.rs
index c41ce2481d7..88b9c69f6f9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_option_take.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_option_take.rs
@@ -1,5 +1,6 @@
-use clippy_utils::diagnostics::span_lint_and_note;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::ty::is_type_diagnostic_item;
+use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, QPath};
 use rustc_lint::LateContext;
 use rustc_span::sym;
@@ -10,13 +11,22 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'
     // Checks if expression type is equal to sym::Option and if the expr is not a syntactic place
     if !recv.is_syntactic_place_expr() && is_expr_option(cx, recv) {
         if let Some(function_name) = source_of_temporary_value(recv) {
-            span_lint_and_note(
+            span_lint_and_then(
                 cx,
                 NEEDLESS_OPTION_TAKE,
                 expr.span,
                 "called `Option::take()` on a temporary value",
-                None,
-                format!("`{function_name}` creates a temporary value, so calling take() has no effect"),
+                |diag| {
+                    diag.note(format!(
+                        "`{function_name}` creates a temporary value, so calling take() has no effect"
+                    ));
+                    diag.span_suggestion(
+                        expr.span.with_lo(recv.span.hi()),
+                        "remove",
+                        "",
+                        Applicability::MachineApplicable,
+                    );
+                },
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs b/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs
new file mode 100644
index 00000000000..7b1199ad1e2
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs
@@ -0,0 +1,67 @@
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, GenericArg, Ty};
+use rustc_span::sym;
+use std::ops::ControlFlow;
+
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::{indent_of, reindent_multiline, snippet_with_applicability};
+use clippy_utils::ty::get_type_diagnostic_name;
+use clippy_utils::visitors::for_each_unconsumed_temporary;
+use clippy_utils::{is_expr_final_block_expr, peel_blocks};
+
+use super::RETURN_AND_THEN;
+
+/// lint if `and_then` is the last expression in a block, and
+/// there are no references or temporaries in the receiver
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &hir::Expr<'_>,
+    recv: &'tcx hir::Expr<'tcx>,
+    arg: &'tcx hir::Expr<'_>,
+) {
+    if !is_expr_final_block_expr(cx.tcx, expr) {
+        return;
+    }
+
+    let recv_type = cx.typeck_results().expr_ty(recv);
+    if !matches!(get_type_diagnostic_name(cx, recv_type), Some(sym::Option | sym::Result)) {
+        return;
+    }
+
+    let has_ref_type = matches!(recv_type.kind(), ty::Adt(_, args) if args
+        .first()
+        .and_then(|arg0: &GenericArg<'tcx>| GenericArg::as_type(*arg0))
+        .is_some_and(Ty::is_ref));
+    let has_temporaries = for_each_unconsumed_temporary(cx, recv, |_| ControlFlow::Break(())).is_break();
+    if has_ref_type && has_temporaries {
+        return;
+    }
+
+    let hir::ExprKind::Closure(&hir::Closure { body, fn_decl, .. }) = arg.kind else {
+        return;
+    };
+
+    let closure_arg = fn_decl.inputs[0];
+    let closure_expr = peel_blocks(cx.tcx.hir().body(body).value);
+
+    let mut applicability = Applicability::MachineApplicable;
+    let arg_snip = snippet_with_applicability(cx, closure_arg.span, "_", &mut applicability);
+    let recv_snip = snippet_with_applicability(cx, recv.span, "_", &mut applicability);
+    let body_snip = snippet_with_applicability(cx, closure_expr.span, "..", &mut applicability);
+    let inner = match body_snip.strip_prefix('{').and_then(|s| s.strip_suffix('}')) {
+        Some(s) => s.trim_start_matches('\n').trim_end(),
+        None => &body_snip,
+    };
+
+    let msg = "use the question mark operator instead of an `and_then` call";
+    let sugg = format!(
+        "let {} = {}?;\n{}",
+        arg_snip,
+        recv_snip,
+        reindent_multiline(inner.into(), false, indent_of(cx, expr.span))
+    );
+
+    span_lint_and_sugg(cx, RETURN_AND_THEN, expr.span, msg, "try", sugg, applicability);
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
index c27d1fb4903..e7adf3b43ba 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
@@ -123,32 +123,60 @@ pub(super) fn check(
     if let hir::ExprKind::Lit(lit) = init.kind {
         match lit.node {
             ast::LitKind::Bool(false) => {
-                check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Or, Replacement {
-                    method_name: "any",
-                    has_args: true,
-                    has_generic_return: false,
-                });
+                check_fold_with_op(
+                    cx,
+                    expr,
+                    acc,
+                    fold_span,
+                    hir::BinOpKind::Or,
+                    Replacement {
+                        method_name: "any",
+                        has_args: true,
+                        has_generic_return: false,
+                    },
+                );
             },
             ast::LitKind::Bool(true) => {
-                check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, Replacement {
-                    method_name: "all",
-                    has_args: true,
-                    has_generic_return: false,
-                });
+                check_fold_with_op(
+                    cx,
+                    expr,
+                    acc,
+                    fold_span,
+                    hir::BinOpKind::And,
+                    Replacement {
+                        method_name: "all",
+                        has_args: true,
+                        has_generic_return: false,
+                    },
+                );
             },
             ast::LitKind::Int(Pu128(0), _) => {
-                check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Add, Replacement {
-                    method_name: "sum",
-                    has_args: false,
-                    has_generic_return: needs_turbofish(cx, expr),
-                });
+                check_fold_with_op(
+                    cx,
+                    expr,
+                    acc,
+                    fold_span,
+                    hir::BinOpKind::Add,
+                    Replacement {
+                        method_name: "sum",
+                        has_args: false,
+                        has_generic_return: needs_turbofish(cx, expr),
+                    },
+                );
             },
             ast::LitKind::Int(Pu128(1), _) => {
-                check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, Replacement {
-                    method_name: "product",
-                    has_args: false,
-                    has_generic_return: needs_turbofish(cx, expr),
-                });
+                check_fold_with_op(
+                    cx,
+                    expr,
+                    acc,
+                    fold_span,
+                    hir::BinOpKind::Mul,
+                    Replacement {
+                        method_name: "product",
+                        has_args: false,
+                        has_generic_return: needs_turbofish(cx, expr),
+                    },
+                );
             },
             _ => (),
         }
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
index 1673a6f8b3a..7af550fa7c6 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
@@ -18,7 +18,7 @@ pub(super) fn check<'tcx>(
     recv: &'tcx hir::Expr<'_>,
     arg: &'tcx hir::Expr<'_>,
     simplify_using: &str,
-) {
+) -> bool {
     let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option);
     let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
     let is_bool = cx.typeck_results().expr_ty(recv).is_bool();
@@ -29,7 +29,7 @@ pub(super) fn check<'tcx>(
             let body_expr = &body.value;
 
             if usage::BindingUsageFinder::are_params_used(cx, body) || is_from_proc_macro(cx, expr) {
-                return;
+                return false;
             }
 
             if eager_or_lazy::switch_to_eager_eval(cx, body_expr) {
@@ -71,8 +71,10 @@ pub(super) fn check<'tcx>(
                             applicability,
                         );
                     });
+                    return true;
                 }
             }
         }
     }
+    false
 }
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index fa0eb9a94b7..fca416d9e64 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -168,7 +168,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
                         TOPLEVEL_REF_ARG,
                         arg.hir_id,
                         arg.pat.span,
-                        "`ref` directly on a function argument is ignored. \
+                        "`ref` directly on a function parameter does not prevent taking ownership of the passed argument. \
                         Consider using a reference type instead",
                     );
                 }
diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
index 962d85c6a9d..ba4af134ccd 100644
--- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
@@ -1,3 +1,4 @@
+
 use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::msrvs::{self, Msrv};
@@ -12,7 +13,7 @@ use rustc_middle::ty;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 use rustc_span::def_id::LocalDefId;
-use rustc_target::spec::abi::Abi;
+use rustc_abi::ExternAbi;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -183,11 +184,11 @@ fn already_const(header: hir::FnHeader) -> bool {
     header.constness == Constness::Const
 }
 
-fn could_be_const_with_abi(msrv: &Msrv, abi: Abi) -> bool {
+fn could_be_const_with_abi(msrv: &Msrv, abi: ExternAbi) -> bool {
     match abi {
-        Abi::Rust => true,
+        ExternAbi::Rust => true,
         // `const extern "C"` was stabilized after 1.62.0
-        Abi::C { unwind: false } => msrv.meets(msrvs::CONST_EXTERN_C_FN),
+        ExternAbi::C { unwind: false } => msrv.meets(msrvs::CONST_EXTERN_C_FN),
         // Rest ABIs are still unstable and need the `const_extern_fn` feature enabled.
         _ => msrv.meets(msrvs::CONST_EXTERN_FN),
     }
diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
index 302db2c914c..9acede4f32d 100644
--- a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
+++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
@@ -152,16 +152,19 @@ fn collect_unsafe_exprs<'tcx>(
             ExprKind::AssignOp(_, lhs, rhs) | ExprKind::Assign(lhs, rhs, _) => {
                 if matches!(
                     lhs.kind,
-                    ExprKind::Path(QPath::Resolved(_, hir::Path {
-                        res: Res::Def(
-                            DefKind::Static {
-                                mutability: Mutability::Mut,
-                                ..
-                            },
-                            _
-                        ),
-                        ..
-                    }))
+                    ExprKind::Path(QPath::Resolved(
+                        _,
+                        hir::Path {
+                            res: Res::Def(
+                                DefKind::Static {
+                                    mutability: Mutability::Mut,
+                                    ..
+                                },
+                                _
+                            ),
+                            ..
+                        }
+                    ))
                 ) {
                     unsafe_ops.push(("modification of a mutable static occurs here", expr.span));
                     collect_unsafe_exprs(cx, rhs, unsafe_ops);
diff --git a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
index 86c084423b7..49fd29d1dd6 100644
--- a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
+++ b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
@@ -18,11 +18,14 @@ declare_clippy_lint! {
     ///
     /// On the other hand, `Mutex`es are, in general, easier to
     /// verify correctness. An atomic does not behave the same as
-    /// an equivalent mutex. See [this issue](https://github.com/rust-lang/rust-clippy/issues/4295)'s commentary for more details.
+    /// an equivalent mutex. See [this issue](https://github.com/rust-lang/rust-clippy/issues/4295)'s
+    /// commentary for more details.
     ///
     /// ### Known problems
-    /// This lint cannot detect if the mutex is actually used
-    /// for waiting before a critical section.
+    /// * This lint cannot detect if the mutex is actually used
+    ///   for waiting before a critical section.
+    /// * This lint has a false positive that warns without considering the case
+    ///   where `Mutex` is used together with `Condvar`.
     ///
     /// ### Example
     /// ```no_run
@@ -48,14 +51,23 @@ declare_clippy_lint! {
     /// Checks for usage of `Mutex<X>` where `X` is an integral
     /// type.
     ///
-    /// ### Why is this bad?
+    /// ### Why restrict this?
     /// Using a mutex just to make access to a plain integer
     /// sequential is
     /// shooting flies with cannons. `std::sync::atomic::AtomicUsize` is leaner and faster.
     ///
+    /// On the other hand, `Mutex`es are, in general, easier to
+    /// verify correctness. An atomic does not behave the same as
+    /// an equivalent mutex. See [this issue](https://github.com/rust-lang/rust-clippy/issues/4295)'s
+    /// commentary for more details.
+    ///
     /// ### Known problems
-    /// This lint cannot detect if the mutex is actually used
-    /// for waiting before a critical section.
+    /// * This lint cannot detect if the mutex is actually used
+    ///   for waiting before a critical section.
+    /// * This lint has a false positive that warns without considering the case
+    ///   where `Mutex` is used together with `Condvar`.
+    /// * This lint suggest using `AtomicU64` instead of `Mutex<u64>`, but
+    ///   `AtomicU64` is not available on some 32-bit platforms.
     ///
     /// ### Example
     /// ```no_run
@@ -70,7 +82,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "pre 1.29.0"]
     pub MUTEX_INTEGER,
-    nursery,
+    restriction,
     "using a mutex for an integer type"
 }
 
@@ -108,7 +120,7 @@ fn get_atomic_name(ty: Ty<'_>) -> Option<&'static str> {
                 UintTy::U32 => Some("AtomicU32"),
                 UintTy::U64 => Some("AtomicU64"),
                 UintTy::Usize => Some("AtomicUsize"),
-                // There's no `AtomicU128`.
+                // `AtomicU128` is unstable and only available on a few platforms: https://github.com/rust-lang/rust/issues/99069
                 UintTy::U128 => None,
             }
         },
@@ -119,7 +131,7 @@ fn get_atomic_name(ty: Ty<'_>) -> Option<&'static str> {
                 IntTy::I32 => Some("AtomicI32"),
                 IntTy::I64 => Some("AtomicI64"),
                 IntTy::Isize => Some("AtomicIsize"),
-                // There's no `AtomicI128`.
+                // `AtomicU128` is unstable and only available on a few platforms: https://github.com/rust-lang/rust/issues/99069
                 IntTy::I128 => None,
             }
         },
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
index b7dc269061c..996251fdf16 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
@@ -20,7 +20,7 @@ use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::kw;
-use rustc_target::spec::abi::Abi;
+use rustc_abi::ExternAbi;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -149,7 +149,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
                     return;
                 }
                 let attrs = cx.tcx.hir().attrs(hir_id);
-                if header.abi != Abi::Rust || requires_exact_signature(attrs) {
+                if header.abi != ExternAbi::Rust || requires_exact_signature(attrs) {
                     return;
                 }
                 header.is_async()
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 30846fb46ac..40c65d1ef9e 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -19,7 +19,7 @@ use rustc_session::declare_lint_pass;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::kw;
 use rustc_span::{Span, sym};
-use rustc_target::spec::abi::Abi;
+use rustc_abi::ExternAbi;
 use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::misc::type_allowed_to_implement_copy;
 
@@ -89,7 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
         match kind {
             FnKind::ItemFn(.., header) => {
                 let attrs = cx.tcx.hir().attrs(hir_id);
-                if header.abi != Abi::Rust || requires_exact_signature(attrs) {
+                if header.abi != ExternAbi::Rust || requires_exact_signature(attrs) {
                     return;
                 }
             },
@@ -181,9 +181,14 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                 && !is_copy(cx, ty)
                 && ty.is_sized(cx.tcx, cx.typing_env())
                 && !allowed_traits.iter().any(|&t| {
-                    implements_trait_with_env_from_iter(cx.tcx, cx.typing_env(), ty, t, None, [None::<
-                        ty::GenericArg<'tcx>,
-                    >])
+                    implements_trait_with_env_from_iter(
+                        cx.tcx,
+                        cx.typing_env(),
+                        ty,
+                        t,
+                        None,
+                        [None::<ty::GenericArg<'tcx>>],
+                    )
                 })
                 && !implements_borrow_trait
                 && !all_borrowable_trait
diff --git a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs
index 2e2916c957d..b73b9083a99 100644
--- a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs
+++ b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs
@@ -5,7 +5,7 @@ use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::{BytePos, Pos};
-use rustc_target::spec::abi::Abi;
+use rustc_abi::ExternAbi;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -46,7 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi {
             for attr in attrs {
                 if let Some(ident) = attr.ident()
                     && ident.name == rustc_span::sym::no_mangle
-                    && fn_sig.header.abi == Abi::Rust
+                    && fn_sig.header.abi == ExternAbi::Rust
                     && let Some((fn_attrs, _)) = fn_snippet.rsplit_once("fn")
                     && !fn_attrs.contains("extern")
                 {
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index 147654675ec..405bbfc9c6f 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -5,6 +5,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_in_const_context;
 use clippy_utils::macros::macro_backtrace;
 use clippy_utils::ty::{InteriorMut, implements_trait};
+use rustc_abi::VariantIdx;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{
@@ -16,7 +17,6 @@ use rustc_middle::ty::adjustment::Adjust;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::impl_lint_pass;
 use rustc_span::{DUMMY_SP, Span, sym};
-use rustc_target::abi::VariantIdx;
 
 // FIXME: this is a correctness problem but there's no suitable
 // warn-by-default category.
diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs
index d9845bc3b0f..9ad32c2bd39 100644
--- a/src/tools/clippy/clippy_lints/src/operators/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs
@@ -265,9 +265,6 @@ declare_clippy_lint! {
     /// `x.trailing_zeros() >= 4` is much clearer than `x & 15
     /// == 0`
     ///
-    /// ### Known problems
-    /// llvm generates better code for `x & 15 == 0` on x86
-    ///
     /// ### Example
     /// ```no_run
     /// # let x = 1;
diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
index b2089487a9f..a3e89671eec 100644
--- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
@@ -19,7 +19,7 @@ use rustc_middle::ty::{self, RegionKind, TyCtxt};
 use rustc_session::impl_lint_pass;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{Span, sym};
-use rustc_target::spec::abi::Abi;
+use rustc_abi::ExternAbi;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -277,7 +277,7 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue {
         let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
         match kind {
             FnKind::ItemFn(.., header) => {
-                if header.abi != Abi::Rust {
+                if header.abi != ExternAbi::Rust {
                     return;
                 }
                 let attrs = cx.tcx.hir().attrs(hir_id);
diff --git a/src/tools/clippy/clippy_lints/src/precedence.rs b/src/tools/clippy/clippy_lints/src/precedence.rs
index 421b2b74755..ec6835db897 100644
--- a/src/tools/clippy/clippy_lints/src/precedence.rs
+++ b/src/tools/clippy/clippy_lints/src/precedence.rs
@@ -3,17 +3,14 @@ use clippy_utils::source::snippet_with_applicability;
 use rustc_ast::ast::BinOpKind::{Add, BitAnd, BitOr, BitXor, Div, Mul, Rem, Shl, Shr, Sub};
 use rustc_ast::ast::{BinOpKind, Expr, ExprKind};
 use rustc_errors::Applicability;
-use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_lint::{EarlyContext, EarlyLintPass, Lint};
 use rustc_session::declare_lint_pass;
 use rustc_span::source_map::Spanned;
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for operations where precedence may be unclear
-    /// and suggests to add parentheses. Currently it catches the following:
-    /// * mixed usage of arithmetic and bit shifting/combining operators without
-    /// parentheses
-    /// * mixed usage of bitmasking and bit shifting operators without parentheses
+    /// Checks for operations where precedence may be unclear and suggests to add parentheses.
+    /// It catches a mixed usage of arithmetic and bit shifting/combining operators without parentheses
     ///
     /// ### Why is this bad?
     /// Not everyone knows the precedence of those operators by
@@ -21,15 +18,32 @@ declare_clippy_lint! {
     /// code.
     ///
     /// ### Example
-    /// * `1 << 2 + 3` equals 32, while `(1 << 2) + 3` equals 7
-    /// * `0x2345 & 0xF000 >> 12` equals 5, while `(0x2345 & 0xF000) >> 12` equals 2
+    /// `1 << 2 + 3` equals 32, while `(1 << 2) + 3` equals 7
     #[clippy::version = "pre 1.29.0"]
     pub PRECEDENCE,
     complexity,
     "operations where precedence may be unclear"
 }
 
-declare_lint_pass!(Precedence => [PRECEDENCE]);
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for bit shifting operations combined with bit masking/combining operators
+    /// and suggest using parentheses.
+    ///
+    /// ### Why restrict this?
+    /// Not everyone knows the precedence of those operators by
+    /// heart, so expressions like these may trip others trying to reason about the
+    /// code.
+    ///
+    /// ### Example
+    /// `0x2345 & 0xF000 >> 12` equals 5, while `(0x2345 & 0xF000) >> 12` equals 2
+    #[clippy::version = "1.86.0"]
+    pub PRECEDENCE_BITS,
+    restriction,
+    "operations mixing bit shifting with bit combining/masking"
+}
+
+declare_lint_pass!(Precedence => [PRECEDENCE, PRECEDENCE_BITS]);
 
 impl EarlyLintPass for Precedence {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
@@ -38,10 +52,10 @@ impl EarlyLintPass for Precedence {
         }
 
         if let ExprKind::Binary(Spanned { node: op, .. }, ref left, ref right) = expr.kind {
-            let span_sugg = |expr: &Expr, sugg, appl| {
+            let span_sugg = |lint: &'static Lint, expr: &Expr, sugg, appl| {
                 span_lint_and_sugg(
                     cx,
-                    PRECEDENCE,
+                    lint,
                     expr.span,
                     "operator precedence might not be obvious",
                     "consider parenthesizing your expression",
@@ -57,37 +71,41 @@ impl EarlyLintPass for Precedence {
             match (op, get_bin_opt(left), get_bin_opt(right)) {
                 (
                     BitAnd | BitOr | BitXor,
-                    Some(Shl | Shr | Add | Div | Mul | Rem | Sub),
-                    Some(Shl | Shr | Add | Div | Mul | Rem | Sub),
+                    Some(left_op @ (Shl | Shr | Add | Div | Mul | Rem | Sub)),
+                    Some(right_op @ (Shl | Shr | Add | Div | Mul | Rem | Sub)),
                 )
-                | (Shl | Shr, Some(Add | Div | Mul | Rem | Sub), Some(Add | Div | Mul | Rem | Sub)) => {
+                | (
+                    Shl | Shr,
+                    Some(left_op @ (Add | Div | Mul | Rem | Sub)),
+                    Some(right_op @ (Add | Div | Mul | Rem | Sub)),
+                ) => {
                     let sugg = format!(
                         "({}) {} ({})",
                         snippet_with_applicability(cx, left.span, "..", &mut applicability),
                         op.as_str(),
                         snippet_with_applicability(cx, right.span, "..", &mut applicability)
                     );
-                    span_sugg(expr, sugg, applicability);
+                    span_sugg(lint_for(&[op, left_op, right_op]), expr, sugg, applicability);
                 },
-                (BitAnd | BitOr | BitXor, Some(Shl | Shr | Add | Div | Mul | Rem | Sub), _)
-                | (Shl | Shr, Some(Add | Div | Mul | Rem | Sub), _) => {
+                (BitAnd | BitOr | BitXor, Some(side_op @ (Shl | Shr | Add | Div | Mul | Rem | Sub)), _)
+                | (Shl | Shr, Some(side_op @ (Add | Div | Mul | Rem | Sub)), _) => {
                     let sugg = format!(
                         "({}) {} {}",
                         snippet_with_applicability(cx, left.span, "..", &mut applicability),
                         op.as_str(),
                         snippet_with_applicability(cx, right.span, "..", &mut applicability)
                     );
-                    span_sugg(expr, sugg, applicability);
+                    span_sugg(lint_for(&[op, side_op]), expr, sugg, applicability);
                 },
-                (BitAnd | BitOr | BitXor, _, Some(Shl | Shr | Add | Div | Mul | Rem | Sub))
-                | (Shl | Shr, _, Some(Add | Div | Mul | Rem | Sub)) => {
+                (BitAnd | BitOr | BitXor, _, Some(side_op @ (Shl | Shr | Add | Div | Mul | Rem | Sub)))
+                | (Shl | Shr, _, Some(side_op @ (Add | Div | Mul | Rem | Sub))) => {
                     let sugg = format!(
                         "{} {} ({})",
                         snippet_with_applicability(cx, left.span, "..", &mut applicability),
                         op.as_str(),
                         snippet_with_applicability(cx, right.span, "..", &mut applicability)
                     );
-                    span_sugg(expr, sugg, applicability);
+                    span_sugg(lint_for(&[op, side_op]), expr, sugg, applicability);
                 },
                 _ => (),
             }
@@ -106,3 +124,11 @@ fn get_bin_opt(expr: &Expr) -> Option<BinOpKind> {
 fn is_bit_op(op: BinOpKind) -> bool {
     matches!(op, BitXor | BitAnd | BitOr | Shl | Shr)
 }
+
+fn lint_for(ops: &[BinOpKind]) -> &'static Lint {
+    if ops.iter().all(|op| is_bit_op(*op)) {
+        PRECEDENCE_BITS
+    } else {
+        PRECEDENCE
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 506adf0f2cc..7fba4b6a6c8 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -1,5 +1,6 @@
-use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then};
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then};
 use clippy_utils::source::SpanRangeExt;
+use clippy_utils::sugg::Sugg;
 use clippy_utils::visitors::contains_unsafe_block;
 use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local, std_or_core};
 use hir::LifetimeName;
@@ -18,7 +19,7 @@ use rustc_middle::ty::{self, Binder, ClauseKind, ExistentialPredicate, List, Pre
 use rustc_session::declare_lint_pass;
 use rustc_span::symbol::Symbol;
 use rustc_span::{Span, sym};
-use rustc_target::spec::abi::Abi;
+use rustc_abi::ExternAbi;
 use rustc_trait_selection::infer::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use std::{fmt, iter};
@@ -159,7 +160,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
 
             check_mut_from_ref(cx, sig, None);
 
-            if !matches!(sig.header.abi, Abi::Rust) {
+            if !matches!(sig.header.abi, ExternAbi::Rust) {
                 // Ignore `extern` functions with non-Rust calling conventions
                 return;
             }
@@ -219,7 +220,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
 
         check_mut_from_ref(cx, sig, Some(body));
 
-        if !matches!(sig.header.abi, Abi::Rust) {
+        if !matches!(sig.header.abi, ExternAbi::Rust) {
             // Ignore `extern` functions with non-Rust calling conventions
             return;
         }
@@ -250,15 +251,24 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
     }
 
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if let ExprKind::Binary(ref op, l, r) = expr.kind {
-            if (op.node == BinOpKind::Eq || op.node == BinOpKind::Ne) && (is_null_path(cx, l) || is_null_path(cx, r)) {
-                span_lint(
-                    cx,
-                    CMP_NULL,
-                    expr.span,
-                    "comparing with null is better expressed by the `.is_null()` method",
-                );
-            }
+        if let ExprKind::Binary(op, l, r) = expr.kind
+            && (op.node == BinOpKind::Eq || op.node == BinOpKind::Ne)
+        {
+            let non_null_path_snippet = match (is_null_path(cx, l), is_null_path(cx, r)) {
+                (true, false) if let Some(sugg) = Sugg::hir_opt(cx, r) => sugg.maybe_par(),
+                (false, true) if let Some(sugg) = Sugg::hir_opt(cx, l) => sugg.maybe_par(),
+                _ => return,
+            };
+
+            span_lint_and_sugg(
+                cx,
+                CMP_NULL,
+                expr.span,
+                "comparing with null is better expressed by the `.is_null()` method",
+                "try",
+                format!("{non_null_path_snippet}.is_null()"),
+                Applicability::MachineApplicable,
+            );
         } else {
             check_invalid_ptr_usage(cx, expr);
         }
diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
index b9e0106fc86..fb1bc494bd9 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
@@ -349,10 +349,14 @@ fn visit_clone_usage(cloned: mir::Local, clone: mir::Local, mir: &mir::Body<'_>,
             local_use_locs: _,
             local_consume_or_mutate_locs: clone_consume_or_mutate_locs,
         },
-    )) = visit_local_usage(&[cloned, clone], mir, mir::Location {
-        block: bb,
-        statement_index: mir.basic_blocks[bb].statements.len(),
-    })
+    )) = visit_local_usage(
+        &[cloned, clone],
+        mir,
+        mir::Location {
+            block: bb,
+            statement_index: mir.basic_blocks[bb].statements.len(),
+        },
+    )
     .map(|mut vec| (vec.remove(0), vec.remove(0)))
     {
         CloneUsage {
diff --git a/src/tools/clippy/clippy_lints/src/redundant_else.rs b/src/tools/clippy/clippy_lints/src/redundant_else.rs
index 3476f56cf33..a1b5a3aff32 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_else.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_else.rs
@@ -1,8 +1,12 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::{indent_of, reindent_multiline, snippet};
 use rustc_ast::ast::{Block, Expr, ExprKind, Stmt, StmtKind};
 use rustc_ast::visit::{Visitor, walk_expr};
+use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_session::declare_lint_pass;
+use rustc_span::Span;
+use std::borrow::Cow;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -75,13 +79,27 @@ impl EarlyLintPass for RedundantElse {
                 _ => break,
             }
         }
-        span_lint_and_help(
+
+        let mut app = Applicability::MachineApplicable;
+        if let ExprKind::Block(block, _) = &els.kind {
+            for stmt in &block.stmts {
+                // If the `else` block contains a local binding or a macro invocation, Clippy shouldn't auto-fix it
+                if matches!(&stmt.kind, StmtKind::Let(_) | StmtKind::MacCall(_)) {
+                    app = Applicability::Unspecified;
+                    break;
+                }
+            }
+        }
+
+        // FIXME: The indentation of the suggestion would be the same as the one of the macro invocation in this implementation, see https://github.com/rust-lang/rust-clippy/pull/13936#issuecomment-2569548202
+        span_lint_and_sugg(
             cx,
             REDUNDANT_ELSE,
-            els.span,
+            els.span.with_lo(then.span.hi()),
             "redundant else block",
-            None,
             "remove the `else` block and move the contents out",
+            make_sugg(cx, els.span, "..", Some(expr.span)).to_string(),
+            app,
         );
     }
 }
@@ -136,3 +154,23 @@ impl BreakVisitor {
         self.check(stmt, Self::visit_stmt)
     }
 }
+
+// Extract the inner contents of an `else` block str
+// e.g. `{ foo(); bar(); }` -> `foo(); bar();`
+fn extract_else_block(mut block: &str) -> String {
+    block = block.strip_prefix("{").unwrap_or(block);
+    block = block.strip_suffix("}").unwrap_or(block);
+    block.trim_end().to_string()
+}
+
+fn make_sugg<'a>(
+    cx: &EarlyContext<'_>,
+    els_span: Span,
+    default: &'a str,
+    indent_relative_to: Option<Span>,
+) -> Cow<'a, str> {
+    let extracted = extract_else_block(&snippet(cx, els_span, default));
+    let indent = indent_relative_to.and_then(|s| indent_of(cx, s));
+
+    reindent_multiline(extracted.into(), false, indent)
+}
diff --git a/src/tools/clippy/clippy_lints/src/same_name_method.rs b/src/tools/clippy/clippy_lints/src/same_name_method.rs
index 8d31641d483..29914d4379f 100644
--- a/src/tools/clippy/clippy_lints/src/same_name_method.rs
+++ b/src/tools/clippy/clippy_lints/src/same_name_method.rs
@@ -62,10 +62,13 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
                 && let TyKind::Path(QPath::Resolved(_, Path { res, .. })) = self_ty.kind
             {
                 if !map.contains_key(res) {
-                    map.insert(*res, ExistingName {
-                        impl_methods: BTreeMap::new(),
-                        trait_methods: BTreeMap::new(),
-                    });
+                    map.insert(
+                        *res,
+                        ExistingName {
+                            impl_methods: BTreeMap::new(),
+                            trait_methods: BTreeMap::new(),
+                        },
+                    );
                 }
                 let existing_name = map.get_mut(res).unwrap();
 
diff --git a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
index f72ff10dd43..b22c638fc36 100644
--- a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
+++ b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
@@ -63,8 +63,7 @@ fn get_pointee_ty_and_count_expr<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'_>,
 ) -> Option<(Ty<'tcx>, &'tcx Expr<'tcx>)> {
-    const METHODS: [&str; 11] = [
-        "write_bytes",
+    const METHODS: [&str; 10] = [
         "copy_to",
         "copy_from",
         "copy_to_nonoverlapping",
@@ -79,7 +78,7 @@ fn get_pointee_ty_and_count_expr<'tcx>(
 
     if let ExprKind::Call(func, [.., count]) = expr.kind
         // Find calls to ptr::{copy, copy_nonoverlapping}
-        // and ptr::{swap_nonoverlapping, write_bytes},
+        // and ptr::swap_nonoverlapping,
         && let ExprKind::Path(ref func_qpath) = func.kind
         && let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id()
         && matches!(cx.tcx.get_diagnostic_name(def_id), Some(
@@ -88,7 +87,6 @@ fn get_pointee_ty_and_count_expr<'tcx>(
             | sym::ptr_slice_from_raw_parts
             | sym::ptr_slice_from_raw_parts_mut
             | sym::ptr_swap_nonoverlapping
-            | sym::ptr_write_bytes
             | sym::slice_from_raw_parts
             | sym::slice_from_raw_parts_mut
         ))
@@ -99,7 +97,7 @@ fn get_pointee_ty_and_count_expr<'tcx>(
         return Some((pointee_ty, count));
     }
     if let ExprKind::MethodCall(method_path, ptr_self, [.., count], _) = expr.kind
-        // Find calls to copy_{from,to}{,_nonoverlapping} and write_bytes methods
+        // Find calls to copy_{from,to}{,_nonoverlapping}
         && let method_ident = method_path.ident.as_str()
         && METHODS.iter().any(|m| *m == method_ident)
 
@@ -121,6 +119,8 @@ impl<'tcx> LateLintPass<'tcx> for SizeOfInElementCount {
              instead of a count of elements of `T`";
 
         if let Some((pointee_ty, count_expr)) = get_pointee_ty_and_count_expr(cx, expr)
+            // Using a number of bytes for a byte type isn't suspicious
+            && pointee_ty != cx.tcx.types.u8
             // Find calls to functions with an element count parameter and get
             // the pointee type and count parameter expression
 
diff --git a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
index 569812d8106..9993e6ae18b 100644
--- a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
+++ b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
@@ -55,13 +55,11 @@ impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome {
                     if let hir::ExprKind::Path(to_digits_path) = &to_digits_call.kind
                         && let to_digits_call_res = cx.qpath_res(to_digits_path, to_digits_call.hir_id)
                         && let Some(to_digits_def_id) = to_digits_call_res.opt_def_id()
-                        && match_def_path(cx, to_digits_def_id, &[
-                            "core",
-                            "char",
-                            "methods",
-                            "<impl char>",
-                            "to_digit",
-                        ])
+                        && match_def_path(
+                            cx,
+                            to_digits_def_id,
+                            &["core", "char", "methods", "<impl char>", "to_digit"],
+                        )
                     {
                         Some((false, char_arg, radix_arg))
                     } else {
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index 391c36df492..579cbf447a2 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -386,22 +386,30 @@ impl<'tcx> LateLintPass<'tcx> for Types {
 
         let is_exported = cx.effective_visibilities.is_exported(def_id);
 
-        self.check_fn_decl(cx, decl, CheckTyContext {
-            is_in_trait_impl,
-            in_body: matches!(fn_kind, FnKind::Closure),
-            is_exported,
-            ..CheckTyContext::default()
-        });
+        self.check_fn_decl(
+            cx,
+            decl,
+            CheckTyContext {
+                is_in_trait_impl,
+                in_body: matches!(fn_kind, FnKind::Closure),
+                is_exported,
+                ..CheckTyContext::default()
+            },
+        );
     }
 
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
         let is_exported = cx.effective_visibilities.is_exported(item.owner_id.def_id);
 
         match item.kind {
-            ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _, _) => self.check_ty(cx, ty, CheckTyContext {
-                is_exported,
-                ..CheckTyContext::default()
-            }),
+            ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _, _) => self.check_ty(
+                cx,
+                ty,
+                CheckTyContext {
+                    is_exported,
+                    ..CheckTyContext::default()
+                },
+            ),
             // functions, enums, structs, impls and traits are covered
             _ => (),
         }
@@ -419,10 +427,14 @@ impl<'tcx> LateLintPass<'tcx> for Types {
                     false
                 };
 
-                self.check_ty(cx, ty, CheckTyContext {
-                    is_in_trait_impl,
-                    ..CheckTyContext::default()
-                });
+                self.check_ty(
+                    cx,
+                    ty,
+                    CheckTyContext {
+                        is_in_trait_impl,
+                        ..CheckTyContext::default()
+                    },
+                );
             },
             // Methods are covered by check_fn.
             // Type aliases are ignored because oftentimes it's impossible to
@@ -438,10 +450,14 @@ impl<'tcx> LateLintPass<'tcx> for Types {
 
         let is_exported = cx.effective_visibilities.is_exported(field.def_id);
 
-        self.check_ty(cx, field.ty, CheckTyContext {
-            is_exported,
-            ..CheckTyContext::default()
-        });
+        self.check_ty(
+            cx,
+            field.ty,
+            CheckTyContext {
+                is_exported,
+                ..CheckTyContext::default()
+            },
+        );
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &TraitItem<'tcx>) {
@@ -469,10 +485,14 @@ impl<'tcx> LateLintPass<'tcx> for Types {
 
     fn check_local(&mut self, cx: &LateContext<'tcx>, local: &LetStmt<'tcx>) {
         if let Some(ty) = local.ty {
-            self.check_ty(cx, ty, CheckTyContext {
-                in_body: true,
-                ..CheckTyContext::default()
-            });
+            self.check_ty(
+                cx,
+                ty,
+                CheckTyContext {
+                    in_body: true,
+                    ..CheckTyContext::default()
+                },
+            );
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/types/type_complexity.rs b/src/tools/clippy/clippy_lints/src/types/type_complexity.rs
index 7f51660293b..0704653385f 100644
--- a/src/tools/clippy/clippy_lints/src/types/type_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/types/type_complexity.rs
@@ -1,9 +1,9 @@
 use clippy_utils::diagnostics::span_lint;
+use rustc_abi::ExternAbi;
 use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_ty};
 use rustc_hir::{self as hir, AmbigArg, GenericParamKind, TyKind};
 use rustc_lint::LateContext;
 use rustc_span::Span;
-use rustc_target::spec::abi::Abi;
 
 use super::TYPE_COMPLEXITY;
 
@@ -50,7 +50,7 @@ impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor {
             TyKind::Path(..) | TyKind::Slice(..) | TyKind::Tup(..) | TyKind::Array(..) => (10 * self.nest, 1),
 
             // function types bring a lot of overhead
-            TyKind::BareFn(bare) if bare.abi == Abi::Rust => (50 * self.nest, 1),
+            TyKind::BareFn(bare) if bare.abi == ExternAbi::Rust => (50 * self.nest, 1),
 
             TyKind::TraitObject(param_bounds, _) => {
                 let has_lifetime_parameters = param_bounds.iter().any(|bound| {
diff --git a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
index 3fc08e8192d..207f2ef4563 100644
--- a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
@@ -257,10 +257,13 @@ fn is_default_method_on_current_ty<'tcx>(tcx: TyCtxt<'tcx>, qpath: QPath<'tcx>,
             }
             if matches!(
                 ty.kind,
-                TyKind::Path(QPath::Resolved(_, hir::Path {
-                    res: Res::SelfTyAlias { .. },
-                    ..
-                },))
+                TyKind::Path(QPath::Resolved(
+                    _,
+                    hir::Path {
+                        res: Res::SelfTyAlias { .. },
+                        ..
+                    },
+                ))
             ) {
                 return true;
             }
diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
index 5e5d6a9e333..b3d26908093 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -1,3 +1,4 @@
+use std::sync::Arc;
 use std::ops::ControlFlow;
 
 use clippy_config::Conf;
@@ -6,7 +7,6 @@ use clippy_utils::is_lint_allowed;
 use clippy_utils::source::walk_span_to_context;
 use clippy_utils::visitors::{Descend, for_each_expr};
 use hir::HirId;
-use rustc_data_structures::sync::Lrc;
 use rustc_hir as hir;
 use rustc_hir::{Block, BlockCheckMode, ItemKind, Node, UnsafeSource};
 use rustc_lexer::{TokenKind, tokenize};
@@ -480,7 +480,7 @@ fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> HasSaf
     if let Some(comment_start) = comment_start
         && let Ok(unsafe_line) = source_map.lookup_line(item.span.lo())
         && let Ok(comment_start_line) = source_map.lookup_line(comment_start)
-        && Lrc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf)
+        && Arc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf)
         && let Some(src) = unsafe_line.sf.src.as_deref()
     {
         return if comment_start_line.line >= unsafe_line.line {
@@ -520,7 +520,7 @@ fn stmt_has_safety_comment(cx: &LateContext<'_>, span: Span, hir_id: HirId) -> H
     if let Some(comment_start) = comment_start
         && let Ok(unsafe_line) = source_map.lookup_line(span.lo())
         && let Ok(comment_start_line) = source_map.lookup_line(comment_start)
-        && Lrc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf)
+        && Arc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf)
         && let Some(src) = unsafe_line.sf.src.as_deref()
     {
         return if comment_start_line.line >= unsafe_line.line {
@@ -580,7 +580,7 @@ fn span_from_macro_expansion_has_safety_comment(cx: &LateContext<'_>, span: Span
         //     ^--------------------------------------------^
         if let Ok(unsafe_line) = source_map.lookup_line(span.lo())
             && let Ok(macro_line) = source_map.lookup_line(ctxt.outer_expn_data().def_site.lo())
-            && Lrc::ptr_eq(&unsafe_line.sf, &macro_line.sf)
+            && Arc::ptr_eq(&unsafe_line.sf, &macro_line.sf)
             && let Some(src) = unsafe_line.sf.src.as_deref()
         {
             if macro_line.line < unsafe_line.line {
@@ -641,7 +641,7 @@ fn span_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
         if let Ok(unsafe_line) = source_map.lookup_line(span.lo())
             && let Some(body_span) = walk_span_to_context(search_span, SyntaxContext::root())
             && let Ok(body_line) = source_map.lookup_line(body_span.lo())
-            && Lrc::ptr_eq(&unsafe_line.sf, &body_line.sf)
+            && Arc::ptr_eq(&unsafe_line.sf, &body_line.sf)
             && let Some(src) = unsafe_line.sf.src.as_deref()
         {
             // Get the text from the start of function body to the unsafe block.
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_semicolon.rs b/src/tools/clippy/clippy_lints/src/unnecessary_semicolon.rs
index efbc536dcb4..e5267620c4f 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_semicolon.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_semicolon.rs
@@ -37,7 +37,7 @@ declare_clippy_lint! {
 
 #[derive(Default)]
 pub struct UnnecessarySemicolon {
-    last_statements: Vec<HirId>,
+    last_statements: Vec<(HirId, bool)>,
 }
 
 impl_lint_pass!(UnnecessarySemicolon => [UNNECESSARY_SEMICOLON]);
@@ -45,27 +45,25 @@ impl_lint_pass!(UnnecessarySemicolon => [UNNECESSARY_SEMICOLON]);
 impl UnnecessarySemicolon {
     /// Enter or leave a block, remembering the last statement of the block.
     fn handle_block(&mut self, cx: &LateContext<'_>, block: &Block<'_>, enter: bool) {
-        // Up to edition 2021, removing the semicolon of the last statement of a block
-        // may result in the scrutinee temporary values to live longer than the block
-        // variables. To avoid this problem, we do not lint the last statement of an
-        // expressionless block.
-        if cx.tcx.sess.edition() <= Edition2021
-            && block.expr.is_none()
+        // The last statement of an expressionless block deserves a special treatment.
+        if block.expr.is_none()
             && let Some(last_stmt) = block.stmts.last()
         {
             if enter {
-                self.last_statements.push(last_stmt.hir_id);
+                let block_ty = cx.typeck_results().node_type(block.hir_id);
+                self.last_statements.push((last_stmt.hir_id, block_ty.is_unit()));
             } else {
                 self.last_statements.pop();
             }
         }
     }
 
-    /// Checks if `stmt` is the last statement in an expressionless block for edition ≤ 2021.
-    fn is_last_in_block(&self, stmt: &Stmt<'_>) -> bool {
+    /// Checks if `stmt` is the last statement in an expressionless block. In this case,
+    /// return `Some` with a boolean which is `true` if the block type is `()`.
+    fn is_last_in_block(&self, stmt: &Stmt<'_>) -> Option<bool> {
         self.last_statements
             .last()
-            .is_some_and(|last_stmt_id| last_stmt_id == &stmt.hir_id)
+            .and_then(|&(stmt_id, is_unit)| (stmt_id == stmt.hir_id).then_some(is_unit))
     }
 }
 
@@ -90,8 +88,22 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessarySemicolon {
             )
             && cx.typeck_results().expr_ty(expr) == cx.tcx.types.unit
         {
-            if self.is_last_in_block(stmt) && leaks_droppable_temporary_with_limited_lifetime(cx, expr) {
-                return;
+            if let Some(block_is_unit) = self.is_last_in_block(stmt) {
+                if cx.tcx.sess.edition() <= Edition2021 && leaks_droppable_temporary_with_limited_lifetime(cx, expr) {
+                    // The expression contains temporaries with limited lifetimes in edition lower than 2024. Those may
+                    // survive until after the end of the current scope instead of until the end of the statement, so do
+                    // not lint this situation.
+                    return;
+                }
+
+                if !block_is_unit {
+                    // Although the expression returns `()`, the block doesn't. This may happen if the expression
+                    // returns early in all code paths, such as a `return value` in the condition of an `if` statement,
+                    // in which case the block type would be `!`. Do not lint in this case, as the statement would
+                    // become the block expression; the block type would become `()` and this may not type correctly
+                    // if the expected type for the block is not `()`.
+                    return;
+                }
             }
 
             let semi_span = expr.span.shrink_to_hi().to(stmt.span.shrink_to_hi());
diff --git a/src/tools/clippy/clippy_lints/src/unneeded_struct_pattern.rs b/src/tools/clippy/clippy_lints/src/unneeded_struct_pattern.rs
index 40ba70d451d..a74eab8b6ae 100644
--- a/src/tools/clippy/clippy_lints/src/unneeded_struct_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/unneeded_struct_pattern.rs
@@ -32,7 +32,7 @@ declare_clippy_lint! {
     ///     None => 0,
     /// };
     /// ```
-    #[clippy::version = "1.83.0"]
+    #[clippy::version = "1.86.0"]
     pub UNNEEDED_STRUCT_PATTERN,
     style,
     "using struct pattern to match against unit variant"
diff --git a/src/tools/clippy/clippy_lints/src/utils/attr_collector.rs b/src/tools/clippy/clippy_lints/src/utils/attr_collector.rs
index 1522553bbf5..169429811d3 100644
--- a/src/tools/clippy/clippy_lints/src/utils/attr_collector.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/attr_collector.rs
@@ -1,14 +1,13 @@
 use std::mem;
-use std::sync::OnceLock;
+use std::sync::{Arc, OnceLock};
 
 use rustc_ast::{Attribute, Crate};
-use rustc_data_structures::sync::Lrc;
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 
 #[derive(Clone, Default)]
-pub struct AttrStorage(pub Lrc<OnceLock<Vec<Span>>>);
+pub struct AttrStorage(pub Arc<OnceLock<Vec<Span>>>);
 
 pub struct AttrCollector {
     storage: AttrStorage,
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index 31ae002e47d..11c14c14777 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -522,7 +522,7 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
 
             let replacement = match (format_string_is_raw, replace_raw) {
                 (false, false) => Some(replacement),
-                (false, true) => Some(replacement.replace('"', "\\\"").replace('\\', "\\\\")),
+                (false, true) => Some(replacement.replace('\\', "\\\\").replace('"', "\\\"")),
                 (true, false) => match conservative_unescape(&replacement) {
                     Ok(unescaped) => Some(unescaped),
                     Err(UnescapeErr::Lint) => None,
diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md
index 251e3dfe41b..41f3b1cbd50 100644
--- a/src/tools/clippy/clippy_utils/README.md
+++ b/src/tools/clippy/clippy_utils/README.md
@@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain:
 
 <!-- begin autogenerated nightly -->
 ```
-nightly-2025-01-28
+nightly-2025-02-06
 ```
 <!-- end autogenerated nightly -->
 
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
index 2eb09bac8d8..ab5f97199ce 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
@@ -362,18 +362,21 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
                 defaultness: ld,
                 sig: lf,
                 generics: lg,
+                contract: lc,
                 body: lb,
             }),
             Fn(box ast::Fn {
                 defaultness: rd,
                 sig: rf,
                 generics: rg,
+                contract: rc,
                 body: rb,
             }),
         ) => {
             eq_defaultness(*ld, *rd)
                 && eq_fn_sig(lf, rf)
                 && eq_generics(lg, rg)
+                && eq_opt_fn_contract(lc, rc)
                 && both(lb.as_ref(), rb.as_ref(), |l, r| eq_block(l, r))
         },
         (Mod(lu, lmk), Mod(ru, rmk)) => {
@@ -497,18 +500,21 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
                 defaultness: ld,
                 sig: lf,
                 generics: lg,
+                contract: lc,
                 body: lb,
             }),
             Fn(box ast::Fn {
                 defaultness: rd,
                 sig: rf,
                 generics: rg,
+                contract: rc,
                 body: rb,
             }),
         ) => {
             eq_defaultness(*ld, *rd)
                 && eq_fn_sig(lf, rf)
                 && eq_generics(lg, rg)
+                && eq_opt_fn_contract(lc, rc)
                 && both(lb.as_ref(), rb.as_ref(), |l, r| eq_block(l, r))
         },
         (
@@ -559,18 +565,21 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
                 defaultness: ld,
                 sig: lf,
                 generics: lg,
+                contract: lc,
                 body: lb,
             }),
             Fn(box ast::Fn {
                 defaultness: rd,
                 sig: rf,
                 generics: rg,
+                contract: rc,
                 body: rb,
             }),
         ) => {
             eq_defaultness(*ld, *rd)
                 && eq_fn_sig(lf, rf)
                 && eq_generics(lg, rg)
+                && eq_opt_fn_contract(lc, rc)
                 && both(lb.as_ref(), rb.as_ref(), |l, r| eq_block(l, r))
         },
         (
@@ -653,6 +662,17 @@ pub fn eq_fn_header(l: &FnHeader, r: &FnHeader) -> bool {
         && eq_ext(&l.ext, &r.ext)
 }
 
+#[expect(clippy::ref_option, reason = "This is the type how it is stored in the AST")]
+pub fn eq_opt_fn_contract(l: &Option<P<FnContract>>, r: &Option<P<FnContract>>) -> bool {
+    match (l, r) {
+        (Some(l), Some(r)) => {
+            eq_expr_opt(l.requires.as_ref(), r.requires.as_ref()) && eq_expr_opt(l.ensures.as_ref(), r.ensures.as_ref())
+        },
+        (None, None) => true,
+        (Some(_), None) | (None, Some(_)) => false,
+    }
+}
+
 pub fn eq_generics(l: &Generics, r: &Generics) -> bool {
     over(&l.params, &r.params, eq_generic_param)
         && over(&l.where_clause.predicates, &r.where_clause.predicates, |l, r| {
diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
index 179d42a8b5d..59aaaa3d9fb 100644
--- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
+++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
@@ -12,6 +12,7 @@
 //! code was written, and check if the span contains that text. Note this will only work correctly
 //! if the span is not from a `macro_rules` based macro.
 
+use rustc_abi::ExternAbi;
 use rustc_ast::AttrStyle;
 use rustc_ast::ast::{AttrKind, Attribute, IntTy, LitIntType, LitKind, StrStyle, TraitObjectSyntax, UintTy};
 use rustc_ast::token::CommentKind;
@@ -26,7 +27,6 @@ use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::symbol::{Ident, kw};
 use rustc_span::{Span, Symbol};
-use rustc_target::spec::abi::Abi;
 
 /// The search pattern to look for. Used by `span_matches_pat`
 #[derive(Clone)]
@@ -233,7 +233,7 @@ fn fn_header_search_pat(header: FnHeader) -> Pat {
         Pat::Str("const")
     } else if header.is_unsafe() {
         Pat::Str("unsafe")
-    } else if header.abi != Abi::Rust {
+    } else if header.abi != ExternAbi::Rust {
         Pat::Str("extern")
     } else {
         Pat::MultiStr(&["fn", "extern"])
@@ -375,7 +375,7 @@ fn ty_search_pat(ty: &Ty<'_>) -> (Pat, Pat) {
         TyKind::BareFn(bare_fn) => (
             if bare_fn.safety.is_unsafe() {
                 Pat::Str("unsafe")
-            } else if bare_fn.abi != Abi::Rust {
+            } else if bare_fn.abi != ExternAbi::Rust {
                 Pat::Str("extern")
             } else {
                 Pat::MultiStr(&["fn", "extern"])
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index a660623f418..db82c458f70 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -4,13 +4,15 @@
 //! executable MIR bodies, so we have to do this instead.
 #![allow(clippy::float_cmp)]
 
+use std::sync::Arc;
+
 use crate::source::{SpanRangeExt, walk_span_to_context};
 use crate::{clip, is_direct_expn_of, sext, unsext};
 
+use rustc_abi::Size;
 use rustc_apfloat::Float;
 use rustc_apfloat::ieee::{Half, Quad};
 use rustc_ast::ast::{self, LitFloatType, LitKind};
-use rustc_data_structures::sync::Lrc;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{
     BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, PatExpr, PatExprKind, QPath, UnOp,
@@ -24,7 +26,6 @@ use rustc_middle::{bug, mir, span_bug};
 use rustc_span::def_id::DefId;
 use rustc_span::symbol::Ident;
 use rustc_span::{SyntaxContext, sym};
-use rustc_target::abi::Size;
 use std::cell::Cell;
 use std::cmp::Ordering;
 use std::hash::{Hash, Hasher};
@@ -37,7 +38,7 @@ pub enum Constant<'tcx> {
     /// A `String` (e.g., "abc").
     Str(String),
     /// A binary string (e.g., `b"abc"`).
-    Binary(Lrc<[u8]>),
+    Binary(Arc<[u8]>),
     /// A single `char` (e.g., `'a'`).
     Char(char),
     /// An integer's bit representation.
@@ -305,7 +306,7 @@ pub fn lit_to_mir_constant<'tcx>(lit: &LitKind, ty: Option<Ty<'tcx>>) -> Constan
     match *lit {
         LitKind::Str(ref is, _) => Constant::Str(is.to_string()),
         LitKind::Byte(b) => Constant::Int(u128::from(b)),
-        LitKind::ByteStr(ref s, _) | LitKind::CStr(ref s, _) => Constant::Binary(Lrc::clone(s)),
+        LitKind::ByteStr(ref s, _) | LitKind::CStr(ref s, _) => Constant::Binary(Arc::clone(s)),
         LitKind::Char(c) => Constant::Char(c),
         LitKind::Int(n, _) => Constant::Int(n.get()),
         LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty {
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index d0eb5318e64..4bbf28115a6 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -10,7 +10,7 @@ use rustc_hir::{
     AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr, ExprField,
     ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName,
     Pat, PatExpr, PatExprKind, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, StructTailExpr,
-    TraitBoundModifiers, Ty, TyKind,
+    TraitBoundModifiers, Ty, TyKind, TyPat, TyPatKind,
 };
 use rustc_lexer::{TokenKind, tokenize};
 use rustc_lint::LateContext;
@@ -1102,6 +1102,22 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
         }
     }
 
+    pub fn hash_ty_pat(&mut self, pat: &TyPat<'_>) {
+        std::mem::discriminant(&pat.kind).hash(&mut self.s);
+        match pat.kind {
+            TyPatKind::Range(s, e, i) => {
+                if let Some(s) = s {
+                    self.hash_const_arg(s);
+                }
+                if let Some(e) = e {
+                    self.hash_const_arg(e);
+                }
+                std::mem::discriminant(&i).hash(&mut self.s);
+            },
+            TyPatKind::Err(_) => {},
+        }
+    }
+
     pub fn hash_pat(&mut self, pat: &Pat<'_>) {
         std::mem::discriminant(&pat.kind).hash(&mut self.s);
         match pat.kind {
@@ -1247,7 +1263,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
             },
             TyKind::Pat(ty, pat) => {
                 self.hash_ty(ty);
-                self.hash_pat(pat);
+                self.hash_ty_pat(pat);
             },
             TyKind::Ptr(mut_ty) => {
                 self.hash_ty(mut_ty.ty);
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 5a5227af907..79cc5066580 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -29,6 +29,7 @@
 
 // FIXME: switch to something more ergonomic here, once available.
 // (Currently there is no way to opt into sysroot crates without `extern crate`.)
+extern crate rustc_abi;
 extern crate rustc_ast;
 extern crate rustc_ast_pretty;
 extern crate rustc_attr_parsing;
@@ -48,7 +49,6 @@ extern crate rustc_middle;
 extern crate rustc_mir_dataflow;
 extern crate rustc_session;
 extern crate rustc_span;
-extern crate rustc_target;
 extern crate rustc_trait_selection;
 extern crate smallvec;
 
@@ -123,7 +123,7 @@ use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::{Ident, Symbol, kw};
 use rustc_span::{InnerSpan, Span, sym};
-use rustc_target::abi::Integer;
+use rustc_abi::Integer;
 use visitors::{Visitable, for_each_unconsumed_temporary};
 
 use crate::consts::{ConstEvalCtxt, Constant, mir_to_const};
@@ -341,6 +341,15 @@ pub fn is_wild(pat: &Pat<'_>) -> bool {
     matches!(pat.kind, PatKind::Wild)
 }
 
+// Checks if arm has the form `None => None`
+pub fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
+    matches!(
+        arm.pat.kind,
+        PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), .. })
+            if is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone)
+    )
+}
+
 /// Checks if the given `QPath` belongs to a type alias.
 pub fn is_ty_alias(qpath: &QPath<'_>) -> bool {
     match *qpath {
diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs
index f4c730ef118..30fd48fc060 100644
--- a/src/tools/clippy/clippy_utils/src/macros.rs
+++ b/src/tools/clippy/clippy_utils/src/macros.rs
@@ -1,12 +1,14 @@
 #![allow(clippy::similar_names)] // `expr` and `expn`
 
+use std::sync::Arc;
+
 use crate::get_unique_attr;
 use crate::visitors::{Descend, for_each_expr_without_closures};
 
 use arrayvec::ArrayVec;
 use rustc_ast::{FormatArgs, FormatArgument, FormatPlaceholder};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::sync::{Lrc, OnceLock};
+use rustc_data_structures::sync::OnceLock;
 use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath};
 use rustc_lint::{LateContext, LintContext};
 use rustc_span::def_id::DefId;
@@ -393,7 +395,7 @@ fn is_assert_arg(cx: &LateContext<'_>, expr: &Expr<'_>, assert_expn: ExpnId) ->
 /// Stores AST [`FormatArgs`] nodes for use in late lint passes, as they are in a desugared form in
 /// the HIR
 #[derive(Default, Clone)]
-pub struct FormatArgsStorage(Lrc<OnceLock<FxHashMap<Span, FormatArgs>>>);
+pub struct FormatArgsStorage(Arc<OnceLock<FxHashMap<Span, FormatArgs>>>);
 
 impl FormatArgsStorage {
     /// Returns an AST [`FormatArgs`] node if a `format_args` expansion is found as a descendant of
diff --git a/src/tools/clippy/clippy_utils/src/mir/mod.rs b/src/tools/clippy/clippy_utils/src/mir/mod.rs
index ccbbccd0dbf..85250f81dc4 100644
--- a/src/tools/clippy/clippy_utils/src/mir/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/mir/mod.rs
@@ -112,10 +112,14 @@ pub fn block_in_cycle(body: &Body<'_>, block: BasicBlock) -> bool {
 
 /// Convenience wrapper around `visit_local_usage`.
 pub fn used_exactly_once(mir: &Body<'_>, local: Local) -> Option<bool> {
-    visit_local_usage(&[local], mir, Location {
-        block: START_BLOCK,
-        statement_index: 0,
-    })
+    visit_local_usage(
+        &[local],
+        mir,
+        Location {
+            block: START_BLOCK,
+            statement_index: 0,
+        },
+    )
     .map(|mut vec| {
         let LocalUsage { local_use_locs, .. } = vec.remove(0);
         let mut locations = local_use_locs
diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs
index d73cb7e3561..24f73b9df26 100644
--- a/src/tools/clippy/clippy_utils/src/msrvs.rs
+++ b/src/tools/clippy/clippy_utils/src/msrvs.rs
@@ -1,4 +1,5 @@
 use rustc_ast::attr::AttributeExt;
+
 use rustc_attr_parsing::{RustcVersion, parse_version};
 use rustc_session::Session;
 use rustc_span::{Symbol, sym};
@@ -18,12 +19,14 @@ macro_rules! msrv_aliases {
 
 // names may refer to stabilized feature flags or library items
 msrv_aliases! {
+    1,84,0 { CONST_OPTION_AS_SLICE }
     1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY, CONST_MUT_REFS, CONST_UNWRAP }
     1,82,0 { IS_NONE_OR, REPEAT_N, RAW_REF_OP }
     1,81,0 { LINT_REASONS_STABILIZATION, ERROR_IN_CORE, EXPLICIT_SELF_TYPE_ELISION }
     1,80,0 { BOX_INTO_ITER, LAZY_CELL }
     1,77,0 { C_STR_LITERALS }
     1,76,0 { PTR_FROM_REF, OPTION_RESULT_INSPECT }
+    1,75,0 { OPTION_AS_SLICE }
     1,74,0 { REPR_RUST }
     1,73,0 { MANUAL_DIV_CEIL }
     1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE }
@@ -40,7 +43,7 @@ msrv_aliases! {
     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 }
-    1,50,0 { BOOL_THEN, CLAMP }
+    1,50,0 { BOOL_THEN, CLAMP, SLICE_FILL }
     1,47,0 { TAU, IS_ASCII_DIGIT_CONST, ARRAY_IMPL_ANY_LEN, SATURATING_SUB_CONST }
     1,46,0 { CONST_IF_MATCH }
     1,45,0 { STR_STRIP_PREFIX }
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 0aaef91e48a..c7890f33f27 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
@@ -179,7 +179,10 @@ fn check_rvalue<'tcx>(
                 ))
             }
         },
-        Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_) | NullOp::UbChecks, _)
+        Rvalue::NullaryOp(
+            NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_) | NullOp::UbChecks | NullOp::ContractChecks,
+            _,
+        )
         | Rvalue::ShallowInitBox(_, _) => Ok(()),
         Rvalue::UnaryOp(_, operand) => {
             let ty = operand.ty(body, tcx);
diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs
index eecbfb3936a..c6a038f7e0c 100644
--- a/src/tools/clippy/clippy_utils/src/source.rs
+++ b/src/tools/clippy/clippy_utils/src/source.rs
@@ -2,8 +2,9 @@
 
 #![allow(clippy::module_name_repetitions)]
 
+use std::sync::Arc;
+
 use rustc_ast::{LitKind, StrStyle};
-use rustc_data_structures::sync::Lrc;
 use rustc_errors::Applicability;
 use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource};
 use rustc_lint::{EarlyContext, LateContext};
@@ -204,7 +205,7 @@ impl fmt::Display for SourceText {
 fn get_source_range(sm: &SourceMap, sp: Range<BytePos>) -> Option<SourceFileRange> {
     let start = sm.lookup_byte_offset(sp.start);
     let end = sm.lookup_byte_offset(sp.end);
-    if !Lrc::ptr_eq(&start.sf, &end.sf) || start.pos > end.pos {
+    if !Arc::ptr_eq(&start.sf, &end.sf) || start.pos > end.pos {
         return None;
     }
     sm.ensure_source_file_source_present(&start.sf);
@@ -277,7 +278,7 @@ fn trim_start(sm: &SourceMap, sp: Range<BytePos>) -> Range<BytePos> {
 }
 
 pub struct SourceFileRange {
-    pub sf: Lrc<SourceFile>,
+    pub sf: Arc<SourceFile>,
     pub range: Range<usize>,
 }
 impl SourceFileRange {
@@ -726,12 +727,15 @@ pub fn str_literal_to_char_literal(
             &snip[1..(snip.len() - 1)]
         };
 
-        let hint = format!("'{}'", match ch {
-            "'" => "\\'",
-            r"\" => "\\\\",
-            "\\\"" => "\"", // no need to escape `"` in `'"'`
-            _ => ch,
-        });
+        let hint = format!(
+            "'{}'",
+            match ch {
+                "'" => "\\'",
+                r"\" => "\\\\",
+                "\\\"" => "\"", // no need to escape `"` in `'"'`
+                _ => ch,
+            }
+        );
 
         Some(hint)
     } else {
diff --git a/src/tools/clippy/clippy_utils/src/str_utils.rs b/src/tools/clippy/clippy_utils/src/str_utils.rs
index 1588ee452da..421b25a77fe 100644
--- a/src/tools/clippy/clippy_utils/src/str_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/str_utils.rs
@@ -370,11 +370,9 @@ mod test {
         assert_eq!(camel_case_split("AbcDef"), vec!["Abc", "Def"]);
         assert_eq!(camel_case_split("Abc"), vec!["Abc"]);
         assert_eq!(camel_case_split("abcDef"), vec!["abc", "Def"]);
-        assert_eq!(camel_case_split("\u{f6}\u{f6}AabABcd"), vec![
-            "\u{f6}\u{f6}",
-            "Aab",
-            "A",
-            "Bcd"
-        ]);
+        assert_eq!(
+            camel_case_split("\u{f6}\u{f6}AabABcd"),
+            vec!["\u{f6}\u{f6}", "Aab", "A", "Bcd"]
+        );
     }
 }
diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs
index e9a05c45747..a5374f6904e 100644
--- a/src/tools/clippy/clippy_utils/src/ty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs
@@ -4,6 +4,7 @@
 
 use core::ops::ControlFlow;
 use itertools::Itertools;
+use rustc_abi::VariantIdx;
 use rustc_ast::ast::Mutability;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
@@ -23,7 +24,6 @@ use rustc_middle::ty::{
 };
 use rustc_span::symbol::Ident;
 use rustc_span::{DUMMY_SP, Span, Symbol, sym};
-use rustc_target::abi::VariantIdx;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
 use rustc_trait_selection::traits::{Obligation, ObligationCause};
diff --git a/src/tools/clippy/lintcheck/src/config.rs b/src/tools/clippy/lintcheck/src/config.rs
index af243f94274..83c3d7aba02 100644
--- a/src/tools/clippy/lintcheck/src/config.rs
+++ b/src/tools/clippy/lintcheck/src/config.rs
@@ -2,6 +2,7 @@ use clap::{Parser, Subcommand, ValueEnum};
 use std::num::NonZero;
 use std::path::PathBuf;
 
+#[allow(clippy::struct_excessive_bools)]
 #[derive(Parser, Clone, Debug)]
 #[command(args_conflicts_with_subcommands = true)]
 pub(crate) struct LintcheckConfig {
@@ -11,6 +12,9 @@ pub(crate) struct LintcheckConfig {
         short = 'j',
         value_name = "N",
         default_value_t = 0,
+        default_value_if("perf", "true", Some("1")), // Limit jobs to 1 when benchmarking
+        conflicts_with("perf"),
+        required = false,
         hide_default_value = true
     )]
     pub max_jobs: usize,
@@ -46,6 +50,11 @@ pub(crate) struct LintcheckConfig {
     /// Run clippy on the dependencies of crates specified in crates-toml
     #[clap(long, conflicts_with("max_jobs"))]
     pub recursive: bool,
+    /// Also produce a `perf.data` file, implies --jobs=1,
+    /// the `perf.data` file can be found at
+    /// `target/lintcheck/sources/<package>-<version>/perf.data`
+    #[clap(long)]
+    pub perf: bool,
     #[command(subcommand)]
     pub subcommand: Option<Commands>,
 }
diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs
index e88d9f427be..8d0d41ab945 100644
--- a/src/tools/clippy/lintcheck/src/main.rs
+++ b/src/tools/clippy/lintcheck/src/main.rs
@@ -116,7 +116,25 @@ impl Crate {
 
         clippy_args.extend(lint_levels_args.iter().map(String::as_str));
 
-        let mut cmd = Command::new("cargo");
+        let mut cmd;
+
+        if config.perf {
+            cmd = Command::new("perf");
+            cmd.args(&[
+                "record",
+                "-e",
+                "instructions", // Only count instructions
+                "-g",           // Enable call-graph, useful for flamegraphs and produces richer reports
+                "--quiet",      // Do not tamper with lintcheck's normal output
+                "-o",
+                "perf.data",
+                "--",
+                "cargo",
+            ]);
+        } else {
+            cmd = Command::new("cargo");
+        }
+
         cmd.arg(if config.fix { "fix" } else { "check" })
             .arg("--quiet")
             .current_dir(&self.path)
@@ -234,12 +252,22 @@ fn normalize_diag(
 }
 
 /// Builds clippy inside the repo to make sure we have a clippy executable we can use.
-fn build_clippy() -> String {
-    let output = Command::new("cargo")
-        .args(["run", "--bin=clippy-driver", "--", "--version"])
-        .stderr(Stdio::inherit())
-        .output()
-        .unwrap();
+fn build_clippy(release_build: bool) -> String {
+    let mut build_cmd = Command::new("cargo");
+    build_cmd.args([
+        "run",
+        "--bin=clippy-driver",
+        if release_build { "-r" } else { "" },
+        "--",
+        "--version",
+    ]);
+
+    if release_build {
+        build_cmd.env("CARGO_PROFILE_RELEASE_DEBUG", "true");
+    }
+
+    let output = build_cmd.stderr(Stdio::inherit()).output().unwrap();
+
     if !output.status.success() {
         eprintln!("Error: Failed to compile Clippy!");
         std::process::exit(1);
@@ -270,13 +298,18 @@ fn main() {
 
 #[allow(clippy::too_many_lines)]
 fn lintcheck(config: LintcheckConfig) {
-    let clippy_ver = build_clippy();
-    let clippy_driver_path = fs::canonicalize(format!("target/debug/clippy-driver{EXE_SUFFIX}")).unwrap();
+    let clippy_ver = build_clippy(config.perf);
+    let clippy_driver_path = fs::canonicalize(format!(
+        "target/{}/clippy-driver{EXE_SUFFIX}",
+        if config.perf { "release" } else { "debug" }
+    ))
+    .unwrap();
 
     // assert that clippy is found
     assert!(
         clippy_driver_path.is_file(),
-        "target/debug/clippy-driver binary not found! {}",
+        "target/{}/clippy-driver binary not found! {}",
+        if config.perf { "release" } else { "debug" },
         clippy_driver_path.display()
     );
 
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index c15d1fe6cd3..ab760287e83 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,6 +1,6 @@
 [toolchain]
 # begin autogenerated nightly
-channel = "nightly-2025-01-28"
+channel = "nightly-2025-02-06"
 # end autogenerated nightly
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
 profile = "minimal"
diff --git a/src/tools/clippy/tests/ui/cmp_null.fixed b/src/tools/clippy/tests/ui/cmp_null.fixed
new file mode 100644
index 00000000000..e5ab765bc86
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cmp_null.fixed
@@ -0,0 +1,32 @@
+#![warn(clippy::cmp_null)]
+#![allow(unused_mut)]
+
+use std::ptr;
+
+fn main() {
+    let x = 0;
+    let p: *const usize = &x;
+    if p.is_null() {
+        //~^ ERROR: comparing with null is better expressed by the `.is_null()` method
+        //~| NOTE: `-D clippy::cmp-null` implied by `-D warnings`
+        println!("This is surprising!");
+    }
+    if p.is_null() {
+        //~^ ERROR: comparing with null is better expressed by the `.is_null()` method
+        println!("This is surprising!");
+    }
+
+    let mut y = 0;
+    let mut m: *mut usize = &mut y;
+    if m.is_null() {
+        //~^ ERROR: comparing with null is better expressed by the `.is_null()` method
+        println!("This is surprising, too!");
+    }
+    if m.is_null() {
+        //~^ ERROR: comparing with null is better expressed by the `.is_null()` method
+        println!("This is surprising, too!");
+    }
+
+    let _ = (x as *const ()).is_null();
+    //~^ ERROR: comparing with null is better expressed by the `.is_null()` method
+}
diff --git a/src/tools/clippy/tests/ui/cmp_null.rs b/src/tools/clippy/tests/ui/cmp_null.rs
index ef1d93940aa..257f7ba2662 100644
--- a/src/tools/clippy/tests/ui/cmp_null.rs
+++ b/src/tools/clippy/tests/ui/cmp_null.rs
@@ -11,10 +11,22 @@ fn main() {
         //~| NOTE: `-D clippy::cmp-null` implied by `-D warnings`
         println!("This is surprising!");
     }
+    if ptr::null() == p {
+        //~^ ERROR: comparing with null is better expressed by the `.is_null()` method
+        println!("This is surprising!");
+    }
+
     let mut y = 0;
     let mut m: *mut usize = &mut y;
     if m == ptr::null_mut() {
         //~^ ERROR: comparing with null is better expressed by the `.is_null()` method
         println!("This is surprising, too!");
     }
+    if ptr::null_mut() == m {
+        //~^ ERROR: comparing with null is better expressed by the `.is_null()` method
+        println!("This is surprising, too!");
+    }
+
+    let _ = x as *const () == ptr::null();
+    //~^ ERROR: comparing with null is better expressed by the `.is_null()` method
 }
diff --git a/src/tools/clippy/tests/ui/cmp_null.stderr b/src/tools/clippy/tests/ui/cmp_null.stderr
index 8362904a5ba..f3b35f3afba 100644
--- a/src/tools/clippy/tests/ui/cmp_null.stderr
+++ b/src/tools/clippy/tests/ui/cmp_null.stderr
@@ -2,16 +2,34 @@ error: comparing with null is better expressed by the `.is_null()` method
   --> tests/ui/cmp_null.rs:9:8
    |
 LL |     if p == ptr::null() {
-   |        ^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^ help: try: `p.is_null()`
    |
    = note: `-D clippy::cmp-null` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::cmp_null)]`
 
 error: comparing with null is better expressed by the `.is_null()` method
-  --> tests/ui/cmp_null.rs:16:8
+  --> tests/ui/cmp_null.rs:14:8
+   |
+LL |     if ptr::null() == p {
+   |        ^^^^^^^^^^^^^^^^ help: try: `p.is_null()`
+
+error: comparing with null is better expressed by the `.is_null()` method
+  --> tests/ui/cmp_null.rs:21:8
    |
 LL |     if m == ptr::null_mut() {
-   |        ^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^^^^^^^^^^ help: try: `m.is_null()`
+
+error: comparing with null is better expressed by the `.is_null()` method
+  --> tests/ui/cmp_null.rs:25:8
+   |
+LL |     if ptr::null_mut() == m {
+   |        ^^^^^^^^^^^^^^^^^^^^ help: try: `m.is_null()`
+
+error: comparing with null is better expressed by the `.is_null()` method
+  --> tests/ui/cmp_null.rs:30:13
+   |
+LL |     let _ = x as *const () == ptr::null();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(x as *const ()).is_null()`
 
-error: aborting due to 2 previous errors
+error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs
index 04446787b6c..a065654e319 100644
--- a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs
+++ b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs
@@ -66,3 +66,19 @@ fn escape_3() {}
 
 /// Backslashes ` \` within code blocks don't count.
 fn escape_4() {}
+
+trait Foo {
+    fn bar();
+}
+
+struct Bar;
+impl Foo for Bar {
+    // NOTE: false positive
+    /// Returns an `Option<Month>` from a i64, assuming a 1-index, January = 1.
+    ///
+    /// `Month::from_i64(n: i64)`: | `1`                  | `2`                   | ... | `12`
+    /// ---------------------------| -------------------- | --------------------- | ... | -----
+    /// ``:                        | Some(Month::January) | Some(Month::February) | ... |
+    /// Some(Month::December)
+    fn bar() {}
+}
diff --git a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr
index 50324010e97..c9fd25eb1a1 100644
--- a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr
+++ b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.stderr
@@ -94,5 +94,17 @@ LL | /// Escaped \` ` backticks don't count, but unescaped backticks do.
    |
    = help: a backtick may be missing a pair
 
-error: aborting due to 10 previous errors
+error: backticks are unbalanced
+  --> tests/ui/doc/unbalanced_ticks.rs:79:9
+   |
+LL |       /// `Month::from_i64(n: i64)`: | `1`                  | `2`                   | ... | `12`
+   |  _________^
+LL | |     /// ---------------------------| -------------------- | --------------------- | ... | -----
+LL | |     /// ``:                        | Some(Month::January) | Some(Month::February) | ... |
+LL | |     /// Some(Month::December)
+   | |_____________________________^
+   |
+   = help: a backtick may be missing a pair
+
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.1.fixed b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.1.fixed
index fd6a94b6a80..3772b465fdb 100644
--- a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.1.fixed
+++ b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.1.fixed
@@ -132,4 +132,13 @@ pub struct BlockComment;
 ))]
 fn empty_line_in_cfg_attr() {}
 
+trait Foo {
+    fn bar();
+}
+
+impl Foo for LineComment {
+    /// comment on assoc item
+    fn bar() {}
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.2.fixed b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.2.fixed
index 7a57dcd9233..3028d03b669 100644
--- a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.2.fixed
+++ b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.2.fixed
@@ -141,4 +141,13 @@ pub struct BlockComment;
 ))]
 fn empty_line_in_cfg_attr() {}
 
+trait Foo {
+    fn bar();
+}
+
+impl Foo for LineComment {
+    /// comment on assoc item
+    fn bar() {}
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.rs b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.rs
index 1da761a5c3d..ae4ebc271fa 100644
--- a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.rs
+++ b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.rs
@@ -144,4 +144,14 @@ pub struct BlockComment;
 ))]
 fn empty_line_in_cfg_attr() {}
 
+trait Foo {
+    fn bar();
+}
+
+impl Foo for LineComment {
+    /// comment on assoc item
+
+    fn bar() {}
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr
index c5d5f3d3759..7b197ae67e0 100644
--- a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr
+++ b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr
@@ -5,11 +5,11 @@ LL | / /// for the crate
 LL | |
    | |_^
 LL |   fn first_in_crate() {}
-   |   ------------------- the comment documents this function
+   |   ----------------- the comment documents this function
    |
    = note: `-D clippy::empty-line-after-doc-comments` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::empty_line_after_doc_comments)]`
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 help: if the comment should document the crate use an inner doc comment
    |
 LL ~ //! Meant to be an
@@ -24,9 +24,9 @@ LL | /     /// for the module
 LL | |
    | |_^
 LL |       fn first_in_module() {}
-   |       -------------------- the comment documents this function
+   |       ------------------ the comment documents this function
    |
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 help: if the comment should document the parent module use an inner doc comment
    |
 LL ~     //! Meant to be an
@@ -42,9 +42,9 @@ LL | |
    | |_^
 LL |       /// Blank line
 LL |       fn indented() {}
-   |       ------------- the comment documents this function
+   |       ----------- the comment documents this function
    |
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 help: if the documentation should include the empty line include it in the comment
    |
 LL |     ///
@@ -57,9 +57,9 @@ LL | / /// This should produce a warning
 LL | |
    | |_^
 LL |   fn with_doc_and_newline() {}
-   |   ------------------------- the comment documents this function
+   |   ----------------------- the comment documents this function
    |
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 
 error: empty lines after doc comment
   --> tests/ui/empty_line_after/doc_comments.rs:44:1
@@ -72,9 +72,9 @@ LL | |
    | |_^
 ...
 LL |   fn three_attributes() {}
-   |   --------------------- the comment documents this function
+   |   ------------------- the comment documents this function
    |
-   = help: if the empty lines are unintentional remove them
+   = help: if the empty lines are unintentional, remove them
 
 error: empty line after doc comment
   --> tests/ui/empty_line_after/doc_comments.rs:56:5
@@ -84,9 +84,9 @@ LL | |     // fn old_code() {}
 LL | |
    | |_^
 LL |       fn new_code() {}
-   |       ------------- the comment documents this function
+   |       ----------- the comment documents this function
    |
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 help: if the doc comment should not document `new_code` comment it out
    |
 LL |     // /// docs for `old_code`
@@ -106,7 +106,7 @@ LL | |
 LL |       struct Multiple;
    |       --------------- the comment documents this struct
    |
-   = help: if the empty lines are unintentional remove them
+   = help: if the empty lines are unintentional, remove them
 help: if the doc comment should not document `Multiple` comment it out
    |
 LL ~     // /// Docs
@@ -126,9 +126,9 @@ LL | |      */
 LL | |
    | |_^
 LL |       fn first_in_module() {}
-   |       -------------------- the comment documents this function
+   |       ------------------ the comment documents this function
    |
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 help: if the comment should document the parent module use an inner doc comment
    |
 LL |     /*!
@@ -145,9 +145,9 @@ LL | |
    | |_^
 ...
 LL |       fn new_code() {}
-   |       ------------- the comment documents this function
+   |       ----------- the comment documents this function
    |
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 help: if the doc comment should not document `new_code` comment it out
    |
 LL -     /**
@@ -163,13 +163,24 @@ LL | |
    | |_^
 LL |       /// Docs for `new_code2`
 LL |       fn new_code2() {}
-   |       -------------- the comment documents this function
+   |       ------------ the comment documents this function
    |
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 help: if the doc comment should not document `new_code2` comment it out
    |
 LL |     // /// Docs for `old_code2`
    |     ++
 
-error: aborting due to 10 previous errors
+error: empty line after doc comment
+  --> tests/ui/empty_line_after/doc_comments.rs:152:5
+   |
+LL | /     /// comment on assoc item
+LL | |
+   | |_^
+LL |       fn bar() {}
+   |       ------ the comment documents this function
+   |
+   = help: if the empty line is unintentional, remove it
+
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr
index a95306e2fa3..519ba6e6761 100644
--- a/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr
+++ b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr
@@ -5,11 +5,11 @@ LL | / #[crate_type = "lib"]
 LL | |
    | |_^
 LL |   fn first_in_crate() {}
-   |   ------------------- the attribute applies to this function
+   |   ----------------- the attribute applies to this function
    |
    = note: `-D clippy::empty-line-after-outer-attr` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::empty_line_after_outer_attr)]`
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 help: if the attribute should apply to the crate use an inner attribute
    |
 LL | #![crate_type = "lib"]
@@ -23,9 +23,9 @@ LL | |
    | |_^
 LL |   /// some comment
 LL |   fn with_one_newline_and_comment() {}
-   |   --------------------------------- the attribute applies to this function
+   |   ------------------------------- the attribute applies to this function
    |
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 
 error: empty line after outer attribute
   --> tests/ui/empty_line_after/outer_attribute.rs:23:1
@@ -34,9 +34,9 @@ LL | / #[inline]
 LL | |
    | |_^
 LL |   fn with_one_newline() {}
-   |   --------------------- the attribute applies to this function
+   |   ------------------- the attribute applies to this function
    |
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 
 error: empty lines after outer attribute
   --> tests/ui/empty_line_after/outer_attribute.rs:30:5
@@ -46,9 +46,9 @@ LL | |
 LL | |
    | |_^
 LL |       fn with_two_newlines() {}
-   |       ---------------------- the attribute applies to this function
+   |       -------------------- the attribute applies to this function
    |
-   = help: if the empty lines are unintentional remove them
+   = help: if the empty lines are unintentional, remove them
 help: if the attribute should apply to the parent module use an inner attribute
    |
 LL |     #![crate_type = "lib"]
@@ -63,7 +63,7 @@ LL | |
 LL |   enum Baz {
    |   -------- the attribute applies to this enum
    |
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 
 error: empty line after outer attribute
   --> tests/ui/empty_line_after/outer_attribute.rs:45:1
@@ -74,7 +74,7 @@ LL | |
 LL |   struct Foo {
    |   ---------- the attribute applies to this struct
    |
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 
 error: empty line after outer attribute
   --> tests/ui/empty_line_after/outer_attribute.rs:53:1
@@ -85,7 +85,7 @@ LL | |
 LL |   mod foo {}
    |   ------- the attribute applies to this module
    |
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 
 error: empty line after outer attribute
   --> tests/ui/empty_line_after/outer_attribute.rs:58:1
@@ -95,9 +95,9 @@ LL | | // Still lint cases where the empty line does not immediately follow the
 LL | |
    | |_^
 LL |   fn comment_before_empty_line() {}
-   |   ------------------------------ the attribute applies to this function
+   |   ---------------------------- the attribute applies to this function
    |
-   = help: if the empty line is unintentional remove it
+   = help: if the empty line is unintentional, remove it
 
 error: empty lines after outer attribute
   --> tests/ui/empty_line_after/outer_attribute.rs:64:1
@@ -107,9 +107,9 @@ LL | / #[allow(unused)]
 LL | |
    | |_^
 LL |   pub fn isolated_comment() {}
-   |   ------------------------- the attribute applies to this function
+   |   ----------------------- the attribute applies to this function
    |
-   = help: if the empty lines are unintentional remove them
+   = help: if the empty lines are unintentional, remove them
 
 error: aborting due to 9 previous errors
 
diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed
index f1baf28200e..abccc30ef87 100644
--- a/src/tools/clippy/tests/ui/eta.fixed
+++ b/src/tools/clippy/tests/ui/eta.fixed
@@ -116,6 +116,11 @@ fn test_redundant_closures_containing_method_calls() {
         t.iter().filter(|x| x.trait_foo_ref());
         t.iter().map(|x| x.trait_foo_ref());
     }
+
+    fn issue14096() {
+        let x = Some("42");
+        let _ = x.map(str::parse::<i16>);
+    }
 }
 
 struct Thunk<T>(Box<dyn FnMut() -> T>);
diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs
index c52a51880bf..9bcee4eba34 100644
--- a/src/tools/clippy/tests/ui/eta.rs
+++ b/src/tools/clippy/tests/ui/eta.rs
@@ -116,6 +116,11 @@ fn test_redundant_closures_containing_method_calls() {
         t.iter().filter(|x| x.trait_foo_ref());
         t.iter().map(|x| x.trait_foo_ref());
     }
+
+    fn issue14096() {
+        let x = Some("42");
+        let _ = x.map(|x| x.parse::<i16>());
+    }
 }
 
 struct Thunk<T>(Box<dyn FnMut() -> T>);
diff --git a/src/tools/clippy/tests/ui/eta.stderr b/src/tools/clippy/tests/ui/eta.stderr
index 1731a4377f5..ac58e87bc5e 100644
--- a/src/tools/clippy/tests/ui/eta.stderr
+++ b/src/tools/clippy/tests/ui/eta.stderr
@@ -71,142 +71,148 @@ LL |     let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(|c| c.to_as
    |                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_ascii_uppercase`
 
 error: redundant closure
-  --> tests/ui/eta.rs:169:22
+  --> tests/ui/eta.rs:122:23
+   |
+LL |         let _ = x.map(|x| x.parse::<i16>());
+   |                       ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `str::parse::<i16>`
+
+error: redundant closure
+  --> tests/ui/eta.rs:174:22
    |
 LL |     requires_fn_once(|| x());
    |                      ^^^^^^ help: replace the closure with the function itself: `x`
 
 error: redundant closure
-  --> tests/ui/eta.rs:176:27
+  --> tests/ui/eta.rs:181:27
    |
 LL |     let a = Some(1u8).map(|a| foo_ptr(a));
    |                           ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo_ptr`
 
 error: redundant closure
-  --> tests/ui/eta.rs:181:27
+  --> tests/ui/eta.rs:186:27
    |
 LL |     let a = Some(1u8).map(|a| closure(a));
    |                           ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `closure`
 
 error: redundant closure
-  --> tests/ui/eta.rs:213:28
+  --> tests/ui/eta.rs:218:28
    |
 LL |     x.into_iter().for_each(|x| add_to_res(x));
    |                            ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res`
 
 error: redundant closure
-  --> tests/ui/eta.rs:214:28
+  --> tests/ui/eta.rs:219:28
    |
 LL |     y.into_iter().for_each(|x| add_to_res(x));
    |                            ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res`
 
 error: redundant closure
-  --> tests/ui/eta.rs:215:28
+  --> tests/ui/eta.rs:220:28
    |
 LL |     z.into_iter().for_each(|x| add_to_res(x));
    |                            ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `add_to_res`
 
 error: redundant closure
-  --> tests/ui/eta.rs:222:21
+  --> tests/ui/eta.rs:227:21
    |
 LL |         Some(1).map(|n| closure(n));
    |                     ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut closure`
 
 error: redundant closure
-  --> tests/ui/eta.rs:226:21
+  --> tests/ui/eta.rs:231:21
    |
 LL |         Some(1).map(|n| in_loop(n));
    |                     ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `in_loop`
 
 error: redundant closure
-  --> tests/ui/eta.rs:319:18
+  --> tests/ui/eta.rs:324:18
    |
 LL |     takes_fn_mut(|| f());
    |                  ^^^^^^ help: replace the closure with the function itself: `&mut f`
 
 error: redundant closure
-  --> tests/ui/eta.rs:322:19
+  --> tests/ui/eta.rs:327:19
    |
 LL |     takes_fn_once(|| f());
    |                   ^^^^^^ help: replace the closure with the function itself: `&mut f`
 
 error: redundant closure
-  --> tests/ui/eta.rs:326:26
+  --> tests/ui/eta.rs:331:26
    |
 LL |     move || takes_fn_mut(|| f_used_once())
    |                          ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut f_used_once`
 
 error: redundant closure
-  --> tests/ui/eta.rs:338:19
+  --> tests/ui/eta.rs:343:19
    |
 LL |     array_opt.map(|a| a.as_slice());
    |                   ^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8; 3]>::as_slice`
 
 error: redundant closure
-  --> tests/ui/eta.rs:341:19
+  --> tests/ui/eta.rs:346:19
    |
 LL |     slice_opt.map(|s| s.len());
    |                   ^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8]>::len`
 
 error: redundant closure
-  --> tests/ui/eta.rs:344:17
+  --> tests/ui/eta.rs:349:17
    |
 LL |     ptr_opt.map(|p| p.is_null());
    |                 ^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<*const usize>::is_null`
 
 error: redundant closure
-  --> tests/ui/eta.rs:348:17
+  --> tests/ui/eta.rs:353:17
    |
 LL |     dyn_opt.map(|d| d.method_on_dyn());
    |                 ^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<dyn TestTrait>::method_on_dyn`
 
 error: redundant closure
-  --> tests/ui/eta.rs:408:19
+  --> tests/ui/eta.rs:413:19
    |
 LL |     let _ = f(&0, |x, y| f2(x, y));
    |                   ^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `f2`
 
 error: redundant closure
-  --> tests/ui/eta.rs:436:22
+  --> tests/ui/eta.rs:441:22
    |
 LL |             test.map(|t| t.method())
    |                      ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `Test::method`
 
 error: redundant closure
-  --> tests/ui/eta.rs:440:22
+  --> tests/ui/eta.rs:445:22
    |
 LL |             test.map(|t| t.method())
    |                      ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `super::Outer::method`
 
 error: redundant closure
-  --> tests/ui/eta.rs:453:18
+  --> tests/ui/eta.rs:458:18
    |
 LL |         test.map(|t| t.method())
    |                  ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `test_mod::Test::method`
 
 error: redundant closure
-  --> tests/ui/eta.rs:460:30
+  --> tests/ui/eta.rs:465:30
    |
 LL |                     test.map(|t| t.method())
    |                              ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `crate::issue_10854::d::Test::method`
 
 error: redundant closure
-  --> tests/ui/eta.rs:479:38
+  --> tests/ui/eta.rs:484:38
    |
 LL |         let x = Box::new(|| None.map(|x| f(x)));
    |                                      ^^^^^^^^ help: replace the closure with the function itself: `&f`
 
 error: redundant closure
-  --> tests/ui/eta.rs:483:38
+  --> tests/ui/eta.rs:488:38
    |
 LL |         let x = Box::new(|| None.map(|x| f(x)));
    |                                      ^^^^^^^^ help: replace the closure with the function itself: `f`
 
 error: redundant closure
-  --> tests/ui/eta.rs:500:35
+  --> tests/ui/eta.rs:505:35
    |
 LL |         let _field = bind.or_else(|| get_default()).unwrap();
    |                                   ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `get_default`
 
-error: aborting due to 34 previous errors
+error: aborting due to 35 previous errors
 
diff --git a/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed b/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed
index fde40437309..118f0b48895 100644
--- a/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed
+++ b/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed
@@ -21,12 +21,15 @@ fn main() {
     let _ = foo().map_err(|()| todo!());
     //~^ ERROR: matching over `()` is more explicit
 
-    println!("{:?}", match foo() {
-        Ok(()) => {},
-        //~^ ERROR: matching over `()` is more explicit
-        Err(()) => {},
-        //~^ ERROR: matching over `()` is more explicit
-    });
+    println!(
+        "{:?}",
+        match foo() {
+            Ok(()) => {},
+            //~^ ERROR: matching over `()` is more explicit
+            Err(()) => {},
+            //~^ ERROR: matching over `()` is more explicit
+        }
+    );
 }
 
 // ignored_unit_patterns in derive macro should be ok
diff --git a/src/tools/clippy/tests/ui/ignored_unit_patterns.rs b/src/tools/clippy/tests/ui/ignored_unit_patterns.rs
index 528844d76e0..92feb9e6c28 100644
--- a/src/tools/clippy/tests/ui/ignored_unit_patterns.rs
+++ b/src/tools/clippy/tests/ui/ignored_unit_patterns.rs
@@ -21,12 +21,15 @@ fn main() {
     let _ = foo().map_err(|_| todo!());
     //~^ ERROR: matching over `()` is more explicit
 
-    println!("{:?}", match foo() {
-        Ok(_) => {},
-        //~^ ERROR: matching over `()` is more explicit
-        Err(_) => {},
-        //~^ ERROR: matching over `()` is more explicit
-    });
+    println!(
+        "{:?}",
+        match foo() {
+            Ok(_) => {},
+            //~^ ERROR: matching over `()` is more explicit
+            Err(_) => {},
+            //~^ ERROR: matching over `()` is more explicit
+        }
+    );
 }
 
 // ignored_unit_patterns in derive macro should be ok
diff --git a/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr b/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr
index 54ff4454d6b..00a254e3919 100644
--- a/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr
+++ b/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr
@@ -26,31 +26,31 @@ LL |     let _ = foo().map_err(|_| todo!());
    |                            ^ help: use `()` instead of `_`: `()`
 
 error: matching over `()` is more explicit
-  --> tests/ui/ignored_unit_patterns.rs:25:12
+  --> tests/ui/ignored_unit_patterns.rs:27:16
    |
-LL |         Ok(_) => {},
-   |            ^ help: use `()` instead of `_`: `()`
+LL |             Ok(_) => {},
+   |                ^ help: use `()` instead of `_`: `()`
 
 error: matching over `()` is more explicit
-  --> tests/ui/ignored_unit_patterns.rs:27:13
+  --> tests/ui/ignored_unit_patterns.rs:29:17
    |
-LL |         Err(_) => {},
-   |             ^ help: use `()` instead of `_`: `()`
+LL |             Err(_) => {},
+   |                 ^ help: use `()` instead of `_`: `()`
 
 error: matching over `()` is more explicit
-  --> tests/ui/ignored_unit_patterns.rs:38:9
+  --> tests/ui/ignored_unit_patterns.rs:41:9
    |
 LL |     let _ = foo().unwrap();
    |         ^ help: use `()` instead of `_`: `()`
 
 error: matching over `()` is more explicit
-  --> tests/ui/ignored_unit_patterns.rs:47:13
+  --> tests/ui/ignored_unit_patterns.rs:50:13
    |
 LL |         (1, _) => unimplemented!(),
    |             ^ help: use `()` instead of `_`: `()`
 
 error: matching over `()` is more explicit
-  --> tests/ui/ignored_unit_patterns.rs:54:13
+  --> tests/ui/ignored_unit_patterns.rs:57:13
    |
 LL |     for (x, _) in v {
    |             ^ help: use `()` instead of `_`: `()`
diff --git a/src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.rs b/src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.rs
index c917fa7f2d0..2f8640cd3f5 100644
--- a/src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.rs
+++ b/src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.rs
@@ -1,5 +1,10 @@
 #![warn(clippy::manual_memcpy)]
-#![allow(clippy::assigning_clones, clippy::useless_vec, clippy::needless_range_loop)]
+#![allow(
+    clippy::assigning_clones,
+    clippy::useless_vec,
+    clippy::needless_range_loop,
+    clippy::manual_slice_fill
+)]
 
 //@no-rustfix
 const LOOP_OFFSET: usize = 5000;
diff --git a/src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.stderr b/src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.stderr
index 803053b2db2..c881e3fac76 100644
--- a/src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.stderr
+++ b/src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.stderr
@@ -1,5 +1,5 @@
 error: it looks like you're manually copying between slices
-  --> tests/ui/manual_memcpy/without_loop_counters.rs:9:5
+  --> tests/ui/manual_memcpy/without_loop_counters.rs:14:5
    |
 LL | /     for i in 0..src.len() {
 LL | |
@@ -12,7 +12,7 @@ LL | |     }
    = help: to override `-D warnings` add `#[allow(clippy::manual_memcpy)]`
 
 error: it looks like you're manually copying between slices
-  --> tests/ui/manual_memcpy/without_loop_counters.rs:16:5
+  --> tests/ui/manual_memcpy/without_loop_counters.rs:21:5
    |
 LL | /     for i in 0..src.len() {
 LL | |
@@ -21,7 +21,7 @@ LL | |     }
    | |_____^ help: try replacing the loop by: `dst[10..(src.len() + 10)].copy_from_slice(&src[..]);`
 
 error: it looks like you're manually copying between slices
-  --> tests/ui/manual_memcpy/without_loop_counters.rs:22:5
+  --> tests/ui/manual_memcpy/without_loop_counters.rs:27:5
    |
 LL | /     for i in 0..src.len() {
 LL | |
@@ -30,7 +30,7 @@ LL | |     }
    | |_____^ help: try replacing the loop by: `dst[..src.len()].copy_from_slice(&src[10..(src.len() + 10)]);`
 
 error: it looks like you're manually copying between slices
-  --> tests/ui/manual_memcpy/without_loop_counters.rs:28:5
+  --> tests/ui/manual_memcpy/without_loop_counters.rs:33:5
    |
 LL | /     for i in 11..src.len() {
 LL | |
@@ -39,7 +39,7 @@ LL | |     }
    | |_____^ help: try replacing the loop by: `dst[11..src.len()].copy_from_slice(&src[(11 - 10)..(src.len() - 10)]);`
 
 error: it looks like you're manually copying between slices
-  --> tests/ui/manual_memcpy/without_loop_counters.rs:34:5
+  --> tests/ui/manual_memcpy/without_loop_counters.rs:39:5
    |
 LL | /     for i in 0..dst.len() {
 LL | |
@@ -48,7 +48,7 @@ LL | |     }
    | |_____^ help: try replacing the loop by: `dst.copy_from_slice(&src[..dst.len()]);`
 
 error: it looks like you're manually copying between slices
-  --> tests/ui/manual_memcpy/without_loop_counters.rs:48:5
+  --> tests/ui/manual_memcpy/without_loop_counters.rs:53:5
    |
 LL | /     for i in 10..256 {
 LL | |
@@ -64,7 +64,7 @@ LL +     dst2[(10 + 500)..(256 + 500)].copy_from_slice(&src[10..256]);
    |
 
 error: it looks like you're manually copying between slices
-  --> tests/ui/manual_memcpy/without_loop_counters.rs:61:5
+  --> tests/ui/manual_memcpy/without_loop_counters.rs:66:5
    |
 LL | /     for i in 10..LOOP_OFFSET {
 LL | |
@@ -73,7 +73,7 @@ LL | |     }
    | |_____^ help: try replacing the loop by: `dst[(10 + LOOP_OFFSET)..(LOOP_OFFSET + LOOP_OFFSET)].copy_from_slice(&src[(10 - some_var)..(LOOP_OFFSET - some_var)]);`
 
 error: it looks like you're manually copying between slices
-  --> tests/ui/manual_memcpy/without_loop_counters.rs:75:5
+  --> tests/ui/manual_memcpy/without_loop_counters.rs:80:5
    |
 LL | /     for i in 0..src_vec.len() {
 LL | |
@@ -82,7 +82,7 @@ LL | |     }
    | |_____^ help: try replacing the loop by: `dst_vec[..src_vec.len()].copy_from_slice(&src_vec[..]);`
 
 error: it looks like you're manually copying between slices
-  --> tests/ui/manual_memcpy/without_loop_counters.rs:105:5
+  --> tests/ui/manual_memcpy/without_loop_counters.rs:110:5
    |
 LL | /     for i in from..from + src.len() {
 LL | |
@@ -91,7 +91,7 @@ LL | |     }
    | |_____^ help: try replacing the loop by: `dst[from..(from + src.len())].copy_from_slice(&src[..(from + src.len() - from)]);`
 
 error: it looks like you're manually copying between slices
-  --> tests/ui/manual_memcpy/without_loop_counters.rs:110:5
+  --> tests/ui/manual_memcpy/without_loop_counters.rs:115:5
    |
 LL | /     for i in from..from + 3 {
 LL | |
@@ -100,7 +100,7 @@ LL | |     }
    | |_____^ help: try replacing the loop by: `dst[from..(from + 3)].copy_from_slice(&src[..(from + 3 - from)]);`
 
 error: it looks like you're manually copying between slices
-  --> tests/ui/manual_memcpy/without_loop_counters.rs:116:5
+  --> tests/ui/manual_memcpy/without_loop_counters.rs:121:5
    |
 LL | /     for i in 0..5 {
 LL | |
@@ -109,7 +109,7 @@ LL | |     }
    | |_____^ help: try replacing the loop by: `dst[..5].copy_from_slice(&src);`
 
 error: it looks like you're manually copying between slices
-  --> tests/ui/manual_memcpy/without_loop_counters.rs:122:5
+  --> tests/ui/manual_memcpy/without_loop_counters.rs:127:5
    |
 LL | /     for i in 0..0 {
 LL | |
@@ -118,7 +118,7 @@ LL | |     }
    | |_____^ help: try replacing the loop by: `dst[..0].copy_from_slice(&src[..0]);`
 
 error: it looks like you're manually copying between slices
-  --> tests/ui/manual_memcpy/without_loop_counters.rs:146:5
+  --> tests/ui/manual_memcpy/without_loop_counters.rs:151:5
    |
 LL | /     for i in 0..4 {
 LL | |
@@ -127,7 +127,7 @@ LL | |     }
    | |_____^ help: try replacing the loop by: `dst.copy_from_slice(&src[..4]);`
 
 error: it looks like you're manually copying between slices
-  --> tests/ui/manual_memcpy/without_loop_counters.rs:152:5
+  --> tests/ui/manual_memcpy/without_loop_counters.rs:157:5
    |
 LL | /     for i in 0..5 {
 LL | |
@@ -136,7 +136,7 @@ LL | |     }
    | |_____^ help: try replacing the loop by: `dst[..5].copy_from_slice(&src);`
 
 error: it looks like you're manually copying between slices
-  --> tests/ui/manual_memcpy/without_loop_counters.rs:158:5
+  --> tests/ui/manual_memcpy/without_loop_counters.rs:163:5
    |
 LL | /     for i in 0..5 {
 LL | |
@@ -145,7 +145,7 @@ LL | |     }
    | |_____^ help: try replacing the loop by: `dst.copy_from_slice(&src);`
 
 error: it looks like you're manually copying between slices
-  --> tests/ui/manual_memcpy/without_loop_counters.rs:205:5
+  --> tests/ui/manual_memcpy/without_loop_counters.rs:210:5
    |
 LL | /     for i in 0..5 {
 LL | |
@@ -154,7 +154,7 @@ LL | |     }
    | |_____^ help: try replacing the loop by: `dst.copy_from_slice(&src[0]);`
 
 error: it looks like you're manually copying between slices
-  --> tests/ui/manual_memcpy/without_loop_counters.rs:211:5
+  --> tests/ui/manual_memcpy/without_loop_counters.rs:216:5
    |
 LL | /     for i in 0..5 {
 LL | |
@@ -163,7 +163,7 @@ LL | |     }
    | |_____^ help: try replacing the loop by: `dst.copy_from_slice(&src[0][1]);`
 
 error: it looks like you're manually copying between slices
-  --> tests/ui/manual_memcpy/without_loop_counters.rs:219:5
+  --> tests/ui/manual_memcpy/without_loop_counters.rs:224:5
    |
 LL | /     for i in 0..src.len() {
 LL | |
diff --git a/src/tools/clippy/tests/ui/manual_option_as_slice.fixed b/src/tools/clippy/tests/ui/manual_option_as_slice.fixed
new file mode 100644
index 00000000000..48337d7654d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_option_as_slice.fixed
@@ -0,0 +1,62 @@
+#![warn(clippy::manual_option_as_slice)]
+#![allow(clippy::redundant_closure, clippy::unwrap_or_default)]
+
+fn check(x: Option<u32>) {
+    _ = x.as_slice();
+
+    _ = x.as_slice();
+
+    _ = x.as_slice();
+    //~^ manual_option_as_slice
+
+    _ = x.as_slice();
+    //~^ manual_option_as_slice
+
+    _ = x.as_slice();
+    //~^ manual_option_as_slice
+
+    _ = x.as_slice();
+    //~^ manual_option_as_slice
+
+    {
+        use std::slice::from_ref;
+        _ = x.as_slice();
+        //~^ manual_option_as_slice
+    }
+
+    // possible false positives
+    let y = x.as_ref();
+    _ = match y {
+        // as_ref outside
+        Some(f) => &[f][..],
+        None => &[][..],
+    };
+    _ = match x.as_ref() {
+        Some(f) => std::slice::from_ref(f),
+        None => &[0],
+    };
+    _ = match x.as_ref() {
+        Some(42) => &[23],
+        Some(f) => std::slice::from_ref(f),
+        None => &[],
+    };
+    let b = &[42];
+    _ = if let Some(_f) = x.as_ref() {
+        std::slice::from_ref(b)
+    } else {
+        &[]
+    };
+    _ = x.as_ref().map_or(&[42][..], std::slice::from_ref);
+    _ = x.as_ref().map_or_else(|| &[42][..1], std::slice::from_ref);
+    _ = x.as_ref().map(|f| std::slice::from_ref(f)).unwrap_or_default();
+}
+
+#[clippy::msrv = "1.74"]
+fn check_msrv(x: Option<u32>) {
+    _ = x.as_ref().map_or(&[][..], std::slice::from_ref);
+}
+
+fn main() {
+    check(Some(1));
+    check_msrv(Some(175));
+}
diff --git a/src/tools/clippy/tests/ui/manual_option_as_slice.rs b/src/tools/clippy/tests/ui/manual_option_as_slice.rs
new file mode 100644
index 00000000000..561a8b53401
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_option_as_slice.rs
@@ -0,0 +1,71 @@
+#![warn(clippy::manual_option_as_slice)]
+#![allow(clippy::redundant_closure, clippy::unwrap_or_default)]
+
+fn check(x: Option<u32>) {
+    _ = match x.as_ref() {
+        //~^ manual_option_as_slice
+        Some(f) => std::slice::from_ref(f),
+        None => &[],
+    };
+
+    _ = if let Some(f) = x.as_ref() {
+        //~^ manual_option_as_slice
+        std::slice::from_ref(f)
+    } else {
+        &[]
+    };
+
+    _ = x.as_ref().map_or(&[][..], std::slice::from_ref);
+    //~^ manual_option_as_slice
+
+    _ = x.as_ref().map_or_else(Default::default, std::slice::from_ref);
+    //~^ manual_option_as_slice
+
+    _ = x.as_ref().map(std::slice::from_ref).unwrap_or_default();
+    //~^ manual_option_as_slice
+
+    _ = x.as_ref().map_or_else(|| &[42][..0], std::slice::from_ref);
+    //~^ manual_option_as_slice
+
+    {
+        use std::slice::from_ref;
+        _ = x.as_ref().map_or_else(<&[_]>::default, from_ref);
+        //~^ manual_option_as_slice
+    }
+
+    // possible false positives
+    let y = x.as_ref();
+    _ = match y {
+        // as_ref outside
+        Some(f) => &[f][..],
+        None => &[][..],
+    };
+    _ = match x.as_ref() {
+        Some(f) => std::slice::from_ref(f),
+        None => &[0],
+    };
+    _ = match x.as_ref() {
+        Some(42) => &[23],
+        Some(f) => std::slice::from_ref(f),
+        None => &[],
+    };
+    let b = &[42];
+    _ = if let Some(_f) = x.as_ref() {
+        std::slice::from_ref(b)
+    } else {
+        &[]
+    };
+    _ = x.as_ref().map_or(&[42][..], std::slice::from_ref);
+    _ = x.as_ref().map_or_else(|| &[42][..1], std::slice::from_ref);
+    _ = x.as_ref().map(|f| std::slice::from_ref(f)).unwrap_or_default();
+}
+
+#[clippy::msrv = "1.74"]
+fn check_msrv(x: Option<u32>) {
+    _ = x.as_ref().map_or(&[][..], std::slice::from_ref);
+}
+
+fn main() {
+    check(Some(1));
+    check_msrv(Some(175));
+}
diff --git a/src/tools/clippy/tests/ui/manual_option_as_slice.stderr b/src/tools/clippy/tests/ui/manual_option_as_slice.stderr
new file mode 100644
index 00000000000..569269d3e2b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_option_as_slice.stderr
@@ -0,0 +1,58 @@
+error: use `Option::as_slice`
+  --> tests/ui/manual_option_as_slice.rs:5:9
+   |
+LL |       _ = match x.as_ref() {
+   |  _________^
+LL | |
+LL | |         Some(f) => std::slice::from_ref(f),
+LL | |         None => &[],
+LL | |     };
+   | |_____^ help: use: `x.as_slice()`
+   |
+   = note: `-D clippy::manual-option-as-slice` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::manual_option_as_slice)]`
+
+error: use `Option::as_slice`
+  --> tests/ui/manual_option_as_slice.rs:11:9
+   |
+LL |       _ = if let Some(f) = x.as_ref() {
+   |  _________^
+LL | |
+LL | |         std::slice::from_ref(f)
+LL | |     } else {
+LL | |         &[]
+LL | |     };
+   | |_____^ help: use: `x.as_slice()`
+
+error: use `Option::as_slice`
+  --> tests/ui/manual_option_as_slice.rs:18:9
+   |
+LL |     _ = x.as_ref().map_or(&[][..], std::slice::from_ref);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `x.as_slice()`
+
+error: use `Option::as_slice`
+  --> tests/ui/manual_option_as_slice.rs:21:9
+   |
+LL |     _ = x.as_ref().map_or_else(Default::default, std::slice::from_ref);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `x.as_slice()`
+
+error: use `Option::as_slice`
+  --> tests/ui/manual_option_as_slice.rs:24:9
+   |
+LL |     _ = x.as_ref().map(std::slice::from_ref).unwrap_or_default();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `x.as_slice()`
+
+error: use `Option::as_slice`
+  --> tests/ui/manual_option_as_slice.rs:27:9
+   |
+LL |     _ = x.as_ref().map_or_else(|| &[42][..0], std::slice::from_ref);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `x.as_slice()`
+
+error: use `Option::as_slice`
+  --> tests/ui/manual_option_as_slice.rs:32:13
+   |
+LL |         _ = x.as_ref().map_or_else(<&[_]>::default, from_ref);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `x.as_slice()`
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/manual_slice_fill.fixed b/src/tools/clippy/tests/ui/manual_slice_fill.fixed
new file mode 100644
index 00000000000..397a156a2dc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_slice_fill.fixed
@@ -0,0 +1,101 @@
+#![warn(clippy::manual_slice_fill)]
+#![allow(clippy::needless_range_loop)]
+
+macro_rules! assign_element {
+    ($slice:ident, $index:expr) => {
+        $slice[$index] = 0;
+    };
+}
+
+macro_rules! assign_element_2 {
+    ($i:expr) => {
+        $i = 0;
+    };
+}
+
+struct NoClone;
+
+fn num() -> usize {
+    5
+}
+
+fn should_lint() {
+    let mut some_slice = [1, 2, 3, 4, 5];
+
+    some_slice.fill(0);
+
+    let x = 5;
+    some_slice.fill(x);
+
+    some_slice.fill(0);
+
+    // This should trigger `manual_slice_fill`, but the applicability is `MaybeIncorrect` since comments
+    // within the loop might be purely informational.
+    some_slice.fill(0);
+}
+
+fn should_not_lint() {
+    let mut some_slice = [1, 2, 3, 4, 5];
+
+    // Should not lint because we can't determine if the scope of the loop is intended to access all the
+    // elements of the slice.
+    for i in 0..5 {
+        some_slice[i] = 0;
+    }
+
+    // Should not lint, as using a function to assign values to elements might be
+    // intentional. For example, the contents of `num()` could be temporary and subject to change
+    // later.
+    for i in 0..some_slice.len() {
+        some_slice[i] = num();
+    }
+
+    // Should not lint because this loop isn't equivalent to `fill`.
+    for i in 0..some_slice.len() {
+        some_slice[i] = 0;
+        println!("foo");
+    }
+
+    // Should not lint because it may be intentional to use a macro to perform an operation equivalent
+    // to `fill`.
+    for i in 0..some_slice.len() {
+        assign_element!(some_slice, i);
+    }
+
+    let another_slice = [1, 2, 3];
+    // Should not lint because the range is not for `some_slice`.
+    for i in 0..another_slice.len() {
+        some_slice[i] = 0;
+    }
+
+    let mut vec: Vec<Option<NoClone>> = Vec::with_capacity(5);
+    // Should not lint because `NoClone` does not have `Clone` trait.
+    for i in 0..vec.len() {
+        vec[i] = None;
+    }
+
+    // Should not lint, as using a function to assign values to elements might be
+    // intentional. For example, the contents of `num()` could be temporary and subject to change
+    // later.
+    for i in &mut some_slice {
+        *i = num();
+    }
+
+    // Should not lint because this loop isn't equivalent to `fill`.
+    for i in &mut some_slice {
+        *i = 0;
+        println!("foo");
+    }
+
+    // Should not lint because it may be intentional to use a macro to perform an operation equivalent
+    // to `fill`.
+    for i in &mut some_slice {
+        assign_element_2!(*i);
+    }
+
+    let mut vec: Vec<Option<NoClone>> = Vec::with_capacity(5);
+    // Should not lint because `NoClone` does not have `Clone` trait.
+    for i in &mut vec {
+        *i = None;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/manual_slice_fill.rs b/src/tools/clippy/tests/ui/manual_slice_fill.rs
new file mode 100644
index 00000000000..c25127ca613
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_slice_fill.rs
@@ -0,0 +1,110 @@
+#![warn(clippy::manual_slice_fill)]
+#![allow(clippy::needless_range_loop)]
+
+macro_rules! assign_element {
+    ($slice:ident, $index:expr) => {
+        $slice[$index] = 0;
+    };
+}
+
+macro_rules! assign_element_2 {
+    ($i:expr) => {
+        $i = 0;
+    };
+}
+
+struct NoClone;
+
+fn num() -> usize {
+    5
+}
+
+fn should_lint() {
+    let mut some_slice = [1, 2, 3, 4, 5];
+
+    for i in 0..some_slice.len() {
+        some_slice[i] = 0;
+    }
+
+    let x = 5;
+    for i in 0..some_slice.len() {
+        some_slice[i] = x;
+    }
+
+    for i in &mut some_slice {
+        *i = 0;
+    }
+
+    // This should trigger `manual_slice_fill`, but the applicability is `MaybeIncorrect` since comments
+    // within the loop might be purely informational.
+    for i in 0..some_slice.len() {
+        some_slice[i] = 0;
+        // foo
+    }
+}
+
+fn should_not_lint() {
+    let mut some_slice = [1, 2, 3, 4, 5];
+
+    // Should not lint because we can't determine if the scope of the loop is intended to access all the
+    // elements of the slice.
+    for i in 0..5 {
+        some_slice[i] = 0;
+    }
+
+    // Should not lint, as using a function to assign values to elements might be
+    // intentional. For example, the contents of `num()` could be temporary and subject to change
+    // later.
+    for i in 0..some_slice.len() {
+        some_slice[i] = num();
+    }
+
+    // Should not lint because this loop isn't equivalent to `fill`.
+    for i in 0..some_slice.len() {
+        some_slice[i] = 0;
+        println!("foo");
+    }
+
+    // Should not lint because it may be intentional to use a macro to perform an operation equivalent
+    // to `fill`.
+    for i in 0..some_slice.len() {
+        assign_element!(some_slice, i);
+    }
+
+    let another_slice = [1, 2, 3];
+    // Should not lint because the range is not for `some_slice`.
+    for i in 0..another_slice.len() {
+        some_slice[i] = 0;
+    }
+
+    let mut vec: Vec<Option<NoClone>> = Vec::with_capacity(5);
+    // Should not lint because `NoClone` does not have `Clone` trait.
+    for i in 0..vec.len() {
+        vec[i] = None;
+    }
+
+    // Should not lint, as using a function to assign values to elements might be
+    // intentional. For example, the contents of `num()` could be temporary and subject to change
+    // later.
+    for i in &mut some_slice {
+        *i = num();
+    }
+
+    // Should not lint because this loop isn't equivalent to `fill`.
+    for i in &mut some_slice {
+        *i = 0;
+        println!("foo");
+    }
+
+    // Should not lint because it may be intentional to use a macro to perform an operation equivalent
+    // to `fill`.
+    for i in &mut some_slice {
+        assign_element_2!(*i);
+    }
+
+    let mut vec: Vec<Option<NoClone>> = Vec::with_capacity(5);
+    // Should not lint because `NoClone` does not have `Clone` trait.
+    for i in &mut vec {
+        *i = None;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/manual_slice_fill.stderr b/src/tools/clippy/tests/ui/manual_slice_fill.stderr
new file mode 100644
index 00000000000..3aa980f6919
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_slice_fill.stderr
@@ -0,0 +1,38 @@
+error: manually filling a slice
+  --> tests/ui/manual_slice_fill.rs:25:5
+   |
+LL | /     for i in 0..some_slice.len() {
+LL | |         some_slice[i] = 0;
+LL | |     }
+   | |_____^ help: try: `some_slice.fill(0);`
+   |
+   = note: `-D clippy::manual-slice-fill` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::manual_slice_fill)]`
+
+error: manually filling a slice
+  --> tests/ui/manual_slice_fill.rs:30:5
+   |
+LL | /     for i in 0..some_slice.len() {
+LL | |         some_slice[i] = x;
+LL | |     }
+   | |_____^ help: try: `some_slice.fill(x);`
+
+error: manually filling a slice
+  --> tests/ui/manual_slice_fill.rs:34:5
+   |
+LL | /     for i in &mut some_slice {
+LL | |         *i = 0;
+LL | |     }
+   | |_____^ help: try: `some_slice.fill(0);`
+
+error: manually filling a slice
+  --> tests/ui/manual_slice_fill.rs:40:5
+   |
+LL | /     for i in 0..some_slice.len() {
+LL | |         some_slice[i] = 0;
+LL | |         // foo
+LL | |     }
+   | |_____^ help: try: `some_slice.fill(0);`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or_default_unfixable.rs b/src/tools/clippy/tests/ui/manual_unwrap_or_default_unfixable.rs
new file mode 100644
index 00000000000..acc54b52816
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default_unfixable.rs
@@ -0,0 +1,15 @@
+//@no-rustfix
+fn issue_12670() {
+    // no auto: type not found
+    #[allow(clippy::match_result_ok)]
+    let _ = if let Some(x) = "1".parse().ok() {
+        x
+    } else {
+        i32::default()
+    };
+    let _ = if let Some(x) = None { x } else { i32::default() };
+    // auto fix with unwrap_or_default
+    let a: Option<i32> = None;
+    let _ = if let Some(x) = a { x } else { i32::default() };
+    let _ = if let Some(x) = Some(99) { x } else { i32::default() };
+}
diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or_default_unfixable.stderr b/src/tools/clippy/tests/ui/manual_unwrap_or_default_unfixable.stderr
new file mode 100644
index 00000000000..3849d33cf25
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default_unfixable.stderr
@@ -0,0 +1,34 @@
+error: if let can be simplified with `.unwrap_or_default()`
+  --> tests/ui/manual_unwrap_or_default_unfixable.rs:5:13
+   |
+LL |       let _ = if let Some(x) = "1".parse().ok() {
+   |  _____________^
+LL | |         x
+LL | |     } else {
+LL | |         i32::default()
+LL | |     };
+   | |_____^ help: ascribe the type i32 and replace your expression with: `"1".parse().ok().unwrap_or_default()`
+   |
+   = note: `-D clippy::manual-unwrap-or-default` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::manual_unwrap_or_default)]`
+
+error: if let can be simplified with `.unwrap_or_default()`
+  --> tests/ui/manual_unwrap_or_default_unfixable.rs:10:13
+   |
+LL |     let _ = if let Some(x) = None { x } else { i32::default() };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `None::<i32>.unwrap_or_default()`
+
+error: if let can be simplified with `.unwrap_or_default()`
+  --> tests/ui/manual_unwrap_or_default_unfixable.rs:13:13
+   |
+LL |     let _ = if let Some(x) = a { x } else { i32::default() };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a.unwrap_or_default()`
+
+error: if let can be simplified with `.unwrap_or_default()`
+  --> tests/ui/manual_unwrap_or_default_unfixable.rs:14:13
+   |
+LL |     let _ = if let Some(x) = Some(99) { x } else { i32::default() };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `Some(99).unwrap_or_default()`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/needless_option_take.fixed b/src/tools/clippy/tests/ui/needless_option_take.fixed
new file mode 100644
index 00000000000..6514b67ef7a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_option_take.fixed
@@ -0,0 +1,58 @@
+struct MyStruct;
+
+impl MyStruct {
+    pub fn get_option() -> Option<Self> {
+        todo!()
+    }
+}
+
+fn return_option() -> Option<i32> {
+    todo!()
+}
+
+fn main() {
+    println!("Testing non erroneous option_take_on_temporary");
+    let mut option = Some(1);
+    let _ = Box::new(move || option.take().unwrap());
+
+    println!("Testing non erroneous option_take_on_temporary");
+    let x = Some(3);
+    x.as_ref();
+
+    let x = Some(3);
+    x.as_ref();
+    //~^ ERROR: called `Option::take()` on a temporary value
+
+    println!("Testing non erroneous option_take_on_temporary");
+    let mut x = Some(3);
+    let y = x.as_mut();
+
+    let mut x = Some(3);
+    let y = x.as_mut();
+    //~^ ERROR: called `Option::take()` on a temporary value
+    let y = x.replace(289);
+    //~^ ERROR: called `Option::take()` on a temporary value
+
+    let y = Some(3).as_mut();
+    //~^ ERROR: called `Option::take()` on a temporary value
+
+    let y = Option::as_mut(&mut x);
+    //~^ ERROR: called `Option::take()` on a temporary value
+
+    let x = return_option();
+    let x = return_option();
+    //~^ ERROR: called `Option::take()` on a temporary value
+
+    let x = MyStruct::get_option();
+    let x = MyStruct::get_option();
+    //~^ ERROR: called `Option::take()` on a temporary value
+
+    let mut my_vec = vec![1, 2, 3];
+    my_vec.push(4);
+    let y = my_vec.first();
+    let y = my_vec.first();
+    //~^ ERROR: called `Option::take()` on a temporary value
+
+    let y = my_vec.first();
+    //~^ ERROR: called `Option::take()` on a temporary value
+}
diff --git a/src/tools/clippy/tests/ui/needless_option_take.stderr b/src/tools/clippy/tests/ui/needless_option_take.stderr
index e036bd53170..3fc339ed79e 100644
--- a/src/tools/clippy/tests/ui/needless_option_take.stderr
+++ b/src/tools/clippy/tests/ui/needless_option_take.stderr
@@ -2,7 +2,9 @@ error: called `Option::take()` on a temporary value
   --> tests/ui/needless_option_take.rs:23:5
    |
 LL |     x.as_ref().take();
-   |     ^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^-------
+   |               |
+   |               help: remove
    |
    = note: `as_ref` creates a temporary value, so calling take() has no effect
    = note: `-D clippy::needless-option-take` implied by `-D warnings`
@@ -12,7 +14,9 @@ error: called `Option::take()` on a temporary value
   --> tests/ui/needless_option_take.rs:31:13
    |
 LL |     let y = x.as_mut().take();
-   |             ^^^^^^^^^^^^^^^^^
+   |             ^^^^^^^^^^-------
+   |                       |
+   |                       help: remove
    |
    = note: `as_mut` creates a temporary value, so calling take() has no effect
 
@@ -20,7 +24,9 @@ error: called `Option::take()` on a temporary value
   --> tests/ui/needless_option_take.rs:33:13
    |
 LL |     let y = x.replace(289).take();
-   |             ^^^^^^^^^^^^^^^^^^^^^
+   |             ^^^^^^^^^^^^^^-------
+   |                           |
+   |                           help: remove
    |
    = note: `replace` creates a temporary value, so calling take() has no effect
 
@@ -28,7 +34,9 @@ error: called `Option::take()` on a temporary value
   --> tests/ui/needless_option_take.rs:36:13
    |
 LL |     let y = Some(3).as_mut().take();
-   |             ^^^^^^^^^^^^^^^^^^^^^^^
+   |             ^^^^^^^^^^^^^^^^-------
+   |                             |
+   |                             help: remove
    |
    = note: `as_mut` creates a temporary value, so calling take() has no effect
 
@@ -36,7 +44,9 @@ error: called `Option::take()` on a temporary value
   --> tests/ui/needless_option_take.rs:39:13
    |
 LL |     let y = Option::as_mut(&mut x).take();
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |             ^^^^^^^^^^^^^^^^^^^^^^-------
+   |                                   |
+   |                                   help: remove
    |
    = note: `as_mut` creates a temporary value, so calling take() has no effect
 
@@ -44,7 +54,9 @@ error: called `Option::take()` on a temporary value
   --> tests/ui/needless_option_take.rs:43:13
    |
 LL |     let x = return_option().take();
-   |             ^^^^^^^^^^^^^^^^^^^^^^
+   |             ^^^^^^^^^^^^^^^-------
+   |                            |
+   |                            help: remove
    |
    = note: `return_option` creates a temporary value, so calling take() has no effect
 
@@ -52,7 +64,9 @@ error: called `Option::take()` on a temporary value
   --> tests/ui/needless_option_take.rs:47:13
    |
 LL |     let x = MyStruct::get_option().take();
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |             ^^^^^^^^^^^^^^^^^^^^^^-------
+   |                                   |
+   |                                   help: remove
    |
    = note: `get_option` creates a temporary value, so calling take() has no effect
 
@@ -60,7 +74,9 @@ error: called `Option::take()` on a temporary value
   --> tests/ui/needless_option_take.rs:53:13
    |
 LL |     let y = my_vec.first().take();
-   |             ^^^^^^^^^^^^^^^^^^^^^
+   |             ^^^^^^^^^^^^^^-------
+   |                           |
+   |                           help: remove
    |
    = note: `first` creates a temporary value, so calling take() has no effect
 
@@ -68,7 +84,9 @@ error: called `Option::take()` on a temporary value
   --> tests/ui/needless_option_take.rs:56:13
    |
 LL |     let y = my_vec.first().take();
-   |             ^^^^^^^^^^^^^^^^^^^^^
+   |             ^^^^^^^^^^^^^^-------
+   |                           |
+   |                           help: remove
    |
    = note: `first` creates a temporary value, so calling take() has no effect
 
diff --git a/src/tools/clippy/tests/ui/needless_range_loop.rs b/src/tools/clippy/tests/ui/needless_range_loop.rs
index 3f242195330..75f1896eded 100644
--- a/src/tools/clippy/tests/ui/needless_range_loop.rs
+++ b/src/tools/clippy/tests/ui/needless_range_loop.rs
@@ -2,7 +2,8 @@
 #![allow(
     clippy::uninlined_format_args,
     clippy::unnecessary_literal_unwrap,
-    clippy::useless_vec
+    clippy::useless_vec,
+    clippy::manual_slice_fill
 )]
 //@no-rustfix
 static STATIC: [usize; 4] = [0, 1, 8, 16];
diff --git a/src/tools/clippy/tests/ui/needless_range_loop.stderr b/src/tools/clippy/tests/ui/needless_range_loop.stderr
index dc2cf437e02..503d796e5e8 100644
--- a/src/tools/clippy/tests/ui/needless_range_loop.stderr
+++ b/src/tools/clippy/tests/ui/needless_range_loop.stderr
@@ -1,5 +1,5 @@
 error: the loop variable `i` is only used to index `vec`
-  --> tests/ui/needless_range_loop.rs:15:14
+  --> tests/ui/needless_range_loop.rs:16:14
    |
 LL |     for i in 0..vec.len() {
    |              ^^^^^^^^^^^^
@@ -12,7 +12,7 @@ LL |     for <item> in &vec {
    |         ~~~~~~    ~~~~
 
 error: the loop variable `i` is only used to index `vec`
-  --> tests/ui/needless_range_loop.rs:26:14
+  --> tests/ui/needless_range_loop.rs:27:14
    |
 LL |     for i in 0..vec.len() {
    |              ^^^^^^^^^^^^
@@ -23,7 +23,7 @@ LL |     for <item> in &vec {
    |         ~~~~~~    ~~~~
 
 error: the loop variable `j` is only used to index `STATIC`
-  --> tests/ui/needless_range_loop.rs:32:14
+  --> tests/ui/needless_range_loop.rs:33:14
    |
 LL |     for j in 0..4 {
    |              ^^^^
@@ -34,7 +34,7 @@ LL |     for <item> in &STATIC {
    |         ~~~~~~    ~~~~~~~
 
 error: the loop variable `j` is only used to index `CONST`
-  --> tests/ui/needless_range_loop.rs:37:14
+  --> tests/ui/needless_range_loop.rs:38:14
    |
 LL |     for j in 0..4 {
    |              ^^^^
@@ -45,7 +45,7 @@ LL |     for <item> in &CONST {
    |         ~~~~~~    ~~~~~~
 
 error: the loop variable `i` is used to index `vec`
-  --> tests/ui/needless_range_loop.rs:42:14
+  --> tests/ui/needless_range_loop.rs:43:14
    |
 LL |     for i in 0..vec.len() {
    |              ^^^^^^^^^^^^
@@ -56,7 +56,7 @@ LL |     for (i, <item>) in vec.iter().enumerate() {
    |         ~~~~~~~~~~~    ~~~~~~~~~~~~~~~~~~~~~~
 
 error: the loop variable `i` is only used to index `vec2`
-  --> tests/ui/needless_range_loop.rs:51:14
+  --> tests/ui/needless_range_loop.rs:52:14
    |
 LL |     for i in 0..vec.len() {
    |              ^^^^^^^^^^^^
@@ -67,7 +67,7 @@ LL |     for <item> in vec2.iter().take(vec.len()) {
    |         ~~~~~~    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: the loop variable `i` is only used to index `vec`
-  --> tests/ui/needless_range_loop.rs:56:14
+  --> tests/ui/needless_range_loop.rs:57:14
    |
 LL |     for i in 5..vec.len() {
    |              ^^^^^^^^^^^^
@@ -78,7 +78,7 @@ LL |     for <item> in vec.iter().skip(5) {
    |         ~~~~~~    ~~~~~~~~~~~~~~~~~~
 
 error: the loop variable `i` is only used to index `vec`
-  --> tests/ui/needless_range_loop.rs:61:14
+  --> tests/ui/needless_range_loop.rs:62:14
    |
 LL |     for i in 0..MAX_LEN {
    |              ^^^^^^^^^^
@@ -89,7 +89,7 @@ LL |     for <item> in vec.iter().take(MAX_LEN) {
    |         ~~~~~~    ~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: the loop variable `i` is only used to index `vec`
-  --> tests/ui/needless_range_loop.rs:66:14
+  --> tests/ui/needless_range_loop.rs:67:14
    |
 LL |     for i in 0..=MAX_LEN {
    |              ^^^^^^^^^^^
@@ -100,7 +100,7 @@ LL |     for <item> in vec.iter().take(MAX_LEN + 1) {
    |         ~~~~~~    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: the loop variable `i` is only used to index `vec`
-  --> tests/ui/needless_range_loop.rs:71:14
+  --> tests/ui/needless_range_loop.rs:72:14
    |
 LL |     for i in 5..10 {
    |              ^^^^^
@@ -111,7 +111,7 @@ LL |     for <item> in vec.iter().take(10).skip(5) {
    |         ~~~~~~    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: the loop variable `i` is only used to index `vec`
-  --> tests/ui/needless_range_loop.rs:76:14
+  --> tests/ui/needless_range_loop.rs:77:14
    |
 LL |     for i in 5..=10 {
    |              ^^^^^^
@@ -122,7 +122,7 @@ LL |     for <item> in vec.iter().take(10 + 1).skip(5) {
    |         ~~~~~~    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: the loop variable `i` is used to index `vec`
-  --> tests/ui/needless_range_loop.rs:81:14
+  --> tests/ui/needless_range_loop.rs:82:14
    |
 LL |     for i in 5..vec.len() {
    |              ^^^^^^^^^^^^
@@ -133,7 +133,7 @@ LL |     for (i, <item>) in vec.iter().enumerate().skip(5) {
    |         ~~~~~~~~~~~    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: the loop variable `i` is used to index `vec`
-  --> tests/ui/needless_range_loop.rs:86:14
+  --> tests/ui/needless_range_loop.rs:87:14
    |
 LL |     for i in 5..10 {
    |              ^^^^^
@@ -144,7 +144,7 @@ LL |     for (i, <item>) in vec.iter().enumerate().take(10).skip(5) {
    |         ~~~~~~~~~~~    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: the loop variable `i` is used to index `vec`
-  --> tests/ui/needless_range_loop.rs:92:14
+  --> tests/ui/needless_range_loop.rs:93:14
    |
 LL |     for i in 0..vec.len() {
    |              ^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/precedence.fixed b/src/tools/clippy/tests/ui/precedence.fixed
index 9864dd2550b..52144a18bac 100644
--- a/src/tools/clippy/tests/ui/precedence.fixed
+++ b/src/tools/clippy/tests/ui/precedence.fixed
@@ -20,10 +20,10 @@ fn main() {
     1 ^ (1 - 1);
     3 | (2 - 1);
     3 & (5 - 2);
-    0x0F00 & (0x00F0 << 4);
-    0x0F00 & (0xF000 >> 4);
-    (0x0F00 << 1) ^ 3;
-    (0x0F00 << 1) | 2;
+    0x0F00 & 0x00F0 << 4;
+    0x0F00 & 0xF000 >> 4;
+    0x0F00 << 1 ^ 3;
+    0x0F00 << 1 | 2;
 
     let b = 3;
     trip!(b * 8);
diff --git a/src/tools/clippy/tests/ui/precedence.stderr b/src/tools/clippy/tests/ui/precedence.stderr
index 329422cb8a6..68ad5cb4829 100644
--- a/src/tools/clippy/tests/ui/precedence.stderr
+++ b/src/tools/clippy/tests/ui/precedence.stderr
@@ -43,29 +43,5 @@ error: operator precedence might not be obvious
 LL |     3 & 5 - 2;
    |     ^^^^^^^^^ help: consider parenthesizing your expression: `3 & (5 - 2)`
 
-error: operator precedence might not be obvious
-  --> tests/ui/precedence.rs:23:5
-   |
-LL |     0x0F00 & 0x00F0 << 4;
-   |     ^^^^^^^^^^^^^^^^^^^^ help: consider parenthesizing your expression: `0x0F00 & (0x00F0 << 4)`
-
-error: operator precedence might not be obvious
-  --> tests/ui/precedence.rs:24:5
-   |
-LL |     0x0F00 & 0xF000 >> 4;
-   |     ^^^^^^^^^^^^^^^^^^^^ help: consider parenthesizing your expression: `0x0F00 & (0xF000 >> 4)`
-
-error: operator precedence might not be obvious
-  --> tests/ui/precedence.rs:25:5
-   |
-LL |     0x0F00 << 1 ^ 3;
-   |     ^^^^^^^^^^^^^^^ help: consider parenthesizing your expression: `(0x0F00 << 1) ^ 3`
-
-error: operator precedence might not be obvious
-  --> tests/ui/precedence.rs:26:5
-   |
-LL |     0x0F00 << 1 | 2;
-   |     ^^^^^^^^^^^^^^^ help: consider parenthesizing your expression: `(0x0F00 << 1) | 2`
-
-error: aborting due to 11 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui/precedence_bits.fixed b/src/tools/clippy/tests/ui/precedence_bits.fixed
new file mode 100644
index 00000000000..82fea0d14e4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/precedence_bits.fixed
@@ -0,0 +1,35 @@
+#![warn(clippy::precedence_bits)]
+#![allow(
+    unused_must_use,
+    clippy::no_effect,
+    clippy::unnecessary_operation,
+    clippy::precedence
+)]
+#![allow(clippy::identity_op)]
+#![allow(clippy::eq_op)]
+
+macro_rules! trip {
+    ($a:expr) => {
+        match $a & 0b1111_1111u8 {
+            0 => println!("a is zero ({})", $a),
+            _ => println!("a is {}", $a),
+        }
+    };
+}
+
+fn main() {
+    1 << 2 + 3;
+    1 + 2 << 3;
+    4 >> 1 + 1;
+    1 + 3 >> 2;
+    1 ^ 1 - 1;
+    3 | 2 - 1;
+    3 & 5 - 2;
+    0x0F00 & (0x00F0 << 4);
+    0x0F00 & (0xF000 >> 4);
+    (0x0F00 << 1) ^ 3;
+    (0x0F00 << 1) | 2;
+
+    let b = 3;
+    trip!(b * 8);
+}
diff --git a/src/tools/clippy/tests/ui/precedence_bits.rs b/src/tools/clippy/tests/ui/precedence_bits.rs
new file mode 100644
index 00000000000..9b353308b6e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/precedence_bits.rs
@@ -0,0 +1,35 @@
+#![warn(clippy::precedence_bits)]
+#![allow(
+    unused_must_use,
+    clippy::no_effect,
+    clippy::unnecessary_operation,
+    clippy::precedence
+)]
+#![allow(clippy::identity_op)]
+#![allow(clippy::eq_op)]
+
+macro_rules! trip {
+    ($a:expr) => {
+        match $a & 0b1111_1111u8 {
+            0 => println!("a is zero ({})", $a),
+            _ => println!("a is {}", $a),
+        }
+    };
+}
+
+fn main() {
+    1 << 2 + 3;
+    1 + 2 << 3;
+    4 >> 1 + 1;
+    1 + 3 >> 2;
+    1 ^ 1 - 1;
+    3 | 2 - 1;
+    3 & 5 - 2;
+    0x0F00 & 0x00F0 << 4;
+    0x0F00 & 0xF000 >> 4;
+    0x0F00 << 1 ^ 3;
+    0x0F00 << 1 | 2;
+
+    let b = 3;
+    trip!(b * 8);
+}
diff --git a/src/tools/clippy/tests/ui/precedence_bits.stderr b/src/tools/clippy/tests/ui/precedence_bits.stderr
new file mode 100644
index 00000000000..f468186b363
--- /dev/null
+++ b/src/tools/clippy/tests/ui/precedence_bits.stderr
@@ -0,0 +1,29 @@
+error: operator precedence might not be obvious
+  --> tests/ui/precedence_bits.rs:28:5
+   |
+LL |     0x0F00 & 0x00F0 << 4;
+   |     ^^^^^^^^^^^^^^^^^^^^ help: consider parenthesizing your expression: `0x0F00 & (0x00F0 << 4)`
+   |
+   = note: `-D clippy::precedence-bits` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::precedence_bits)]`
+
+error: operator precedence might not be obvious
+  --> tests/ui/precedence_bits.rs:29:5
+   |
+LL |     0x0F00 & 0xF000 >> 4;
+   |     ^^^^^^^^^^^^^^^^^^^^ help: consider parenthesizing your expression: `0x0F00 & (0xF000 >> 4)`
+
+error: operator precedence might not be obvious
+  --> tests/ui/precedence_bits.rs:30:5
+   |
+LL |     0x0F00 << 1 ^ 3;
+   |     ^^^^^^^^^^^^^^^ help: consider parenthesizing your expression: `(0x0F00 << 1) ^ 3`
+
+error: operator precedence might not be obvious
+  --> tests/ui/precedence_bits.rs:31:5
+   |
+LL |     0x0F00 << 1 | 2;
+   |     ^^^^^^^^^^^^^^^ help: consider parenthesizing your expression: `(0x0F00 << 1) | 2`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/print_literal.fixed b/src/tools/clippy/tests/ui/print_literal.fixed
index 1705a7ff01b..328e9a9b999 100644
--- a/src/tools/clippy/tests/ui/print_literal.fixed
+++ b/src/tools/clippy/tests/ui/print_literal.fixed
@@ -66,3 +66,17 @@ fn main() {
 
     println!("mixed: {{hello}} {world}");
 }
+
+fn issue_13959() {
+    println!("\"");
+    println!(
+        "
+        foo
+        \\
+        \\\\
+        \"
+        \\\"
+        bar
+"
+    );
+}
diff --git a/src/tools/clippy/tests/ui/print_literal.rs b/src/tools/clippy/tests/ui/print_literal.rs
index d10b26b5887..3130d0b6998 100644
--- a/src/tools/clippy/tests/ui/print_literal.rs
+++ b/src/tools/clippy/tests/ui/print_literal.rs
@@ -66,3 +66,18 @@ fn main() {
 
     println!("mixed: {} {world}", "{hello}");
 }
+
+fn issue_13959() {
+    println!("{}", r#"""#);
+    println!(
+        "{}",
+        r#"
+        foo
+        \
+        \\
+        "
+        \"
+        bar
+"#
+    );
+}
diff --git a/src/tools/clippy/tests/ui/print_literal.stderr b/src/tools/clippy/tests/ui/print_literal.stderr
index c4cbb8bed70..d967b7c2407 100644
--- a/src/tools/clippy/tests/ui/print_literal.stderr
+++ b/src/tools/clippy/tests/ui/print_literal.stderr
@@ -192,5 +192,41 @@ LL -     println!("mixed: {} {world}", "{hello}");
 LL +     println!("mixed: {{hello}} {world}");
    |
 
-error: aborting due to 16 previous errors
+error: literal with an empty format string
+  --> tests/ui/print_literal.rs:71:20
+   |
+LL |     println!("{}", r#"""#);
+   |                    ^^^^^^
+   |
+help: try
+   |
+LL -     println!("{}", r#"""#);
+LL +     println!("\"");
+   |
+
+error: literal with an empty format string
+  --> tests/ui/print_literal.rs:74:9
+   |
+LL | /         r#"
+LL | |         foo
+LL | |         \
+LL | |         \\
+...  |
+LL | |         bar
+LL | | "#
+   | |__^
+   |
+help: try
+   |
+LL ~         "
+LL +         foo
+LL +         \\
+LL +         \\\\
+LL +         \"
+LL +         \\\"
+LL +         bar
+LL ~ "
+   |
+
+error: aborting due to 18 previous errors
 
diff --git a/src/tools/clippy/tests/ui/redundant_else.fixed b/src/tools/clippy/tests/ui/redundant_else.fixed
new file mode 100644
index 00000000000..47aa79302d2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_else.fixed
@@ -0,0 +1,154 @@
+#![warn(clippy::redundant_else)]
+#![allow(clippy::needless_return, clippy::if_same_then_else, clippy::needless_late_init)]
+
+fn main() {
+    loop {
+        // break
+        if foo() {
+            println!("Love your neighbor;");
+            break;
+        }
+        //~^ ERROR: redundant else block
+        println!("yet don't pull down your hedge.");
+        // continue
+        if foo() {
+            println!("He that lies down with Dogs,");
+            continue;
+        }
+        //~^ ERROR: redundant else block
+        println!("shall rise up with fleas.");
+        // match block
+        if foo() {
+            match foo() {
+                1 => break,
+                _ => return,
+            }
+        }
+        //~^ ERROR: redundant else block
+        println!("You may delay, but time will not.");
+    }
+    // else if
+    if foo() {
+        return;
+    } else if foo() {
+        return;
+    }
+    //~^ ERROR: redundant else block
+    println!("A fat kitchen makes a lean will.");
+    // let binding outside of block
+    let _ = {
+        if foo() {
+            return;
+        }
+        //~^ ERROR: redundant else block
+        1
+    };
+    // else if with let binding outside of block
+    let _ = {
+        if foo() {
+            return;
+        } else if foo() {
+            return;
+        }
+        //~^ ERROR: redundant else block
+        2
+    };
+    // inside if let
+    let _ = if let Some(1) = foo() {
+        let _ = 1;
+        if foo() {
+            return;
+        }
+        //~^ ERROR: redundant else block
+        1
+    } else {
+        1
+    };
+
+    //
+    // non-lint cases
+    //
+
+    // sanity check
+    if foo() {
+        let _ = 1;
+    } else {
+        println!("Who is wise? He that learns from every one.");
+    }
+    // else if without else
+    if foo() {
+        return;
+    } else if foo() {
+        foo()
+    };
+    // nested if return
+    if foo() {
+        if foo() {
+            return;
+        }
+    } else {
+        foo()
+    };
+    // match with non-breaking branch
+    if foo() {
+        match foo() {
+            1 => foo(),
+            _ => return,
+        }
+    } else {
+        println!("Three may keep a secret, if two of them are dead.");
+    }
+    // let binding
+    let _ = if foo() {
+        return;
+    } else {
+        1
+    };
+    // assign
+    let mut a;
+    a = if foo() {
+        return;
+    } else {
+        1
+    };
+    // assign-op
+    a += if foo() {
+        return;
+    } else {
+        1
+    };
+    // if return else if else
+    if foo() {
+        return;
+    } else if foo() {
+        1
+    } else {
+        2
+    };
+    // if else if return else
+    if foo() {
+        1
+    } else if foo() {
+        return;
+    } else {
+        2
+    };
+    // else if with let binding
+    let _ = if foo() {
+        return;
+    } else if foo() {
+        return;
+    } else {
+        2
+    };
+    // inside function call
+    Box::new(if foo() {
+        return;
+    } else {
+        1
+    });
+}
+
+fn foo<T>() -> T {
+    unimplemented!("I'm not Santa Claus")
+}
diff --git a/src/tools/clippy/tests/ui/redundant_else.stderr b/src/tools/clippy/tests/ui/redundant_else.stderr
index b649a210b5f..ecc16f7cda5 100644
--- a/src/tools/clippy/tests/ui/redundant_else.stderr
+++ b/src/tools/clippy/tests/ui/redundant_else.stderr
@@ -1,88 +1,123 @@
 error: redundant else block
-  --> tests/ui/redundant_else.rs:10:16
+  --> tests/ui/redundant_else.rs:10:10
    |
 LL |           } else {
-   |  ________________^
+   |  __________^
 LL | |
 LL | |             println!("yet don't pull down your hedge.");
 LL | |         }
    | |_________^
    |
-   = help: remove the `else` block and move the contents out
    = note: `-D clippy::redundant-else` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::redundant_else)]`
+help: remove the `else` block and move the contents out
+   |
+LL ~         }
+LL +
+LL +         println!("yet don't pull down your hedge.");
+   |
 
 error: redundant else block
-  --> tests/ui/redundant_else.rs:18:16
+  --> tests/ui/redundant_else.rs:18:10
    |
 LL |           } else {
-   |  ________________^
+   |  __________^
 LL | |
 LL | |             println!("shall rise up with fleas.");
 LL | |         }
    | |_________^
    |
-   = help: remove the `else` block and move the contents out
+help: remove the `else` block and move the contents out
+   |
+LL ~         }
+LL +
+LL +         println!("shall rise up with fleas.");
+   |
 
 error: redundant else block
-  --> tests/ui/redundant_else.rs:28:16
+  --> tests/ui/redundant_else.rs:28:10
    |
 LL |           } else {
-   |  ________________^
+   |  __________^
 LL | |
 LL | |             println!("You may delay, but time will not.");
 LL | |         }
    | |_________^
    |
-   = help: remove the `else` block and move the contents out
+help: remove the `else` block and move the contents out
+   |
+LL ~         }
+LL +
+LL +         println!("You may delay, but time will not.");
+   |
 
 error: redundant else block
-  --> tests/ui/redundant_else.rs:38:12
+  --> tests/ui/redundant_else.rs:38:6
    |
 LL |       } else {
-   |  ____________^
+   |  ______^
 LL | |
 LL | |         println!("A fat kitchen makes a lean will.");
 LL | |     }
    | |_____^
    |
-   = help: remove the `else` block and move the contents out
+help: remove the `else` block and move the contents out
+   |
+LL ~     }
+LL +
+LL +     println!("A fat kitchen makes a lean will.");
+   |
 
 error: redundant else block
-  --> tests/ui/redundant_else.rs:46:16
+  --> tests/ui/redundant_else.rs:46:10
    |
 LL |           } else {
-   |  ________________^
+   |  __________^
 LL | |
 LL | |             1
 LL | |         }
    | |_________^
    |
-   = help: remove the `else` block and move the contents out
+help: remove the `else` block and move the contents out
+   |
+LL ~         }
+LL +
+LL +         1
+   |
 
 error: redundant else block
-  --> tests/ui/redundant_else.rs:57:16
+  --> tests/ui/redundant_else.rs:57:10
    |
 LL |           } else {
-   |  ________________^
+   |  __________^
 LL | |
 LL | |             2
 LL | |         }
    | |_________^
    |
-   = help: remove the `else` block and move the contents out
+help: remove the `else` block and move the contents out
+   |
+LL ~         }
+LL +
+LL +         2
+   |
 
 error: redundant else block
-  --> tests/ui/redundant_else.rs:67:16
+  --> tests/ui/redundant_else.rs:67:10
    |
 LL |           } else {
-   |  ________________^
+   |  __________^
 LL | |
 LL | |             1
 LL | |         }
    | |_________^
    |
-   = help: remove the `else` block and move the contents out
+help: remove the `else` block and move the contents out
+   |
+LL ~         }
+LL +
+LL +         1
+   |
 
 error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui/return_and_then.fixed b/src/tools/clippy/tests/ui/return_and_then.fixed
new file mode 100644
index 00000000000..9736a51ac86
--- /dev/null
+++ b/src/tools/clippy/tests/ui/return_and_then.fixed
@@ -0,0 +1,67 @@
+#![warn(clippy::return_and_then)]
+
+fn main() {
+    fn test_opt_block(opt: Option<i32>) -> Option<i32> {
+        let n = opt?;
+        let mut ret = n + 1;
+        ret += n;
+        if n > 1 { Some(ret) } else { None }
+    }
+
+    fn test_opt_func(opt: Option<i32>) -> Option<i32> {
+        let n = opt?;
+        test_opt_block(Some(n))
+    }
+
+    fn test_call_chain() -> Option<i32> {
+        let n = gen_option(1)?;
+        test_opt_block(Some(n))
+    }
+
+    fn test_res_block(opt: Result<i32, i32>) -> Result<i32, i32> {
+        let n = opt?;
+        if n > 1 { Ok(n + 1) } else { Err(n) }
+    }
+
+    fn test_res_func(opt: Result<i32, i32>) -> Result<i32, i32> {
+        let n = opt?;
+        test_res_block(Ok(n))
+    }
+
+    fn test_ref_only() -> Option<i32> {
+        // ref: empty string
+        let x = Some("")?;
+        if x.len() > 2 { Some(3) } else { None }
+    }
+
+    fn test_tmp_only() -> Option<i32> {
+        // unused temporary: vec![1, 2, 4]
+        let x = Some(match (vec![1, 2, 3], vec![1, 2, 4]) {
+            (a, _) if a.len() > 1 => a,
+            (_, b) => b,
+        })?;
+        if x.len() > 2 { Some(3) } else { None }
+    }
+
+    // should not lint
+    fn test_tmp_ref() -> Option<String> {
+        String::from("<BOOM>")
+            .strip_prefix("<")
+            .and_then(|s| s.strip_suffix(">").map(String::from))
+    }
+
+    // should not lint
+    fn test_unconsumed_tmp() -> Option<i32> {
+        [1, 2, 3]
+            .iter()
+            .map(|x| x + 1)
+            .collect::<Vec<_>>() // temporary Vec created here
+            .as_slice() // creates temporary slice
+            .first() // creates temporary reference
+            .and_then(|x| test_opt_block(Some(*x)))
+    }
+}
+
+fn gen_option(n: i32) -> Option<i32> {
+    Some(n)
+}
diff --git a/src/tools/clippy/tests/ui/return_and_then.rs b/src/tools/clippy/tests/ui/return_and_then.rs
new file mode 100644
index 00000000000..8bcbdfc3a63
--- /dev/null
+++ b/src/tools/clippy/tests/ui/return_and_then.rs
@@ -0,0 +1,63 @@
+#![warn(clippy::return_and_then)]
+
+fn main() {
+    fn test_opt_block(opt: Option<i32>) -> Option<i32> {
+        opt.and_then(|n| {
+            let mut ret = n + 1;
+            ret += n;
+            if n > 1 { Some(ret) } else { None }
+        })
+    }
+
+    fn test_opt_func(opt: Option<i32>) -> Option<i32> {
+        opt.and_then(|n| test_opt_block(Some(n)))
+    }
+
+    fn test_call_chain() -> Option<i32> {
+        gen_option(1).and_then(|n| test_opt_block(Some(n)))
+    }
+
+    fn test_res_block(opt: Result<i32, i32>) -> Result<i32, i32> {
+        opt.and_then(|n| if n > 1 { Ok(n + 1) } else { Err(n) })
+    }
+
+    fn test_res_func(opt: Result<i32, i32>) -> Result<i32, i32> {
+        opt.and_then(|n| test_res_block(Ok(n)))
+    }
+
+    fn test_ref_only() -> Option<i32> {
+        // ref: empty string
+        Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None })
+    }
+
+    fn test_tmp_only() -> Option<i32> {
+        // unused temporary: vec![1, 2, 4]
+        Some(match (vec![1, 2, 3], vec![1, 2, 4]) {
+            (a, _) if a.len() > 1 => a,
+            (_, b) => b,
+        })
+        .and_then(|x| if x.len() > 2 { Some(3) } else { None })
+    }
+
+    // should not lint
+    fn test_tmp_ref() -> Option<String> {
+        String::from("<BOOM>")
+            .strip_prefix("<")
+            .and_then(|s| s.strip_suffix(">").map(String::from))
+    }
+
+    // should not lint
+    fn test_unconsumed_tmp() -> Option<i32> {
+        [1, 2, 3]
+            .iter()
+            .map(|x| x + 1)
+            .collect::<Vec<_>>() // temporary Vec created here
+            .as_slice() // creates temporary slice
+            .first() // creates temporary reference
+            .and_then(|x| test_opt_block(Some(*x)))
+    }
+}
+
+fn gen_option(n: i32) -> Option<i32> {
+    Some(n)
+}
diff --git a/src/tools/clippy/tests/ui/return_and_then.stderr b/src/tools/clippy/tests/ui/return_and_then.stderr
new file mode 100644
index 00000000000..b2e8bf2ca45
--- /dev/null
+++ b/src/tools/clippy/tests/ui/return_and_then.stderr
@@ -0,0 +1,101 @@
+error: use the question mark operator instead of an `and_then` call
+  --> tests/ui/return_and_then.rs:5:9
+   |
+LL | /         opt.and_then(|n| {
+LL | |             let mut ret = n + 1;
+LL | |             ret += n;
+LL | |             if n > 1 { Some(ret) } else { None }
+LL | |         })
+   | |__________^
+   |
+   = note: `-D clippy::return-and-then` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::return_and_then)]`
+help: try
+   |
+LL ~         let n = opt?;
+LL +         let mut ret = n + 1;
+LL +         ret += n;
+LL +         if n > 1 { Some(ret) } else { None }
+   |
+
+error: use the question mark operator instead of an `and_then` call
+  --> tests/ui/return_and_then.rs:13:9
+   |
+LL |         opt.and_then(|n| test_opt_block(Some(n)))
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL ~         let n = opt?;
+LL +         test_opt_block(Some(n))
+   |
+
+error: use the question mark operator instead of an `and_then` call
+  --> tests/ui/return_and_then.rs:17:9
+   |
+LL |         gen_option(1).and_then(|n| test_opt_block(Some(n)))
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL ~         let n = gen_option(1)?;
+LL +         test_opt_block(Some(n))
+   |
+
+error: use the question mark operator instead of an `and_then` call
+  --> tests/ui/return_and_then.rs:21:9
+   |
+LL |         opt.and_then(|n| if n > 1 { Ok(n + 1) } else { Err(n) })
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL ~         let n = opt?;
+LL +         if n > 1 { Ok(n + 1) } else { Err(n) }
+   |
+
+error: use the question mark operator instead of an `and_then` call
+  --> tests/ui/return_and_then.rs:25:9
+   |
+LL |         opt.and_then(|n| test_res_block(Ok(n)))
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL ~         let n = opt?;
+LL +         test_res_block(Ok(n))
+   |
+
+error: use the question mark operator instead of an `and_then` call
+  --> tests/ui/return_and_then.rs:30:9
+   |
+LL |         Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None })
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL ~         let x = Some("")?;
+LL +         if x.len() > 2 { Some(3) } else { None }
+   |
+
+error: use the question mark operator instead of an `and_then` call
+  --> tests/ui/return_and_then.rs:35:9
+   |
+LL | /         Some(match (vec![1, 2, 3], vec![1, 2, 4]) {
+LL | |             (a, _) if a.len() > 1 => a,
+LL | |             (_, b) => b,
+LL | |         })
+LL | |         .and_then(|x| if x.len() > 2 { Some(3) } else { None })
+   | |_______________________________________________________________^
+   |
+help: try
+   |
+LL ~         let x = Some(match (vec![1, 2, 3], vec![1, 2, 4]) {
+LL +             (a, _) if a.len() > 1 => a,
+LL +             (_, b) => b,
+LL +         })?;
+LL +         if x.len() > 2 { Some(3) } else { None }
+   |
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/size_of_in_element_count/expressions.rs b/src/tools/clippy/tests/ui/size_of_in_element_count/expressions.rs
index 91b7ea3922c..f405ba200ac 100644
--- a/src/tools/clippy/tests/ui/size_of_in_element_count/expressions.rs
+++ b/src/tools/clippy/tests/ui/size_of_in_element_count/expressions.rs
@@ -8,11 +8,11 @@ fn main() {
     const SIZE: usize = 128;
     const HALF_SIZE: usize = SIZE / 2;
     const DOUBLE_SIZE: usize = SIZE * 2;
-    let mut x = [2u8; SIZE];
-    let mut y = [2u8; SIZE];
+    let mut x = [2u16; SIZE];
+    let mut y = [2u16; SIZE];
 
     // Count expression involving multiplication of size_of (Should trigger the lint)
-    unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::<u8>() * SIZE) };
+    unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::<u16>() * SIZE) };
     //~^ ERROR: found a count of bytes instead of a count of elements of `T`
 
     // Count expression involving nested multiplications of size_of (Should trigger the lint)
@@ -20,22 +20,19 @@ fn main() {
     //~^ ERROR: found a count of bytes instead of a count of elements of `T`
 
     // Count expression involving divisions of size_of (Should trigger the lint)
-    unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::<u8>() / 2) };
+    unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::<u16>() / 2) };
     //~^ ERROR: found a count of bytes instead of a count of elements of `T`
 
     // Count expression involving divisions by size_of (Should not trigger the lint)
-    unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / size_of::<u8>()) };
+    unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / size_of::<u16>()) };
 
     // Count expression involving divisions by multiple size_of (Should not trigger the lint)
-    unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / (2 * size_of::<u8>())) };
+    unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / (2 * size_of::<u16>())) };
 
     // Count expression involving recursive divisions by size_of (Should trigger the lint)
-    unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / (2 / size_of::<u8>())) };
+    unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / (2 / size_of::<u16>())) };
     //~^ ERROR: found a count of bytes instead of a count of elements of `T`
 
     // No size_of calls (Should not trigger the lint)
     unsafe { copy(x.as_ptr(), y.as_mut_ptr(), SIZE) };
-
-    // Different types for pointee and size_of (Should not trigger the lint)
-    unsafe { y.as_mut_ptr().write_bytes(0u8, size_of::<u16>() / 2 * SIZE) };
 }
diff --git a/src/tools/clippy/tests/ui/size_of_in_element_count/expressions.stderr b/src/tools/clippy/tests/ui/size_of_in_element_count/expressions.stderr
index 6396afd7f39..74be0d7773d 100644
--- a/src/tools/clippy/tests/ui/size_of_in_element_count/expressions.stderr
+++ b/src/tools/clippy/tests/ui/size_of_in_element_count/expressions.stderr
@@ -1,8 +1,8 @@
 error: found a count of bytes instead of a count of elements of `T`
   --> tests/ui/size_of_in_element_count/expressions.rs:15:62
    |
-LL |     unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::<u8>() * SIZE) };
-   |                                                              ^^^^^^^^^^^^^^^^^^^^^^
+LL |     unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::<u16>() * SIZE) };
+   |                                                              ^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
    = note: `-D clippy::size-of-in-element-count` implied by `-D warnings`
@@ -19,16 +19,16 @@ LL |     unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * si
 error: found a count of bytes instead of a count of elements of `T`
   --> tests/ui/size_of_in_element_count/expressions.rs:23:47
    |
-LL |     unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::<u8>() / 2) };
-   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::<u16>() / 2) };
+   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
 
 error: found a count of bytes instead of a count of elements of `T`
   --> tests/ui/size_of_in_element_count/expressions.rs:33:47
    |
-LL |     unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / (2 / size_of::<u8>())) };
-   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / (2 / size_of::<u16>())) };
+   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
 
diff --git a/src/tools/clippy/tests/ui/size_of_in_element_count/functions.rs b/src/tools/clippy/tests/ui/size_of_in_element_count/functions.rs
index 3501cbdf81c..af18136a1db 100644
--- a/src/tools/clippy/tests/ui/size_of_in_element_count/functions.rs
+++ b/src/tools/clippy/tests/ui/size_of_in_element_count/functions.rs
@@ -11,57 +11,52 @@ fn main() {
     const SIZE: usize = 128;
     const HALF_SIZE: usize = SIZE / 2;
     const DOUBLE_SIZE: usize = SIZE * 2;
-    let mut x = [2u8; SIZE];
-    let mut y = [2u8; SIZE];
+    let mut x = [2u16; SIZE];
+    let mut y = [2u16; SIZE];
 
     // Count is size_of (Should trigger the lint)
-    unsafe { copy_nonoverlapping::<u8>(x.as_ptr(), y.as_mut_ptr(), size_of::<u8>()) };
+    unsafe { copy_nonoverlapping::<u16>(x.as_ptr(), y.as_mut_ptr(), size_of::<u16>()) };
     //~^ ERROR: found a count of bytes instead of a count of elements of `T`
     unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) };
     //~^ ERROR: found a count of bytes instead of a count of elements of `T`
 
-    unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::<u8>()) };
+    unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::<u16>()) };
     //~^ ERROR: found a count of bytes instead of a count of elements of `T`
-    unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of::<u8>()) };
+    unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of::<u16>()) };
     //~^ ERROR: found a count of bytes instead of a count of elements of `T`
-    unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::<u8>()) };
+    unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::<u16>()) };
     //~^ ERROR: found a count of bytes instead of a count of elements of `T`
-    unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::<u8>()) };
+    unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::<u16>()) };
     //~^ ERROR: found a count of bytes instead of a count of elements of `T`
 
-    unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::<u8>()) };
+    unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::<u16>()) };
     //~^ ERROR: found a count of bytes instead of a count of elements of `T`
     unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) };
     //~^ ERROR: found a count of bytes instead of a count of elements of `T`
 
-    unsafe { y.as_mut_ptr().write_bytes(0u8, size_of::<u8>() * SIZE) };
-    //~^ ERROR: found a count of bytes instead of a count of elements of `T`
-    unsafe { write_bytes(y.as_mut_ptr(), 0u8, size_of::<u8>() * SIZE) };
-    //~^ ERROR: found a count of bytes instead of a count of elements of `T`
-
-    unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::<u8>() * SIZE) };
+    unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::<u16>() * SIZE) };
     //~^ ERROR: found a count of bytes instead of a count of elements of `T`
 
-    slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::<u8>() * SIZE);
+    slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::<u16>() * SIZE);
     //~^ ERROR: found a count of bytes instead of a count of elements of `T`
-    slice_from_raw_parts(y.as_ptr(), size_of::<u8>() * SIZE);
+    slice_from_raw_parts(y.as_ptr(), size_of::<u16>() * SIZE);
     //~^ ERROR: found a count of bytes instead of a count of elements of `T`
 
-    unsafe { from_raw_parts_mut(y.as_mut_ptr(), size_of::<u8>() * SIZE) };
+    unsafe { from_raw_parts_mut(y.as_mut_ptr(), size_of::<u16>() * SIZE) };
     //~^ ERROR: found a count of bytes instead of a count of elements of `T`
-    unsafe { from_raw_parts(y.as_ptr(), size_of::<u8>() * SIZE) };
+    unsafe { from_raw_parts(y.as_ptr(), size_of::<u16>() * SIZE) };
     //~^ ERROR: found a count of bytes instead of a count of elements of `T`
 
-    unsafe { y.as_mut_ptr().sub(size_of::<u8>()) };
+    unsafe { y.as_mut_ptr().sub(size_of::<u16>()) };
     //~^ ERROR: found a count of bytes instead of a count of elements of `T`
-    y.as_ptr().wrapping_sub(size_of::<u8>());
+    y.as_ptr().wrapping_sub(size_of::<u16>());
     //~^ ERROR: found a count of bytes instead of a count of elements of `T`
-    unsafe { y.as_ptr().add(size_of::<u8>()) };
+    unsafe { y.as_ptr().add(size_of::<u16>()) };
     //~^ ERROR: found a count of bytes instead of a count of elements of `T`
-    y.as_mut_ptr().wrapping_add(size_of::<u8>());
+    y.as_mut_ptr().wrapping_add(size_of::<u16>());
     //~^ ERROR: found a count of bytes instead of a count of elements of `T`
-    unsafe { y.as_ptr().offset(size_of::<u8>() as isize) };
+    unsafe { y.as_ptr().offset(size_of::<u16>() as isize) };
     //~^ ERROR: found a count of bytes instead of a count of elements of `T`
-    y.as_mut_ptr().wrapping_offset(size_of::<u8>() as isize);
+    y.as_mut_ptr().wrapping_offset(size_of::<u16>() as isize);
     //~^ ERROR: found a count of bytes instead of a count of elements of `T`
 }
diff --git a/src/tools/clippy/tests/ui/size_of_in_element_count/functions.stderr b/src/tools/clippy/tests/ui/size_of_in_element_count/functions.stderr
index abde7dc7cd2..de54789b225 100644
--- a/src/tools/clippy/tests/ui/size_of_in_element_count/functions.stderr
+++ b/src/tools/clippy/tests/ui/size_of_in_element_count/functions.stderr
@@ -1,8 +1,8 @@
 error: found a count of bytes instead of a count of elements of `T`
-  --> tests/ui/size_of_in_element_count/functions.rs:18:68
+  --> tests/ui/size_of_in_element_count/functions.rs:18:69
    |
-LL |     unsafe { copy_nonoverlapping::<u8>(x.as_ptr(), y.as_mut_ptr(), size_of::<u8>()) };
-   |                                                                    ^^^^^^^^^^^^^^^
+LL |     unsafe { copy_nonoverlapping::<u16>(x.as_ptr(), y.as_mut_ptr(), size_of::<u16>()) };
+   |                                                                     ^^^^^^^^^^^^^^^^
    |
    = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
    = note: `-D clippy::size-of-in-element-count` implied by `-D warnings`
@@ -19,40 +19,40 @@ LL |     unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x
 error: found a count of bytes instead of a count of elements of `T`
   --> tests/ui/size_of_in_element_count/functions.rs:23:49
    |
-LL |     unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::<u8>()) };
-   |                                                 ^^^^^^^^^^^^^^^
+LL |     unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::<u16>()) };
+   |                                                 ^^^^^^^^^^^^^^^^
    |
    = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
 
 error: found a count of bytes instead of a count of elements of `T`
   --> tests/ui/size_of_in_element_count/functions.rs:25:64
    |
-LL |     unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of::<u8>()) };
-   |                                                                ^^^^^^^^^^^^^^^
+LL |     unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of::<u16>()) };
+   |                                                                ^^^^^^^^^^^^^^^^
    |
    = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
 
 error: found a count of bytes instead of a count of elements of `T`
   --> tests/ui/size_of_in_element_count/functions.rs:27:51
    |
-LL |     unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::<u8>()) };
-   |                                                   ^^^^^^^^^^^^^^^
+LL |     unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::<u16>()) };
+   |                                                   ^^^^^^^^^^^^^^^^
    |
    = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
 
 error: found a count of bytes instead of a count of elements of `T`
   --> tests/ui/size_of_in_element_count/functions.rs:29:66
    |
-LL |     unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::<u8>()) };
-   |                                                                  ^^^^^^^^^^^^^^^
+LL |     unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::<u16>()) };
+   |                                                                  ^^^^^^^^^^^^^^^^
    |
    = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
 
 error: found a count of bytes instead of a count of elements of `T`
   --> tests/ui/size_of_in_element_count/functions.rs:32:47
    |
-LL |     unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::<u8>()) };
-   |                                               ^^^^^^^^^^^^^^^
+LL |     unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::<u16>()) };
+   |                                               ^^^^^^^^^^^^^^^^
    |
    = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
 
@@ -65,108 +65,92 @@ LL |     unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) };
    = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
 
 error: found a count of bytes instead of a count of elements of `T`
-  --> tests/ui/size_of_in_element_count/functions.rs:37:46
+  --> tests/ui/size_of_in_element_count/functions.rs:37:66
    |
-LL |     unsafe { y.as_mut_ptr().write_bytes(0u8, size_of::<u8>() * SIZE) };
-   |                                              ^^^^^^^^^^^^^^^^^^^^^^
+LL |     unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::<u16>() * SIZE) };
+   |                                                                  ^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
 
 error: found a count of bytes instead of a count of elements of `T`
-  --> tests/ui/size_of_in_element_count/functions.rs:39:47
+  --> tests/ui/size_of_in_element_count/functions.rs:40:46
    |
-LL |     unsafe { write_bytes(y.as_mut_ptr(), 0u8, size_of::<u8>() * SIZE) };
-   |                                               ^^^^^^^^^^^^^^^^^^^^^^
+LL |     slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::<u16>() * SIZE);
+   |                                              ^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
 
 error: found a count of bytes instead of a count of elements of `T`
-  --> tests/ui/size_of_in_element_count/functions.rs:42:66
+  --> tests/ui/size_of_in_element_count/functions.rs:42:38
    |
-LL |     unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::<u8>() * SIZE) };
-   |                                                                  ^^^^^^^^^^^^^^^^^^^^^^
+LL |     slice_from_raw_parts(y.as_ptr(), size_of::<u16>() * SIZE);
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
 
 error: found a count of bytes instead of a count of elements of `T`
-  --> tests/ui/size_of_in_element_count/functions.rs:45:46
+  --> tests/ui/size_of_in_element_count/functions.rs:45:49
    |
-LL |     slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::<u8>() * SIZE);
-   |                                              ^^^^^^^^^^^^^^^^^^^^^^
+LL |     unsafe { from_raw_parts_mut(y.as_mut_ptr(), size_of::<u16>() * SIZE) };
+   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
 
 error: found a count of bytes instead of a count of elements of `T`
-  --> tests/ui/size_of_in_element_count/functions.rs:47:38
+  --> tests/ui/size_of_in_element_count/functions.rs:47:41
    |
-LL |     slice_from_raw_parts(y.as_ptr(), size_of::<u8>() * SIZE);
-   |                                      ^^^^^^^^^^^^^^^^^^^^^^
+LL |     unsafe { from_raw_parts(y.as_ptr(), size_of::<u16>() * SIZE) };
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
 
 error: found a count of bytes instead of a count of elements of `T`
-  --> tests/ui/size_of_in_element_count/functions.rs:50:49
+  --> tests/ui/size_of_in_element_count/functions.rs:50:33
    |
-LL |     unsafe { from_raw_parts_mut(y.as_mut_ptr(), size_of::<u8>() * SIZE) };
-   |                                                 ^^^^^^^^^^^^^^^^^^^^^^
+LL |     unsafe { y.as_mut_ptr().sub(size_of::<u16>()) };
+   |                                 ^^^^^^^^^^^^^^^^
    |
    = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
 
 error: found a count of bytes instead of a count of elements of `T`
-  --> tests/ui/size_of_in_element_count/functions.rs:52:41
+  --> tests/ui/size_of_in_element_count/functions.rs:52:29
    |
-LL |     unsafe { from_raw_parts(y.as_ptr(), size_of::<u8>() * SIZE) };
-   |                                         ^^^^^^^^^^^^^^^^^^^^^^
+LL |     y.as_ptr().wrapping_sub(size_of::<u16>());
+   |                             ^^^^^^^^^^^^^^^^
    |
    = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
 
 error: found a count of bytes instead of a count of elements of `T`
-  --> tests/ui/size_of_in_element_count/functions.rs:55:33
+  --> tests/ui/size_of_in_element_count/functions.rs:54:29
    |
-LL |     unsafe { y.as_mut_ptr().sub(size_of::<u8>()) };
-   |                                 ^^^^^^^^^^^^^^^
+LL |     unsafe { y.as_ptr().add(size_of::<u16>()) };
+   |                             ^^^^^^^^^^^^^^^^
    |
    = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
 
 error: found a count of bytes instead of a count of elements of `T`
-  --> tests/ui/size_of_in_element_count/functions.rs:57:29
+  --> tests/ui/size_of_in_element_count/functions.rs:56:33
    |
-LL |     y.as_ptr().wrapping_sub(size_of::<u8>());
-   |                             ^^^^^^^^^^^^^^^
+LL |     y.as_mut_ptr().wrapping_add(size_of::<u16>());
+   |                                 ^^^^^^^^^^^^^^^^
    |
    = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
 
 error: found a count of bytes instead of a count of elements of `T`
-  --> tests/ui/size_of_in_element_count/functions.rs:59:29
+  --> tests/ui/size_of_in_element_count/functions.rs:58:32
    |
-LL |     unsafe { y.as_ptr().add(size_of::<u8>()) };
-   |                             ^^^^^^^^^^^^^^^
+LL |     unsafe { y.as_ptr().offset(size_of::<u16>() as isize) };
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
 
 error: found a count of bytes instead of a count of elements of `T`
-  --> tests/ui/size_of_in_element_count/functions.rs:61:33
+  --> tests/ui/size_of_in_element_count/functions.rs:60:36
    |
-LL |     y.as_mut_ptr().wrapping_add(size_of::<u8>());
-   |                                 ^^^^^^^^^^^^^^^
+LL |     y.as_mut_ptr().wrapping_offset(size_of::<u16>() as isize);
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
 
-error: found a count of bytes instead of a count of elements of `T`
-  --> tests/ui/size_of_in_element_count/functions.rs:63:32
-   |
-LL |     unsafe { y.as_ptr().offset(size_of::<u8>() as isize) };
-   |                                ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
-
-error: found a count of bytes instead of a count of elements of `T`
-  --> tests/ui/size_of_in_element_count/functions.rs:65:36
-   |
-LL |     y.as_mut_ptr().wrapping_offset(size_of::<u8>() as isize);
-   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
-
-error: aborting due to 21 previous errors
+error: aborting due to 19 previous errors
 
diff --git a/src/tools/clippy/tests/ui/suspicious_doc_comments.fixed b/src/tools/clippy/tests/ui/suspicious_doc_comments.fixed
index 614fc03571e..d3df6a41cb1 100644
--- a/src/tools/clippy/tests/ui/suspicious_doc_comments.fixed
+++ b/src/tools/clippy/tests/ui/suspicious_doc_comments.fixed
@@ -1,5 +1,6 @@
 #![allow(unused)]
 #![warn(clippy::suspicious_doc_comments)]
+#![allow(clippy::empty_line_after_doc_comments)]
 
 //! Real module documentation.
 //! Fake module documentation.
diff --git a/src/tools/clippy/tests/ui/suspicious_doc_comments.rs b/src/tools/clippy/tests/ui/suspicious_doc_comments.rs
index 7dcba0fefc9..04db2b199c0 100644
--- a/src/tools/clippy/tests/ui/suspicious_doc_comments.rs
+++ b/src/tools/clippy/tests/ui/suspicious_doc_comments.rs
@@ -1,5 +1,6 @@
 #![allow(unused)]
 #![warn(clippy::suspicious_doc_comments)]
+#![allow(clippy::empty_line_after_doc_comments)]
 
 //! Real module documentation.
 ///! Fake module documentation.
diff --git a/src/tools/clippy/tests/ui/suspicious_doc_comments.stderr b/src/tools/clippy/tests/ui/suspicious_doc_comments.stderr
index f12053b1595..c34e39cd0fc 100644
--- a/src/tools/clippy/tests/ui/suspicious_doc_comments.stderr
+++ b/src/tools/clippy/tests/ui/suspicious_doc_comments.stderr
@@ -1,5 +1,5 @@
 error: this is an outer doc comment and does not apply to the parent module or crate
-  --> tests/ui/suspicious_doc_comments.rs:5:1
+  --> tests/ui/suspicious_doc_comments.rs:6:1
    |
 LL | ///! Fake module documentation.
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -12,7 +12,7 @@ LL | //! Fake module documentation.
    |
 
 error: this is an outer doc comment and does not apply to the parent module or crate
-  --> tests/ui/suspicious_doc_comments.rs:9:5
+  --> tests/ui/suspicious_doc_comments.rs:10:5
    |
 LL |     ///! This module contains useful functions.
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -23,7 +23,7 @@ LL |     //! This module contains useful functions.
    |
 
 error: this is an outer doc comment and does not apply to the parent module or crate
-  --> tests/ui/suspicious_doc_comments.rs:21:5
+  --> tests/ui/suspicious_doc_comments.rs:22:5
    |
 LL | /     /**! This module contains useful functions.
 LL | |      */
@@ -36,7 +36,7 @@ LL +      */
    |
 
 error: this is an outer doc comment and does not apply to the parent module or crate
-  --> tests/ui/suspicious_doc_comments.rs:35:5
+  --> tests/ui/suspicious_doc_comments.rs:36:5
    |
 LL | /     ///! This module
 LL | |     ///! contains
@@ -51,7 +51,7 @@ LL ~     //! useful functions.
    |
 
 error: this is an outer doc comment and does not apply to the parent module or crate
-  --> tests/ui/suspicious_doc_comments.rs:43:5
+  --> tests/ui/suspicious_doc_comments.rs:44:5
    |
 LL | /     ///! a
 LL | |     ///! b
@@ -64,7 +64,7 @@ LL ~     //! b
    |
 
 error: this is an outer doc comment and does not apply to the parent module or crate
-  --> tests/ui/suspicious_doc_comments.rs:51:5
+  --> tests/ui/suspicious_doc_comments.rs:52:5
    |
 LL |     ///! a
    |     ^^^^^^
@@ -75,7 +75,7 @@ LL |     //! a
    |
 
 error: this is an outer doc comment and does not apply to the parent module or crate
-  --> tests/ui/suspicious_doc_comments.rs:57:5
+  --> tests/ui/suspicious_doc_comments.rs:58:5
    |
 LL | /     ///! a
 LL | |
@@ -90,7 +90,7 @@ LL ~     //! b
    |
 
 error: this is an outer doc comment and does not apply to the parent module or crate
-  --> tests/ui/suspicious_doc_comments.rs:69:5
+  --> tests/ui/suspicious_doc_comments.rs:70:5
    |
 LL |     ///! Very cool macro
    |     ^^^^^^^^^^^^^^^^^^^^
@@ -101,7 +101,7 @@ LL |     //! Very cool macro
    |
 
 error: this is an outer doc comment and does not apply to the parent module or crate
-  --> tests/ui/suspicious_doc_comments.rs:76:5
+  --> tests/ui/suspicious_doc_comments.rs:77:5
    |
 LL |     ///! Huh.
    |     ^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr b/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr
index fb8fb1a0090..26166e2fc8d 100644
--- a/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr
+++ b/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr
@@ -1,4 +1,4 @@
-error: `ref` directly on a function argument is ignored. Consider using a reference type instead
+error: `ref` directly on a function parameter does not prevent taking ownership of the passed argument. Consider using a reference type instead
   --> tests/ui/toplevel_ref_arg_non_rustfix.rs:9:15
    |
 LL | fn the_answer(ref mut x: u8) {
@@ -7,7 +7,7 @@ LL | fn the_answer(ref mut x: u8) {
    = note: `-D clippy::toplevel-ref-arg` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::toplevel_ref_arg)]`
 
-error: `ref` directly on a function argument is ignored. Consider using a reference type instead
+error: `ref` directly on a function parameter does not prevent taking ownership of the passed argument. Consider using a reference type instead
   --> tests/ui/toplevel_ref_arg_non_rustfix.rs:20:24
    |
 LL |         fn fun_example(ref _x: usize) {}
diff --git a/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.fixed b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.fixed
index 7a3b79553de..343c88b9815 100644
--- a/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.fixed
@@ -55,3 +55,9 @@ fn no_borrow_issue(a: u32, b: u32) {
         None => {},
     }
 }
+
+fn issue14100() -> bool {
+    // Removing the `;` would make the block type be `()` instead of `!`, and this could no longer be
+    // cast into the `bool` function return type.
+    if return true {};
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.fixed b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.fixed
index d186d5e7ebc..1cba5760eb0 100644
--- a/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.fixed
@@ -55,3 +55,9 @@ fn no_borrow_issue(a: u32, b: u32) {
         None => {},
     }
 }
+
+fn issue14100() -> bool {
+    // Removing the `;` would make the block type be `()` instead of `!`, and this could no longer be
+    // cast into the `bool` function return type.
+    if return true {};
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_semicolon.rs b/src/tools/clippy/tests/ui/unnecessary_semicolon.rs
index 3028c5b27b3..6abbbd79aaf 100644
--- a/src/tools/clippy/tests/ui/unnecessary_semicolon.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_semicolon.rs
@@ -55,3 +55,9 @@ fn no_borrow_issue(a: u32, b: u32) {
         None => {},
     };
 }
+
+fn issue14100() -> bool {
+    // Removing the `;` would make the block type be `()` instead of `!`, and this could no longer be
+    // cast into the `bool` function return type.
+    if return true {};
+}
diff --git a/src/tools/clippy/tests/ui/write_literal.fixed b/src/tools/clippy/tests/ui/write_literal.fixed
index 3d216b76cbf..f1def776e1b 100644
--- a/src/tools/clippy/tests/ui/write_literal.fixed
+++ b/src/tools/clippy/tests/ui/write_literal.fixed
@@ -62,3 +62,19 @@ fn main() {
     writeln!(v, "hello {0} {1}, world {2}", 2, 3, 4);
     //~^ ERROR: literal with an empty format string
 }
+
+fn issue_13959() {
+    let mut v = Vec::new();
+    writeln!(v, "\"");
+    writeln!(
+        v,
+        "
+        foo
+        \\
+        \\\\
+        \"
+        \\\"
+        bar
+"
+    );
+}
diff --git a/src/tools/clippy/tests/ui/write_literal.rs b/src/tools/clippy/tests/ui/write_literal.rs
index 79d6daa2e3b..1b7df91b47e 100644
--- a/src/tools/clippy/tests/ui/write_literal.rs
+++ b/src/tools/clippy/tests/ui/write_literal.rs
@@ -62,3 +62,20 @@ fn main() {
     writeln!(v, "{0} {1} {2}, {3} {4}", "hello", 2, 3, "world", 4);
     //~^ ERROR: literal with an empty format string
 }
+
+fn issue_13959() {
+    let mut v = Vec::new();
+    writeln!(v, "{}", r#"""#);
+    writeln!(
+        v,
+        "{}",
+        r#"
+        foo
+        \
+        \\
+        "
+        \"
+        bar
+"#
+    );
+}
diff --git a/src/tools/clippy/tests/ui/write_literal.stderr b/src/tools/clippy/tests/ui/write_literal.stderr
index 9f4cdfd91e8..35c93d567cd 100644
--- a/src/tools/clippy/tests/ui/write_literal.stderr
+++ b/src/tools/clippy/tests/ui/write_literal.stderr
@@ -144,5 +144,41 @@ LL -     writeln!(v, "{0} {1} {2}, {3} {4}", "hello", 2, 3, "world", 4);
 LL +     writeln!(v, "hello {0} {1}, world {2}", 2, 3, 4);
    |
 
-error: aborting due to 12 previous errors
+error: literal with an empty format string
+  --> tests/ui/write_literal.rs:68:23
+   |
+LL |     writeln!(v, "{}", r#"""#);
+   |                       ^^^^^^
+   |
+help: try
+   |
+LL -     writeln!(v, "{}", r#"""#);
+LL +     writeln!(v, "\"");
+   |
+
+error: literal with an empty format string
+  --> tests/ui/write_literal.rs:72:9
+   |
+LL | /         r#"
+LL | |         foo
+LL | |         \
+LL | |         \\
+...  |
+LL | |         bar
+LL | | "#
+   | |__^
+   |
+help: try
+   |
+LL ~         "
+LL +         foo
+LL +         \\
+LL +         \\\\
+LL +         \"
+LL +         \\\"
+LL +         bar
+LL ~ "
+   |
+
+error: aborting due to 14 previous errors
 
diff --git a/src/tools/clippy/util/gh-pages/index_template.html b/src/tools/clippy/util/gh-pages/index_template.html
index deb0ef0b499..a9b64628003 100644
--- a/src/tools/clippy/util/gh-pages/index_template.html
+++ b/src/tools/clippy/util/gh-pages/index_template.html
@@ -24,14 +24,16 @@ Otherwise, have a great day =^.^=
     <link id="styleNight" rel="stylesheet" href="https://rust-lang.github.io/mdBook/tomorrow-night.css" disabled="true"> {# #}
     <link id="styleAyu" rel="stylesheet" href="https://rust-lang.github.io/mdBook/ayu-highlight.css" disabled="true"> {# #}
     <link rel="stylesheet" href="style.css"> {# #}
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/highlight.min.js" defer></script> {# #}
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/languages/rust.min.js" defer></script> {# #}
+    <script src="script.js" defer></script> {# #}
 </head> {# #}
 <body> {# #}
-    <script src="theme.js"></script> {# #}
     <div id="settings-dropdown"> {# #}
         <button class="settings-icon" tabindex="-1"></button> {# #}
         <div class="settings-menu" tabindex="-1"> {# #}
             <div class="setting-radio-name">Theme</div> {# #}
-            <select id="theme-choice" onchange="setTheme(this.value, true)"> {# #}
+            <select id="theme-choice"> {# #}
                 <option value="ayu">Ayu</option> {# #}
                 <option value="coal">Coal</option> {# #}
                 <option value="light">Light</option> {# #}
@@ -39,11 +41,12 @@ Otherwise, have a great day =^.^=
                 <option value="rust">Rust</option> {# #}
             </select> {# #}
             <label> {# #}
-                <input type="checkbox" id="disable-shortcuts" onchange="changeSetting(this)"> {#+ #}
+                <input type="checkbox" id="disable-shortcuts"> {#+ #}
                 <span>Disable keyboard shortcuts</span> {# #}
             </label> {# #}
         </div> {# #}
     </div> {# #}
+    <script src="theme.js"></script> {# #}
 
     <div class="container"> {# #}
         <div class="page-header"> {# #}
@@ -133,10 +136,10 @@ Otherwise, have a great day =^.^=
                         </div> {# #}
                     </div> {# #}
                     <div class="col-12 col-md-2 btn-group expansion-group"> {# #}
-                        <button title="Collapse All" class="btn btn-default expansion-control" type="button" onclick="toggleExpansion(false)"> {# #}
+                        <button title="Collapse All" class="btn btn-default expansion-control" type="button" id="collapse-all"> {# #}
                             <span class="glyphicon glyphicon-collapse-up"></span> {# #}
                         </button> {# #}
-                        <button title="Expand All" class="btn btn-default expansion-control" type="button" onclick="toggleExpansion(true)"> {# #}
+                        <button title="Expand All" class="btn btn-default expansion-control" type="button" id="expand-all"> {# #}
                             <span class="glyphicon glyphicon-collapse-down"></span> {# #}
                         </button> {# #}
                     </div> {# #}
@@ -145,13 +148,13 @@ Otherwise, have a great day =^.^=
             {% for lint in lints %}
                 <article class="panel panel-default" id="{{lint.id}}"> {# #}
                     <input id="label-{{lint.id}}" type="checkbox"> {# #}
-                    <label for="label-{{lint.id}}" onclick="highlightIfNeeded('{{lint.id}}')"> {# #}
+                    <label for="label-{{lint.id}}"> {# #}
                         <header class="panel-heading"> {# #}
                             <h2 class="panel-title"> {# #}
                                 <div class="panel-title-name" id="lint-{{lint.id}}"> {# #}
                                     <span>{{lint.id}}</span> {#+ #}
-                                    <a href="#{{lint.id}}" onclick="lintAnchor(event)" class="anchor label label-default">&para;</a> {#+ #}
-                                    <a href="" class="anchor label label-default" onclick="copyToClipboard(event)"> {# #}
+                                    <a href="#{{lint.id}}" class="lint-anchor anchor label label-default">&para;</a> {#+ #}
+                                    <a href="" class="copy-to-clipboard anchor label label-default"> {# #}
                                         &#128203; {# #}
                                     </a> {# #}
                                 </div> {# #}
@@ -227,9 +230,5 @@ Otherwise, have a great day =^.^=
             ></path> {# #}
         </svg> {# #}
     </a> {# #}
-
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/highlight.min.js"></script> {# #}
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/languages/rust.min.js"></script> {# #}
-    <script src="script.js"></script> {# #}
 </body> {# #}
 </html> {# #}
diff --git a/src/tools/clippy/util/gh-pages/script.js b/src/tools/clippy/util/gh-pages/script.js
index 34d76ad642e..c942a6a05a1 100644
--- a/src/tools/clippy/util/gh-pages/script.js
+++ b/src/tools/clippy/util/gh-pages/script.js
@@ -1,3 +1,5 @@
+"use strict";
+
 window.searchState = {
     timeout: null,
     inputElem: document.getElementById("search-input"),
@@ -124,13 +126,6 @@ function toggleElements(filter, value) {
     }
 }
 
-function changeSetting(elem) {
-    if (elem.id === "disable-shortcuts") {
-        disableShortcuts = elem.checked;
-        storeValue(elem.id, elem.checked);
-    }
-}
-
 function onEachLazy(lazyArray, func) {
     const arr = Array.prototype.slice.call(lazyArray);
     for (const el of arr) {
@@ -138,17 +133,9 @@ function onEachLazy(lazyArray, func) {
     }
 }
 
-function highlightIfNeeded(lintId) {
-    onEachLazy(document.querySelectorAll(`#${lintId} pre > code:not(.hljs)`), el => {
-        hljs.highlightElement(el.parentElement)
-        el.classList.add("highlighted");
-    });
-}
-
 function expandLint(lintId) {
     const elem = document.querySelector(`#${lintId} > input[type="checkbox"]`);
     elem.checked = true;
-    highlightIfNeeded(lintId);
 }
 
 function lintAnchor(event) {
@@ -194,13 +181,9 @@ function handleBlur(event, elementId) {
 }
 
 function toggleExpansion(expand) {
-    onEachLazy(
-        document.querySelectorAll("article"),
-        expand ? el => {
-            el.classList.remove("collapsed");
-            highlightIfNeeded(el);
-        } : el => el.classList.add("collapsed"),
-    );
+    for (const checkbox of document.querySelectorAll("article input[type=checkbox]")) {
+        checkbox.checked = expand;
+    }
 }
 
 // Returns the current URL without any query parameter or hash.
@@ -535,7 +518,7 @@ function parseURLFilters() {
         for (const [corres_key, corres_value] of Object.entries(URL_PARAMS_CORRESPONDENCE)) {
             if (corres_value === key) {
                 if (key !== "versions") {
-                    const settings  = new Set(value.split(","));
+                    const settings = new Set(value.split(","));
                     onEachLazy(document.querySelectorAll(`#lint-${key} ul input`), elem => {
                         elem.checked = settings.has(elem.getAttribute("data-value"));
                         updateFilter(elem, corres_key, true);
@@ -555,12 +538,60 @@ function parseURLFilters() {
     }
 }
 
-document.getElementById(`theme-choice`).value = loadValue("theme");
-let disableShortcuts = loadValue('disable-shortcuts') === "true";
-document.getElementById("disable-shortcuts").checked = disableShortcuts;
+function addListeners() {
+    disableShortcutsButton.addEventListener("change", () => {
+        disableShortcuts = disableShortcutsButton.checked;
+        storeValue("disable-shortcuts", disableShortcuts);
+    });
+
+    document.getElementById("expand-all").addEventListener("click", () => toggleExpansion(true));
+    document.getElementById("collapse-all").addEventListener("click", () => toggleExpansion(false));
+
+    // A delegated listener to avoid the upfront cost of >1000 listeners
+    document.addEventListener("click", event => {
+        if (!event.target instanceof HTMLAnchorElement) {
+            return;
+        }
+
+        if (event.target.classList.contains("lint-anchor")) {
+            lintAnchor(event);
+        } else if (event.target.classList.contains("copy-to-clipboard")) {
+            copyToClipboard(event);
+        }
+    });
+
+    document.addEventListener("keypress", handleShortcut);
+    document.addEventListener("keydown", handleShortcut);
+}
+
+// Highlight code blocks only when they approach the viewport so that clicking the "Expand All"
+// button doesn't take a long time
+function highlightLazily() {
+    if (!'IntersectionObserver' in window) {
+        return;
+    }
+    const observer = new IntersectionObserver((entries) => {
+        for (const entry of entries) {
+            if (entry.isIntersecting) {
+                observer.unobserve(entry.target);
+                for (const code of entry.target.querySelectorAll("pre code")) {
+                    hljs.highlightElement(code);
+                }
+            }
+        }
+    });
+    for (const docs of document.querySelectorAll(".lint-docs")) {
+        observer.observe(docs);
+    }
+}
+
+let disableShortcuts = loadValue("disable-shortcuts") === "true";
+
+const disableShortcutsButton = document.getElementById("disable-shortcuts");
+disableShortcutsButton.checked = disableShortcuts;
 
-document.addEventListener("keypress", handleShortcut);
-document.addEventListener("keydown", handleShortcut);
+addListeners();
+highlightLazily();
 
 generateSettings();
 generateSearch();
diff --git a/src/tools/clippy/util/gh-pages/style.css b/src/tools/clippy/util/gh-pages/style.css
index 896f2fdac76..3cc7a919c23 100644
--- a/src/tools/clippy/util/gh-pages/style.css
+++ b/src/tools/clippy/util/gh-pages/style.css
@@ -1,9 +1,5 @@
 blockquote { font-size: 1em; }
 
-[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
-    display: none !important;
-}
-
 .dropdown-menu {
     color: var(--fg);
     background: var(--theme-popup-bg);
@@ -188,8 +184,8 @@ details {
     padding: .5em .5em 0;
 }
 
-code {
-    white-space: pre !important;
+pre {
+    padding: 0;
 }
 
 summary {
diff --git a/src/tools/clippy/util/gh-pages/theme.js b/src/tools/clippy/util/gh-pages/theme.js
index 90f57d4469d..a5dfeed9e8c 100644
--- a/src/tools/clippy/util/gh-pages/theme.js
+++ b/src/tools/clippy/util/gh-pages/theme.js
@@ -1,3 +1,5 @@
+"use strict";
+
 function storeValue(settingName, value) {
     try {
         localStorage.setItem(`clippy-lint-list-${settingName}`, value);
@@ -57,4 +59,11 @@ function setTheme(theme, store) {
     } else {
         setTheme(theme, false);
     }
+
+    const themeChoice = document.getElementById("theme-choice");
+
+    themeChoice.value = loadValue("theme");
+    document.getElementById("theme-choice").addEventListener("change", (e) => {
+        setTheme(themeChoice.value, true);
+    });
 })();
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 8c96554738e..452a2e9a9d5 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -882,14 +882,6 @@ fn iter_header(
         }
         let ln = ln.trim();
 
-        // Assume that any directives will be found before the first module or function. This
-        // doesn't seem to be an optimization with a warm page cache. Maybe with a cold one.
-        // FIXME(jieyouxu): this will cause `//@` directives in the rest of the test file to
-        // not be checked.
-        if ln.starts_with("fn") || ln.starts_with("mod") {
-            return;
-        }
-
         let Some(directive_line) = line_directive(line_number, comment, ln) else {
             continue;
         };
diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs
index ebba16d41f9..023658a3dd4 100644
--- a/src/tools/compiletest/src/header/tests.rs
+++ b/src/tools/compiletest/src/header/tests.rs
@@ -251,9 +251,10 @@ fn revisions() {
     let config: Config = cfg().build();
 
     assert_eq!(parse_rs(&config, "//@ revisions: a b c").revisions, vec!["a", "b", "c"],);
-    assert_eq!(parse_makefile(&config, "# revisions: hello there").revisions, vec![
-        "hello", "there"
-    ],);
+    assert_eq!(
+        parse_makefile(&config, "# revisions: hello there").revisions,
+        vec!["hello", "there"],
+    );
 }
 
 #[test]
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index ca48abda5fc..0e2da2b02ca 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1417,9 +1417,7 @@ impl<'test> TestCx<'test> {
     }
 
     fn is_rustdoc(&self) -> bool {
-        self.config.src_base.ends_with("rustdoc-ui")
-            || self.config.src_base.ends_with("rustdoc-js")
-            || self.config.src_base.ends_with("rustdoc-json")
+        matches!(self.config.suite.as_str(), "rustdoc-ui" | "rustdoc-js" | "rustdoc-json")
     }
 
     fn get_mir_dump_dir(&self) -> PathBuf {
diff --git a/src/tools/compiletest/src/runtest/rustdoc_json.rs b/src/tools/compiletest/src/runtest/rustdoc_json.rs
index 31fdb0a5d13..bf7eb2e109a 100644
--- a/src/tools/compiletest/src/runtest/rustdoc_json.rs
+++ b/src/tools/compiletest/src/runtest/rustdoc_json.rs
@@ -16,13 +16,12 @@ impl TestCx<'_> {
             self.fatal_proc_rec("rustdoc failed!", &proc_res);
         }
 
-        let root = self.config.find_rust_src_root().unwrap();
         let mut json_out = out_dir.join(self.testpaths.file.file_stem().unwrap());
         json_out.set_extension("json");
         let res = self.run_command_to_procres(
             Command::new(self.config.jsondocck_path.as_ref().unwrap())
                 .arg("--doc-dir")
-                .arg(root.join(&out_dir))
+                .arg(&out_dir)
                 .arg("--template")
                 .arg(&self.testpaths.file),
         );
diff --git a/src/tools/coverage-dump/src/covfun.rs b/src/tools/coverage-dump/src/covfun.rs
index 33fac3edccd..82ebd33d0d1 100644
--- a/src/tools/coverage-dump/src/covfun.rs
+++ b/src/tools/coverage-dump/src/covfun.rs
@@ -95,10 +95,13 @@ pub(crate) fn dump_covfun_mappings(
         // has increased or decreased the number of physical counters needed.
         // (It's possible for the generated code to have more counters that
         // aren't used by any mappings, but that should hopefully be rare.)
-        println!("Highest counter ID seen: {}", match max_counter {
-            Some(id) => format!("c{id}"),
-            None => "(none)".to_owned(),
-        });
+        println!(
+            "Highest counter ID seen: {}",
+            match max_counter {
+                Some(id) => format!("c{id}"),
+                None => "(none)".to_owned(),
+            }
+        );
         println!();
     }
     Ok(())
diff --git a/src/tools/features-status-dump/Cargo.toml b/src/tools/features-status-dump/Cargo.toml
new file mode 100644
index 00000000000..35be71a46e5
--- /dev/null
+++ b/src/tools/features-status-dump/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "features-status-dump"
+version = "0.1.0"
+license = "MIT OR Apache-2.0"
+edition = "2021"
+
+[dependencies]
+anyhow = { version = "1", features = ["backtrace"] }
+clap = { version = "4", features = ["derive"] }
+serde = { version = "1.0.125", features = [ "derive" ] }
+serde_json = "1.0.59"
+tidy = { path = "../tidy", features = ["build-metrics"] }
diff --git a/src/tools/features-status-dump/src/main.rs b/src/tools/features-status-dump/src/main.rs
new file mode 100644
index 00000000000..1ce98d1506d
--- /dev/null
+++ b/src/tools/features-status-dump/src/main.rs
@@ -0,0 +1,53 @@
+use std::collections::HashMap;
+use std::fs::File;
+use std::io::BufWriter;
+use std::path::PathBuf;
+
+use anyhow::{Context, Result};
+use clap::Parser;
+use tidy::features::{Feature, collect_lang_features, collect_lib_features};
+
+#[derive(Debug, Parser)]
+struct Cli {
+    /// Path to `library/` directory.
+    #[arg(long)]
+    library_path: PathBuf,
+    /// Path to `compiler/` directory.
+    #[arg(long)]
+    compiler_path: PathBuf,
+    /// Path to `output/` directory.
+    #[arg(long)]
+    output_path: PathBuf,
+}
+
+#[derive(Debug, serde::Serialize)]
+struct FeaturesStatus {
+    lang_features_status: HashMap<String, Feature>,
+    lib_features_status: HashMap<String, Feature>,
+}
+
+fn main() -> Result<()> {
+    let Cli { compiler_path, library_path, output_path } = Cli::parse();
+
+    let lang_features_status = collect_lang_features(&compiler_path, &mut false);
+    let lib_features_status = collect_lib_features(&library_path)
+        .into_iter()
+        .filter(|&(ref name, _)| !lang_features_status.contains_key(name))
+        .collect();
+    let features_status = FeaturesStatus { lang_features_status, lib_features_status };
+
+    let output_dir = output_path.parent().with_context(|| {
+        format!("failed to get parent dir of output path `{}`", output_path.display())
+    })?;
+    std::fs::create_dir_all(output_dir).with_context(|| {
+        format!("failed to create output directory at `{}`", output_dir.display())
+    })?;
+
+    let output_file = File::create(&output_path).with_context(|| {
+        format!("failed to create file at given output path `{}`", output_path.display())
+    })?;
+    let writer = BufWriter::new(output_file);
+    serde_json::to_writer_pretty(writer, &features_status)
+        .context("failed to write json output")?;
+    Ok(())
+}
diff --git a/src/tools/generate-copyright/src/cargo_metadata.rs b/src/tools/generate-copyright/src/cargo_metadata.rs
index 420579372ac..51e353e9b22 100644
--- a/src/tools/generate-copyright/src/cargo_metadata.rs
+++ b/src/tools/generate-copyright/src/cargo_metadata.rs
@@ -98,12 +98,15 @@ pub fn get_metadata(
             }
             // otherwise it's an out-of-tree dependency
             let package_id = Package { name: package.name, version: package.version.to_string() };
-            output.insert(package_id, PackageMetadata {
-                license: package.license.unwrap_or_else(|| String::from("Unspecified")),
-                authors: package.authors,
-                notices: BTreeMap::new(),
-                is_in_libstd: None,
-            });
+            output.insert(
+                package_id,
+                PackageMetadata {
+                    license: package.license.unwrap_or_else(|| String::from("Unspecified")),
+                    authors: package.authors,
+                    notices: BTreeMap::new(),
+                    is_in_libstd: None,
+                },
+            );
         }
     }
 
diff --git a/src/tools/generate-copyright/src/main.rs b/src/tools/generate-copyright/src/main.rs
index 0a446ecff5b..7a014989e68 100644
--- a/src/tools/generate-copyright/src/main.rs
+++ b/src/tools/generate-copyright/src/main.rs
@@ -24,12 +24,16 @@ fn main() -> Result<(), Error> {
     let root_path = std::path::absolute(".")?;
 
     // Scan Cargo dependencies
-    let mut collected_cargo_metadata =
-        cargo_metadata::get_metadata_and_notices(&cargo, &out_dir.join("vendor"), &root_path, &[
+    let mut collected_cargo_metadata = cargo_metadata::get_metadata_and_notices(
+        &cargo,
+        &out_dir.join("vendor"),
+        &root_path,
+        &[
             Path::new("./Cargo.toml"),
             Path::new("./src/tools/cargo/Cargo.toml"),
             Path::new("./library/Cargo.toml"),
-        ])?;
+        ],
+    )?;
 
     let library_collected_cargo_metadata = cargo_metadata::get_metadata_and_notices(
         &cargo,
diff --git a/src/tools/jsondoclint/src/validator/tests.rs b/src/tools/jsondoclint/src/validator/tests.rs
index a37e6c2eb5c..28deb7e7cee 100644
--- a/src/tools/jsondoclint/src/validator/tests.rs
+++ b/src/tools/jsondoclint/src/validator/tests.rs
@@ -21,32 +21,42 @@ fn errors_on_missing_links() {
         root: Id(0),
         crate_version: None,
         includes_private: false,
-        index: FxHashMap::from_iter([(Id(0), Item {
-            name: Some("root".to_owned()),
-            id: Id(0),
-            crate_id: 0,
-            span: None,
-            visibility: Visibility::Public,
-            docs: None,
-            links: FxHashMap::from_iter([("Not Found".to_owned(), Id(1))]),
-            attrs: vec![],
-            deprecation: None,
-            inner: ItemEnum::Module(Module { is_crate: true, items: vec![], is_stripped: false }),
-        })]),
+        index: FxHashMap::from_iter([(
+            Id(0),
+            Item {
+                name: Some("root".to_owned()),
+                id: Id(0),
+                crate_id: 0,
+                span: None,
+                visibility: Visibility::Public,
+                docs: None,
+                links: FxHashMap::from_iter([("Not Found".to_owned(), Id(1))]),
+                attrs: vec![],
+                deprecation: None,
+                inner: ItemEnum::Module(Module {
+                    is_crate: true,
+                    items: vec![],
+                    is_stripped: false,
+                }),
+            },
+        )]),
         paths: FxHashMap::default(),
         external_crates: FxHashMap::default(),
         format_version: rustdoc_json_types::FORMAT_VERSION,
     };
 
-    check(&k, &[Error {
-        kind: ErrorKind::NotFound(vec![vec![
-            SelectorPart::Field("index".to_owned()),
-            SelectorPart::Field("0".to_owned()),
-            SelectorPart::Field("links".to_owned()),
-            SelectorPart::Field("Not Found".to_owned()),
-        ]]),
-        id: Id(1),
-    }]);
+    check(
+        &k,
+        &[Error {
+            kind: ErrorKind::NotFound(vec![vec![
+                SelectorPart::Field("index".to_owned()),
+                SelectorPart::Field("0".to_owned()),
+                SelectorPart::Field("links".to_owned()),
+                SelectorPart::Field("Not Found".to_owned()),
+            ]]),
+            id: Id(1),
+        }],
+    );
 }
 
 // Test we would catch
@@ -58,48 +68,60 @@ fn errors_on_local_in_paths_and_not_index() {
         crate_version: None,
         includes_private: false,
         index: FxHashMap::from_iter([
-            (Id(0), Item {
-                id: Id(0),
-                crate_id: 0,
-                name: Some("microcore".to_owned()),
-                span: None,
-                visibility: Visibility::Public,
-                docs: None,
-                links: FxHashMap::from_iter([(("prim@i32".to_owned(), Id(2)))]),
-                attrs: Vec::new(),
-                deprecation: None,
-                inner: ItemEnum::Module(Module {
-                    is_crate: true,
-                    items: vec![Id(1)],
-                    is_stripped: false,
-                }),
-            }),
-            (Id(1), Item {
-                id: Id(1),
-                crate_id: 0,
-                name: Some("i32".to_owned()),
-                span: None,
-                visibility: Visibility::Public,
-                docs: None,
-                links: FxHashMap::default(),
-                attrs: Vec::new(),
-                deprecation: None,
-                inner: ItemEnum::Primitive(Primitive { name: "i32".to_owned(), impls: vec![] }),
-            }),
+            (
+                Id(0),
+                Item {
+                    id: Id(0),
+                    crate_id: 0,
+                    name: Some("microcore".to_owned()),
+                    span: None,
+                    visibility: Visibility::Public,
+                    docs: None,
+                    links: FxHashMap::from_iter([(("prim@i32".to_owned(), Id(2)))]),
+                    attrs: Vec::new(),
+                    deprecation: None,
+                    inner: ItemEnum::Module(Module {
+                        is_crate: true,
+                        items: vec![Id(1)],
+                        is_stripped: false,
+                    }),
+                },
+            ),
+            (
+                Id(1),
+                Item {
+                    id: Id(1),
+                    crate_id: 0,
+                    name: Some("i32".to_owned()),
+                    span: None,
+                    visibility: Visibility::Public,
+                    docs: None,
+                    links: FxHashMap::default(),
+                    attrs: Vec::new(),
+                    deprecation: None,
+                    inner: ItemEnum::Primitive(Primitive { name: "i32".to_owned(), impls: vec![] }),
+                },
+            ),
         ]),
-        paths: FxHashMap::from_iter([(Id(2), ItemSummary {
-            crate_id: 0,
-            path: vec!["microcore".to_owned(), "i32".to_owned()],
-            kind: ItemKind::Primitive,
-        })]),
+        paths: FxHashMap::from_iter([(
+            Id(2),
+            ItemSummary {
+                crate_id: 0,
+                path: vec!["microcore".to_owned(), "i32".to_owned()],
+                kind: ItemKind::Primitive,
+            },
+        )]),
         external_crates: FxHashMap::default(),
         format_version: rustdoc_json_types::FORMAT_VERSION,
     };
 
-    check(&krate, &[Error {
-        id: Id(2),
-        kind: ErrorKind::Custom("Id for local item in `paths` but not in `index`".to_owned()),
-    }]);
+    check(
+        &krate,
+        &[Error {
+            id: Id(2),
+            kind: ErrorKind::Custom("Id for local item in `paths` but not in `index`".to_owned()),
+        }],
+    );
 }
 
 #[test]
@@ -117,84 +139,96 @@ fn errors_on_missing_path() {
         crate_version: None,
         includes_private: false,
         index: FxHashMap::from_iter([
-            (Id(0), Item {
-                id: Id(0),
-                crate_id: 0,
-                name: Some("foo".to_owned()),
-                span: None,
-                visibility: Visibility::Public,
-                docs: None,
-                links: FxHashMap::default(),
-                attrs: Vec::new(),
-                deprecation: None,
-                inner: ItemEnum::Module(Module {
-                    is_crate: true,
-                    items: vec![Id(1), Id(2)],
-                    is_stripped: false,
-                }),
-            }),
-            (Id(1), Item {
-                id: Id(0),
-                crate_id: 0,
-                name: Some("Bar".to_owned()),
-                span: None,
-                visibility: Visibility::Public,
-                docs: None,
-                links: FxHashMap::default(),
-                attrs: Vec::new(),
-                deprecation: None,
-                inner: ItemEnum::Struct(Struct {
-                    kind: StructKind::Unit,
-                    generics: generics.clone(),
-                    impls: vec![],
-                }),
-            }),
-            (Id(2), Item {
-                id: Id(0),
-                crate_id: 0,
-                name: Some("mk_bar".to_owned()),
-                span: None,
-                visibility: Visibility::Public,
-                docs: None,
-                links: FxHashMap::default(),
-                attrs: Vec::new(),
-                deprecation: None,
-                inner: ItemEnum::Function(Function {
-                    sig: FunctionSignature {
-                        inputs: vec![],
-                        output: Some(Type::ResolvedPath(Path {
-                            path: "Bar".to_owned(),
-                            id: Id(1),
-                            args: None,
-                        })),
-                        is_c_variadic: false,
-                    },
-                    generics,
-                    header: FunctionHeader {
-                        is_const: false,
-                        is_unsafe: false,
-                        is_async: false,
-                        abi: Abi::Rust,
-                    },
-                    has_body: true,
-                }),
-            }),
+            (
+                Id(0),
+                Item {
+                    id: Id(0),
+                    crate_id: 0,
+                    name: Some("foo".to_owned()),
+                    span: None,
+                    visibility: Visibility::Public,
+                    docs: None,
+                    links: FxHashMap::default(),
+                    attrs: Vec::new(),
+                    deprecation: None,
+                    inner: ItemEnum::Module(Module {
+                        is_crate: true,
+                        items: vec![Id(1), Id(2)],
+                        is_stripped: false,
+                    }),
+                },
+            ),
+            (
+                Id(1),
+                Item {
+                    id: Id(0),
+                    crate_id: 0,
+                    name: Some("Bar".to_owned()),
+                    span: None,
+                    visibility: Visibility::Public,
+                    docs: None,
+                    links: FxHashMap::default(),
+                    attrs: Vec::new(),
+                    deprecation: None,
+                    inner: ItemEnum::Struct(Struct {
+                        kind: StructKind::Unit,
+                        generics: generics.clone(),
+                        impls: vec![],
+                    }),
+                },
+            ),
+            (
+                Id(2),
+                Item {
+                    id: Id(0),
+                    crate_id: 0,
+                    name: Some("mk_bar".to_owned()),
+                    span: None,
+                    visibility: Visibility::Public,
+                    docs: None,
+                    links: FxHashMap::default(),
+                    attrs: Vec::new(),
+                    deprecation: None,
+                    inner: ItemEnum::Function(Function {
+                        sig: FunctionSignature {
+                            inputs: vec![],
+                            output: Some(Type::ResolvedPath(Path {
+                                path: "Bar".to_owned(),
+                                id: Id(1),
+                                args: None,
+                            })),
+                            is_c_variadic: false,
+                        },
+                        generics,
+                        header: FunctionHeader {
+                            is_const: false,
+                            is_unsafe: false,
+                            is_async: false,
+                            abi: Abi::Rust,
+                        },
+                        has_body: true,
+                    }),
+                },
+            ),
         ]),
-        paths: FxHashMap::from_iter([(Id(0), ItemSummary {
-            crate_id: 0,
-            path: vec!["foo".to_owned()],
-            kind: ItemKind::Module,
-        })]),
+        paths: FxHashMap::from_iter([(
+            Id(0),
+            ItemSummary { crate_id: 0, path: vec!["foo".to_owned()], kind: ItemKind::Module },
+        )]),
         external_crates: FxHashMap::default(),
         format_version: rustdoc_json_types::FORMAT_VERSION,
     };
 
-    check(&krate, &[Error {
-        kind: ErrorKind::Custom(
-            r#"No entry in '$.paths' for Path { path: "Bar", id: Id(1), args: None }"#.to_owned(),
-        ),
-        id: Id(1),
-    }]);
+    check(
+        &krate,
+        &[Error {
+            kind: ErrorKind::Custom(
+                r#"No entry in '$.paths' for Path { path: "Bar", id: Id(1), args: None }"#
+                    .to_owned(),
+            ),
+            id: Id(1),
+        }],
+    );
 }
 
 #[test]
@@ -204,18 +238,25 @@ fn checks_local_crate_id_is_correct() {
         root: Id(0),
         crate_version: None,
         includes_private: false,
-        index: FxHashMap::from_iter([(Id(0), Item {
-            id: Id(0),
-            crate_id: LOCAL_CRATE_ID.wrapping_add(1),
-            name: Some("irrelavent".to_owned()),
-            span: None,
-            visibility: Visibility::Public,
-            docs: None,
-            links: FxHashMap::default(),
-            attrs: Vec::new(),
-            deprecation: None,
-            inner: ItemEnum::Module(Module { is_crate: true, items: vec![], is_stripped: false }),
-        })]),
+        index: FxHashMap::from_iter([(
+            Id(0),
+            Item {
+                id: Id(0),
+                crate_id: LOCAL_CRATE_ID.wrapping_add(1),
+                name: Some("irrelavent".to_owned()),
+                span: None,
+                visibility: Visibility::Public,
+                docs: None,
+                links: FxHashMap::default(),
+                attrs: Vec::new(),
+                deprecation: None,
+                inner: ItemEnum::Module(Module {
+                    is_crate: true,
+                    items: vec![],
+                    is_stripped: false,
+                }),
+            },
+        )]),
         paths: FxHashMap::default(),
         external_crates: FxHashMap::default(),
         format_version: FORMAT_VERSION,
diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs
index f6e84465780..9fd33e23204 100644
--- a/src/tools/lint-docs/src/lib.rs
+++ b/src/tools/lint-docs/src/lib.rs
@@ -19,24 +19,30 @@ mod groups;
 /// level of the lint, which will be more difficult to support, since rustc
 /// currently does not track that historical information.
 static RENAMES: &[(Level, &[(&str, &str)])] = &[
-    (Level::Allow, &[
-        ("single-use-lifetime", "single-use-lifetimes"),
-        ("elided-lifetime-in-path", "elided-lifetimes-in-paths"),
-        ("async-idents", "keyword-idents"),
-        ("disjoint-capture-migration", "rust-2021-incompatible-closure-captures"),
-        ("keyword-idents", "keyword-idents-2018"),
-        ("or-patterns-back-compat", "rust-2021-incompatible-or-patterns"),
-    ]),
-    (Level::Warn, &[
-        ("bare-trait-object", "bare-trait-objects"),
-        ("unstable-name-collision", "unstable-name-collisions"),
-        ("unused-doc-comment", "unused-doc-comments"),
-        ("redundant-semicolon", "redundant-semicolons"),
-        ("overlapping-patterns", "overlapping-range-endpoints"),
-        ("non-fmt-panic", "non-fmt-panics"),
-        ("unused-tuple-struct-fields", "dead-code"),
-        ("static-mut-ref", "static-mut-refs"),
-    ]),
+    (
+        Level::Allow,
+        &[
+            ("single-use-lifetime", "single-use-lifetimes"),
+            ("elided-lifetime-in-path", "elided-lifetimes-in-paths"),
+            ("async-idents", "keyword-idents"),
+            ("disjoint-capture-migration", "rust-2021-incompatible-closure-captures"),
+            ("keyword-idents", "keyword-idents-2018"),
+            ("or-patterns-back-compat", "rust-2021-incompatible-or-patterns"),
+        ],
+    ),
+    (
+        Level::Warn,
+        &[
+            ("bare-trait-object", "bare-trait-objects"),
+            ("unstable-name-collision", "unstable-name-collisions"),
+            ("unused-doc-comment", "unused-doc-comments"),
+            ("redundant-semicolon", "redundant-semicolons"),
+            ("overlapping-patterns", "overlapping-range-endpoints"),
+            ("non-fmt-panic", "non-fmt-panics"),
+            ("unused-tuple-struct-fields", "dead-code"),
+            ("static-mut-ref", "static-mut-refs"),
+        ],
+    ),
     (Level::Deny, &[("exceeding-bitshifts", "arithmetic-overflow")]),
 ];
 
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 685f5670ab4..6b051da1b5a 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -29,7 +29,7 @@ use std::num::NonZero;
 use std::ops::Range;
 use std::path::PathBuf;
 use std::str::FromStr;
-use std::sync::Once;
+use std::sync::{Arc, Once};
 use std::sync::atomic::{AtomicI32, AtomicU32, Ordering};
 
 use miri::{
@@ -38,7 +38,6 @@ use miri::{
 };
 use rustc_abi::ExternAbi;
 use rustc_data_structures::sync;
-use rustc_data_structures::sync::Lrc;
 use rustc_driver::Compilation;
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_hir::{self as hir, Node};
@@ -134,7 +133,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
                 // HACK: rustc will emit "crate ... required to be available in rlib format, but
                 // was not found in this form" errors once we use `tcx.dependency_formats()` if
                 // there's no rlib provided, so setting a dummy path here to workaround those errors.
-                Lrc::make_mut(&mut crate_source).rlib = Some((PathBuf::new(), PathKind::All));
+                Arc::make_mut(&mut crate_source).rlib = Some((PathBuf::new(), PathKind::All));
                 crate_source
             };
         });
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 45054c37c40..a717d8ccf28 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -1,3 +1,4 @@
+#![cfg_attr(bootstrap, feature(trait_upcasting))]
 #![feature(rustc_private)]
 #![feature(cell_update)]
 #![feature(float_gamma)]
@@ -9,7 +10,6 @@
 #![feature(yeet_expr)]
 #![feature(nonzero_ops)]
 #![feature(let_chains)]
-#![feature(trait_upcasting)]
 #![feature(strict_overflow_ops)]
 #![feature(pointer_is_aligned_to)]
 #![feature(unqualified_local_imports)]
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 4735db48e81..6bd1076a8a8 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -1151,6 +1151,11 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
     }
 
     #[inline(always)]
+    fn contract_checks(ecx: &InterpCx<'tcx, Self>) -> InterpResult<'tcx, bool> {
+        interp_ok(ecx.tcx.sess.contract_checks())
+    }
+
+    #[inline(always)]
     fn thread_local_static_pointer(
         ecx: &mut MiriInterpCx<'tcx>,
         def_id: DefId,
diff --git a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs
index f450e7e652c..1fd791a91f0 100644
--- a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs
+++ b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs
@@ -1,9 +1,6 @@
 // Validation stops this too early.
 //@compile-flags: -Zmiri-disable-validation
 
-#![feature(trait_upcasting)]
-#![allow(incomplete_features)]
-
 trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
     #[allow(dead_code)]
     fn a(&self) -> i32 {
diff --git a/src/tools/miri/tests/fail/intrinsics/disjoint_bitor.rs b/src/tools/miri/tests/fail/intrinsics/disjoint_bitor.rs
new file mode 100644
index 00000000000..a7127143330
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/disjoint_bitor.rs
@@ -0,0 +1,5 @@
+#![feature(core_intrinsics)]
+fn main() {
+    // one bit in common
+    unsafe { std::intrinsics::disjoint_bitor(0b01101001_u8, 0b10001110) }; //~ ERROR: Undefined Behavior
+}
diff --git a/src/tools/miri/tests/fail/intrinsics/disjoint_bitor.stderr b/src/tools/miri/tests/fail/intrinsics/disjoint_bitor.stderr
new file mode 100644
index 00000000000..82502953118
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/disjoint_bitor.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: `assume` called with `false`
+  --> tests/fail/intrinsics/disjoint_bitor.rs:LL:CC
+   |
+LL |     unsafe { std::intrinsics::disjoint_bitor(0b01101001_u8, 0b10001110) };
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `assume` called with `false`
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at tests/fail/intrinsics/disjoint_bitor.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.rs
new file mode 100644
index 00000000000..5a997ad8ec4
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.rs
@@ -0,0 +1,5 @@
+fn main() {
+    unsafe {
+        (&1_u8 as *const u8).offset_from(&2_u8); //~ERROR: not both derived from the same allocation
+    }
+}
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.stderr
new file mode 100644
index 00000000000..34d7c6a8021
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: `ptr_offset_from` called on two different pointers that are not both derived from the same allocation
+  --> tests/fail/intrinsics/ptr_offset_from_different_allocs.rs:LL:CC
+   |
+LL |         (&1_u8 as *const u8).offset_from(&2_u8);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers that are not both derived from the same allocation
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at tests/fail/intrinsics/ptr_offset_from_different_allocs.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs
index 0acda559d3a..0d34e711ca7 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs
@@ -15,6 +15,6 @@ fn main() {
         let _ = p1.byte_offset_from(p1);
 
         // UB because different pointers.
-        let _ = p1.byte_offset_from(p2); //~ERROR: no provenance
+        let _ = p1.byte_offset_from(p2); //~ERROR: not both derived from the same allocation
     }
 }
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr
index 7ef66390fcd..897945d6d5d 100644
--- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: out-of-bounds `offset_from` origin: expected a pointer to the end of 1 byte of memory, but got 0xb[noalloc] which is a dangling pointer (it has no provenance)
+error: Undefined Behavior: `ptr_offset_from` called on two different pointers that are not both derived from the same allocation
   --> tests/fail/intrinsics/ptr_offset_from_different_ints.rs:LL:CC
    |
 LL |         let _ = p1.byte_offset_from(p2);
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from` origin: expected a pointer to the end of 1 byte of memory, but got 0xb[noalloc] which is a dangling pointer (it has no provenance)
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers that are not both derived from the same allocation
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.rs
new file mode 100644
index 00000000000..06f6b7a0117
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.rs
@@ -0,0 +1,7 @@
+fn main() {
+    let mem = [0u8; 1];
+    let ptr = mem.as_ptr();
+    unsafe {
+        ptr.wrapping_add(4).offset_from(ptr); //~ERROR: the memory range between them is not in-bounds of an allocation
+    }
+}
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.stderr
new file mode 100644
index 00000000000..67df633bef5
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: `ptr_offset_from` called on two different pointers where the memory range between them is not in-bounds of an allocation
+  --> tests/fail/intrinsics/ptr_offset_from_oob.rs:LL:CC
+   |
+LL |         ptr.wrapping_add(4).offset_from(ptr);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers where the memory range between them is not in-bounds of an allocation
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at tests/fail/intrinsics/ptr_offset_from_oob.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/pass/binops.rs b/src/tools/miri/tests/pass/binops.rs
index 0988d7ccc4c..0aff7acb29d 100644
--- a/src/tools/miri/tests/pass/binops.rs
+++ b/src/tools/miri/tests/pass/binops.rs
@@ -2,23 +2,23 @@
 
 fn test_nil() {
     assert_eq!((), ());
-    assert!((!(() != ())));
-    assert!((!(() < ())));
-    assert!((() <= ()));
-    assert!((!(() > ())));
-    assert!((() >= ()));
+    assert!(!(() != ()));
+    assert!(!(() < ()));
+    assert!(() <= ());
+    assert!(!(() > ()));
+    assert!(() >= ());
 }
 
 fn test_bool() {
-    assert!((!(true < false)));
-    assert!((!(true <= false)));
-    assert!((true > false));
-    assert!((true >= false));
+    assert!(!(true < false));
+    assert!(!(true <= false));
+    assert!(true > false);
+    assert!(true >= false);
 
-    assert!((false < true));
-    assert!((false <= true));
-    assert!((!(false > true)));
-    assert!((!(false >= true)));
+    assert!(false < true);
+    assert!(false <= true);
+    assert!(!(false > true));
+    assert!(!(false >= true));
 
     // Bools support bitwise binops
     assert_eq!(false & false, false);
@@ -65,9 +65,9 @@ fn test_class() {
 
     assert_eq!(q, r);
     r.y = 17;
-    assert!((r.y != q.y));
+    assert!(r.y != q.y);
     assert_eq!(r.y, 17);
-    assert!((q != r));
+    assert!(q != r);
 }
 
 pub fn main() {
diff --git a/src/tools/miri/tests/pass/box-custom-alloc.rs b/src/tools/miri/tests/pass/box-custom-alloc.rs
index 71ce019187c..f0614313e50 100644
--- a/src/tools/miri/tests/pass/box-custom-alloc.rs
+++ b/src/tools/miri/tests/pass/box-custom-alloc.rs
@@ -1,7 +1,6 @@
 //@revisions: stack tree
 //@[tree]compile-flags: -Zmiri-tree-borrows
-#![allow(incomplete_features)] // for trait upcasting
-#![feature(allocator_api, trait_upcasting)]
+#![feature(allocator_api)]
 
 use std::alloc::{AllocError, Allocator, Layout};
 use std::cell::Cell;
diff --git a/src/tools/miri/tests/pass/dyn-upcast.rs b/src/tools/miri/tests/pass/dyn-upcast.rs
index f100c4d6a86..6f8adc09640 100644
--- a/src/tools/miri/tests/pass/dyn-upcast.rs
+++ b/src/tools/miri/tests/pass/dyn-upcast.rs
@@ -1,6 +1,3 @@
-#![feature(trait_upcasting)]
-#![allow(incomplete_features)]
-
 use std::fmt;
 
 fn main() {
diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py
index a639dc20a60..3688513987d 100755
--- a/src/tools/publish_toolstate.py
+++ b/src/tools/publish_toolstate.py
@@ -30,13 +30,18 @@ except ImportError:
 # These should be collaborators of the rust-lang/rust repository (with at least
 # read privileges on it). CI will fail otherwise.
 MAINTAINERS = {
-    "book": {"carols10cents"},
-    "nomicon": {"frewsxcv", "Gankra", "JohnTitor"},
-    "reference": {"Havvy", "matthewjasper", "ehuss"},
-    "rust-by-example": {"marioidival"},
-    "embedded-book": {"adamgreig", "andre-richter", "jamesmunns", "therealprof"},
+    "book": {"ehuss", "chriskrycho", "carols10cents"},
+    "nomicon": {"ehuss", "JohnTitor"},
+    "reference": {"ehuss"},
+    "rust-by-example": {"ehuss", "marioidival"},
+    "embedded-book": {
+        "ehuss",
+        "adamgreig",
+        "andre-richter",
+        "jamesmunns",
+        "therealprof",
+    },
     "edition-guide": {"ehuss"},
-    "rustc-dev-guide": {"spastorino", "amanjeev", "JohnTitor"},
 }
 
 LABELS = {
@@ -46,7 +51,6 @@ LABELS = {
     "rust-by-example": ["C-bug"],
     "embedded-book": ["C-bug"],
     "edition-guide": ["C-bug"],
-    "rustc-dev-guide": ["C-bug"],
 }
 
 REPOS = {
@@ -56,7 +60,6 @@ REPOS = {
     "rust-by-example": "https://github.com/rust-lang/rust-by-example",
     "embedded-book": "https://github.com/rust-embedded/book",
     "edition-guide": "https://github.com/rust-lang/edition-guide",
-    "rustc-dev-guide": "https://github.com/rust-lang/rustc-dev-guide",
 }
 
 
diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs
index 8d99924a2d1..33dc57cbc07 100644
--- a/src/tools/run-make-support/src/external_deps/rustc.rs
+++ b/src/tools/run-make-support/src/external_deps/rustc.rs
@@ -338,6 +338,18 @@ impl Rustc {
         self
     }
 
+    /// Specify `-C debuginfo=...`.
+    pub fn debuginfo(&mut self, level: &str) -> &mut Self {
+        self.cmd.arg(format!("-Cdebuginfo={level}"));
+        self
+    }
+
+    /// Specify `-C split-debuginfo={packed,unpacked,off}`.
+    pub fn split_debuginfo(&mut self, split_kind: &str) -> &mut Self {
+        self.cmd.arg(format!("-Csplit-debuginfo={split_kind}"));
+        self
+    }
+
     /// Pass the `--verbose` flag.
     pub fn verbose(&mut self) -> &mut Self {
         self.cmd.arg("--verbose");
diff --git a/src/tools/run-make-support/src/fs.rs b/src/tools/run-make-support/src/fs.rs
index 7ebe4a9ca13..ceb4ebbaca5 100644
--- a/src/tools/run-make-support/src/fs.rs
+++ b/src/tools/run-make-support/src/fs.rs
@@ -238,9 +238,7 @@ pub fn set_permissions<P: AsRef<Path>>(path: P, perm: std::fs::Permissions) {
     ));
 }
 
-/// A function which prints all file names in the directory `dir` similarly to Unix's `ls`.
-/// Useful for debugging.
-/// Usage: `eprintln!("{:#?}", shallow_find_dir_entries(some_dir));`
+/// List directory entries immediately under the given `dir`.
 #[track_caller]
 pub fn shallow_find_dir_entries<P: AsRef<Path>>(dir: P) -> Vec<PathBuf> {
     let paths = read_dir(dir);
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index a8c9bec57fd..7e63ab3159a 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -94,8 +94,8 @@ pub use artifact_names::{
 
 /// Path-related helpers.
 pub use path_helpers::{
-    cwd, filename_contains, filename_not_in_denylist, has_extension, has_prefix, has_suffix,
-    not_contains, path, shallow_find_files, build_root, source_root,
+    build_root, cwd, filename_contains, filename_not_in_denylist, has_extension, has_prefix,
+    has_suffix, not_contains, path, shallow_find_directories, shallow_find_files, source_root,
 };
 
 /// Helpers for scoped test execution where certain properties are attempted to be maintained.
diff --git a/src/tools/run-make-support/src/path_helpers.rs b/src/tools/run-make-support/src/path_helpers.rs
index 1c59f2feea4..b766e50e523 100644
--- a/src/tools/run-make-support/src/path_helpers.rs
+++ b/src/tools/run-make-support/src/path_helpers.rs
@@ -59,6 +59,25 @@ pub fn shallow_find_files<P: AsRef<Path>, F: Fn(&PathBuf) -> bool>(
     matching_files
 }
 
+/// Browse the directory `path` non-recursively and return all directories which respect the
+/// parameters outlined by `closure`.
+#[track_caller]
+pub fn shallow_find_directories<P: AsRef<Path>, F: Fn(&PathBuf) -> bool>(
+    path: P,
+    filter: F,
+) -> Vec<PathBuf> {
+    let mut matching_files = Vec::new();
+    for entry in rfs::read_dir(path) {
+        let entry = entry.expect("failed to read directory entry.");
+        let path = entry.path();
+
+        if path.is_dir() && filter(&path) {
+            matching_files.push(path);
+        }
+    }
+    matching_files
+}
+
 /// Returns true if the filename at `path` does not contain `expected`.
 pub fn not_contains<P: AsRef<Path>>(path: P, expected: &str) -> bool {
     !path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().contains(expected))
diff --git a/src/tools/rust-installer/src/compression.rs b/src/tools/rust-installer/src/compression.rs
index 96c48657c46..df3a98ae789 100644
--- a/src/tools/rust-installer/src/compression.rs
+++ b/src/tools/rust-installer/src/compression.rs
@@ -81,14 +81,17 @@ impl CompressionFormat {
         let file = crate::util::create_new_file(path)?;
 
         Ok(match self {
-            CompressionFormat::Gz => Box::new(GzEncoder::new(file, match profile {
-                CompressionProfile::Fast => flate2::Compression::fast(),
-                CompressionProfile::Balanced => flate2::Compression::new(6),
-                CompressionProfile::Best => flate2::Compression::best(),
-                CompressionProfile::NoOp => panic!(
-                    "compression profile 'no-op' should not call `CompressionFormat::encode`."
-                ),
-            })),
+            CompressionFormat::Gz => Box::new(GzEncoder::new(
+                file,
+                match profile {
+                    CompressionProfile::Fast => flate2::Compression::fast(),
+                    CompressionProfile::Balanced => flate2::Compression::new(6),
+                    CompressionProfile::Best => flate2::Compression::best(),
+                    CompressionProfile::NoOp => panic!(
+                        "compression profile 'no-op' should not call `CompressionFormat::encode`."
+                    ),
+                },
+            )),
             CompressionFormat::Xz => {
                 let encoder = match profile {
                     CompressionProfile::NoOp => panic!(
diff --git a/src/tools/rustc-perf-wrapper/Cargo.toml b/src/tools/rustc-perf-wrapper/Cargo.toml
deleted file mode 100644
index 416bfef41d7..00000000000
--- a/src/tools/rustc-perf-wrapper/Cargo.toml
+++ /dev/null
@@ -1,7 +0,0 @@
-[package]
-name = "rustc-perf-wrapper"
-version = "0.1.0"
-edition = "2021"
-
-[dependencies]
-clap = { version = "4.5.7", features = ["derive", "env"] }
diff --git a/src/tools/rustc-perf-wrapper/README.md b/src/tools/rustc-perf-wrapper/README.md
deleted file mode 100644
index d7655459a2f..00000000000
--- a/src/tools/rustc-perf-wrapper/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# rustc-perf wrapper
-Utility tool for invoking [`rustc-perf`](https://github.com/rust-lang/rustc-perf) for benchmarking/profiling
-a stage1/2 compiler built by bootstrap using `x perf -- <command>`.
diff --git a/src/tools/rustc-perf-wrapper/src/config.rs b/src/tools/rustc-perf-wrapper/src/config.rs
deleted file mode 100644
index a88abfe4723..00000000000
--- a/src/tools/rustc-perf-wrapper/src/config.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-use std::fmt::{Display, Formatter};
-
-#[derive(Clone, Copy, Debug, clap::ValueEnum)]
-#[value(rename_all = "PascalCase")]
-pub enum Profile {
-    Check,
-    Debug,
-    Doc,
-    Opt,
-    Clippy,
-}
-
-impl Display for Profile {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
-        let name = match self {
-            Profile::Check => "Check",
-            Profile::Debug => "Debug",
-            Profile::Doc => "Doc",
-            Profile::Opt => "Opt",
-            Profile::Clippy => "Clippy",
-        };
-        f.write_str(name)
-    }
-}
-
-#[derive(Clone, Copy, Debug, clap::ValueEnum)]
-#[value(rename_all = "PascalCase")]
-pub enum Scenario {
-    Full,
-    IncrFull,
-    IncrUnchanged,
-    IncrPatched,
-}
-
-impl Display for Scenario {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
-        let name = match self {
-            Scenario::Full => "Full",
-            Scenario::IncrFull => "IncrFull",
-            Scenario::IncrUnchanged => "IncrUnchanged",
-            Scenario::IncrPatched => "IncrPatched",
-        };
-        f.write_str(name)
-    }
-}
diff --git a/src/tools/rustc-perf-wrapper/src/main.rs b/src/tools/rustc-perf-wrapper/src/main.rs
deleted file mode 100644
index e6c885e23de..00000000000
--- a/src/tools/rustc-perf-wrapper/src/main.rs
+++ /dev/null
@@ -1,178 +0,0 @@
-use std::fs::create_dir_all;
-use std::path::{Path, PathBuf};
-use std::process::Command;
-
-use clap::Parser;
-
-use crate::config::{Profile, Scenario};
-
-mod config;
-
-/// Performs profiling or benchmarking with [`rustc-perf`](https://github.com/rust-lang/rustc-perf)
-/// using a locally built compiler.
-#[derive(Debug, clap::Parser)]
-// Hide arguments from BuildContext in the default usage string.
-// Clap does not seem to have a way of disabling the usage of these arguments.
-#[clap(override_usage = "rustc-perf-wrapper [OPTIONS] <COMMAND>")]
-pub struct Args {
-    #[clap(subcommand)]
-    cmd: PerfCommand,
-
-    #[clap(flatten)]
-    ctx: BuildContext,
-}
-
-#[derive(Debug, clap::Parser)]
-enum PerfCommand {
-    /// Run `profile_local eprintln`.
-    /// This executes the compiler on the given benchmarks and stores its stderr output.
-    Eprintln {
-        #[clap(flatten)]
-        opts: SharedOpts,
-    },
-    /// Run `profile_local samply`
-    /// This executes the compiler on the given benchmarks and profiles it with `samply`.
-    /// You need to install `samply`, e.g. using `cargo install samply`.
-    Samply {
-        #[clap(flatten)]
-        opts: SharedOpts,
-    },
-    /// Run `profile_local cachegrind`.
-    /// This executes the compiler on the given benchmarks under `Cachegrind`.
-    Cachegrind {
-        #[clap(flatten)]
-        opts: SharedOpts,
-    },
-    Benchmark {
-        /// Identifier to associate benchmark results with
-        id: String,
-
-        #[clap(flatten)]
-        opts: SharedOpts,
-    },
-    Compare {
-        /// The name of the base artifact to be compared.
-        base: String,
-
-        /// The name of the modified artifact to be compared.
-        modified: String,
-    },
-}
-
-#[derive(Debug, clap::Parser)]
-struct SharedOpts {
-    /// Select the benchmarks that you want to run (separated by commas).
-    /// If unspecified, all benchmarks will be executed.
-    #[clap(long, global = true, value_delimiter = ',')]
-    include: Vec<String>,
-
-    /// Select the benchmarks matching a prefix in this comma-separated list that you don't want to run.
-    #[clap(long, global = true, value_delimiter = ',')]
-    exclude: Vec<String>,
-
-    /// Select the scenarios that should be benchmarked.
-    #[clap(
-        long,
-        global = true,
-        value_delimiter = ',',
-        default_value = "Full,IncrFull,IncrUnchanged,IncrPatched"
-    )]
-    scenarios: Vec<Scenario>,
-    /// Select the profiles that should be benchmarked.
-    #[clap(long, global = true, value_delimiter = ',', default_value = "Check,Debug,Opt")]
-    profiles: Vec<Profile>,
-}
-
-/// These arguments are mostly designed to be passed from bootstrap, not by users
-/// directly.
-#[derive(Debug, clap::Parser)]
-struct BuildContext {
-    /// Compiler binary that will be benchmarked/profiled.
-    #[clap(long, hide = true, env = "RUSTC_REAL")]
-    compiler: PathBuf,
-    /// rustc-perf collector binary that will be used for running benchmarks/profilers.
-    #[clap(long, hide = true, env = "PERF_COLLECTOR")]
-    collector: PathBuf,
-    /// Directory where to store results.
-    #[clap(long, hide = true, env = "PERF_RESULT_DIR")]
-    results_dir: PathBuf,
-}
-
-fn main() {
-    let args = Args::parse();
-    run(args);
-}
-
-fn run(args: Args) {
-    let mut cmd = Command::new(args.ctx.collector);
-    let db_path = args.ctx.results_dir.join("results.db");
-
-    match &args.cmd {
-        PerfCommand::Eprintln { opts }
-        | PerfCommand::Samply { opts }
-        | PerfCommand::Cachegrind { opts } => {
-            cmd.arg("profile_local");
-            cmd.arg(match &args.cmd {
-                PerfCommand::Eprintln { .. } => "eprintln",
-                PerfCommand::Samply { .. } => "samply",
-                PerfCommand::Cachegrind { .. } => "cachegrind",
-                _ => unreachable!(),
-            });
-
-            cmd.arg("--out-dir").arg(&args.ctx.results_dir);
-
-            apply_shared_opts(&mut cmd, opts);
-            execute_benchmark(&mut cmd, &args.ctx.compiler);
-
-            println!("You can find the results at `{}`", args.ctx.results_dir.display());
-        }
-        PerfCommand::Benchmark { id, opts } => {
-            cmd.arg("bench_local");
-            cmd.arg("--db").arg(&db_path);
-            cmd.arg("--id").arg(id);
-
-            apply_shared_opts(&mut cmd, opts);
-            create_dir_all(&args.ctx.results_dir).unwrap();
-            execute_benchmark(&mut cmd, &args.ctx.compiler);
-        }
-        PerfCommand::Compare { base, modified } => {
-            cmd.arg("bench_cmp");
-            cmd.arg("--db").arg(&db_path);
-            cmd.arg(base).arg(modified);
-
-            create_dir_all(&args.ctx.results_dir).unwrap();
-            cmd.status().expect("error while running rustc-perf bench_cmp");
-        }
-    }
-}
-
-fn apply_shared_opts(cmd: &mut Command, opts: &SharedOpts) {
-    if !opts.include.is_empty() {
-        cmd.arg("--include").arg(opts.include.join(","));
-    }
-    if !opts.exclude.is_empty() {
-        cmd.arg("--exclude").arg(opts.exclude.join(","));
-    }
-    if !opts.profiles.is_empty() {
-        cmd.arg("--profiles")
-            .arg(opts.profiles.iter().map(|p| p.to_string()).collect::<Vec<_>>().join(","));
-    }
-    if !opts.scenarios.is_empty() {
-        cmd.arg("--scenarios")
-            .arg(opts.scenarios.iter().map(|p| p.to_string()).collect::<Vec<_>>().join(","));
-    }
-}
-
-fn execute_benchmark(cmd: &mut Command, compiler: &Path) {
-    cmd.arg(compiler);
-    println!("Running `rustc-perf` using `{}`", compiler.display());
-
-    const MANIFEST_DIR: &str = env!("CARGO_MANIFEST_DIR");
-
-    let rustc_perf_dir = Path::new(MANIFEST_DIR).join("../rustc-perf");
-
-    // We need to set the working directory to `src/tools/perf`, so that it can find the directory
-    // with compile-time benchmarks.
-    let cmd = cmd.current_dir(rustc_perf_dir);
-    cmd.status().expect("error while running rustc-perf collector");
-}
diff --git a/src/tools/rustdoc-gui/tester.js b/src/tools/rustdoc-gui/tester.js
index c5874b4ee02..ff87b76aa45 100644
--- a/src/tools/rustdoc-gui/tester.js
+++ b/src/tools/rustdoc-gui/tester.js
@@ -197,7 +197,6 @@ async function main(argv) {
         const args = [
             "--variable", "DOC_PATH", opts["doc_folder"].split("\\").join("/"),
             "--enable-fail-on-js-error", "--allow-file-access-from-files",
-            "--no-sandbox",
         ];
         if (opts["debug"]) {
             debug = true;
diff --git a/src/tools/rustfmt/src/config/file_lines.rs b/src/tools/rustfmt/src/config/file_lines.rs
index c53ec6371e9..2f2a6c8d552 100644
--- a/src/tools/rustfmt/src/config/file_lines.rs
+++ b/src/tools/rustfmt/src/config/file_lines.rs
@@ -3,9 +3,9 @@
 use itertools::Itertools;
 use std::collections::HashMap;
 use std::path::PathBuf;
+use std::sync::Arc;
 use std::{cmp, fmt, iter, str};
 
-use rustc_data_structures::sync::Lrc;
 use rustc_span::SourceFile;
 use serde::{Deserialize, Deserializer, Serialize, Serializer, ser};
 use serde_json as json;
@@ -13,7 +13,7 @@ use thiserror::Error;
 
 /// A range of lines in a file, inclusive of both ends.
 pub struct LineRange {
-    pub(crate) file: Lrc<SourceFile>,
+    pub(crate) file: Arc<SourceFile>,
     pub(crate) lo: usize,
     pub(crate) hi: usize,
 }
diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs
index 34077c5f866..afd847f9515 100644
--- a/src/tools/rustfmt/src/parse/session.rs
+++ b/src/tools/rustfmt/src/parse/session.rs
@@ -1,7 +1,8 @@
 use std::path::Path;
+use std::sync::Arc;
 use std::sync::atomic::{AtomicBool, Ordering};
 
-use rustc_data_structures::sync::{IntoDynSyncSend, Lrc};
+use rustc_data_structures::sync::IntoDynSyncSend;
 use rustc_errors::emitter::{DynEmitter, Emitter, HumanEmitter, SilentEmitter, stderr_destination};
 use rustc_errors::registry::Registry;
 use rustc_errors::translation::Translate;
@@ -25,17 +26,17 @@ use crate::{Config, ErrorKind, FileName};
 /// ParseSess holds structs necessary for constructing a parser.
 pub(crate) struct ParseSess {
     raw_psess: RawParseSess,
-    ignore_path_set: Lrc<IgnorePathSet>,
-    can_reset_errors: Lrc<AtomicBool>,
+    ignore_path_set: Arc<IgnorePathSet>,
+    can_reset_errors: Arc<AtomicBool>,
 }
 
 /// Emit errors against every files expect ones specified in the `ignore_path_set`.
 struct SilentOnIgnoredFilesEmitter {
-    ignore_path_set: IntoDynSyncSend<Lrc<IgnorePathSet>>,
-    source_map: Lrc<SourceMap>,
+    ignore_path_set: IntoDynSyncSend<Arc<IgnorePathSet>>,
+    source_map: Arc<SourceMap>,
     emitter: Box<DynEmitter>,
     has_non_ignorable_parser_errors: bool,
-    can_reset: Lrc<AtomicBool>,
+    can_reset: Arc<AtomicBool>,
 }
 
 impl SilentOnIgnoredFilesEmitter {
@@ -96,9 +97,9 @@ impl From<Color> for ColorConfig {
 }
 
 fn default_dcx(
-    source_map: Lrc<SourceMap>,
-    ignore_path_set: Lrc<IgnorePathSet>,
-    can_reset: Lrc<AtomicBool>,
+    source_map: Arc<SourceMap>,
+    ignore_path_set: Arc<IgnorePathSet>,
+    can_reset: Arc<AtomicBool>,
     show_parse_errors: bool,
     color: Color,
 ) -> DiagCtxt {
@@ -139,16 +140,16 @@ fn default_dcx(
 impl ParseSess {
     pub(crate) fn new(config: &Config) -> Result<ParseSess, ErrorKind> {
         let ignore_path_set = match IgnorePathSet::from_ignore_list(&config.ignore()) {
-            Ok(ignore_path_set) => Lrc::new(ignore_path_set),
+            Ok(ignore_path_set) => Arc::new(ignore_path_set),
             Err(e) => return Err(ErrorKind::InvalidGlobPattern(e)),
         };
-        let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
-        let can_reset_errors = Lrc::new(AtomicBool::new(false));
+        let source_map = Arc::new(SourceMap::new(FilePathMapping::empty()));
+        let can_reset_errors = Arc::new(AtomicBool::new(false));
 
         let dcx = default_dcx(
-            Lrc::clone(&source_map),
-            Lrc::clone(&ignore_path_set),
-            Lrc::clone(&can_reset_errors),
+            Arc::clone(&source_map),
+            Arc::clone(&ignore_path_set),
+            Arc::clone(&can_reset_errors),
             config.show_parse_errors(),
             config.color(),
         );
@@ -211,7 +212,7 @@ impl ParseSess {
         self.raw_psess.source_map().span_to_filename(span).into()
     }
 
-    pub(crate) fn span_to_file_contents(&self, span: Span) -> Lrc<rustc_span::SourceFile> {
+    pub(crate) fn span_to_file_contents(&self, span: Span) -> Arc<rustc_span::SourceFile> {
         self.raw_psess
             .source_map()
             .lookup_source_file(span.data().lo)
@@ -255,11 +256,11 @@ impl ParseSess {
         SnippetProvider::new(
             source_file.start_pos,
             source_file.end_position(),
-            Lrc::clone(source_file.src.as_ref().unwrap()),
+            Arc::clone(source_file.src.as_ref().unwrap()),
         )
     }
 
-    pub(crate) fn get_original_snippet(&self, file_name: &FileName) -> Option<Lrc<String>> {
+    pub(crate) fn get_original_snippet(&self, file_name: &FileName) -> Option<Arc<String>> {
         self.raw_psess
             .source_map()
             .get_source_file(&file_name.into())
@@ -331,7 +332,7 @@ mod tests {
         use std::sync::atomic::AtomicU32;
 
         struct TestEmitter {
-            num_emitted_errors: Lrc<AtomicU32>,
+            num_emitted_errors: Arc<AtomicU32>,
         }
 
         impl Translate for TestEmitter {
@@ -365,15 +366,15 @@ mod tests {
         }
 
         fn build_emitter(
-            num_emitted_errors: Lrc<AtomicU32>,
-            can_reset: Lrc<AtomicBool>,
-            source_map: Option<Lrc<SourceMap>>,
+            num_emitted_errors: Arc<AtomicU32>,
+            can_reset: Arc<AtomicBool>,
+            source_map: Option<Arc<SourceMap>>,
             ignore_list: Option<IgnoreList>,
         ) -> SilentOnIgnoredFilesEmitter {
             let emitter_writer = TestEmitter { num_emitted_errors };
             let source_map =
-                source_map.unwrap_or_else(|| Lrc::new(SourceMap::new(FilePathMapping::empty())));
-            let ignore_path_set = Lrc::new(
+                source_map.unwrap_or_else(|| Arc::new(SourceMap::new(FilePathMapping::empty())));
+            let ignore_path_set = Arc::new(
                 IgnorePathSet::from_ignore_list(&ignore_list.unwrap_or_default()).unwrap(),
             );
             SilentOnIgnoredFilesEmitter {
@@ -393,10 +394,10 @@ mod tests {
 
         #[test]
         fn handles_fatal_parse_error_in_ignored_file() {
-            let num_emitted_errors = Lrc::new(AtomicU32::new(0));
-            let can_reset_errors = Lrc::new(AtomicBool::new(false));
+            let num_emitted_errors = Arc::new(AtomicU32::new(0));
+            let can_reset_errors = Arc::new(AtomicBool::new(false));
             let ignore_list = get_ignore_list(r#"ignore = ["foo.rs"]"#);
-            let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
+            let source_map = Arc::new(SourceMap::new(FilePathMapping::empty()));
             let source =
                 String::from(r#"extern "system" fn jni_symbol!( funcName ) ( ... ) -> {} "#);
             source_map.new_source_file(
@@ -405,9 +406,9 @@ mod tests {
             );
             let registry = Registry::new(&[]);
             let mut emitter = build_emitter(
-                Lrc::clone(&num_emitted_errors),
-                Lrc::clone(&can_reset_errors),
-                Some(Lrc::clone(&source_map)),
+                Arc::clone(&num_emitted_errors),
+                Arc::clone(&can_reset_errors),
+                Some(Arc::clone(&source_map)),
                 Some(ignore_list),
             );
             let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1)));
@@ -420,10 +421,10 @@ mod tests {
         #[nightly_only_test]
         #[test]
         fn handles_recoverable_parse_error_in_ignored_file() {
-            let num_emitted_errors = Lrc::new(AtomicU32::new(0));
-            let can_reset_errors = Lrc::new(AtomicBool::new(false));
+            let num_emitted_errors = Arc::new(AtomicU32::new(0));
+            let can_reset_errors = Arc::new(AtomicBool::new(false));
             let ignore_list = get_ignore_list(r#"ignore = ["foo.rs"]"#);
-            let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
+            let source_map = Arc::new(SourceMap::new(FilePathMapping::empty()));
             let source = String::from(r#"pub fn bar() { 1x; }"#);
             source_map.new_source_file(
                 SourceMapFileName::Real(RealFileName::LocalPath(PathBuf::from("foo.rs"))),
@@ -431,9 +432,9 @@ mod tests {
             );
             let registry = Registry::new(&[]);
             let mut emitter = build_emitter(
-                Lrc::clone(&num_emitted_errors),
-                Lrc::clone(&can_reset_errors),
-                Some(Lrc::clone(&source_map)),
+                Arc::clone(&num_emitted_errors),
+                Arc::clone(&can_reset_errors),
+                Some(Arc::clone(&source_map)),
                 Some(ignore_list),
             );
             let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1)));
@@ -446,9 +447,9 @@ mod tests {
         #[nightly_only_test]
         #[test]
         fn handles_recoverable_parse_error_in_non_ignored_file() {
-            let num_emitted_errors = Lrc::new(AtomicU32::new(0));
-            let can_reset_errors = Lrc::new(AtomicBool::new(false));
-            let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
+            let num_emitted_errors = Arc::new(AtomicU32::new(0));
+            let can_reset_errors = Arc::new(AtomicBool::new(false));
+            let source_map = Arc::new(SourceMap::new(FilePathMapping::empty()));
             let source = String::from(r#"pub fn bar() { 1x; }"#);
             source_map.new_source_file(
                 SourceMapFileName::Real(RealFileName::LocalPath(PathBuf::from("foo.rs"))),
@@ -456,9 +457,9 @@ mod tests {
             );
             let registry = Registry::new(&[]);
             let mut emitter = build_emitter(
-                Lrc::clone(&num_emitted_errors),
-                Lrc::clone(&can_reset_errors),
-                Some(Lrc::clone(&source_map)),
+                Arc::clone(&num_emitted_errors),
+                Arc::clone(&can_reset_errors),
+                Some(Arc::clone(&source_map)),
                 None,
             );
             let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1)));
@@ -471,9 +472,9 @@ mod tests {
         #[nightly_only_test]
         #[test]
         fn handles_mix_of_recoverable_parse_error() {
-            let num_emitted_errors = Lrc::new(AtomicU32::new(0));
-            let can_reset_errors = Lrc::new(AtomicBool::new(false));
-            let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
+            let num_emitted_errors = Arc::new(AtomicU32::new(0));
+            let can_reset_errors = Arc::new(AtomicBool::new(false));
+            let source_map = Arc::new(SourceMap::new(FilePathMapping::empty()));
             let ignore_list = get_ignore_list(r#"ignore = ["foo.rs"]"#);
             let bar_source = String::from(r#"pub fn bar() { 1x; }"#);
             let foo_source = String::from(r#"pub fn foo() { 1x; }"#);
@@ -493,9 +494,9 @@ mod tests {
             );
             let registry = Registry::new(&[]);
             let mut emitter = build_emitter(
-                Lrc::clone(&num_emitted_errors),
-                Lrc::clone(&can_reset_errors),
-                Some(Lrc::clone(&source_map)),
+                Arc::clone(&num_emitted_errors),
+                Arc::clone(&can_reset_errors),
+                Some(Arc::clone(&source_map)),
                 Some(ignore_list),
             );
             let bar_span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1)));
diff --git a/src/tools/rustfmt/src/source_file.rs b/src/tools/rustfmt/src/source_file.rs
index 73f8ecb5529..e942058a0a8 100644
--- a/src/tools/rustfmt/src/source_file.rs
+++ b/src/tools/rustfmt/src/source_file.rs
@@ -1,6 +1,7 @@
 use std::fs;
 use std::io::{self, Write};
 use std::path::Path;
+use std::sync::Arc;
 
 use crate::NewlineStyle;
 use crate::config::FileName;
@@ -14,8 +15,6 @@ use crate::create_emitter;
 #[cfg(test)]
 use crate::formatting::FileRecord;
 
-use rustc_data_structures::sync::Lrc;
-
 // Append a newline to the end of each file.
 pub(crate) fn append_newline(s: &mut String) {
     s.push('\n');
@@ -88,11 +87,11 @@ where
     // source map instead of hitting the file system. This also supports getting
     // original text for `FileName::Stdin`.
     let original_text = if newline_style != NewlineStyle::Auto && *filename != FileName::Stdin {
-        Lrc::new(fs::read_to_string(ensure_real_path(filename))?)
+        Arc::new(fs::read_to_string(ensure_real_path(filename))?)
     } else {
         match psess.and_then(|psess| psess.get_original_snippet(filename)) {
             Some(ori) => ori,
-            None => Lrc::new(fs::read_to_string(ensure_real_path(filename))?),
+            None => Arc::new(fs::read_to_string(ensure_real_path(filename))?),
         }
     };
 
diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs
index bdcb619153d..a5cfc542a17 100644
--- a/src/tools/rustfmt/src/visitor.rs
+++ b/src/tools/rustfmt/src/visitor.rs
@@ -1,8 +1,8 @@
 use std::cell::{Cell, RefCell};
 use std::rc::Rc;
+use std::sync::Arc;
 
 use rustc_ast::{ast, token::Delimiter, visit};
-use rustc_data_structures::sync::Lrc;
 use rustc_span::{BytePos, Pos, Span, symbol};
 use tracing::debug;
 
@@ -32,7 +32,7 @@ use crate::{ErrorKind, FormatReport, FormattingError};
 /// Creates a string slice corresponding to the specified span.
 pub(crate) struct SnippetProvider {
     /// A pointer to the content of the file we are formatting.
-    big_snippet: Lrc<String>,
+    big_snippet: Arc<String>,
     /// A position of the start of `big_snippet`, used as an offset.
     start_pos: usize,
     /// An end position of the file that this snippet lives.
@@ -46,7 +46,7 @@ impl SnippetProvider {
         Some(&self.big_snippet[start_index..end_index])
     }
 
-    pub(crate) fn new(start_pos: BytePos, end_pos: BytePos, big_snippet: Lrc<String>) -> Self {
+    pub(crate) fn new(start_pos: BytePos, end_pos: BytePos, big_snippet: Arc<String>) -> Self {
         let start_pos = start_pos.to_usize();
         let end_pos = end_pos.to_usize();
         SnippetProvider {
diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml
index 2f424a482b5..9a4d0891b4a 100644
--- a/src/tools/tidy/Cargo.toml
+++ b/src/tools/tidy/Cargo.toml
@@ -12,11 +12,15 @@ miropt-test-tools = { path = "../miropt-test-tools" }
 walkdir = "2"
 ignore = "0.4.18"
 semver = "1.0"
+serde = { version = "1.0.125", features = ["derive"], optional = true }
 termcolor = "1.1.3"
 rustc-hash = "2.0.0"
 fluent-syntax = "0.11.1"
 similar = "2.5.0"
 
+[features]
+build-metrics = ["dep:serde"]
+
 [[bin]]
 name = "rust-tidy"
 path = "src/main.rs"
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index 45b40b17ea3..e69de29bb2d 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -1 +0,0 @@
-run-make/split-debuginfo/Makefile
diff --git a/src/tools/tidy/src/ext_tool_checks.rs b/src/tools/tidy/src/ext_tool_checks.rs
index 2a4cff1d12e..4f9a20fa9e2 100644
--- a/src/tools/tidy/src/ext_tool_checks.rs
+++ b/src/tools/tidy/src/ext_tool_checks.rs
@@ -95,10 +95,14 @@ fn check_impl(
         if res.is_err() && show_diff {
             eprintln!("\npython linting failed! Printing diff suggestions:");
 
-            let _ = run_ruff(root_path, outdir, py_path, &cfg_args, &file_args, &[
-                "check".as_ref(),
-                "--diff".as_ref(),
-            ]);
+            let _ = run_ruff(
+                root_path,
+                outdir,
+                py_path,
+                &cfg_args,
+                &file_args,
+                &["check".as_ref(), "--diff".as_ref()],
+            );
         }
         // Rethrow error
         let _ = res?;
@@ -120,10 +124,14 @@ fn check_impl(
             if show_diff {
                 eprintln!("\npython formatting does not match! Printing diff:");
 
-                let _ = run_ruff(root_path, outdir, py_path, &cfg_args, &file_args, &[
-                    "format".as_ref(),
-                    "--diff".as_ref(),
-                ]);
+                let _ = run_ruff(
+                    root_path,
+                    outdir,
+                    py_path,
+                    &cfg_args,
+                    &file_args,
+                    &["format".as_ref(), "--diff".as_ref()],
+                );
             }
             eprintln!("rerun tidy with `--extra-checks=py:fmt --bless` to reformat Python code");
         }
@@ -148,10 +156,11 @@ fn check_impl(
         let files;
         if file_args_clang_format.is_empty() {
             let llvm_wrapper = root_path.join("compiler/rustc_llvm/llvm-wrapper");
-            files = find_with_extension(root_path, Some(llvm_wrapper.as_path()), &[
-                OsStr::new("h"),
-                OsStr::new("cpp"),
-            ])?;
+            files = find_with_extension(
+                root_path,
+                Some(llvm_wrapper.as_path()),
+                &[OsStr::new("h"), OsStr::new("cpp")],
+            )?;
             file_args_clang_format.extend(files.iter().map(|p| p.as_os_str()));
         }
         let args = merge_args(&cfg_args_clang_format, &file_args_clang_format);
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index 4f24eb21242..fcd7943e6e0 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -27,6 +27,7 @@ const FEATURE_GROUP_START_PREFIX: &str = "// feature-group-start";
 const FEATURE_GROUP_END_PREFIX: &str = "// feature-group-end";
 
 #[derive(Debug, PartialEq, Clone)]
+#[cfg_attr(feature = "build-metrics", derive(serde::Serialize))]
 pub enum Status {
     Accepted,
     Removed,
@@ -45,6 +46,7 @@ impl fmt::Display for Status {
 }
 
 #[derive(Debug, Clone)]
+#[cfg_attr(feature = "build-metrics", derive(serde::Serialize))]
 pub struct Feature {
     pub level: Status,
     pub since: Option<Version>,
diff --git a/src/tools/tidy/src/features/version.rs b/src/tools/tidy/src/features/version.rs
index 0830c226caf..6a902e80f8e 100644
--- a/src/tools/tidy/src/features/version.rs
+++ b/src/tools/tidy/src/features/version.rs
@@ -8,6 +8,7 @@ mod tests;
 pub const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION";
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+#[cfg_attr(feature = "build-metrics", derive(serde::Serialize))]
 pub enum Version {
     Explicit { parts: [u32; 3] },
     CurrentPlaceholder,
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index 839d23fb9a7..39c9a148e9e 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -2218,26 +2218,12 @@ ui/issues/issue-3993.rs
 ui/issues/issue-39970.rs
 ui/issues/issue-39984.rs
 ui/issues/issue-40000.rs
-ui/issues/issue-40136.rs
-ui/issues/issue-40235.rs
 ui/issues/issue-4025.rs
 ui/issues/issue-40288-2.rs
 ui/issues/issue-40288.rs
-ui/issues/issue-40350.rs
-ui/issues/issue-40408.rs
-ui/issues/issue-40610.rs
-ui/issues/issue-40749.rs
-ui/issues/issue-40782.rs
-ui/issues/issue-40827.rs
-ui/issues/issue-40845.rs
-ui/issues/issue-40861.rs
-ui/issues/issue-40883.rs
 ui/issues/issue-40951.rs
 ui/issues/issue-41053.rs
-ui/issues/issue-41139.rs
-ui/issues/issue-41213.rs
 ui/issues/issue-41229-ref-str.rs
-ui/issues/issue-41272.rs
 ui/issues/issue-41298.rs
 ui/issues/issue-41479.rs
 ui/issues/issue-41498.rs
@@ -2360,7 +2346,6 @@ ui/issues/issue-4830.rs
 ui/issues/issue-48364.rs
 ui/issues/issue-48728.rs
 ui/issues/issue-4875.rs
-ui/issues/issue-48838.rs
 ui/issues/issue-48984.rs
 ui/issues/issue-49298.rs
 ui/issues/issue-4935.rs
@@ -3146,7 +3131,6 @@ ui/nll/issue-97997.rs
 ui/nll/issue-98170.rs
 ui/nll/issue-98589-closures-relate-named-regions.rs
 ui/nll/issue-98693.rs
-ui/nll/polonius/issue-46589.rs
 ui/nll/relate_tys/issue-48071.rs
 ui/nll/ty-outlives/issue-53789-1.rs
 ui/nll/ty-outlives/issue-53789-2.rs
diff --git a/src/tools/tidy/src/known_bug.rs b/src/tools/tidy/src/known_bug.rs
index a8771654144..e1921715ab9 100644
--- a/src/tools/tidy/src/known_bug.rs
+++ b/src/tools/tidy/src/known_bug.rs
@@ -14,13 +14,10 @@ pub fn check(filepath: &Path, bad: &mut bool) {
         let test_path_segments_str =
             test_path_segments.iter().map(|s| s.as_str()).collect::<Vec<&str>>();
 
-        if !matches!(test_path_segments_str[..], [
-            ..,
-            "tests",
-            "crashes",
-            "auxiliary",
-            _aux_file_rs
-        ]) && !contents.lines().any(|line| line.starts_with("//@ known-bug: "))
+        if !matches!(
+            test_path_segments_str[..],
+            [.., "tests", "crashes", "auxiliary", _aux_file_rs]
+        ) && !contents.lines().any(|line| line.starts_with("//@ known-bug: "))
         {
             tidy_error!(
                 bad,
diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs
index c650fd0eec6..c708ff7150c 100644
--- a/src/tools/tidy/src/pal.rs
+++ b/src/tools/tidy/src/pal.rs
@@ -48,8 +48,9 @@ const EXCEPTION_PATHS: &[&str] = &[
     // we must use `#[cfg(windows)]` to conditionally compile the
     // correct `VaList` structure for windows.
     "library/core/src/ffi/va_list.rs",
-    // We placed a linkage against Windows libraries here
+    // core::ffi contains platform-specific type and linkage configuration
     "library/core/src/ffi/mod.rs",
+    "library/core/src/ffi/primitives.rs",
     "library/std/src/sys", // Platform-specific code for std lives here.
     "library/std/src/os",  // Platform-specific public interfaces
     // Temporary `std` exceptions
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index d66ba157d10..fe51231c481 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -17,7 +17,7 @@ use ignore::Walk;
 const ENTRY_LIMIT: u32 = 901;
 // FIXME: The following limits should be reduced eventually.
 
-const ISSUES_ENTRY_LIMIT: u32 = 1658;
+const ISSUES_ENTRY_LIMIT: u32 = 1634;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
     "rs",     // test source files
diff --git a/src/tools/unicode-table-generator/src/raw_emitter.rs b/src/tools/unicode-table-generator/src/raw_emitter.rs
index 46010692fe5..ee94d3c93a6 100644
--- a/src/tools/unicode-table-generator/src/raw_emitter.rs
+++ b/src/tools/unicode-table-generator/src/raw_emitter.rs
@@ -355,12 +355,15 @@ impl Canonicalized {
         let unique_mapping = unique_mapping
             .into_iter()
             .map(|(key, value)| {
-                (key, match value {
-                    UniqueMapping::Canonicalized(idx) => {
-                        u8::try_from(canonical_words.len() + idx).unwrap()
-                    }
-                    UniqueMapping::Canonical(idx) => u8::try_from(idx).unwrap(),
-                })
+                (
+                    key,
+                    match value {
+                        UniqueMapping::Canonicalized(idx) => {
+                            u8::try_from(canonical_words.len() + idx).unwrap()
+                        }
+                        UniqueMapping::Canonical(idx) => u8::try_from(idx).unwrap(),
+                    },
+                )
             })
             .collect::<HashMap<_, _>>();
 
@@ -375,21 +378,24 @@ impl Canonicalized {
         let canonicalized_words = canonicalized_words
             .into_iter()
             .map(|v| {
-                (u8::try_from(v.0).unwrap(), match v.1 {
-                    Mapping::RotateAndInvert(amount) => {
-                        assert_eq!(amount, amount & LOWER_6);
-                        1 << 6 | (amount as u8)
-                    }
-                    Mapping::Rotate(amount) => {
-                        assert_eq!(amount, amount & LOWER_6);
-                        amount as u8
-                    }
-                    Mapping::Invert => 1 << 6,
-                    Mapping::ShiftRight(shift_by) => {
-                        assert_eq!(shift_by, shift_by & LOWER_6);
-                        1 << 7 | (shift_by as u8)
-                    }
-                })
+                (
+                    u8::try_from(v.0).unwrap(),
+                    match v.1 {
+                        Mapping::RotateAndInvert(amount) => {
+                            assert_eq!(amount, amount & LOWER_6);
+                            1 << 6 | (amount as u8)
+                        }
+                        Mapping::Rotate(amount) => {
+                            assert_eq!(amount, amount & LOWER_6);
+                            amount as u8
+                        }
+                        Mapping::Invert => 1 << 6,
+                        Mapping::ShiftRight(shift_by) => {
+                            assert_eq!(shift_by, shift_by & LOWER_6);
+                            1 << 7 | (shift_by as u8)
+                        }
+                    },
+                )
             })
             .collect::<Vec<(u8, u8)>>();
         Canonicalized { unique_mapping, canonical_words, canonicalized_words }