about summary refs log tree commit diff
path: root/src/tools
diff options
context:
space:
mode:
authorJakub Beránek <berykubik@gmail.com>2025-01-20 15:54:51 +0100
committerGitHub <noreply@github.com>2025-01-20 15:54:51 +0100
commit470ab13c5c28a42e706ee8cee92e44257065324f (patch)
treeea612d81208c7fa15d3477ca173d9fe6a18ccc83 /src/tools
parent1b5b0515f9c12ea8181deec0d9997fe9af6ab417 (diff)
parent1e0204beae7c0ebc5cddc64d1375bc7ee95f41db (diff)
Merge pull request #2215 from Kobzol/pull
rustc pull
Diffstat (limited to 'src/tools')
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/.github/workflows/clippy_dev.yml3
-rw-r--r--src/tools/clippy/.github/workflows/clippy_mq.yml27
-rw-r--r--src/tools/clippy/.github/workflows/clippy_pr.yml7
-rw-r--r--src/tools/clippy/.github/workflows/deploy.yml10
-rw-r--r--src/tools/clippy/.github/workflows/lintcheck.yml8
-rw-r--r--src/tools/clippy/.github/workflows/remark.yml3
-rw-r--r--src/tools/clippy/CHANGELOG.md47
-rw-r--r--src/tools/clippy/Cargo.toml2
-rw-r--r--src/tools/clippy/book/src/development/infrastructure/changelog_update.md5
-rw-r--r--src/tools/clippy/book/src/development/method_checking.md2
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md27
-rw-r--r--src/tools/clippy/clippy.toml2
-rw-r--r--src/tools/clippy/clippy_config/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_config/src/conf.rs20
-rw-r--r--src/tools/clippy/clippy_dev/src/fmt.rs6
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/missing_headers.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/entry.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/equatable_if_let.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs127
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_to_string.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs51
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_div_ceil.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_ignore_case_cmp.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs61
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_range_patterns.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_bool.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/needless_match.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/single_match.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs41
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_flatten.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_identity.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_collect.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/str_splitn.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_doc.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_inline.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_continue.rs139
-rw-r--r--src/tools/clippy/clippy_lints/src/new_without_default.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/no_effect.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/non_expressive_names.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_else.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_locals.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/regex.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/std_instead_of_core.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/string_patterns.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/swap.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/trailing_empty_array.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/types/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_literal_bound.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_async.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs35
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/vec.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/vec_init_then_push.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/zombie_processes.rs2
-rw-r--r--src/tools/clippy/clippy_utils/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_utils/README.md2
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils/mod.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs59
-rw-r--r--src/tools/clippy/clippy_utils/src/higher.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs48
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/mod.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs20
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/possible_origin.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/transitive_relation.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/msrvs.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs2
-rw-r--r--src/tools/clippy/lintcheck/src/output.rs2
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/tests/compile-test.rs2
-rw-r--r--src/tools/clippy/tests/missing-test-files.rs2
-rw-r--r--src/tools/clippy/tests/ui-internal/custom_ice_message.stderr1
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.fixed79
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs79
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.stderr77
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr3
-rw-r--r--src/tools/clippy/tests/ui/author/if.stdout4
-rw-r--r--src/tools/clippy/tests/ui/author/loop.stdout4
-rw-r--r--src/tools/clippy/tests/ui/author/matches.stdout8
-rw-r--r--src/tools/clippy/tests/ui/author/struct.stdout8
-rw-r--r--src/tools/clippy/tests/ui/borrow_as_ptr.fixed8
-rw-r--r--src/tools/clippy/tests/ui/borrow_as_ptr.rs8
-rw-r--r--src/tools/clippy/tests/ui/borrow_as_ptr.stderr14
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs11
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr28
-rw-r--r--src/tools/clippy/tests/ui/boxed_local.rs1
-rw-r--r--src/tools/clippy/tests/ui/boxed_local.stderr4
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-10972-tait.rs9
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-13862.rs19
-rw-r--r--src/tools/clippy/tests/ui/doc/doc-fixable.fixed2
-rw-r--r--src/tools/clippy/tests/ui/doc/doc-fixable.rs2
-rw-r--r--src/tools/clippy/tests/ui/double_ended_iterator_last.fixed53
-rw-r--r--src/tools/clippy/tests/ui/double_ended_iterator_last.rs53
-rw-r--r--src/tools/clippy/tests/ui/double_ended_iterator_last.stderr17
-rw-r--r--src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed6
-rw-r--r--src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr19
-rw-r--r--src/tools/clippy/tests/ui/infinite_iter.rs2
-rw-r--r--src/tools/clippy/tests/ui/iter_overeager_cloned.fixed7
-rw-r--r--src/tools/clippy/tests/ui/iter_overeager_cloned.rs7
-rw-r--r--src/tools/clippy/tests/ui/iter_overeager_cloned.stderr38
-rw-r--r--src/tools/clippy/tests/ui/len_zero.fixed22
-rw-r--r--src/tools/clippy/tests/ui/len_zero.rs22
-rw-r--r--src/tools/clippy/tests/ui/len_zero.stderr42
-rw-r--r--src/tools/clippy/tests/ui/manual_div_ceil.fixed22
-rw-r--r--src/tools/clippy/tests/ui/manual_div_ceil.rs22
-rw-r--r--src/tools/clippy/tests/ui/manual_div_ceil.stderr56
-rw-r--r--src/tools/clippy/tests/ui/manual_div_ceil_with_feature.fixed27
-rw-r--r--src/tools/clippy/tests/ui/manual_div_ceil_with_feature.rs27
-rw-r--r--src/tools/clippy/tests/ui/manual_div_ceil_with_feature.stderr68
-rw-r--r--src/tools/clippy/tests/ui/manual_is_ascii_check.fixed5
-rw-r--r--src/tools/clippy/tests/ui/manual_is_ascii_check.rs5
-rw-r--r--src/tools/clippy/tests/ui/manual_is_ascii_check.stderr24
-rw-r--r--src/tools/clippy/tests/ui/map_flatten.rs12
-rw-r--r--src/tools/clippy/tests/ui/map_flatten.stderr11
-rw-r--r--src/tools/clippy/tests/ui/map_identity.fixed15
-rw-r--r--src/tools/clippy/tests/ui/map_identity.rs15
-rw-r--r--src/tools/clippy/tests/ui/map_identity.stderr14
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs29
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed1
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs1
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr16
-rw-r--r--src/tools/clippy/tests/ui/needless_arbitrary_self_type.fixed5
-rw-r--r--src/tools/clippy/tests/ui/needless_arbitrary_self_type.rs5
-rw-r--r--src/tools/clippy/tests/ui/needless_arbitrary_self_type.stderr14
-rw-r--r--src/tools/clippy/tests/ui/needless_continue.rs65
-rw-r--r--src/tools/clippy/tests/ui/needless_continue.stderr80
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed8
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs8
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr8
-rw-r--r--src/tools/clippy/tests/ui/slow_vector_initialization.rs26
-rw-r--r--src/tools/clippy/tests/ui/slow_vector_initialization.stderr143
-rw-r--r--src/tools/clippy/tests/ui/starts_ends_with.fixed2
-rw-r--r--src/tools/clippy/tests/ui/starts_ends_with.rs2
-rw-r--r--src/tools/clippy/tests/ui/std_instead_of_core.fixed2
-rw-r--r--src/tools/clippy/tests/ui/std_instead_of_core.rs2
-rw-r--r--src/tools/clippy/tests/ui/trailing_empty_array.rs14
-rw-r--r--src/tools/clippy/tests/ui/transmute.rs22
-rw-r--r--src/tools/clippy/tests/ui/transmute.stderr36
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_map_or.fixed14
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_map_or.rs4
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_map_or.stderr66
-rw-r--r--src/tools/clippy/tests/ui/useless_vec.rs15
-rw-r--r--src/tools/clippy/tests/ui/useless_vec.stderr21
-rw-r--r--src/tools/compiletest/src/common.rs12
-rw-r--r--src/tools/compiletest/src/header/tests.rs2
-rw-r--r--src/tools/compiletest/src/lib.rs2
-rw-r--r--src/tools/compiletest/src/runtest.rs14
-rw-r--r--src/tools/compiletest/src/runtest/js_doc.rs2
-rw-r--r--src/tools/compiletest/src/runtest/run_make.rs11
-rw-r--r--src/tools/compiletest/src/tests.rs27
-rw-r--r--src/tools/generate-copyright/src/main.rs5
-rw-r--r--src/tools/generate-copyright/templates/COPYRIGHT-library.html23
-rw-r--r--src/tools/generate-copyright/templates/COPYRIGHT.html26
-rw-r--r--src/tools/jsondocck/src/main.rs27
-rw-r--r--src/tools/jsondoclint/src/validator.rs6
-rw-r--r--src/tools/jsondoclint/src/validator/tests.rs97
-rw-r--r--src/tools/lint-docs/src/lib.rs75
-rw-r--r--src/tools/miri/.github/workflows/ci.yml2
-rw-r--r--src/tools/miri/CONTRIBUTING.md2
-rw-r--r--src/tools/miri/README.md4
-rwxr-xr-xsrc/tools/miri/ci/ci.sh5
-rw-r--r--src/tools/miri/etc/rust_analyzer_vscode.json10
-rwxr-xr-xsrc/tools/miri/miri10
-rw-r--r--src/tools/miri/miri-script/src/commands.rs6
-rw-r--r--src/tools/miri/miri-script/src/main.rs1
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/concurrency/cpu_affinity.rs8
-rw-r--r--src/tools/miri/src/concurrency/sync.rs90
-rw-r--r--src/tools/miri/src/concurrency/thread.rs83
-rw-r--r--src/tools/miri/src/helpers.rs8
-rw-r--r--src/tools/miri/src/lib.rs10
-rw-r--r--src/tools/miri/src/machine.rs66
-rw-r--r--src/tools/miri/src/shims/files.rs259
-rw-r--r--src/tools/miri/src/shims/native_lib.rs2
-rw-r--r--src/tools/miri/src/shims/time.rs12
-rw-r--r--src/tools/miri/src/shims/unix/fd.rs9
-rw-r--r--src/tools/miri/src/shims/unix/foreign_items.rs323
-rw-r--r--src/tools/miri/src/shims/unix/freebsd/foreign_items.rs27
-rw-r--r--src/tools/miri/src/shims/unix/fs.rs36
-rw-r--r--src/tools/miri/src/shims/unix/linux_like/epoll.rs181
-rw-r--r--src/tools/miri/src/shims/unix/linux_like/eventfd.rs99
-rw-r--r--src/tools/miri/src/shims/unix/macos/foreign_items.rs32
-rw-r--r--src/tools/miri/src/shims/unix/macos/sync.rs2
-rw-r--r--src/tools/miri/src/shims/unix/solarish/foreign_items.rs36
-rw-r--r--src/tools/miri/src/shims/unix/unnamed_socket.rs218
-rw-r--r--src/tools/miri/src/shims/windows/handle.rs2
-rw-r--r--src/tools/miri/src/shims/windows/sync.rs3
-rw-r--r--src/tools/miri/tests/fail-dep/libc/affinity.rs3
-rw-r--r--src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/libc/libc_epoll_unsupported_fd.rs2
-rw-r--r--src/tools/miri/tests/fail-dep/libc/memrchr_null.rs5
-rw-r--r--src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs37
-rw-r--r--src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr35
-rw-r--r--src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr6
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-affinity.rs3
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs2
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs2
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs7
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-fs.rs20
-rw-r--r--src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs54
-rw-r--r--src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr2
-rw-r--r--src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr2
-rw-r--r--src/tools/miri/tests/pass/backtrace/backtrace-std.stderr2
-rw-r--r--src/tools/miri/tests/pass/shims/pipe.rs13
-rw-r--r--src/tools/miri/triagebot.toml8
-rw-r--r--src/tools/opt-dist/src/bolt.rs13
-rw-r--r--src/tools/opt-dist/src/main.rs28
-rw-r--r--src/tools/replace-version-placeholder/src/main.rs7
-rw-r--r--src/tools/run-make-support/src/external_deps/rustdoc.rs3
-rw-r--r--src/tools/run-make-support/src/lib.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout.rs4
-rw-r--r--src/tools/rustbook/Cargo.lock230
m---------src/tools/rustc-perf0
-rw-r--r--src/tools/rustdoc-js/tester.js2
-rw-r--r--src/tools/rustfmt/src/patterns.rs41
-rw-r--r--src/tools/rustfmt/tests/source/pattern.rs10
-rw-r--r--src/tools/rustfmt/tests/target/pattern.rs8
-rw-r--r--src/tools/tidy/src/allowed_run_make_makefiles.txt1
-rw-r--r--src/tools/tidy/src/style.rs94
266 files changed, 3868 insertions, 1566 deletions
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject fd784878cfa843e3e29a6654ecf564c62fae673
+Subproject 045bf21b36a2e1f3ed85e38278d1c3cc4305e13
diff --git a/src/tools/clippy/.github/workflows/clippy_dev.yml b/src/tools/clippy/.github/workflows/clippy_dev.yml
index bcb3193ad67..d6534fbaff9 100644
--- a/src/tools/clippy/.github/workflows/clippy_dev.yml
+++ b/src/tools/clippy/.github/workflows/clippy_dev.yml
@@ -17,6 +17,9 @@ jobs:
     # Setup
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        # Unsetting this would make so that any malicious package could get our Github Token
+        persist-credentials: false
 
     # Run
     - name: Build
diff --git a/src/tools/clippy/.github/workflows/clippy_mq.yml b/src/tools/clippy/.github/workflows/clippy_mq.yml
index 49622048050..dee7d028655 100644
--- a/src/tools/clippy/.github/workflows/clippy_mq.yml
+++ b/src/tools/clippy/.github/workflows/clippy_mq.yml
@@ -23,6 +23,8 @@ jobs:
       uses: actions/checkout@v4
       with:
         ref: ${{ github.ref }}
+        # Unsetting this would make so that any malicious package could get our Github Token
+        persist-credentials: false
 
     # Run
     - name: Check Changelog
@@ -63,6 +65,8 @@ jobs:
     # Setup
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        persist-credentials: false
 
     - name: Install i686 dependencies
       if: matrix.host == 'i686-unknown-linux-gnu'
@@ -74,7 +78,8 @@ jobs:
     - name: Install toolchain
       run: |
         rustup set default-host ${{ matrix.host }}
-        rustup show active-toolchain
+        # Use a way compatible with Rustup pre-1.28.0 and Rustup 1.28.0
+        rustup show active-toolchain || rustup toolchain install
 
     # Run
     - name: Build
@@ -121,9 +126,13 @@ jobs:
      # Setup
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        persist-credentials: false
 
     - name: Install toolchain
-      run: rustup show active-toolchain
+      run: |
+        # Use a way compatible with Rustup pre-1.28.0 and Rustup 1.28.0
+        rustup show active-toolchain || rustup toolchain install
 
     - name: Test metadata collection
       run: cargo collect-metadata
@@ -136,9 +145,13 @@ jobs:
     # Setup
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        persist-credentials: false
 
     - name: Install toolchain
-      run: rustup show active-toolchain
+      run: |
+        # Use a way compatible with Rustup pre-1.28.0 and Rustup 1.28.0
+        rustup show active-toolchain || rustup toolchain install
 
     # Run
     - name: Build Integration Test
@@ -188,9 +201,13 @@ jobs:
     # Setup
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        persist-credentials: false
 
     - name: Install toolchain
-      run: rustup show active-toolchain
+      run: |
+        # Use a way compatible with Rustup pre-1.28.0 and Rustup 1.28.0
+        rustup show active-toolchain || rustup toolchain install
 
     # Download
     - name: Download target dir
@@ -205,7 +222,7 @@ jobs:
     # Run
     - name: Test ${{ matrix.integration }}
       run: |
-          TOOLCHAIN=$(rustup show active-toolchain | cut -f1 -d' ')
+          TOOLCHAIN=$(rustup show active-toolchain | head -n 1 | cut -f1 -d' ')
           rustup run $TOOLCHAIN $CARGO_TARGET_DIR/debug/integration --show-output
       env:
         INTEGRATION: ${{ matrix.integration }}
diff --git a/src/tools/clippy/.github/workflows/clippy_pr.yml b/src/tools/clippy/.github/workflows/clippy_pr.yml
index 2e5b5bd41df..80523d91f4f 100644
--- a/src/tools/clippy/.github/workflows/clippy_pr.yml
+++ b/src/tools/clippy/.github/workflows/clippy_pr.yml
@@ -25,9 +25,14 @@ jobs:
     # Setup
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        # Unsetting this would make so that any malicious package could get our Github Token
+        persist-credentials: false
 
     - name: Install toolchain
-      run: rustup show active-toolchain
+      run: |
+        # Use a way compatible with Rustup pre-1.28.0 and Rustup 1.28.0
+        rustup show active-toolchain || rustup toolchain install
 
     # Run
     - name: Build
diff --git a/src/tools/clippy/.github/workflows/deploy.yml b/src/tools/clippy/.github/workflows/deploy.yml
index 32dc251c836..b42f3e7712f 100644
--- a/src/tools/clippy/.github/workflows/deploy.yml
+++ b/src/tools/clippy/.github/workflows/deploy.yml
@@ -22,19 +22,27 @@ jobs:
     # Setup
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        # Unsetting this would make so that any malicious package could get our Github Token
+        persist-credentials: false
 
     - name: Checkout
       uses: actions/checkout@v4
       with:
         ref: ${{ env.TARGET_BRANCH }}
         path: 'out'
+        # Unsetting this would make so that any malicious package could get our Github Token
+        persist-credentials: false
 
     # Run
     - name: Set tag name
       if: startswith(github.ref, 'refs/tags/')
       run: |
-        TAG=$(basename ${{ github.ref }})
+        TAG=$(basename "${TAGNAME}")
         echo "TAG_NAME=$TAG" >> $GITHUB_ENV
+      env:
+        # Make sure that the reference gets expanded before injecting it
+        TAGNAME: ${{ github.ref }}
     - name: Set beta to true
       if: github.ref == 'refs/heads/beta'
       run: echo "BETA=true" >> $GITHUB_ENV
diff --git a/src/tools/clippy/.github/workflows/lintcheck.yml b/src/tools/clippy/.github/workflows/lintcheck.yml
index 3cbda0b3824..64966f1d189 100644
--- a/src/tools/clippy/.github/workflows/lintcheck.yml
+++ b/src/tools/clippy/.github/workflows/lintcheck.yml
@@ -21,6 +21,8 @@ jobs:
       uses: actions/checkout@v4
       with:
         fetch-depth: 2
+        # Unsetting this would make so that any malicious package could get our Github Token
+        persist-credentials: false
 
     # HEAD is the generated merge commit `refs/pull/N/merge` between the PR and `master`, `HEAD^`
     # being the commit from `master` that is the base of the merge
@@ -73,6 +75,9 @@ jobs:
     steps:
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        # Unsetting this would make so that any malicious package could get our Github Token
+        persist-credentials: false
 
     - name: Cache lintcheck bin
       id: cache-lintcheck-bin
@@ -103,6 +108,9 @@ jobs:
     steps:
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        # Unsetting this would make so that any malicious package could get our Github Token
+        persist-credentials: false
 
     - name: Restore lintcheck bin
       uses: actions/cache/restore@v4
diff --git a/src/tools/clippy/.github/workflows/remark.yml b/src/tools/clippy/.github/workflows/remark.yml
index 0d402fe7064..69d00dc027e 100644
--- a/src/tools/clippy/.github/workflows/remark.yml
+++ b/src/tools/clippy/.github/workflows/remark.yml
@@ -12,6 +12,9 @@ jobs:
     # Setup
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        # Unsetting this would make so that any malicious package could get our Github Token
+        persist-credentials: false
 
     - name: Setup Node.js
       uses: actions/setup-node@v4
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index b6033de9350..1770e8095a0 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6,11 +6,52 @@ document.
 
 ## Unreleased / Beta / In Rust Nightly
 
-[aa0d5513...master](https://github.com/rust-lang/rust-clippy/compare/aa0d5513...master)
+[786fbd6d...master](https://github.com/rust-lang/rust-clippy/compare/786fbd6d...master)
+
+## Rust 1.84
+
+Current stable, released 2025-01-09
+
+[View all 84 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-10-03T21%3A23%3A58Z..2024-11-14T17%3A41%3A37Z+base%3Amaster)
+
+### New Lints
+
+* Added [`unnecessary_map_or`] to `style`
+  [#11796](https://github.com/rust-lang/rust-clippy/pull/11796)
+* Added [`arbitrary_source_item_ordering`] to `restriction`
+  [#13376](https://github.com/rust-lang/rust-clippy/pull/13376)
+* Added [`map_with_unused_argument_over_ranges`] to `restriction`
+  [#13034](https://github.com/rust-lang/rust-clippy/pull/13034)
+* Added [`map_all_any_identity`] to `complexity`
+  [#13499](https://github.com/rust-lang/rust-clippy/pull/13499)
+* Added [`needless_as_bytes`] to `complexity`
+  [#13437](https://github.com/rust-lang/rust-clippy/pull/13437)
+* Added [`unnecessary_literal_bound`] to `pedantic`
+  [#13395](https://github.com/rust-lang/rust-clippy/pull/13395)
+* Added [`manual_ignore_case_cmp`] to `perf`
+  [#13334](https://github.com/rust-lang/rust-clippy/pull/13334)
+* Added [`regex_creation_in_loops`] to `perf`
+  [#13412](https://github.com/rust-lang/rust-clippy/pull/13412)
+
+### Moves and Deprecations
+
+* Moved [`manual_is_power_of_two`] to `pedantic` (From `complexity`, now allow-by-default)
+  [#13553](https://github.com/rust-lang/rust-clippy/pull/13553)
+* Move [`module_name_repetitions`] to `restriction` (from `pedantic`)
+  [#13541](https://github.com/rust-lang/rust-clippy/pull/13541)
+
+### Enhancements
+
+* [`doc_markdown`]: Added the following identifiers to [`doc-valid-idents`]:
+  CoAP, MHz, GHz, and THz
+  [#13633](https://github.com/rust-lang/rust-clippy/pull/13633)
+  [#13460](https://github.com/rust-lang/rust-clippy/pull/13460)
+* [`large_const_arrays`]: Changed the default of [`array-size-threshold`] to `16kb` (from `512kb`)
+  [#13485](https://github.com/rust-lang/rust-clippy/pull/13485)
 
 ## Rust 1.83
 
-Current stable, released 2024-11-28
+Released 2024-11-28
 
 [View all 64 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-08-25T09%3A59%3A01Z..2024-10-03T13%3A42%3A56Z+base%3Amaster)
 
@@ -5493,6 +5534,7 @@ Released 2018-09-13
 [`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
 [`doc_nested_refdefs`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_nested_refdefs
 [`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons
+[`double_ended_iterator_last`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_ended_iterator_last
 [`double_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_must_use
 [`double_neg`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_neg
 [`double_parens`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_parens
@@ -6252,6 +6294,7 @@ Released 2018-09-13
 [`future-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#future-size-threshold
 [`ignore-interior-mutability`]: https://doc.rust-lang.org/clippy/lint_configuration.html#ignore-interior-mutability
 [`large-error-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#large-error-threshold
+[`lint-inconsistent-struct-field-initializers`]: https://doc.rust-lang.org/clippy/lint_configuration.html#lint-inconsistent-struct-field-initializers
 [`literal-representation-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#literal-representation-threshold
 [`matches-for-let-else`]: https://doc.rust-lang.org/clippy/lint_configuration.html#matches-for-let-else
 [`max-fn-params-bools`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-fn-params-bools
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index 77cb0006ff8..efa59fecc0e 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "clippy"
 # begin autogenerated version
-version = "0.1.85"
+version = "0.1.86"
 # end autogenerated version
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
diff --git a/src/tools/clippy/book/src/development/infrastructure/changelog_update.md b/src/tools/clippy/book/src/development/infrastructure/changelog_update.md
index df9b1bbe18f..2b2c096b049 100644
--- a/src/tools/clippy/book/src/development/infrastructure/changelog_update.md
+++ b/src/tools/clippy/book/src/development/infrastructure/changelog_update.md
@@ -83,7 +83,12 @@ As section headers, we use:
 
 ```
 ### New Lints
+* Added [`LINT`] to `GROUP`
+
 ### Moves and Deprecations
+* Moved [`LINT`] to `GROUP` (From `GROUP`, now LEVEL-by-default)
+* Renamed `LINT` to [`LINT`]
+
 ### Enhancements
 ### False Positive Fixes
 ### Suggestion Fixes/Improvements
diff --git a/src/tools/clippy/book/src/development/method_checking.md b/src/tools/clippy/book/src/development/method_checking.md
index 9c5d4b516db..b3126024b99 100644
--- a/src/tools/clippy/book/src/development/method_checking.md
+++ b/src/tools/clippy/book/src/development/method_checking.md
@@ -21,7 +21,7 @@ use clippy_utils::is_trait_method;
 impl<'tcx> LateLintPass<'tcx> for OurFancyMethodLint {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         // Check our expr is calling a method with pattern matching
-        if let hir::ExprKind::MethodCall(path, _, [self_arg, ..]) = &expr.kind
+        if let hir::ExprKind::MethodCall(path, _, [self_arg, ..], _) = &expr.kind
             // Check if the name of this method is `our_fancy_method`
             && path.ident.name.as_str() == "our_fancy_method"
             // We can check the type of the self argument whenever necessary.
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index ea1d7d11389..181e794e6e4 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -582,6 +582,33 @@ The maximum size of the `Err`-variant in a `Result` returned from a function
 * [`result_large_err`](https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err)
 
 
+## `lint-inconsistent-struct-field-initializers`
+Whether to suggest reordering constructor fields when initializers are present.
+
+Warnings produced by this configuration aren't necessarily fixed by just reordering the fields. Even if the
+suggested code would compile, it can change semantics if the initializer expressions have side effects. The
+following example [from rust-clippy#11846] shows how the suggestion can run into borrow check errors:
+
+```rust
+struct MyStruct {
+    vector: Vec<u32>,
+    length: usize
+}
+fn main() {
+    let vector = vec![1,2,3];
+    MyStruct { length: vector.len(), vector};
+}
+```
+
+[from rust-clippy#11846]: https://github.com/rust-lang/rust-clippy/issues/11846#issuecomment-1820747924
+
+**Default Value:** `false`
+
+---
+**Affected lints:**
+* [`inconsistent_struct_constructor`](https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_struct_constructor)
+
+
 ## `literal-representation-threshold`
 The lower bound for linting decimal literals
 
diff --git a/src/tools/clippy/clippy.toml b/src/tools/clippy/clippy.toml
index a7b0cc56ea1..f4789c9d030 100644
--- a/src/tools/clippy/clippy.toml
+++ b/src/tools/clippy/clippy.toml
@@ -1,5 +1,7 @@
 avoid-breaking-exported-api = false
 
+lint-inconsistent-struct-field-initializers = true
+
 [[disallowed-methods]]
 path = "rustc_lint::context::LintContext::lint"
 reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead"
diff --git a/src/tools/clippy/clippy_config/Cargo.toml b/src/tools/clippy/clippy_config/Cargo.toml
index 3f18a0bc7d2..c761e207c6b 100644
--- a/src/tools/clippy/clippy_config/Cargo.toml
+++ b/src/tools/clippy/clippy_config/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "clippy_config"
 # begin autogenerated version
-version = "0.1.85"
+version = "0.1.86"
 # end autogenerated version
 edition = "2021"
 publish = false
diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs
index bffa04f6f09..c616589c56e 100644
--- a/src/tools/clippy/clippy_config/src/conf.rs
+++ b/src/tools/clippy/clippy_config/src/conf.rs
@@ -532,6 +532,26 @@ define_Conf! {
     /// The maximum size of the `Err`-variant in a `Result` returned from a function
     #[lints(result_large_err)]
     large_error_threshold: u64 = 128,
+    /// Whether to suggest reordering constructor fields when initializers are present.
+    ///
+    /// Warnings produced by this configuration aren't necessarily fixed by just reordering the fields. Even if the
+    /// suggested code would compile, it can change semantics if the initializer expressions have side effects. The
+    /// following example [from rust-clippy#11846] shows how the suggestion can run into borrow check errors:
+    ///
+    /// ```rust
+    /// struct MyStruct {
+    ///     vector: Vec<u32>,
+    ///     length: usize
+    /// }
+    /// fn main() {
+    ///     let vector = vec![1,2,3];
+    ///     MyStruct { length: vector.len(), vector};
+    /// }
+    /// ```
+    ///
+    /// [from rust-clippy#11846]: https://github.com/rust-lang/rust-clippy/issues/11846#issuecomment-1820747924
+    #[lints(inconsistent_struct_constructor)]
+    lint_inconsistent_struct_field_initializers: bool = false,
     /// The lower bound for linting decimal literals
     #[lints(decimal_literal_representation)]
     literal_representation_threshold: u64 = 16384,
diff --git a/src/tools/clippy/clippy_dev/src/fmt.rs b/src/tools/clippy/clippy_dev/src/fmt.rs
index c6673859282..790dafa811f 100644
--- a/src/tools/clippy/clippy_dev/src/fmt.rs
+++ b/src/tools/clippy/clippy_dev/src/fmt.rs
@@ -179,8 +179,8 @@ fn fmt_conf(check: bool) -> Result<(), Error> {
                 #[expect(clippy::drain_collect)]
                 fields.push(ClippyConf {
                     name,
-                    lints: lints.drain(..).collect(),
                     attrs: &conf[attrs_start..attrs_end],
+                    lints: lints.drain(..).collect(),
                     field: conf[field_start..i].trim_end(),
                 });
                 attrs_start = i;
@@ -191,8 +191,8 @@ fn fmt_conf(check: bool) -> Result<(), Error> {
                 #[expect(clippy::drain_collect)]
                 fields.push(ClippyConf {
                     name,
-                    lints: lints.drain(..).collect(),
                     attrs: &conf[attrs_start..attrs_end],
+                    lints: lints.drain(..).collect(),
                     field: conf[field_start..i].trim_end(),
                 });
                 attrs_start = i;
@@ -220,8 +220,8 @@ fn fmt_conf(check: bool) -> Result<(), Error> {
     }
     fields.push(ClippyConf {
         name,
-        lints,
         attrs: &conf[attrs_start..attrs_end],
+        lints,
         field: conf[field_start..].trim_end(),
     });
 
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index c1f8e82f698..b575ac1bf4c 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "clippy_lints"
 # begin autogenerated version
-version = "0.1.85"
+version = "0.1.86"
 # end autogenerated version
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
diff --git a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
index 74153990266..380b094d017 100644
--- a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
+++ b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
@@ -428,8 +428,8 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
 
             // Makes a note of the current item for comparison with the next.
             cur_t = Some(CurItem {
-                order: module_level_order,
                 item,
+                order: module_level_order,
                 name: get_item_name(item),
             });
         }
@@ -464,7 +464,7 @@ fn convert_module_item_kind(value: &ItemKind<'_>) -> SourceItemOrderingModuleIte
         ItemKind::Use(..) => Use,
         ItemKind::Static(..) => Static,
         ItemKind::Const(..) => Const,
-        ItemKind::Fn{ .. } => Fn,
+        ItemKind::Fn { .. } => Fn,
         ItemKind::Macro(..) => Macro,
         ItemKind::Mod(..) => Mod,
         ItemKind::ForeignMod { .. } => ForeignMod,
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 32c28c09c36..8c91c65eaf7 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
@@ -66,7 +66,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item_span: Span, attrs: &[Attribute])
 
 fn lint_mixed_attrs(cx: &EarlyContext<'_>, attrs: &[Attribute]) {
     let mut attrs_iter = attrs.iter().filter(|attr| !attr.span.from_expansion());
-    let span = if let (Some(first), Some(last)) = (attrs_iter.next(), attrs_iter.last()) {
+    let span = if let (Some(first), Some(last)) = (attrs_iter.next(), attrs_iter.next_back()) {
         first.span.with_hi(last.span.hi())
     } else {
         return;
diff --git a/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs
index 67aa33ca06c..6057144bc6a 100644
--- a/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs
@@ -1,11 +1,13 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::Msrv;
-use clippy_utils::source::snippet_with_context;
+use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
+use clippy_utils::sugg::has_enclosing_paren;
 use clippy_utils::{is_lint_allowed, msrvs, std_or_core};
 use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Ty, TyKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::adjustment::Adjust;
+use rustc_span::BytePos;
 
 use super::BORROW_AS_PTR;
 
@@ -32,12 +34,21 @@ pub(super) fn check<'tcx>(
             return false;
         }
 
-        let suggestion = if msrv.meets(msrvs::RAW_REF_OP) {
+        let (suggestion, span) = if msrv.meets(msrvs::RAW_REF_OP) {
             let operator_kind = match mutability {
                 Mutability::Not => "const",
                 Mutability::Mut => "mut",
             };
-            format!("&raw {operator_kind} {snip}")
+            // Make sure that the span to be replaced doesn't include parentheses, that could break the
+            // suggestion.
+            let span = if has_enclosing_paren(snippet_with_applicability(cx, expr.span, "", &mut app)) {
+                expr.span
+                    .with_lo(expr.span.lo() + BytePos(1))
+                    .with_hi(expr.span.hi() - BytePos(1))
+            } else {
+                expr.span
+            };
+            (format!("&raw {operator_kind} {snip}"), span)
         } else {
             let Some(std_or_core) = std_or_core(cx) else {
                 return false;
@@ -46,18 +57,10 @@ pub(super) fn check<'tcx>(
                 Mutability::Not => "addr_of",
                 Mutability::Mut => "addr_of_mut",
             };
-            format!("{std_or_core}::ptr::{macro_name}!({snip})")
+            (format!("{std_or_core}::ptr::{macro_name}!({snip})"), expr.span)
         };
 
-        span_lint_and_sugg(
-            cx,
-            BORROW_AS_PTR,
-            expr.span,
-            "borrow as raw pointer",
-            "try",
-            suggestion,
-            Applicability::MachineApplicable,
-        );
+        span_lint_and_sugg(cx, BORROW_AS_PTR, span, "borrow as raw pointer", "try", suggestion, app);
         return true;
     }
     false
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index c64c0e15144..d90cf124fe4 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -836,11 +836,8 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
             as_underscore::check(cx, expr, cast_to_hir);
             as_pointer_underscore::check(cx, cast_to, cast_to_hir);
 
-            let was_borrow_as_ptr_emitted = if self.msrv.meets(msrvs::BORROW_AS_PTR) {
-                borrow_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir, &self.msrv)
-            } else {
-                false
-            };
+            let was_borrow_as_ptr_emitted = self.msrv.meets(msrvs::BORROW_AS_PTR)
+                && borrow_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir, &self.msrv);
             if self.msrv.meets(msrvs::PTR_FROM_REF) && !was_borrow_as_ptr_emitted {
                 ref_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir);
             }
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 7451fb909ef..3ff10d850f8 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -372,6 +372,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::methods::CLONE_ON_REF_PTR_INFO,
     crate::methods::COLLAPSIBLE_STR_REPLACE_INFO,
     crate::methods::CONST_IS_EMPTY_INFO,
+    crate::methods::DOUBLE_ENDED_ITERATOR_LAST_INFO,
     crate::methods::DRAIN_COLLECT_INFO,
     crate::methods::ERR_EXPECT_INFO,
     crate::methods::EXPECT_FUN_CALL_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
index 3b3a78cb115..c04a73c890f 100644
--- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
+++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
@@ -3,8 +3,11 @@ use clippy_utils::numeric_literal;
 use clippy_utils::source::snippet_opt;
 use rustc_ast::ast::{LitFloatType, LitIntType, LitKind};
 use rustc_errors::Applicability;
-use rustc_hir::intravisit::{Visitor, walk_expr, walk_stmt};
-use rustc_hir::{Block, Body, ConstContext, Expr, ExprKind, FnRetTy, HirId, Lit, Stmt, StmtKind, StructTailExpr};
+use rustc_hir::intravisit::{Visitor, walk_expr, walk_pat, walk_stmt};
+use rustc_hir::{
+    Block, Body, ConstContext, Expr, ExprKind, FnRetTy, HirId, Lit, Pat, PatExpr, PatExprKind, PatKind, Stmt, StmtKind,
+    StructTailExpr,
+};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, FloatTy, IntTy, PolyFnSig, Ty};
@@ -219,6 +222,22 @@ impl<'tcx> Visitor<'tcx> for NumericFallbackVisitor<'_, 'tcx> {
         walk_expr(self, expr);
     }
 
+    fn visit_pat(&mut self, pat: &'tcx Pat<'_>) {
+        match pat.kind {
+            PatKind::Expr(&PatExpr {
+                hir_id,
+                kind: PatExprKind::Lit { lit, .. },
+                ..
+            }) => {
+                let ty = self.cx.typeck_results().node_type(hir_id);
+                self.check_lit(lit, ty, hir_id);
+                return;
+            },
+            _ => {},
+        }
+        walk_pat(self, pat)
+    }
+
     fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
         match stmt.kind {
             // we cannot check the exact type since it's a hir::Ty which does not implement `is_numeric`
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 7c2f5efd8dd..91ddbb44ff8 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -419,7 +419,7 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
         id: LocalDefId,
     ) -> Self::Result {
         if let Some(header) = kind.header()
-            && header.safety.is_unsafe()
+            && header.is_unsafe()
         {
             ControlFlow::Break(())
         } else {
diff --git a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
index 40377dd841e..8e2af6bf14a 100644
--- a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
@@ -1,6 +1,6 @@
 use super::{DocHeaders, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_note};
-use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
+use clippy_utils::ty::{implements_trait_with_env, is_type_diagnostic_item};
 use clippy_utils::{is_doc_hidden, return_ty};
 use rustc_hir::{BodyId, FnSig, OwnerId, Safety};
 use rustc_lint::LateContext;
@@ -32,7 +32,7 @@ pub fn check(
     }
 
     let span = cx.tcx.def_span(owner_id);
-    match (headers.safety, sig.header.safety) {
+    match (headers.safety, sig.header.safety()) {
         (false, Safety::Unsafe) => span_lint(
             cx,
             MISSING_SAFETY_DOC,
@@ -70,7 +70,14 @@ pub fn check(
             && let typeck = cx.tcx.typeck_body(body_id)
             && let body = cx.tcx.hir().body(body_id)
             && let ret_ty = typeck.expr_ty(body.value)
-            && implements_trait(cx, ret_ty, future, &[])
+            && implements_trait_with_env(
+                cx.tcx,
+                ty::TypingEnv::non_body_analysis(cx.tcx, owner_id.def_id),
+                ret_ty,
+                future,
+                Some(owner_id.def_id.to_def_id()),
+                &[],
+            )
             && let ty::Coroutine(_, subs) = ret_ty.kind()
             && is_type_diagnostic_item(cx, subs.as_coroutine().return_ty(), sym::Result)
         {
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index c835b81679b..7561a6cf2a7 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -797,8 +797,8 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
         parser.into_offset_iter(),
         &doc,
         Fragments {
-            fragments: &fragments,
             doc: &doc,
+            fragments: &fragments,
         },
     ))
 }
diff --git a/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs b/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs
index 2327da0ccff..1f89cab9148 100644
--- a/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs
@@ -25,7 +25,7 @@ pub(super) fn check(
             // page. So associated items or impl blocks are not part of this list.
             ItemKind::Static(..)
                 | ItemKind::Const(..)
-                | ItemKind::Fn{ .. }
+                | ItemKind::Fn { .. }
                 | ItemKind::Macro(..)
                 | ItemKind::Mod(..)
                 | ItemKind::TyAlias(..)
diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs
index 70524e458c7..2bec4f2f99e 100644
--- a/src/tools/clippy/clippy_lints/src/entry.rs
+++ b/src/tools/clippy/clippy_lints/src/entry.rs
@@ -678,12 +678,12 @@ fn find_insert_calls<'tcx>(
         map: contains_expr.map,
         key: contains_expr.key,
         ctxt: expr.span.ctxt(),
-        edits: Vec::new(),
-        is_map_used: false,
         allow_insert_closure: true,
         can_use_entry: true,
         in_tail_pos: true,
         is_single_insert: true,
+        is_map_used: false,
+        edits: Vec::new(),
         loops: Vec::new(),
         locals: HirIdSet::default(),
     };
diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
index 9c8edfd6113..8a5cf7f56d5 100644
--- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
+++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
@@ -56,7 +56,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
         PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)),
         PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a),
         PatKind::Ref(x, _) | PatKind::Box(x) | PatKind::Deref(x) | PatKind::Guard(x, _) => unary_pattern(x),
-        PatKind::Path(_) | PatKind::Lit(_) => true,
+        PatKind::Path(_) | PatKind::Expr(_) => true,
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 2cd48ef98e5..c0b4743fd71 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -182,7 +182,7 @@ fn check_clousure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tc
                 // will succeed iff `T: 'static`. But the region of `T` is always erased by `typeck.expr_ty()` when
                 // T is a generic type. For example, return type of `Option<String>::as_deref()` is a generic.
                 // So we have a hack like this.
-                && generic_args.len() > 0
+                && !generic_args.is_empty()
             {
                 return;
             }
diff --git a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
index 017571c38db..854fe144c29 100644
--- a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
@@ -34,7 +34,7 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body:
         ImplicitSelfKind::None => return,
     };
 
-    let name = if sig.header.safety.is_unsafe() {
+    let name = if sig.header.is_unsafe() {
         name.strip_suffix("_unchecked").unwrap_or(name)
     } else {
         name
diff --git a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
index 3ded8dc3012..8a74951ef63 100644
--- a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
@@ -20,8 +20,8 @@ pub(super) fn check_fn<'tcx>(
     def_id: LocalDefId,
 ) {
     let safety = match kind {
-        intravisit::FnKind::ItemFn(_, _, hir::FnHeader { safety, .. }) => safety,
-        intravisit::FnKind::Method(_, sig) => sig.header.safety,
+        intravisit::FnKind::ItemFn(_, _, header) => header.safety(),
+        intravisit::FnKind::Method(_, sig) => sig.header.safety(),
         intravisit::FnKind::Closure => return,
     };
 
@@ -31,7 +31,7 @@ pub(super) fn check_fn<'tcx>(
 pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
     if let hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(eid)) = item.kind {
         let body = cx.tcx.hir().body(eid);
-        check_raw_ptr(cx, sig.header.safety, sig.decl, body, item.owner_id.def_id);
+        check_raw_ptr(cx, sig.header.safety(), sig.decl, body, item.owner_id.def_id);
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
index 4427edb752e..ef272c305d3 100644
--- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
@@ -243,11 +243,11 @@ fn collect_supertrait_bounds<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds
                 && !predicates.is_empty()
             {
                 Some(ImplTraitBound {
+                    span: bound.span(),
                     predicates,
+                    trait_def_id,
                     args: path.args.map_or([].as_slice(), |p| p.args),
                     constraints: path.args.map_or([].as_slice(), |p| p.constraints),
-                    trait_def_id,
-                    span: bound.span(),
                 })
             } else {
                 None
diff --git a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
index 4fcd2abb769..39ff3c13bcc 100644
--- a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
+++ b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
@@ -1,19 +1,21 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_config::Conf;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::fulfill_or_allowed;
 use clippy_utils::source::snippet;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::Applicability;
-use rustc_hir::{self as hir, ExprKind, StructTailExpr};
+use rustc_hir::{self as hir, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::declare_lint_pass;
+use rustc_middle::ty::TyCtxt;
+use rustc_session::impl_lint_pass;
+use rustc_span::Span;
 use rustc_span::symbol::Symbol;
-use std::fmt::{self, Write as _};
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for struct constructors where all fields are shorthand and
-    /// the order of the field init shorthand in the constructor is inconsistent
-    /// with the order in the struct definition.
+    /// Checks for struct constructors where the order of the field
+    /// init in the constructor is inconsistent with the order in the
+    /// struct definition.
     ///
     /// ### Why is this bad?
     /// Since the order of fields in a constructor doesn't affect the
@@ -59,16 +61,37 @@ declare_clippy_lint! {
     #[clippy::version = "1.52.0"]
     pub INCONSISTENT_STRUCT_CONSTRUCTOR,
     pedantic,
-    "the order of the field init shorthand is inconsistent with the order in the struct definition"
+    "the order of the field init is inconsistent with the order in the struct definition"
 }
 
-declare_lint_pass!(InconsistentStructConstructor => [INCONSISTENT_STRUCT_CONSTRUCTOR]);
+pub struct InconsistentStructConstructor {
+    lint_inconsistent_struct_field_initializers: bool,
+}
+
+impl InconsistentStructConstructor {
+    pub fn new(conf: &'static Conf) -> Self {
+        Self {
+            lint_inconsistent_struct_field_initializers: conf.lint_inconsistent_struct_field_initializers,
+        }
+    }
+}
+
+impl_lint_pass!(InconsistentStructConstructor => [INCONSISTENT_STRUCT_CONSTRUCTOR]);
 
 impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
-        if let ExprKind::Struct(qpath, fields, base) = expr.kind
-            && fields.iter().all(|f| f.is_shorthand)
-            && !expr.span.from_expansion()
+        let ExprKind::Struct(_, fields, _) = expr.kind else {
+            return;
+        };
+        let all_fields_are_shorthand = fields.iter().all(|f| f.is_shorthand);
+        let applicability = if all_fields_are_shorthand {
+            Applicability::MachineApplicable
+        } else if self.lint_inconsistent_struct_field_initializers {
+            Applicability::MaybeIncorrect
+        } else {
+            return;
+        };
+        if !expr.span.from_expansion()
             && let ty = cx.typeck_results().expr_ty(expr)
             && let Some(adt_def) = ty.ty_adt_def()
             && adt_def.is_struct()
@@ -85,36 +108,24 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor {
                 return;
             }
 
-            let mut ordered_fields: Vec<_> = fields.iter().map(|f| f.ident.name).collect();
-            ordered_fields.sort_unstable_by_key(|id| def_order_map[id]);
-
-            let mut fields_snippet = String::new();
-            let (last_ident, idents) = ordered_fields.split_last().unwrap();
-            for ident in idents {
-                let _: fmt::Result = write!(fields_snippet, "{ident}, ");
-            }
-            fields_snippet.push_str(&last_ident.to_string());
-
-            let base_snippet = if let StructTailExpr::Base(base) = base {
-                format!(", ..{}", snippet(cx, base.span, ".."))
-            } else {
-                String::new()
-            };
-
-            let sugg = format!(
-                "{} {{ {fields_snippet}{base_snippet} }}",
-                snippet(cx, qpath.span(), ".."),
-            );
+            let span = field_with_attrs_span(cx.tcx, fields.first().unwrap())
+                .with_hi(field_with_attrs_span(cx.tcx, fields.last().unwrap()).hi());
 
             if !fulfill_or_allowed(cx, INCONSISTENT_STRUCT_CONSTRUCTOR, Some(ty_hir_id)) {
-                span_lint_and_sugg(
+                span_lint_and_then(
                     cx,
                     INCONSISTENT_STRUCT_CONSTRUCTOR,
-                    expr.span,
+                    span,
                     "struct constructor field order is inconsistent with struct definition field order",
-                    "try",
-                    sugg,
-                    Applicability::MachineApplicable,
+                    |diag| {
+                        let msg = if all_fields_are_shorthand {
+                            "try"
+                        } else {
+                            "if the field evaluation order doesn't matter, try"
+                        };
+                        let sugg = suggestion(cx, fields, &def_order_map);
+                        diag.span_suggestion(span, msg, sugg, applicability);
+                    },
                 );
             }
         }
@@ -135,3 +146,45 @@ fn is_consistent_order<'tcx>(fields: &'tcx [hir::ExprField<'tcx>], def_order_map
 
     true
 }
+
+fn suggestion<'tcx>(
+    cx: &LateContext<'_>,
+    fields: &'tcx [hir::ExprField<'tcx>],
+    def_order_map: &FxHashMap<Symbol, usize>,
+) -> String {
+    let ws = fields
+        .windows(2)
+        .map(|w| {
+            let w0_span = field_with_attrs_span(cx.tcx, &w[0]);
+            let w1_span = field_with_attrs_span(cx.tcx, &w[1]);
+            let span = w0_span.between(w1_span);
+            snippet(cx, span, " ")
+        })
+        .collect::<Vec<_>>();
+
+    let mut fields = fields.to_vec();
+    fields.sort_unstable_by_key(|field| def_order_map[&field.ident.name]);
+    let field_snippets = fields
+        .iter()
+        .map(|field| snippet(cx, field_with_attrs_span(cx.tcx, field), ".."))
+        .collect::<Vec<_>>();
+
+    assert_eq!(field_snippets.len(), ws.len() + 1);
+
+    let mut sugg = String::new();
+    for i in 0..field_snippets.len() {
+        sugg += &field_snippets[i];
+        if i < ws.len() {
+            sugg += &ws[i];
+        }
+    }
+    sugg
+}
+
+fn field_with_attrs_span(tcx: TyCtxt<'_>, field: &hir::ExprField<'_>) -> Span {
+    if let Some(attr) = tcx.hir().attrs(field.hir_id).first() {
+        field.span.with_lo(attr.span.lo())
+    } else {
+        field.span
+    }
+}
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 e096dd25175..415b47adac5 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
@@ -95,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
         if let ImplItemKind::Fn(ref signature, _) = impl_item.kind
             // #11201
             && let header = signature.header
-            && header.safety.is_safe()
+            && header.is_safe()
             && header.abi == Abi::Rust
             && impl_item.ident.name == sym::to_string
             && let decl = signature.decl
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 3ea758e176f..5418acc105e 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::{SpanRangeExt, snippet_with_context};
 use clippy_utils::sugg::{Sugg, has_enclosing_paren};
+use clippy_utils::ty::implements_trait;
 use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, is_trait_method, peel_ref_operators};
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
@@ -8,8 +9,8 @@ use rustc_hir::def::Res;
 use rustc_hir::def_id::{DefId, DefIdSet};
 use rustc_hir::{
     AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind,
-    ImplicitSelfKind, Item, ItemKind, Mutability, Node, OpaqueTyOrigin, PatKind, PathSegment, PrimTy, QPath,
-    TraitItemRef, TyKind,
+    ImplicitSelfKind, Item, ItemKind, Mutability, Node, OpaqueTyOrigin, PatExprKind, PatKind, PathSegment, PrimTy,
+    QPath, TraitItemRef, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
@@ -163,7 +164,13 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
         if let ExprKind::Let(lt) = expr.kind
             && match lt.pat.kind {
                 PatKind::Slice([], None, []) => true,
-                PatKind::Lit(lit) if is_empty_string(lit) => true,
+                PatKind::Expr(lit) => match lit.kind {
+                    PatExprKind::Lit { lit, .. } => match lit.node {
+                        LitKind::Str(lit, _) => lit.as_str().is_empty(),
+                        _ => false,
+                    },
+                    _ => false,
+                },
                 _ => false,
             }
             && !expr.span.from_expansion()
@@ -620,18 +627,30 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
         })
     }
 
-    let ty = &cx.typeck_results().expr_ty(expr).peel_refs();
-    match ty.kind() {
-        ty::Dynamic(tt, ..) => tt.principal().is_some_and(|principal| {
-            let is_empty = sym!(is_empty);
-            cx.tcx
-                .associated_items(principal.def_id())
-                .filter_by_name_unhygienic(is_empty)
-                .any(|item| is_is_empty(cx, item))
-        }),
-        ty::Alias(ty::Projection, proj) => has_is_empty_impl(cx, proj.def_id),
-        ty::Adt(id, _) => has_is_empty_impl(cx, id.did()),
-        ty::Array(..) | ty::Slice(..) | ty::Str => true,
-        _ => false,
+    fn ty_has_is_empty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, depth: usize) -> bool {
+        match ty.kind() {
+            ty::Dynamic(tt, ..) => tt.principal().is_some_and(|principal| {
+                let is_empty = sym!(is_empty);
+                cx.tcx
+                    .associated_items(principal.def_id())
+                    .filter_by_name_unhygienic(is_empty)
+                    .any(|item| is_is_empty(cx, item))
+            }),
+            ty::Alias(ty::Projection, proj) => has_is_empty_impl(cx, proj.def_id),
+            ty::Adt(id, _) => {
+                has_is_empty_impl(cx, id.did())
+                    || (cx.tcx.recursion_limit().value_within_limit(depth)
+                        && cx.tcx.get_diagnostic_item(sym::Deref).is_some_and(|deref_id| {
+                            implements_trait(cx, ty, deref_id, &[])
+                                && cx
+                                    .get_associated_type(ty, deref_id, "Target")
+                                    .is_some_and(|deref_ty| ty_has_is_empty(cx, deref_ty, depth + 1))
+                        }))
+            },
+            ty::Array(..) | ty::Slice(..) | ty::Str => true,
+            _ => false,
+        }
     }
+
+    ty_has_is_empty(cx, cx.typeck_results().expr_ty(expr).peel_refs(), 0)
 }
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index d33013ba663..fad6f9d0880 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -649,7 +649,11 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(|_| Box::new(implicit_return::ImplicitReturn));
     store.register_late_pass(move |_| Box::new(implicit_saturating_sub::ImplicitSaturatingSub::new(conf)));
     store.register_late_pass(|_| Box::new(default_numeric_fallback::DefaultNumericFallback));
-    store.register_late_pass(|_| Box::new(inconsistent_struct_constructor::InconsistentStructConstructor));
+    store.register_late_pass(move |_| {
+        Box::new(inconsistent_struct_constructor::InconsistentStructConstructor::new(
+            conf,
+        ))
+    });
     store.register_late_pass(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions));
     store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports));
     store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(conf)));
diff --git a/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs b/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs
index f88605fbea0..6be30f3c957 100644
--- a/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs
@@ -38,8 +38,8 @@ pub(super) fn check<'tcx>(
         cx,
         label,
         inner_labels: label.into_iter().collect(),
-        is_finite: false,
         loop_depth: 0,
+        is_finite: false,
     };
     loop_visitor.visit_block(loop_block);
 
diff --git a/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs b/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs
index 312bcb55a95..006addb987f 100644
--- a/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs
+++ b/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs
@@ -220,11 +220,11 @@ impl<'tcx> LateLintPass<'tcx> for ExprMetavarsInUnsafe {
         // `check_stmt_post` on `(Late)LintPass`, which we'd need to detect when we're leaving a macro span
 
         let mut vis = BodyVisitor {
+            macro_unsafe_blocks: Vec::new(),
             #[expect(clippy::bool_to_int_with_if)] // obfuscates the meaning
             expn_depth: if body.value.span.from_expansion() { 1 } else { 0 },
-            macro_unsafe_blocks: Vec::new(),
-            lint: self,
-            cx
+            cx,
+            lint: self
         };
         vis.visit_body(body);
     }
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 bbb89bee835..aa59b047b16 100644
--- a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs
@@ -2,14 +2,15 @@ use clippy_utils::SpanlessEq;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::sugg::Sugg;
-use rustc_ast::{BinOpKind, LitKind};
+use clippy_utils::sugg::{Sugg, has_enclosing_paren};
+use rustc_ast::{BinOpKind, LitIntType, LitKind, UnOp};
 use rustc_data_structures::packed::Pu128;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self};
 use rustc_session::impl_lint_pass;
+use rustc_span::source_map::Spanned;
 use rustc_span::symbol::Symbol;
 
 use clippy_config::Conf;
@@ -138,9 +139,40 @@ fn build_suggestion(
     applicability: &mut Applicability,
 ) {
     let dividend_sugg = Sugg::hir_with_applicability(cx, lhs, "..", applicability).maybe_par();
+    let type_suffix = if cx.typeck_results().expr_ty(lhs).is_numeric()
+        && matches!(
+            lhs.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 {
+        String::new()
+    };
+    let dividend_sugg_str = dividend_sugg.into_string();
+    // If `dividend_sugg` has enclosing paren like `(-2048)` and we need to add type suffix in the
+    // suggestion message, we want to make a suggestion string before `div_ceil` like
+    // `(-2048_{type_suffix})`.
+    let suggestion_before_div_ceil = if has_enclosing_paren(&dividend_sugg_str) {
+        format!(
+            "{}{})",
+            &dividend_sugg_str[..dividend_sugg_str.len() - 1].to_string(),
+            type_suffix
+        )
+    } else {
+        format!("{dividend_sugg_str}{type_suffix}")
+    };
     let divisor_snippet = snippet_with_applicability(cx, rhs.span.source_callsite(), "..", applicability);
 
-    let sugg = format!("{dividend_sugg}.div_ceil({divisor_snippet})");
+    let sugg = format!("{suggestion_before_div_ceil}.div_ceil({divisor_snippet})");
 
     span_lint_and_sugg(
         cx,
diff --git a/src/tools/clippy/clippy_lints/src/manual_ignore_case_cmp.rs b/src/tools/clippy/clippy_lints/src/manual_ignore_case_cmp.rs
index dabfac3f613..506f4f6d9de 100644
--- a/src/tools/clippy/clippy_lints/src/manual_ignore_case_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_ignore_case_cmp.rs
@@ -32,7 +32,7 @@ declare_clippy_lint! {
     ///    a.eq_ignore_ascii_case(b) || a.eq_ignore_ascii_case("abc")
     /// }
     /// ```
-    #[clippy::version = "1.82.0"]
+    #[clippy::version = "1.84.0"]
     pub MANUAL_IGNORE_CASE_CMP,
     perf,
     "manual case-insensitive ASCII comparison"
diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
index 3f01f3cf30a..9860deba843 100644
--- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
@@ -7,9 +7,9 @@ use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operator
 use rustc_ast::LitKind::{Byte, Char};
 use rustc_ast::ast::RangeLimits;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, Node, Param, PatKind, RangeEnd};
+use rustc_hir::{Expr, ExprKind, Node, Param, PatKind, RangeEnd, PatExpr, PatExprKind, Lit};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
+use rustc_middle::ty::{self, Ty};
 use rustc_session::impl_lint_pass;
 use rustc_span::{Span, sym};
 
@@ -114,8 +114,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
             && !matches!(cx.typeck_results().expr_ty(arg).peel_refs().kind(), ty::Param(_))
         {
             let arg = peel_ref_operators(cx, arg);
-            let ty_sugg = get_ty_sugg(cx, arg, start);
-            let range = check_range(start, end);
+            let ty_sugg = get_ty_sugg(cx, arg);
+            let range = check_expr_range(start, end);
             check_is_ascii(cx, expr.span, arg, &range, ty_sugg);
         }
     }
@@ -123,19 +123,14 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
     extract_msrv_attr!(LateContext);
 }
 
-fn get_ty_sugg(cx: &LateContext<'_>, arg: &Expr<'_>, bound_expr: &Expr<'_>) -> Option<(Span, &'static str)> {
-    if let ExprKind::Lit(lit) = bound_expr.kind
-        && let local_hid = path_to_local(arg)?
-        && let Node::Param(Param { ty_span, span, .. }) = cx.tcx.parent_hir_node(local_hid)
+fn get_ty_sugg<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'_>) -> Option<(Span, Ty<'tcx>)> {
+    let local_hid = path_to_local(arg)?;
+    if let Node::Param(Param { ty_span, span, .. }) = cx.tcx.parent_hir_node(local_hid)
         // `ty_span` and `span` are the same for inferred type, thus a type suggestion must be given
         && ty_span == span
     {
-        let ty_str = match lit.node {
-            Char(_) => "char",
-            Byte(_) => "u8",
-            _ => return None,
-        };
-        return Some((*ty_span, ty_str));
+        let arg_type = cx.typeck_results().expr_ty(arg);
+        return Some((*ty_span, arg_type));
     }
     None
 }
@@ -145,7 +140,7 @@ fn check_is_ascii(
     span: Span,
     recv: &Expr<'_>,
     range: &CharRange,
-    ty_sugg: Option<(Span, &'_ str)>,
+    ty_sugg: Option<(Span, Ty<'_>)>,
 ) {
     let sugg = match range {
         CharRange::UpperChar => "is_ascii_uppercase",
@@ -159,8 +154,8 @@ fn check_is_ascii(
     let mut app = Applicability::MachineApplicable;
     let recv = Sugg::hir_with_context(cx, recv, span.ctxt(), default_snip, &mut app).maybe_par();
     let mut suggestion = vec![(span, format!("{recv}.{sugg}()"))];
-    if let Some((ty_span, ty_str)) = ty_sugg {
-        suggestion.push((ty_span, format!("{recv}: {ty_str}")));
+    if let Some((ty_span, ty)) = ty_sugg {
+        suggestion.push((ty_span, format!("{recv}: {ty}")));
     }
 
     span_lint_and_then(
@@ -196,19 +191,33 @@ fn check_pat(pat_kind: &PatKind<'_>) -> CharRange {
     }
 }
 
-fn check_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange {
+fn check_expr_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange {
     if let ExprKind::Lit(start_lit) = &start.kind
         && let ExprKind::Lit(end_lit) = &end.kind
     {
-        match (&start_lit.node, &end_lit.node) {
-            (Char('a'), Char('z')) | (Byte(b'a'), Byte(b'z')) => CharRange::LowerChar,
-            (Char('A'), Char('Z')) | (Byte(b'A'), Byte(b'Z')) => CharRange::UpperChar,
-            (Char('a'), Char('f')) | (Byte(b'a'), Byte(b'f')) => CharRange::LowerHexLetter,
-            (Char('A'), Char('F')) | (Byte(b'A'), Byte(b'F')) => CharRange::UpperHexLetter,
-            (Char('0'), Char('9')) | (Byte(b'0'), Byte(b'9')) => CharRange::Digit,
-            _ => CharRange::Otherwise,
-        }
+        check_lit_range(start_lit, end_lit)
     } else {
         CharRange::Otherwise
     }
 }
+
+fn check_range(start: &PatExpr<'_>, end: &PatExpr<'_>) -> CharRange {
+    if let PatExprKind::Lit{ lit: start_lit, negated: false } = &start.kind
+        && let PatExprKind::Lit{ lit: end_lit, negated: false  } = &end.kind
+    {
+        check_lit_range(start_lit, end_lit)
+    } else {
+        CharRange::Otherwise
+    }
+}
+
+fn check_lit_range(start_lit: &Lit, end_lit: &Lit) -> CharRange {
+    match (&start_lit.node, &end_lit.node) {
+        (Char('a'), Char('z')) | (Byte(b'a'), Byte(b'z')) => CharRange::LowerChar,
+        (Char('A'), Char('Z')) | (Byte(b'A'), Byte(b'Z')) => CharRange::UpperChar,
+        (Char('a'), Char('f')) | (Byte(b'a'), Byte(b'f')) => CharRange::LowerHexLetter,
+        (Char('A'), Char('F')) | (Byte(b'A'), Byte(b'F')) => CharRange::UpperHexLetter,
+        (Char('0'), Char('9')) | (Byte(b'0'), Byte(b'9')) => CharRange::Digit,
+        _ => CharRange::Otherwise,
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs
index ffa3eacf354..2e5a92915d9 100644
--- a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs
@@ -3,7 +3,7 @@ use clippy_utils::source::SpanRangeExt;
 use rustc_ast::LitKind;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd, UnOp};
+use rustc_hir::{PatExpr, PatExprKind, PatKind, RangeEnd};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
@@ -38,14 +38,13 @@ declare_clippy_lint! {
 }
 declare_lint_pass!(ManualRangePatterns => [MANUAL_RANGE_PATTERNS]);
 
-fn expr_as_i128(expr: &Expr<'_>) -> Option<i128> {
-    if let ExprKind::Unary(UnOp::Neg, expr) = expr.kind {
-        expr_as_i128(expr).map(|num| -num)
-    } else if let ExprKind::Lit(lit) = expr.kind
+fn expr_as_i128(expr: &PatExpr<'_>) -> Option<i128> {
+    if let PatExprKind::Lit { lit, negated } = expr.kind
         && let LitKind::Int(num, _) = lit.node
     {
         // Intentionally not handling numbers greater than i128::MAX (for u128 literals) for now.
-        num.get().try_into().ok()
+        let n = i128::try_from(num.get()).ok()?;
+        Some(if negated { -n } else { n })
     } else {
         None
     }
@@ -58,7 +57,7 @@ struct Num {
 }
 
 impl Num {
-    fn new(expr: &Expr<'_>) -> Option<Self> {
+    fn new(expr: &PatExpr<'_>) -> Option<Self> {
         Some(Self {
             val: expr_as_i128(expr)?,
             span: expr.span,
@@ -90,7 +89,7 @@ impl LateLintPass<'_> for ManualRangePatterns {
             let mut ranges_found = Vec::new();
 
             for pat in pats {
-                if let PatKind::Lit(lit) = pat.kind
+                if let PatKind::Expr(lit) = pat.kind
                     && let Some(num) = Num::new(lit)
                 {
                     numbers_found.insert(num.val);
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_bool.rs b/src/tools/clippy/clippy_lints/src/matches/match_bool.rs
index 69105ff0d5c..7e43d222a66 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_bool.rs
@@ -4,7 +4,7 @@ use clippy_utils::source::{expr_block, snippet};
 use clippy_utils::sugg::Sugg;
 use rustc_ast::LitKind;
 use rustc_errors::Applicability;
-use rustc_hir::{Arm, Expr, ExprKind, PatKind};
+use rustc_hir::{Arm, Expr, PatExprKind, PatKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
 
@@ -21,8 +21,8 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>]
             move |diag| {
                 if arms.len() == 2 {
                     // no guards
-                    let exprs = if let PatKind::Lit(arm_bool) = arms[0].pat.kind {
-                        if let ExprKind::Lit(lit) = arm_bool.kind {
+                    let exprs = if let PatKind::Expr(arm_bool) = arms[0].pat.kind {
+                        if let PatExprKind::Lit { lit, .. } = arm_bool.kind {
                             match lit.node {
                                 LitKind::Bool(true) => Some((arms[0].body, arms[1].body)),
                                 LitKind::Bool(false) => Some((arms[1].body, arms[0].body)),
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
index 4b731d75972..28e05c273d5 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
@@ -7,7 +7,7 @@ use rustc_arena::DroplessArena;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{Arm, Expr, ExprKind, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatKind, RangeEnd};
+use rustc_hir::{Arm, Expr, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatExprKind, PatKind, RangeEnd};
 use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::ty;
@@ -311,9 +311,9 @@ impl<'a> NormalizedPat<'a> {
                 );
                 Self::Tuple(None, pats)
             },
-            PatKind::Lit(e) => match &e.kind {
+            PatKind::Expr(e) => match &e.kind {
                 // TODO: Handle negative integers. They're currently treated as a wild match.
-                ExprKind::Lit(lit) => match lit.node {
+                PatExprKind::Lit { lit, negated: false } => match lit.node {
                     LitKind::Str(sym, _) => Self::LitStr(sym),
                     LitKind::ByteStr(ref bytes, _) | LitKind::CStr(ref bytes, _) => Self::LitBytes(bytes),
                     LitKind::Byte(val) => Self::LitInt(val.into()),
@@ -330,7 +330,7 @@ impl<'a> NormalizedPat<'a> {
                 let start = match start {
                     None => 0,
                     Some(e) => match &e.kind {
-                        ExprKind::Lit(lit) => match lit.node {
+                        PatExprKind::Lit { lit, negated: false } => match lit.node {
                             LitKind::Int(val, _) => val.get(),
                             LitKind::Char(val) => val.into(),
                             LitKind::Byte(val) => val.into(),
@@ -342,7 +342,7 @@ impl<'a> NormalizedPat<'a> {
                 let (end, bounds) = match end {
                     None => (u128::MAX, RangeEnd::Included),
                     Some(e) => match &e.kind {
-                        ExprKind::Lit(lit) => match lit.node {
+                        PatExprKind::Lit { lit, negated: false } => match lit.node {
                             LitKind::Int(val, _) => (val.get(), bounds),
                             LitKind::Char(val) => (val.into(), bounds),
                             LitKind::Byte(val) => (val.into(), bounds),
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
index 1267fc9d0a5..9f5b7c855a1 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
@@ -5,7 +5,7 @@ use clippy_utils::ty::is_type_lang_item;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{Visitor, walk_expr};
-use rustc_hir::{Arm, Expr, ExprKind, LangItem, PatKind};
+use rustc_hir::{Arm, Expr, ExprKind, PatExpr, PatExprKind, LangItem, PatKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
 use rustc_span::Span;
@@ -85,8 +85,8 @@ fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<(
     };
 
     for arm in arms {
-        if let PatKind::Lit(Expr {
-            kind: ExprKind::Lit(lit),
+        if let PatKind::Expr(PatExpr {
+            kind: PatExprKind::Lit { lit, negated: false },
             ..
         }) = arm.pat.kind
             && let LitKind::Str(symbol, _) = lit.node
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index 1fd2ebcb54a..ac1eae07eff 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -583,11 +583,6 @@ declare_clippy_lint! {
     /// are the same on purpose, you can factor them
     /// [using `|`](https://doc.rust-lang.org/book/patterns.html#multiple-patterns).
     ///
-    /// ### Known problems
-    /// False positive possible with order dependent `match`
-    /// (see issue
-    /// [#860](https://github.com/rust-lang/rust-clippy/issues/860)).
-    ///
     /// ### Example
     /// ```rust,ignore
     /// match foo {
diff --git a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
index 63bea586caf..0d5575efc22 100644
--- a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
@@ -8,7 +8,7 @@ use clippy_utils::{
 };
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::OptionNone;
-use rustc_hir::{Arm, BindingMode, ByRef, Expr, ExprKind, ItemKind, Node, Pat, PatKind, Path, QPath};
+use rustc_hir::{Arm, BindingMode, ByRef, Expr, ExprKind, ItemKind, Node, Pat, PatExprKind, PatKind, Path, QPath};
 use rustc_lint::LateContext;
 use rustc_span::sym;
 
@@ -133,7 +133,7 @@ fn expr_ty_matches_p_ty(cx: &LateContext<'_>, expr: &Expr<'_>, p_expr: &Expr<'_>
         },
         // compare match_expr ty with RetTy in `fn foo() -> RetTy`
         Node::Item(item) => {
-            if let ItemKind::Fn{ .. } = item.kind {
+            if let ItemKind::Fn { .. } = item.kind {
                 let output = cx
                     .tcx
                     .fn_sig(item.owner_id)
@@ -189,8 +189,12 @@ fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
             });
         },
         // Example: `5 => 5`
-        (PatKind::Lit(pat_lit_expr), ExprKind::Lit(expr_spanned)) => {
-            if let ExprKind::Lit(pat_spanned) = &pat_lit_expr.kind {
+        (PatKind::Expr(pat_expr_expr), ExprKind::Lit(expr_spanned)) => {
+            if let PatExprKind::Lit {
+                lit: pat_spanned,
+                negated: false,
+            } = &pat_expr_expr.kind
+            {
                 return pat_spanned.node == expr_spanned.node;
             }
         },
diff --git a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
index 856311899f2..4a5d3c516b8 100644
--- a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
@@ -34,13 +34,13 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
             if let Arm { pat, guard: None, .. } = *arm {
                 if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind {
                     let lhs_const = if let Some(lhs) = lhs {
-                        ConstEvalCtxt::new(cx).eval(lhs)?
+                        ConstEvalCtxt::new(cx).eval_pat_expr(lhs)?
                     } else {
                         let min_val_const = ty.numeric_min_val(cx.tcx)?;
                         mir_to_const(cx.tcx, mir::Const::from_ty_const(min_val_const, ty, cx.tcx))?
                     };
                     let rhs_const = if let Some(rhs) = rhs {
-                        ConstEvalCtxt::new(cx).eval(rhs)?
+                        ConstEvalCtxt::new(cx).eval_pat_expr(rhs)?
                     } else {
                         let max_val_const = ty.numeric_max_val(cx.tcx)?;
                         mir_to_const(cx.tcx, mir::Const::from_ty_const(max_val_const, ty, cx.tcx))?
@@ -57,8 +57,10 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
                     });
                 }
 
-                if let PatKind::Lit(value) = pat.kind {
-                    let value = ConstEvalCtxt::new(cx).eval_full_int(value)?;
+                if let PatKind::Expr(value) = pat.kind {
+                    let value = ConstEvalCtxt::new(cx)
+                        .eval_pat_expr(value)?
+                        .int_value(cx.tcx, cx.typeck_results().node_type(pat.hir_id))?;
                     return Some(SpannedRange {
                         span: pat.span,
                         node: (value, EndBound::Included(value)),
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
index 264458a86ef..edac97344a0 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -1,6 +1,6 @@
 use super::REDUNDANT_PATTERN_MATCHING;
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::source::{snippet, walk_span_to_context};
+use clippy_utils::source::walk_span_to_context;
 use clippy_utils::sugg::{Sugg, make_unop};
 use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop};
 use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr_without_closures};
@@ -9,7 +9,7 @@ use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp};
+use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatExprKind, PatKind, QPath, UnOp};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, GenericArgKind, Ty};
 use rustc_span::{Span, Symbol, sym};
@@ -74,8 +74,8 @@ fn find_match_true<'tcx>(
     span: Span,
     message: &'static str,
 ) {
-    if let PatKind::Lit(lit) = pat.kind
-        && let ExprKind::Lit(lit) = lit.kind
+    if let PatKind::Expr(lit) = pat.kind
+        && let PatExprKind::Lit { lit, negated: false } = lit.kind
         && let LitKind::Bool(pat_is_true) = lit.node
     {
         let mut applicability = Applicability::MachineApplicable;
@@ -274,7 +274,9 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
                 ExprKind::AddrOf(_, _, borrowed) => borrowed,
                 _ => op,
             };
-            let mut sugg = format!("{}.{good_method}", snippet(cx, result_expr.span, "_"));
+            let mut app = Applicability::MachineApplicable;
+            let receiver_sugg = Sugg::hir_with_applicability(cx, result_expr, "_", &mut app).maybe_par();
+            let mut sugg = format!("{receiver_sugg}.{good_method}");
 
             if let Some(guard) = maybe_guard {
                 // wow, the HIR for match guards in `PAT if let PAT = expr && expr => ...` is annoying!
@@ -307,7 +309,7 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
                 format!("redundant pattern matching, consider using `{good_method}`"),
                 "try",
                 sugg,
-                Applicability::MachineApplicable,
+                app,
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
index 10ca6832d9c..38f876fed80 100644
--- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
@@ -9,7 +9,7 @@ use rustc_arena::DroplessArena;
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{Visitor, walk_pat};
-use rustc_hir::{Arm, Expr, ExprKind, HirId, Node, Pat, PatKind, QPath, StmtKind};
+use rustc_hir::{Arm, Expr, ExprKind, HirId, Node, Pat, PatExpr, PatExprKind, PatKind, QPath, StmtKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, AdtDef, TyCtxt, TypeckResults, VariantDef};
 use rustc_span::{Span, sym};
@@ -114,7 +114,7 @@ fn report_single_pattern(cx: &LateContext<'_>, ex: &Expr<'_>, arm: &Arm<'_>, exp
     }
 
     let (pat, pat_ref_count) = peel_hir_pat_refs(arm.pat);
-    let (msg, sugg) = if let PatKind::Path(_) | PatKind::Lit(_) = pat.kind
+    let (msg, sugg) = if let PatKind::Path(_) | PatKind::Expr(_) = pat.kind
         && let (ty, ty_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(ex))
         && let Some(spe_trait_id) = cx.tcx.lang_items().structural_peq_trait()
         && let Some(pe_trait_id) = cx.tcx.lang_items().eq_trait()
@@ -126,8 +126,8 @@ fn report_single_pattern(cx: &LateContext<'_>, ex: &Expr<'_>, arm: &Arm<'_>, exp
         // scrutinee derives PartialEq and the pattern is a constant.
         let pat_ref_count = match pat.kind {
             // string literals are already a reference.
-            PatKind::Lit(Expr {
-                kind: ExprKind::Lit(lit),
+            PatKind::Expr(PatExpr {
+                kind: PatExprKind::Lit { lit, negated: false },
                 ..
             }) if lit.node.is_str() || lit.node.is_bytestr() => pat_ref_count + 1,
             _ => pat_ref_count,
@@ -345,7 +345,7 @@ impl<'a> PatState<'a> {
 
             PatKind::Guard(..) => {
                 matches!(self, Self::Wild)
-            }
+            },
 
             // Patterns for things which can only contain a single sub-pattern.
             PatKind::Binding(_, _, _, Some(pat)) | PatKind::Ref(pat, _) | PatKind::Box(pat) | PatKind::Deref(pat) => {
@@ -384,7 +384,7 @@ impl<'a> PatState<'a> {
 
             PatKind::Wild
             | PatKind::Binding(_, _, _, None)
-            | PatKind::Lit(_)
+            | PatKind::Expr(_)
             | PatKind::Range(..)
             | PatKind::Path(_)
             | PatKind::Never
diff --git a/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs
new file mode 100644
index 00000000000..208172980c9
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs
@@ -0,0 +1,41 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_trait_method;
+use clippy_utils::ty::implements_trait;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_middle::ty::Instance;
+use rustc_span::{Span, sym};
+
+use super::DOUBLE_ENDED_ITERATOR_LAST;
+
+pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, self_expr: &'_ Expr<'_>, call_span: Span) {
+    let typeck = cx.typeck_results();
+
+    // if the "last" method is that of Iterator
+    if is_trait_method(cx, expr, sym::Iterator)
+        // if self implements DoubleEndedIterator
+        && let Some(deiter_id) = cx.tcx.get_diagnostic_item(sym::DoubleEndedIterator)
+        && let self_type = cx.typeck_results().expr_ty(self_expr)
+        && implements_trait(cx, self_type.peel_refs(), deiter_id, &[])
+        // resolve the method definition
+        && let id = typeck.type_dependent_def_id(expr.hir_id).unwrap()
+        && let args = typeck.node_args(expr.hir_id)
+        && let Ok(Some(fn_def)) = Instance::try_resolve(cx.tcx, cx.typing_env(), id, args)
+        // find the provided definition of Iterator::last
+        && let Some(item) = cx.tcx.get_diagnostic_item(sym::Iterator)
+        && let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name.as_str() == "last")
+        // if the resolved method is the same as the provided definition
+        && fn_def.def_id() == last_def.def_id
+    {
+        span_lint_and_sugg(
+            cx,
+            DOUBLE_ENDED_ITERATOR_LAST,
+            call_span,
+            "called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator",
+            "try",
+            "next_back()".to_string(),
+            Applicability::MachineApplicable,
+        );
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
index 07a7a12b162..f7bb8c1d696 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_flatten.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_trait_method;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{is_trait_method, span_contains_comment};
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
@@ -17,10 +17,15 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, map_
         let mut applicability = Applicability::MachineApplicable;
 
         let closure_snippet = snippet_with_applicability(cx, map_arg.span, "..", &mut applicability);
+        let span = expr.span.with_lo(map_span.lo());
+        // If the methods are separated with comments, we don't apply suggestion automatically.
+        if span_contains_comment(cx.tcx.sess.source_map(), span) {
+            applicability = Applicability::Unspecified;
+        }
         span_lint_and_sugg(
             cx,
             MAP_FLATTEN,
-            expr.span.with_lo(map_span.lo()),
+            span,
             format!("called `map(..).flatten()` on `{caller_ty_name}`"),
             format!("try replacing `map` with `{method_to_use}` and remove the `.flatten()`"),
             format!("{method_to_use}({closure_snippet})"),
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
index 1f204de01da..05360144657 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
@@ -1,8 +1,9 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_expr_untyped_identity_function, is_trait_method};
+use clippy_utils::{is_expr_untyped_identity_function, is_trait_method, path_to_local};
+use rustc_ast::BindingMode;
 use rustc_errors::Applicability;
-use rustc_hir as hir;
+use rustc_hir::{self as hir, Node, PatKind};
 use rustc_lint::LateContext;
 use rustc_span::{Span, sym};
 
@@ -24,6 +25,16 @@ pub(super) fn check(
         && is_expr_untyped_identity_function(cx, map_arg)
         && let Some(sugg_span) = expr.span.trim_start(caller.span)
     {
+        // If the result of `.map(identity)` is used as a mutable reference,
+        // the caller must not be an immutable binding.
+        if cx.typeck_results().expr_ty_adjusted(expr).is_mutable_ptr()
+            && let Some(hir_id) = path_to_local(caller)
+            && let Node::Pat(pat) = cx.tcx.hir_node(hir_id)
+            && !matches!(pat.kind, PatKind::Binding(BindingMode::MUT, ..))
+        {
+            return;
+        }
+
         span_lint_and_sugg(
             cx,
             MAP_IDENTITY,
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 810287fa541..3965c4d4087 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -14,6 +14,7 @@ mod clone_on_copy;
 mod clone_on_ref_ptr;
 mod cloned_instead_of_copied;
 mod collapsible_str_replace;
+mod double_ended_iterator_last;
 mod drain_collect;
 mod err_expect;
 mod expect_fun_call;
@@ -4284,6 +4285,32 @@ declare_clippy_lint! {
     "map of a trivial closure (not dependent on parameter) over a range"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Checks for `Iterator::last` being called on a  `DoubleEndedIterator`, which can be replaced
+    /// with `DoubleEndedIterator::next_back`.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// `Iterator::last` is implemented by consuming the iterator, which is unnecessary if
+    /// the iterator is a `DoubleEndedIterator`. Since Rust traits do not allow specialization,
+    /// `Iterator::last` cannot be optimized for `DoubleEndedIterator`.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// let last_arg = "echo hello world".split(' ').last();
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// let last_arg = "echo hello world".split(' ').next_back();
+    /// ```
+    #[clippy::version = "1.85.0"]
+    pub DOUBLE_ENDED_ITERATOR_LAST,
+    perf,
+    "using `Iterator::last` on a `DoubleEndedIterator`"
+}
+
 pub struct Methods {
     avoid_breaking_exported_api: bool,
     msrv: Msrv,
@@ -4449,6 +4476,7 @@ impl_lint_pass!(Methods => [
     MAP_ALL_ANY_IDENTITY,
     MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES,
     UNNECESSARY_MAP_OR,
+    DOUBLE_ENDED_ITERATOR_LAST,
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -4931,6 +4959,7 @@ impl Methods {
                             false,
                         );
                     }
+                    double_ended_iterator_last::check(cx, expr, recv, call_span);
                 },
                 ("len", []) => {
                     if let Some(("as_bytes", prev_recv, [], _, _)) = method_call(recv) {
@@ -5280,7 +5309,7 @@ fn lint_binary_expr_with_method_call(cx: &LateContext<'_>, info: &mut BinaryExpr
 }
 
 const FN_HEADER: hir::FnHeader = hir::FnHeader {
-    safety: hir::Safety::Safe,
+    safety: hir::HeaderSafety::Normal(hir::Safety::Safe),
     constness: hir::Constness::NotConst,
     asyncness: hir::IsAsync::NotAsync,
     abi: rustc_target::spec::abi::Abi::Rust,
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs b/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs
index 348f740e7dd..6993150fb57 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs
@@ -7,6 +7,7 @@ use rustc_span::Span;
 use super::NEEDLESS_CHARACTER_ITERATION;
 use super::utils::get_last_chain_binding_hir_id;
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::paths::CHAR_IS_ASCII;
 use clippy_utils::source::SpanRangeExt;
 use clippy_utils::{match_def_path, path_to_local_id, peel_blocks};
 
@@ -77,7 +78,7 @@ fn handle_expr(
             if revert != is_all
                 && let ExprKind::Path(path) = fn_path.kind
                 && let Some(fn_def_id) = cx.qpath_res(&path, fn_path.hir_id).opt_def_id()
-                && match_def_path(cx, fn_def_id, &["core", "char", "methods", "<impl char>", "is_ascii"])
+                && match_def_path(cx, fn_def_id, &CHAR_IS_ASCII)
                 && path_to_local_id(peels_expr_ref(arg), first_param)
                 && let Some(snippet) = before_chars.get_source_text(cx)
             {
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
index ea4984f83ad..2780c3f8af5 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -470,14 +470,14 @@ fn detect_iter_and_into_iters<'tcx: 'a, 'a>(
     captured_ids: HirIdSet,
 ) -> Option<Vec<IterFunction>> {
     let mut visitor = IterFunctionVisitor {
-        uses: Vec::new(),
-        target: id,
-        seen_other: false,
-        cx,
-        current_mutably_captured_ids: HirIdSet::default(),
         illegal_mutable_capture_ids: captured_ids,
+        current_mutably_captured_ids: HirIdSet::default(),
+        cx,
+        uses: Vec::new(),
         hir_id_uses_map: FxHashMap::default(),
         current_statement_hir_id: None,
+        seen_other: false,
+        target: id,
     };
     visitor.visit_block(block);
     if visitor.seen_other {
diff --git a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs
index db2b9d4d92f..82e66a0500a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs
@@ -1,6 +1,7 @@
 use std::ops::ControlFlow;
 
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::paths::STDIN;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::for_each_local_use_after_expr;
@@ -33,7 +34,7 @@ fn parse_fails_on_trailing_newline(ty: Ty<'_>) -> bool {
 
 pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) {
     if let Some(recv_adt) = cx.typeck_results().expr_ty(recv).ty_adt_def()
-        && match_def_path(cx, recv_adt.did(), &["std", "io", "stdio", "Stdin"])
+        && match_def_path(cx, recv_adt.did(), &STDIN)
         && let ExprKind::Path(QPath::Resolved(_, path)) = arg.peel_borrows().kind
         && let Res::Local(local_id) = path.res
     {
diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
index c6d4ef5911e..8a99974394c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
@@ -297,8 +297,8 @@ fn parse_iter_usage<'tcx>(
                     {
                         Some(IterUsage {
                             kind: IterUsageKind::NextTuple,
-                            span: e.span,
                             unwrap_kind: None,
+                            span: e.span,
                         })
                     } else {
                         None
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
index b5d8972d7aa..c27d1fb4903 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
@@ -124,30 +124,30 @@ pub(super) fn check(
         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,
-                    method_name: "any",
                 });
             },
             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,
-                    method_name: "all",
                 });
             },
             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),
-                    method_name: "sum",
                 });
             },
             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),
-                    method_name: "product",
                 });
             },
             _ => (),
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs
index 1199d289761..b7dbebe60a4 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs
@@ -7,7 +7,7 @@ use clippy_utils::source::snippet_opt;
 use clippy_utils::sugg::{Sugg, make_binop};
 use clippy_utils::ty::{get_type_diagnostic_name, implements_trait};
 use clippy_utils::visitors::is_local_used;
-use clippy_utils::{is_from_proc_macro, path_to_local_id};
+use clippy_utils::{get_parent_expr, is_from_proc_macro, path_to_local_id};
 use rustc_ast::LitKind::Bool;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, PatKind};
@@ -96,11 +96,25 @@ pub(super) fn check<'a>(
             Sugg::hir(cx, non_binding_location, "")
         )));
 
-        let binop = make_binop(op.node, &Sugg::hir(cx, recv, ".."), &inner_non_binding)
-            .maybe_par()
-            .into_string();
+        let mut app = Applicability::MachineApplicable;
+        let binop = make_binop(
+            op.node,
+            &Sugg::hir_with_applicability(cx, recv, "..", &mut app),
+            &inner_non_binding,
+        );
 
-        (binop, "a standard comparison", Applicability::MaybeIncorrect)
+        let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr) {
+            match parent_expr.kind {
+                ExprKind::Binary(..) | ExprKind::Unary(..) | ExprKind::Cast(..) => binop.maybe_par(),
+                ExprKind::MethodCall(_, receiver, _, _) if receiver.hir_id == expr.hir_id => binop.maybe_par(),
+                _ => binop,
+            }
+        } else {
+            binop
+        }
+        .into_string();
+
+        (sugg, "a standard comparison", app)
     } else if !def_bool
         && msrv.meets(msrvs::OPTION_RESULT_IS_VARIANT_AND)
         && let Some(recv_callsite) = snippet_opt(cx, recv.span.source_callsite())
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index 42107581ab4..964f1603f0e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -494,7 +494,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
     for (_, node) in cx.tcx.hir().parent_iter(expr.hir_id) {
         match node {
             Node::Stmt(_) => return true,
-            Node::Block(..) => continue,
+            Node::Block(..) => {},
             Node::Item(item) => {
                 if let ItemKind::Fn { body: body_id, .. } = &item.kind
                     && let output_ty = return_ty(cx, item.owner_id)
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 121c4326d64..2572e186ce6 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
@@ -2,7 +2,7 @@ use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::qualify_min_const_fn::is_min_const_fn;
-use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, trait_ref_of_method};
+use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, is_in_test, trait_ref_of_method};
 use rustc_errors::Applicability;
 use rustc_hir::def_id::CRATE_DEF_ID;
 use rustc_hir::intravisit::FnKind;
@@ -97,6 +97,11 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
         span: Span,
         def_id: LocalDefId,
     ) {
+        let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
+        if is_in_test(cx.tcx, hir_id) {
+            return;
+        }
+
         if !self.msrv.meets(msrvs::CONST_IF_MATCH) {
             return;
         }
@@ -136,8 +141,6 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
             return;
         }
 
-        let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
-
         // Const fns are not allowed as methods in a trait.
         {
             let parent = cx.tcx.hir().get_parent_item(hir_id).def_id;
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index 1141728640d..29dcbaa9e62 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -192,7 +192,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
 
     fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
         match it.kind {
-            hir::ItemKind::Fn{ .. } => {
+            hir::ItemKind::Fn { .. } => {
                 // ignore main()
                 if it.ident.name == sym::main {
                     let at_root = cx.tcx.local_parent(it.owner_id.def_id) == CRATE_DEF_ID;
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index b18f18d89e5..05aa425de9e 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
             return;
         }
         match it.kind {
-            hir::ItemKind::Fn{ .. } => {
+            hir::ItemKind::Fn { .. } => {
                 let desc = "a function";
                 let attrs = cx.tcx.hir().attrs(it.hir_id());
                 check_missing_inline_attrs(cx, attrs, it.span, desc);
diff --git a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
index 3c47d0edfdc..5f7fde30f03 100644
--- a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
@@ -1,4 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
 use rustc_ast::ast::{BindingMode, ByRef, Lifetime, Mutability, Param, PatKind, Path, TyKind};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
@@ -80,7 +81,8 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod
                     applicability = Applicability::HasPlaceholders;
                     "&'_ mut self".to_string()
                 } else {
-                    format!("&{} mut self", &lifetime.ident.name)
+                    let lt_name = snippet_with_applicability(cx, lifetime.ident.span, "..", &mut applicability);
+                    format!("&{lt_name} mut self")
                 }
             },
             (Mode::Ref(None), Mutability::Not) => "&self".to_string(),
@@ -89,7 +91,8 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod
                     applicability = Applicability::HasPlaceholders;
                     "&'_ self".to_string()
                 } else {
-                    format!("&{} self", &lifetime.ident.name)
+                    let lt_name = snippet_with_applicability(cx, lifetime.ident.span, "..", &mut applicability);
+                    format!("&{lt_name} self")
                 }
             },
             (Mode::Value, Mutability::Mut) => "mut self".to_string(),
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
index f69913ddbfd..7f91e555054 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
@@ -9,7 +9,7 @@ use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::{Body, Expr, ExprKind, Mutability, Path, QPath};
-use rustc_index::bit_set::BitSet;
+use rustc_index::bit_set::DenseBitSet;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir::{Rvalue, StatementKind};
@@ -390,7 +390,7 @@ fn replace_types<'tcx>(
     projection_predicates: &[ProjectionPredicate<'tcx>],
     args: &mut [GenericArg<'tcx>],
 ) -> bool {
-    let mut replaced = BitSet::new_empty(args.len());
+    let mut replaced = DenseBitSet::new_empty(args.len());
 
     let mut deque = VecDeque::with_capacity(args.len());
     deque.push_back((param_ty, new_ty));
diff --git a/src/tools/clippy/clippy_lints/src/needless_continue.rs b/src/tools/clippy/clippy_lints/src/needless_continue.rs
index c48232f9905..05b31fc84b9 100644
--- a/src/tools/clippy/clippy_lints/src/needless_continue.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_continue.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::source::{indent_of, snippet, snippet_block};
-use rustc_ast::ast;
+use rustc_ast::{Block, Label, ast};
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_session::declare_lint_pass;
 use rustc_span::Span;
@@ -11,6 +11,7 @@ declare_clippy_lint! {
     /// that contain a `continue` statement in either their main blocks or their
     /// `else`-blocks, when omitting the `else`-block possibly with some
     /// rearrangement of code can make the code easier to understand.
+    /// The lint also checks if the last statement in the loop is a `continue`
     ///
     /// ### Why is this bad?
     /// Having explicit `else` blocks for `if` statements
@@ -75,6 +76,49 @@ declare_clippy_lint! {
     ///     # break;
     /// }
     /// ```
+    ///
+    /// ```rust
+    /// # use std::io::ErrorKind;
+    ///
+    /// fn foo() -> ErrorKind { ErrorKind::NotFound }
+    /// for _ in 0..10 {
+    ///     match foo() {
+    ///         ErrorKind::NotFound => {
+    ///             eprintln!("not found");
+    ///             continue
+    ///         }
+    ///         ErrorKind::TimedOut => {
+    ///             eprintln!("timeout");
+    ///             continue
+    ///         }
+    ///         _ => {
+    ///             eprintln!("other error");
+    ///             continue
+    ///         }
+    ///     }
+    /// }
+    /// ```
+    /// Could be rewritten as
+    ///
+    ///
+    /// ```rust
+    /// # use std::io::ErrorKind;
+    ///
+    /// fn foo() -> ErrorKind { ErrorKind::NotFound }
+    /// for _ in 0..10 {
+    ///     match foo() {
+    ///         ErrorKind::NotFound => {
+    ///             eprintln!("not found");
+    ///         }
+    ///         ErrorKind::TimedOut => {
+    ///             eprintln!("timeout");
+    ///         }
+    ///         _ => {
+    ///             eprintln!("other error");
+    ///         }
+    ///     }
+    /// }
+    /// ```
     #[clippy::version = "pre 1.29.0"]
     pub NEEDLESS_CONTINUE,
     pedantic,
@@ -144,7 +188,7 @@ impl EarlyLintPass for NeedlessContinue {
 ///
 /// - The expression is a `continue` node.
 /// - The expression node is a block with the first statement being a `continue`.
-fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&ast::Label>) -> bool {
+fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&Label>) -> bool {
     match else_expr.kind {
         ast::ExprKind::Block(ref else_block, _) => is_first_block_stmt_continue(else_block, label),
         ast::ExprKind::Continue(l) => compare_labels(label, l.as_ref()),
@@ -152,7 +196,7 @@ fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&ast::Label>)
     }
 }
 
-fn is_first_block_stmt_continue(block: &ast::Block, label: Option<&ast::Label>) -> bool {
+fn is_first_block_stmt_continue(block: &Block, label: Option<&Label>) -> bool {
     block.stmts.first().is_some_and(|stmt| match stmt.kind {
         ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => {
             if let ast::ExprKind::Continue(ref l) = e.kind {
@@ -166,7 +210,7 @@ fn is_first_block_stmt_continue(block: &ast::Block, label: Option<&ast::Label>)
 }
 
 /// If the `continue` has a label, check it matches the label of the loop.
-fn compare_labels(loop_label: Option<&ast::Label>, continue_label: Option<&ast::Label>) -> bool {
+fn compare_labels(loop_label: Option<&Label>, continue_label: Option<&Label>) -> bool {
     match (loop_label, continue_label) {
         // `loop { continue; }` or `'a loop { continue; }`
         (_, None) => true,
@@ -181,7 +225,7 @@ fn compare_labels(loop_label: Option<&ast::Label>, continue_label: Option<&ast::
 /// the AST object representing the loop block of `expr`.
 fn with_loop_block<F>(expr: &ast::Expr, mut func: F)
 where
-    F: FnMut(&ast::Block, Option<&ast::Label>),
+    F: FnMut(&Block, Option<&Label>),
 {
     if let ast::ExprKind::While(_, loop_block, label)
     | ast::ExprKind::ForLoop {
@@ -205,7 +249,7 @@ where
 /// - The `else` expression.
 fn with_if_expr<F>(stmt: &ast::Stmt, mut func: F)
 where
-    F: FnMut(&ast::Expr, &ast::Expr, &ast::Block, &ast::Expr),
+    F: FnMut(&ast::Expr, &ast::Expr, &Block, &ast::Expr),
 {
     match stmt.kind {
         ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => {
@@ -231,14 +275,14 @@ struct LintData<'a> {
     /// The condition expression for the above `if`.
     if_cond: &'a ast::Expr,
     /// The `then` block of the `if` statement.
-    if_block: &'a ast::Block,
+    if_block: &'a Block,
     /// The `else` block of the `if` statement.
     /// Note that we only work with `if` exprs that have an `else` branch.
     else_expr: &'a ast::Expr,
     /// The 0-based index of the `if` statement in the containing loop block.
     stmt_idx: usize,
     /// The statements of the loop block.
-    loop_block: &'a ast::Block,
+    loop_block: &'a Block,
 }
 
 const MSG_REDUNDANT_CONTINUE_EXPRESSION: &str = "this `continue` expression is redundant";
@@ -329,33 +373,74 @@ fn suggestion_snippet_for_continue_inside_else(cx: &EarlyContext<'_>, data: &Lin
     )
 }
 
-fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) {
-    if let ast::ExprKind::Loop(loop_block, loop_label, ..) = &expr.kind
-        && let Some(last_stmt) = loop_block.stmts.last()
+fn check_last_stmt_in_expr<F>(inner_expr: &ast::Expr, func: &F)
+where
+    F: Fn(Option<&Label>, Span),
+{
+    match &inner_expr.kind {
+        ast::ExprKind::Continue(continue_label) => {
+            func(continue_label.as_ref(), inner_expr.span);
+        },
+        ast::ExprKind::If(_, then_block, else_block) => {
+            check_last_stmt_in_block(then_block, func);
+            if let Some(else_block) = else_block {
+                check_last_stmt_in_expr(else_block, func);
+            }
+        },
+        ast::ExprKind::Match(_, arms, _) => {
+            for arm in arms {
+                if let Some(expr) = &arm.body {
+                    check_last_stmt_in_expr(expr, func);
+                }
+            }
+        },
+        ast::ExprKind::Block(b, _) => {
+            check_last_stmt_in_block(b, func);
+        },
+        _ => {},
+    }
+}
+
+fn check_last_stmt_in_block<F>(b: &Block, func: &F)
+where
+    F: Fn(Option<&Label>, Span),
+{
+    if let Some(last_stmt) = b.stmts.last()
         && let ast::StmtKind::Expr(inner_expr) | ast::StmtKind::Semi(inner_expr) = &last_stmt.kind
-        && let ast::ExprKind::Continue(continue_label) = inner_expr.kind
-        && compare_labels(loop_label.as_ref(), continue_label.as_ref())
     {
-        span_lint_and_help(
-            cx,
-            NEEDLESS_CONTINUE,
-            last_stmt.span,
-            MSG_REDUNDANT_CONTINUE_EXPRESSION,
-            None,
-            DROP_CONTINUE_EXPRESSION_MSG,
-        );
+        check_last_stmt_in_expr(inner_expr, func);
     }
+}
+
+fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) {
     with_loop_block(expr, |loop_block, label| {
-        for (i, stmt) in loop_block.stmts.iter().enumerate() {
+        let p = |continue_label: Option<&Label>, span: Span| {
+            if compare_labels(label, continue_label) {
+                span_lint_and_help(
+                    cx,
+                    NEEDLESS_CONTINUE,
+                    span,
+                    MSG_REDUNDANT_CONTINUE_EXPRESSION,
+                    None,
+                    DROP_CONTINUE_EXPRESSION_MSG,
+                );
+            }
+        };
+
+        let stmts = &loop_block.stmts;
+        for (i, stmt) in stmts.iter().enumerate() {
+            let mut maybe_emitted_in_if = false;
             with_if_expr(stmt, |if_expr, cond, then_block, else_expr| {
                 let data = &LintData {
-                    stmt_idx: i,
                     if_expr,
                     if_cond: cond,
                     if_block: then_block,
                     else_expr,
+                    stmt_idx: i,
                     loop_block,
                 };
+
+                maybe_emitted_in_if = true;
                 if needless_continue_in_else(else_expr, label) {
                     emit_warning(
                         cx,
@@ -365,8 +450,14 @@ fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) {
                     );
                 } else if is_first_block_stmt_continue(then_block, label) {
                     emit_warning(cx, data, DROP_ELSE_BLOCK_MSG, LintType::ContinueInsideThenBlock);
+                } else {
+                    maybe_emitted_in_if = false;
                 }
             });
+
+            if i == stmts.len() - 1 && !maybe_emitted_in_if {
+                check_last_stmt_in_block(loop_block, &p);
+            }
         }
     });
 }
@@ -400,7 +491,7 @@ fn erode_from_back(s: &str) -> String {
     if ret.is_empty() { s.to_string() } else { ret }
 }
 
-fn span_of_first_expr_in_block(block: &ast::Block) -> Option<Span> {
+fn span_of_first_expr_in_block(block: &Block) -> Option<Span> {
     block.stmts.first().map(|stmt| stmt.span)
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs
index abdce69e764..688374b5676 100644
--- a/src/tools/clippy/clippy_lints/src/new_without_default.rs
+++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs
@@ -75,7 +75,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
                     if let hir::ImplItemKind::Fn(ref sig, _) = impl_item.kind {
                         let name = impl_item.ident.name;
                         let id = impl_item.owner_id;
-                        if sig.header.safety.is_unsafe() {
+                        if sig.header.is_unsafe() {
                             // can't be implemented for unsafe new
                             return;
                         }
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index 92644456f63..ccd50758044 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -144,7 +144,7 @@ impl NoEffect {
                     |diag| {
                         for parent in cx.tcx.hir().parent_iter(stmt.hir_id) {
                             if let Node::Item(item) = parent.1
-                                && let ItemKind::Fn{ .. } = item.kind
+                                && let ItemKind::Fn { .. } = item.kind
                                 && let Node::Block(block) = cx.tcx.parent_hir_node(stmt.hir_id)
                                 && let [.., final_stmt] = block.stmts
                                 && final_stmt.hir_id == stmt.hir_id
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 ebd301d5156..8409d179b0f 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -189,6 +189,8 @@ impl<'tcx> NonCopyConst<'tcx> {
     }
 
     fn is_value_unfrozen_raw_inner(cx: &LateContext<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> bool {
+        // No branch that we check (yet) should continue if val isn't a ValTree::Branch
+        let ty::ValTree::Branch(val) = val else { return false };
         match *ty.kind() {
             // the fact that we have to dig into every structs to search enums
             // leads us to the point checking `UnsafeCell` directly is the only option.
@@ -197,12 +199,13 @@ impl<'tcx> NonCopyConst<'tcx> {
             // contained value.
             ty::Adt(def, ..) if def.is_union() => false,
             ty::Array(ty, _) => val
-                .unwrap_branch()
                 .iter()
                 .any(|field| Self::is_value_unfrozen_raw_inner(cx, *field, ty)),
             ty::Adt(def, args) if def.is_enum() => {
-                let (&variant_index, fields) = val.unwrap_branch().split_first().unwrap();
-                let variant_index = VariantIdx::from_u32(variant_index.unwrap_leaf().to_u32());
+                let Some((&ty::ValTree::Leaf(variant_index), fields)) = val.split_first() else {
+                    return false;
+                };
+                let variant_index = VariantIdx::from_u32(variant_index.to_u32());
                 fields
                     .iter()
                     .copied()
@@ -215,12 +218,10 @@ impl<'tcx> NonCopyConst<'tcx> {
                     .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, field, ty))
             },
             ty::Adt(def, args) => val
-                .unwrap_branch()
                 .iter()
                 .zip(def.non_enum_variant().fields.iter().map(|field| field.ty(cx.tcx, args)))
                 .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, *field, ty)),
             ty::Tuple(tys) => val
-                .unwrap_branch()
                 .iter()
                 .zip(tys)
                 .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, *field, ty)),
diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
index 2fee1c72a91..56c4157d6fe 100644
--- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
+++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
@@ -270,10 +270,10 @@ impl SimilarNamesNameVisitor<'_, '_, '_> {
             return;
         }
         self.0.names.push(ExistingName {
-            exemptions: get_exemptions(interned_name).unwrap_or(&[]),
             interned: ident.name,
             span: ident.span,
             len: count,
+            exemptions: get_exemptions(interned_name).unwrap_or(&[]),
         });
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
index 65ef56fd211..0eca788c787 100644
--- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -47,6 +47,7 @@ impl ArithmeticSideEffects {
         Self {
             allowed_binary,
             allowed_unary,
+            const_span: None,
             disallowed_int_methods: [
                 sym::saturating_div,
                 sym::wrapping_div,
@@ -55,7 +56,6 @@ impl ArithmeticSideEffects {
             ]
             .into_iter()
             .collect(),
-            const_span: None,
             expr_span: None,
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs b/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs
index d2529d4d9f8..668f09bbfd5 100644
--- a/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs
+++ b/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs
@@ -143,11 +143,11 @@ impl<'tcx> LateLintPass<'tcx> for PathbufThenPush<'tcx> {
             self.searcher = Some(PathbufPushSearcher {
                 local_id: id,
                 lhs_is_let: true,
-                name: name.name,
                 let_ty_span: local.ty.map(|ty| ty.span),
-                err_span: local.span,
                 init_val: *init_expr,
                 arg: None,
+                name: name.name,
+                err_span: local.span,
             });
         }
     }
@@ -165,10 +165,10 @@ impl<'tcx> LateLintPass<'tcx> for PathbufThenPush<'tcx> {
                 local_id: id,
                 lhs_is_let: false,
                 let_ty_span: None,
-                name: name.ident.name,
-                err_span: expr.span,
                 init_val: *right,
                 arg: None,
+                name: name.ident.name,
+                err_span: expr.span,
             });
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index a86926d8416..506adf0f2cc 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -541,7 +541,7 @@ fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Optio
             .collect();
         if let Some(args) = args
             && !args.is_empty()
-            && body.is_none_or(|body| sig.header.safety.is_unsafe() || contains_unsafe_block(cx, body.value))
+            && body.is_none_or(|body| sig.header.is_unsafe() || contains_unsafe_block(cx, body.value))
         {
             span_lint_and_then(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/redundant_else.rs b/src/tools/clippy/clippy_lints/src/redundant_else.rs
index 6a1d40334e7..a27f9b63114 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_else.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_else.rs
@@ -69,7 +69,6 @@ impl EarlyLintPass for RedundantElse {
                 ExprKind::If(_, next_then, Some(next_els)) => {
                     then = next_then;
                     els = next_els;
-                    continue;
                 },
                 // else if without else
                 ExprKind::If(..) => return,
diff --git a/src/tools/clippy/clippy_lints/src/redundant_locals.rs b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
index 4f46ca3c715..658d93e634c 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_locals.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
@@ -17,9 +17,9 @@ declare_clippy_lint! {
     /// Checks for redundant redefinitions of local bindings.
     ///
     /// ### Why is this bad?
-    /// Redundant redefinitions of local bindings do not change behavior and are likely to be unintended.
+    /// Redundant redefinitions of local bindings do not change behavior other than variable's lifetimes and are likely to be unintended.
     ///
-    /// Note that although these bindings do not affect your code's meaning, they _may_ affect `rustc`'s stack allocation.
+    /// These rebindings can be intentional to shorten the lifetimes of variables because they affect when the `Drop` implementation is called. Other than that, they do not affect your code's meaning but they _may_ affect `rustc`'s stack allocation.
     ///
     /// ### Example
     /// ```no_run
@@ -41,7 +41,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.73.0"]
     pub REDUNDANT_LOCALS,
-    correctness,
+    suspicious,
     "redundant redefinition of a local binding"
 }
 declare_lint_pass!(RedundantLocals => [REDUNDANT_LOCALS]);
diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs
index 6a5bf1b8045..9443dca154e 100644
--- a/src/tools/clippy/clippy_lints/src/regex.rs
+++ b/src/tools/clippy/clippy_lints/src/regex.rs
@@ -24,6 +24,11 @@ declare_clippy_lint! {
     /// ```ignore
     /// Regex::new("(")
     /// ```
+    ///
+    /// Use instead:
+    /// ```ignore
+    /// Regex::new("\(")
+    /// ```
     #[clippy::version = "pre 1.29.0"]
     pub INVALID_REGEX,
     correctness,
@@ -49,6 +54,11 @@ declare_clippy_lint! {
     /// ```ignore
     /// Regex::new("^foobar")
     /// ```
+    ///
+    /// Use instead:
+    /// ```ignore
+    /// str::starts_with("foobar")
+    /// ```
     #[clippy::version = "pre 1.29.0"]
     pub TRIVIAL_REGEX,
     nursery,
@@ -87,7 +97,7 @@ declare_clippy_lint! {
     ///     }
     /// }
     /// ```
-    #[clippy::version = "1.83.0"]
+    #[clippy::version = "1.84.0"]
     pub REGEX_CREATION_IN_LOOPS,
     perf,
     "regular expression compilation performed in a loop"
diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
index c690696aefc..597bfddecbc 100644
--- a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
+++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
@@ -282,9 +282,9 @@ impl<'tcx> Visitor<'tcx> for StmtsChecker<'_, '_, '_, '_, 'tcx> {
                 }
             {
                 let mut apa = AuxParamsAttr {
-                    first_bind_ident: ident,
                     first_block_hir_id: self.ap.curr_block_hir_id,
                     first_block_span: self.ap.curr_block_span,
+                    first_bind_ident: ident,
                     first_method_span: {
                         let expr_or_init = expr_or_init(self.cx, expr);
                         if let hir::ExprKind::MethodCall(_, local_expr, _, span) = expr_or_init.kind {
@@ -395,8 +395,8 @@ impl Default for AuxParamsAttr {
             counter: 0,
             has_expensive_expr_after_last_attr: false,
             first_block_hir_id: HirId::INVALID,
-            first_bind_ident: Ident::empty(),
             first_block_span: DUMMY_SP,
+            first_bind_ident: Ident::empty(),
             first_method_span: DUMMY_SP,
             first_stmt_span: DUMMY_SP,
             last_bind_ident: Ident::empty(),
diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
index 8c8f11569c8..d2d693eaa1f 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::macros::matching_root_macro_call;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{
@@ -203,14 +203,18 @@ impl SlowVectorInit {
             "len",
         );
 
-        span_lint_and_then(cx, SLOW_VECTOR_INITIALIZATION, slow_fill.span, msg, |diag| {
-            diag.span_suggestion(
-                vec_alloc.allocation_expr.span.source_callsite(),
-                "consider replacing this with",
-                format!("vec![0; {len_expr}]"),
-                Applicability::Unspecified,
-            );
-        });
+        let span_to_replace = slow_fill
+            .span
+            .with_lo(vec_alloc.allocation_expr.span.source_callsite().lo());
+        span_lint_and_sugg(
+            cx,
+            SLOW_VECTOR_INITIALIZATION,
+            span_to_replace,
+            msg,
+            "consider replacing this with",
+            format!("vec![0; {len_expr}]"),
+            Applicability::Unspecified,
+        );
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
index 82ff13a5aff..8ec7bfe9edd 100644
--- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
+++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
@@ -180,7 +180,7 @@ fn is_stable(cx: &LateContext<'_>, mut def_id: DefId, msrv: &Msrv) -> bool {
         if let Some(stability) = cx.tcx.lookup_stability(def_id)
             && let StabilityLevel::Stable {
                 since,
-                allowed_through_unstable_modules: false,
+                allowed_through_unstable_modules: None,
             } = stability.level
         {
             let stable = match since {
diff --git a/src/tools/clippy/clippy_lints/src/string_patterns.rs b/src/tools/clippy/clippy_lints/src/string_patterns.rs
index 0d85b1b858a..3834087f797 100644
--- a/src/tools/clippy/clippy_lints/src/string_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/string_patterns.rs
@@ -11,7 +11,7 @@ use clippy_utils::visitors::{Descend, for_each_expr};
 use itertools::Itertools;
 use rustc_ast::{BinOpKind, LitKind};
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, PatKind};
+use rustc_hir::{Expr, ExprKind, PatExprKind, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::impl_lint_pass;
@@ -171,7 +171,7 @@ fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr<
                         return ControlFlow::Break(());
                     }
                     if arm.pat.walk_short(|pat| match pat.kind {
-                        PatKind::Lit(expr) if let ExprKind::Lit(lit) = expr.kind => {
+                        PatKind::Expr(expr) if let PatExprKind::Lit { lit, negated: false } = expr.kind => {
                             if let LitKind::Char(_) = lit.node {
                                 set_char_spans.push(lit.span);
                             }
diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs
index 78f0b7d121c..ff116800512 100644
--- a/src/tools/clippy/clippy_lints/src/swap.rs
+++ b/src/tools/clippy/clippy_lints/src/swap.rs
@@ -384,9 +384,9 @@ impl<'tcx> IndexBinding<'_, 'tcx> {
 
     fn is_used_after_swap(&mut self, idx_ident: Ident) -> bool {
         let mut v = IndexBindingVisitor {
-            found_used: false,
-            suggest_span: self.suggest_span,
             idx: idx_ident,
+            suggest_span: self.suggest_span,
+            found_used: false,
         };
 
         for stmt in self.block.stmts {
diff --git a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
index a1d92c3ac71..82cc5155380 100644
--- a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
+++ b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::has_repr_attr;
+use clippy_utils::{has_repr_attr, is_in_test};
 use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
@@ -37,7 +37,10 @@ declare_lint_pass!(TrailingEmptyArray => [TRAILING_EMPTY_ARRAY]);
 
 impl<'tcx> LateLintPass<'tcx> for TrailingEmptyArray {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
-        if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_attr(cx, item.hir_id()) {
+        if is_struct_with_trailing_zero_sized_array(cx, item)
+            && !has_repr_attr(cx, item.hir_id())
+            && !is_in_test(cx.tcx, item.hir_id())
+        {
             span_lint_and_help(
                 cx,
                 TRAILING_EMPTY_ARRAY,
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
index 48d65eb15d9..26323af3122 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
@@ -30,17 +30,14 @@ pub(super) fn check<'tcx>(
             | (ReducedTy::UnorderedFields(from_sub_ty), ReducedTy::OrderedFields(Some(to_sub_ty))) => {
                 from_ty = from_sub_ty;
                 to_ty = to_sub_ty;
-                continue;
             },
             (ReducedTy::OrderedFields(Some(from_sub_ty)), ReducedTy::Other(to_sub_ty)) if reduced_tys.to_fat_ptr => {
                 from_ty = from_sub_ty;
                 to_ty = to_sub_ty;
-                continue;
             },
             (ReducedTy::Other(from_sub_ty), ReducedTy::OrderedFields(Some(to_sub_ty))) if reduced_tys.from_fat_ptr => {
                 from_ty = from_sub_ty;
                 to_ty = to_sub_ty;
-                continue;
             },
 
             // ptr <-> ptr
@@ -50,7 +47,6 @@ pub(super) fn check<'tcx>(
             {
                 from_ty = from_sub_ty;
                 to_ty = to_sub_ty;
-                continue;
             },
 
             // fat ptr <-> (*size, *size)
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index 363aea8be72..43cce625c64 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -388,8 +388,8 @@ impl<'tcx> LateLintPass<'tcx> for Types {
 
         self.check_fn_decl(cx, decl, CheckTyContext {
             is_in_trait_impl,
-            is_exported,
             in_body: matches!(fn_kind, FnKind::Closure),
+            is_exported,
             ..CheckTyContext::default()
         });
     }
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_literal_bound.rs b/src/tools/clippy/clippy_lints/src/unnecessary_literal_bound.rs
index 8165a45bc5b..9f107fbeec0 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_literal_bound.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_literal_bound.rs
@@ -47,7 +47,7 @@ declare_clippy_lint! {
     ///     }
     /// }
     /// ```
-    #[clippy::version = "1.83.0"]
+    #[clippy::version = "1.84.0"]
     pub UNNECESSARY_LITERAL_BOUND,
     pedantic,
     "detects &str that could be &'static str in function return types"
diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
index 50a97579df7..8923484bb58 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -92,7 +92,7 @@ impl EarlyLintPass for UnnestedOrPatterns {
 }
 
 fn lint_unnested_or_patterns(cx: &EarlyContext<'_>, pat: &Pat) {
-    if let Ident(.., None) | Lit(_) | Wild | Path(..) | Range(..) | Rest | MacCall(_) = pat.kind {
+    if let Ident(.., None) | Expr(_) | Wild | Path(..) | Range(..) | Rest | MacCall(_) = pat.kind {
         // This is a leaf pattern, so cloning is unprofitable.
         return;
     }
@@ -228,7 +228,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us
         // Therefore they are not some form of constructor `C`,
         // with which a pattern `C(p_0)` may be formed,
         // which we would want to join with other `C(p_j)`s.
-        Ident(.., None) | Lit(_) | Wild | Err(_) | Never | Path(..) | Range(..) | Rest | MacCall(_)
+        Ident(.., None) | Expr(_) | Wild | Err(_) | Never | Path(..) | Range(..) | Rest | MacCall(_)
         // Skip immutable refs, as grouping them saves few characters,
         // and almost always requires adding parens (increasing noisiness).
         // In the case of only two patterns, replacement adds net characters.
diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs
index c899b1868a6..d00bd7f2b3d 100644
--- a/src/tools/clippy/clippy_lints/src/unused_async.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_async.rs
@@ -120,8 +120,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
             let mut visitor = AsyncFnVisitor {
                 cx,
                 found_await: false,
-                async_depth: 0,
                 await_in_async_block: None,
+                async_depth: 0,
             };
             walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), def_id);
             if !visitor.found_await {
@@ -129,9 +129,9 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
                 // The actual linting happens in `check_crate_post`, once we've found all
                 // uses of local async functions that do require asyncness to pass typeck
                 self.unused_async_fns.push(UnusedAsyncFn {
-                    await_in_async_block: visitor.await_in_async_block,
-                    fn_span: span,
                     def_id,
+                    fn_span: span,
+                    await_in_async_block: visitor.await_in_async_block,
                 });
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index 89bb429e265..eaa119b045f 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -245,9 +245,9 @@ impl<'tcx> UnwrappableVariablesVisitor<'_, 'tcx> {
         let prev_len = self.unwrappables.len();
         for unwrap_info in collect_unwrap_info(self.cx, if_expr, cond, branch, else_branch, true) {
             let mut delegate = MutationVisitor {
-                tcx: self.cx.tcx,
                 is_mutated: false,
                 local_id: unwrap_info.local_id,
+                tcx: self.cx.tcx,
             };
 
             let vis = ExprUseVisitor::for_clippy(self.cx, cond.hir_id.owner.def_id, &mut delegate);
@@ -397,8 +397,8 @@ impl<'tcx> LateLintPass<'tcx> for Unwrap {
         }
 
         let mut v = UnwrappableVariablesVisitor {
-            cx,
             unwrappables: Vec::new(),
+            cx,
         };
 
         walk_fn(&mut v, kind, decl, body.id(), fn_id);
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index c2dcb5ae1f9..4dcc8ac7fb0 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -4,7 +4,7 @@ use rustc_ast::ast::{LitFloatType, LitKind};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::{
     self as hir, BindingMode, CaptureBy, Closure, ClosureKind, ConstArg, ConstArgKind, CoroutineKind, ExprKind,
-    FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, StructTailExpr, TyKind,
+    FnRetTy, HirId, Lit, PatExprKind, PatKind, QPath, StmtKind, StructTailExpr, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::declare_lint_pass;
@@ -643,6 +643,27 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
         self.expr(expr);
     }
 
+    fn pat_expr(&self, lit: &Binding<&hir::PatExpr<'_>>) {
+        let kind = |kind| chain!(self, "let PatExprKind::{kind} = {lit}.kind");
+        macro_rules! kind {
+            ($($t:tt)*) => (kind(format_args!($($t)*)));
+        }
+        match lit.value.kind {
+            PatExprKind::Lit { lit, negated } => {
+                bind!(self, lit);
+                bind!(self, negated);
+                kind!("Lit{{ref {lit}, {negated} }}");
+                self.lit(lit);
+            },
+            PatExprKind::ConstBlock(_) => kind!("ConstBlock(_)"),
+            PatExprKind::Path(ref qpath) => {
+                bind!(self, qpath);
+                kind!("Path(ref {qpath})");
+                self.qpath(qpath);
+            },
+        }
+    }
+
     fn pat(&self, pat: &Binding<&hir::Pat<'_>>) {
         let kind = |kind| chain!(self, "let PatKind::{kind} = {pat}.kind");
         macro_rules! kind {
@@ -717,17 +738,17 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                 kind!("Guard({pat}, {cond})");
                 self.pat(pat);
                 self.expr(cond);
-            }
-            PatKind::Lit(lit_expr) => {
+            },
+            PatKind::Expr(lit_expr) => {
                 bind!(self, lit_expr);
-                kind!("Lit({lit_expr})");
-                self.expr(lit_expr);
+                kind!("Expr({lit_expr})");
+                self.pat_expr(lit_expr);
             },
             PatKind::Range(start, end, end_kind) => {
                 opt_bind!(self, start, end);
                 kind!("Range({start}, {end}, RangeEnd::{end_kind:?})");
-                start.if_some(|e| self.expr(e));
-                end.if_some(|e| self.expr(e));
+                start.if_some(|e| self.pat_expr(e));
+                end.if_some(|e| self.pat_expr(e));
             },
             PatKind::Slice(start, middle, end) => {
                 bind!(self, start, end);
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
index a5fad68eea1..08c178ed229 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
@@ -73,6 +73,7 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
         SimplifiedType::Slice,
         SimplifiedType::Str,
         SimplifiedType::Bool,
+        SimplifiedType::Char,
     ]
     .iter()
     .flat_map(|&ty| cx.tcx.incoherent_impls(ty).iter())
diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs
index ef1c46154d2..0730b561bc2 100644
--- a/src/tools/clippy/clippy_lints/src/vec.rs
+++ b/src/tools/clippy/clippy_lints/src/vec.rs
@@ -8,7 +8,7 @@ use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::SpanRangeExt;
 use clippy_utils::ty::is_copy;
 use clippy_utils::visitors::for_each_local_use_after_expr;
-use clippy_utils::{get_parent_expr, higher, is_in_test, is_trait_method};
+use clippy_utils::{get_parent_expr, higher, is_in_test, is_trait_method, span_contains_comment};
 use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, LetStmt, Mutability, Node, Pat, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -132,9 +132,19 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
     fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
         for (span, lint_opt) in &self.span_to_lint_map {
             if let Some((hir_id, suggest_slice, snippet, applicability)) = lint_opt {
-                let help_msg = format!("you can use {} directly", suggest_slice.desc(),);
+                let help_msg = format!("you can use {} directly", suggest_slice.desc());
                 span_lint_hir_and_then(cx, USELESS_VEC, *hir_id, *span, "useless use of `vec!`", |diag| {
-                    diag.span_suggestion(*span, help_msg, snippet, *applicability);
+                    // If the `vec!` macro contains comment, better not make the suggestion machine
+                    // applicable as it would remove them.
+                    let applicability = if *applicability != Applicability::Unspecified
+                        && let source_map = cx.tcx.sess.source_map()
+                        && span_contains_comment(source_map, *span)
+                    {
+                        Applicability::Unspecified
+                    } else {
+                        *applicability
+                    };
+                    diag.span_suggestion(*span, help_msg, snippet, applicability);
                 });
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
index cbc6885ae5d..d87d554eb07 100644
--- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
+++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
@@ -166,8 +166,8 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush {
                 local_id: id,
                 init,
                 lhs_is_let: true,
-                name: name.name,
                 let_ty_span: local.ty.map(|ty| ty.span),
+                name: name.name,
                 err_span: local.span,
                 found: 0,
                 last_push_expr: init_expr.hir_id,
@@ -206,8 +206,8 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush {
                 && name.ident.as_str() == "push"
             {
                 self.searcher = Some(VecPushSearcher {
-                    found: searcher.found + 1,
                     err_span: searcher.err_span.to(stmt.span),
+                    found: searcher.found + 1,
                     last_push_expr: expr.hir_id,
                     ..searcher
                 });
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index a42ddcdae35..31ae002e47d 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -248,8 +248,8 @@ impl Write {
     pub fn new(conf: &'static Conf, format_args: FormatArgsStorage) -> Self {
         Self {
             format_args,
-            allow_print_in_tests: conf.allow_print_in_tests,
             in_debug_impl: false,
+            allow_print_in_tests: conf.allow_print_in_tests,
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/zombie_processes.rs b/src/tools/clippy/clippy_lints/src/zombie_processes.rs
index a702e0785a9..4df34891a2b 100644
--- a/src/tools/clippy/clippy_lints/src/zombie_processes.rs
+++ b/src/tools/clippy/clippy_lints/src/zombie_processes.rs
@@ -300,8 +300,8 @@ fn check<'tcx>(cx: &LateContext<'tcx>, spawn_expr: &'tcx Expr<'tcx>, cause: Caus
     };
 
     let mut vis = ExitPointFinder {
-        cx,
         state: ExitPointState::WalkUpTo(spawn_expr.hir_id),
+        cx,
     };
     if let Break(ExitCallFound) = vis.visit_block(block) {
         // Visitor found an unconditional `exit()` call, so don't lint.
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index 945827c98c1..7fa070cd226 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "clippy_utils"
 # begin autogenerated version
-version = "0.1.85"
+version = "0.1.86"
 # end autogenerated version
 edition = "2021"
 description = "Helpful tools for writing lints, provided as they are used in Clippy"
diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md
index 73fefbcd570..c267b804124 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-2024-12-26
+nightly-2025-01-09
 ```
 <!-- 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 623d9c76086..2eb09bac8d8 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
@@ -36,7 +36,7 @@ pub fn eq_pat(l: &Pat, r: &Pat) -> bool {
         (Paren(l), _) => eq_pat(l, r),
         (_, Paren(r)) => eq_pat(l, r),
         (Wild, Wild) | (Rest, Rest) => true,
-        (Lit(l), Lit(r)) => eq_expr(l, r),
+        (Expr(l), Expr(r)) => eq_expr(l, r),
         (Ident(b1, i1, s1), Ident(b2, i2, s2)) => {
             b1 == b2 && eq_id(*i1, *i2) && both(s1.as_deref(), s2.as_deref(), eq_pat)
         },
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index 43ddf06730d..d46beddf731 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -4,7 +4,6 @@
 //! executable MIR bodies, so we have to do this instead.
 #![allow(clippy::float_cmp)]
 
-use crate::macros::HirNode;
 use crate::source::{SpanRangeExt, walk_span_to_context};
 use crate::{clip, is_direct_expn_of, sext, unsext};
 
@@ -13,7 +12,7 @@ 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, QPath, UnOp};
+use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp, PatExpr, PatExprKind};
 use rustc_lexer::tokenize;
 use rustc_lint::LateContext;
 use rustc_middle::mir::ConstValue;
@@ -442,30 +441,48 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
         }
     }
 
+    pub fn eval_pat_expr(&self, pat_expr: &PatExpr<'_>) -> Option<Constant<'tcx>> {
+        match &pat_expr.kind {
+            PatExprKind::Lit { lit, negated } => {
+                let ty = self.typeck.node_type_opt(pat_expr.hir_id);
+                let val = lit_to_mir_constant(&lit.node, ty);
+                if *negated {
+                    self.constant_negate(&val, ty?)
+                } else {
+                    Some(val)
+                }
+            }
+            PatExprKind::ConstBlock(ConstBlock { body, ..}) => self.expr(self.tcx.hir().body(*body).value),
+            PatExprKind::Path(qpath) => self.qpath(qpath, pat_expr.hir_id),
+        }
+    }
+
+    fn qpath(&self, qpath: &QPath<'_>, hir_id: HirId) -> Option<Constant<'tcx>> {
+        let is_core_crate = if let Some(def_id) = self.typeck.qpath_res(qpath, hir_id).opt_def_id() {
+            self.tcx.crate_name(def_id.krate) == sym::core
+        } else {
+            false
+        };
+        self.fetch_path_and_apply(qpath, hir_id, self.typeck.node_type(hir_id), |self_, result| {
+            let result = mir_to_const(self_.tcx, result)?;
+            // If source is already Constant we wouldn't want to override it with CoreConstant
+            self_.source.set(
+                if is_core_crate && !matches!(self_.source.get(), ConstantSource::Constant) {
+                    ConstantSource::CoreConstant
+                } else {
+                    ConstantSource::Constant
+                },
+            );
+            Some(result)
+        })
+    }
+
     /// Simple constant folding: Insert an expression, get a constant or none.
     fn expr(&self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
         match e.kind {
             ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.tcx.hir().body(body).value),
             ExprKind::DropTemps(e) => self.expr(e),
-            ExprKind::Path(ref qpath) => {
-                let is_core_crate = if let Some(def_id) = self.typeck.qpath_res(qpath, e.hir_id()).opt_def_id() {
-                    self.tcx.crate_name(def_id.krate) == sym::core
-                } else {
-                    false
-                };
-                self.fetch_path_and_apply(qpath, e.hir_id, self.typeck.expr_ty(e), |self_, result| {
-                    let result = mir_to_const(self_.tcx, result)?;
-                    // If source is already Constant we wouldn't want to override it with CoreConstant
-                    self_.source.set(
-                        if is_core_crate && !matches!(self_.source.get(), ConstantSource::Constant) {
-                            ConstantSource::CoreConstant
-                        } else {
-                            ConstantSource::Constant
-                        },
-                    );
-                    Some(result)
-                })
-            },
+            ExprKind::Path(ref qpath) => self.qpath(qpath, e.hir_id),
             ExprKind::Block(block, _) => self.block(block),
             ExprKind::Lit(lit) => {
                 if is_direct_expn_of(e.span, "cfg").is_some() {
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index 4e12577b6df..60be7e4a4d3 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -196,8 +196,8 @@ impl<'hir> IfOrIfLet<'hir> {
             if let ExprKind::DropTemps(new_cond) = cond.kind {
                 return Some(Self {
                     cond: new_cond,
-                    r#else,
                     then,
+                    r#else,
                 });
             }
             if let ExprKind::Let(..) = cond.kind {
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 7c4e834f841..a1c48d5c36c 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -9,8 +9,8 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{
     AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr, ExprField,
     ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName,
-    Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, StructTailExpr, TraitBoundModifiers, Ty,
-    TyKind,
+    Pat, PatExpr, PatExprKind, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, StructTailExpr,
+    TraitBoundModifiers, Ty, TyKind,
 };
 use rustc_lexer::{TokenKind, tokenize};
 use rustc_lint::LateContext;
@@ -489,6 +489,24 @@ impl HirEqInterExpr<'_, '_, '_> {
         li.name == ri.name && self.eq_pat(lp, rp)
     }
 
+    fn eq_pat_expr(&mut self, left: &PatExpr<'_>, right: &PatExpr<'_>) -> bool {
+        match (&left.kind, &right.kind) {
+            (
+                &PatExprKind::Lit {
+                    lit: left,
+                    negated: left_neg,
+                },
+                &PatExprKind::Lit {
+                    lit: right,
+                    negated: right_neg,
+                },
+            ) => left_neg == right_neg && left.node == right.node,
+            (PatExprKind::ConstBlock(left), PatExprKind::ConstBlock(right)) => self.eq_body(left.body, right.body),
+            (PatExprKind::Path(left), PatExprKind::Path(right)) => self.eq_qpath(left, right),
+            (PatExprKind::Lit { .. } | PatExprKind::ConstBlock(..) | PatExprKind::Path(..), _) => false,
+        }
+    }
+
     /// Checks whether two patterns are the same.
     fn eq_pat(&mut self, left: &Pat<'_>, right: &Pat<'_>) -> bool {
         match (&left.kind, &right.kind) {
@@ -507,11 +525,11 @@ impl HirEqInterExpr<'_, '_, '_> {
                 eq
             },
             (PatKind::Path(l), PatKind::Path(r)) => self.eq_qpath(l, r),
-            (&PatKind::Lit(l), &PatKind::Lit(r)) => self.eq_expr(l, r),
+            (&PatKind::Expr(l), &PatKind::Expr(r)) => self.eq_pat_expr(l, r),
             (&PatKind::Tuple(l, ls), &PatKind::Tuple(r, rs)) => ls == rs && over(l, r, |l, r| self.eq_pat(l, r)),
             (&PatKind::Range(ref ls, ref le, li), &PatKind::Range(ref rs, ref re, ri)) => {
-                both(ls.as_ref(), rs.as_ref(), |a, b| self.eq_expr(a, b))
-                    && both(le.as_ref(), re.as_ref(), |a, b| self.eq_expr(a, b))
+                both(ls.as_ref(), rs.as_ref(), |a, b| self.eq_pat_expr(a, b))
+                    && both(le.as_ref(), re.as_ref(), |a, b| self.eq_pat_expr(a, b))
                     && (li == ri)
             },
             (&PatKind::Ref(le, ref lm), &PatKind::Ref(re, ref rm)) => lm == rm && self.eq_pat(le, re),
@@ -788,8 +806,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
         Self {
             cx,
             maybe_typeck_results: cx.maybe_typeck_results(),
-            path_check: PathCheck::default(),
             s: FxHasher::default(),
+            path_check: PathCheck::default(),
         }
     }
 
@@ -1073,6 +1091,18 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
         // self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s);
     }
 
+    pub fn hash_pat_expr(&mut self, lit: &PatExpr<'_>) {
+        std::mem::discriminant(&lit.kind).hash(&mut self.s);
+        match &lit.kind {
+            PatExprKind::Lit { lit, negated } => {
+                lit.node.hash(&mut self.s);
+                negated.hash(&mut self.s);
+            },
+            PatExprKind::ConstBlock(c) => self.hash_body(c.body),
+            PatExprKind::Path(qpath) => self.hash_qpath(qpath),
+        }
+    }
+
     pub fn hash_pat(&mut self, pat: &Pat<'_>) {
         std::mem::discriminant(&pat.kind).hash(&mut self.s);
         match pat.kind {
@@ -1084,7 +1114,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 }
             },
             PatKind::Box(pat) | PatKind::Deref(pat) => self.hash_pat(pat),
-            PatKind::Lit(expr) => self.hash_expr(expr),
+            PatKind::Expr(expr) => self.hash_pat_expr(expr),
             PatKind::Or(pats) => {
                 for pat in pats {
                     self.hash_pat(pat);
@@ -1093,10 +1123,10 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
             PatKind::Path(ref qpath) => self.hash_qpath(qpath),
             PatKind::Range(s, e, i) => {
                 if let Some(s) = s {
-                    self.hash_expr(s);
+                    self.hash_pat_expr(s);
                 }
                 if let Some(e) = e {
-                    self.hash_expr(e);
+                    self.hash_pat_expr(e);
                 }
                 std::mem::discriminant(&i).hash(&mut self.s);
             },
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index ba4a0f44584..eecfc3fb13f 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -1243,9 +1243,9 @@ pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'
 
     let mut v = V {
         cx,
-        allow_closure: true,
         loops: Vec::new(),
         locals: HirIdSet::default(),
+        allow_closure: true,
         captures: HirIdMap::default(),
     };
     v.visit_expr(expr);
@@ -1777,7 +1777,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
                 },
             }
         },
-        PatKind::Lit(..) | PatKind::Range(..) | PatKind::Err(_) | PatKind::Deref(_) | PatKind::Guard(..) => true,
+        PatKind::Expr(..) | PatKind::Range(..) | PatKind::Err(_) | PatKind::Deref(_) | PatKind::Guard(..) => true,
     }
 }
 
diff --git a/src/tools/clippy/clippy_utils/src/mir/mod.rs b/src/tools/clippy/clippy_utils/src/mir/mod.rs
index 3924e384c37..ccbbccd0dbf 100644
--- a/src/tools/clippy/clippy_utils/src/mir/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/mir/mod.rs
@@ -1,5 +1,5 @@
 use rustc_hir::{Expr, HirId};
-use rustc_index::bit_set::BitSet;
+use rustc_index::bit_set::DenseBitSet;
 use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::{
     BasicBlock, Body, InlineAsmOperand, Local, Location, Place, START_BLOCK, StatementKind, TerminatorKind, traversal,
@@ -88,7 +88,7 @@ impl<'tcx> Visitor<'tcx> for V<'_> {
 
 /// Checks if the block is part of a cycle
 pub fn block_in_cycle(body: &Body<'_>, block: BasicBlock) -> bool {
-    let mut seen = BitSet::new_empty(body.basic_blocks.len());
+    let mut seen = DenseBitSet::new_empty(body.basic_blocks.len());
     let mut to_visit = Vec::with_capacity(body.basic_blocks.len() / 2);
 
     seen.insert(block);
diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
index 17e6558a41c..5eb9b3b8f22 100644
--- a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
+++ b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
@@ -2,7 +2,7 @@ use super::possible_origin::PossibleOriginVisitor;
 use super::transitive_relation::TransitiveRelation;
 use crate::ty::is_copy;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_index::bit_set::BitSet;
+use rustc_index::bit_set::DenseBitSet;
 use rustc_lint::LateContext;
 use rustc_middle::mir::visit::Visitor as _;
 use rustc_middle::mir::{self, Mutability};
@@ -21,19 +21,19 @@ struct PossibleBorrowerVisitor<'a, 'b, 'tcx> {
     possible_borrower: TransitiveRelation,
     body: &'b mir::Body<'tcx>,
     cx: &'a LateContext<'tcx>,
-    possible_origin: FxHashMap<mir::Local, BitSet<mir::Local>>,
+    possible_origin: FxHashMap<mir::Local, DenseBitSet<mir::Local>>,
 }
 
 impl<'a, 'b, 'tcx> PossibleBorrowerVisitor<'a, 'b, 'tcx> {
     fn new(
         cx: &'a LateContext<'tcx>,
         body: &'b mir::Body<'tcx>,
-        possible_origin: FxHashMap<mir::Local, BitSet<mir::Local>>,
+        possible_origin: FxHashMap<mir::Local, DenseBitSet<mir::Local>>,
     ) -> Self {
         Self {
             possible_borrower: TransitiveRelation::default(),
-            cx,
             body,
+            cx,
             possible_origin,
         }
     }
@@ -56,7 +56,7 @@ impl<'a, 'b, 'tcx> PossibleBorrowerVisitor<'a, 'b, 'tcx> {
             }
         }
 
-        let bs = BitSet::new_empty(self.body.local_decls.len());
+        let bs = DenseBitSet::new_empty(self.body.local_decls.len());
         PossibleBorrowerMap {
             map,
             maybe_live,
@@ -119,7 +119,7 @@ impl<'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'_, '_, 'tcx> {
             let mut mutable_variables: Vec<mir::Local> = mutable_borrowers
                 .iter()
                 .filter_map(|r| self.possible_origin.get(r))
-                .flat_map(BitSet::iter)
+                .flat_map(DenseBitSet::iter)
                 .collect();
 
             if ContainsRegion.visit_ty(self.body.local_decls[*dest].ty).is_break() {
@@ -171,10 +171,10 @@ fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) {
 #[allow(clippy::module_name_repetitions)]
 pub struct PossibleBorrowerMap<'b, 'tcx> {
     /// Mapping `Local -> its possible borrowers`
-    pub map: FxHashMap<mir::Local, BitSet<mir::Local>>,
+    pub map: FxHashMap<mir::Local, DenseBitSet<mir::Local>>,
     maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive<'tcx>>,
-    // Caches to avoid allocation of `BitSet` on every query
-    pub bitset: (BitSet<mir::Local>, BitSet<mir::Local>),
+    // Caches to avoid allocation of `DenseBitSet` on every query
+    pub bitset: (DenseBitSet<mir::Local>, DenseBitSet<mir::Local>),
 }
 
 impl<'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> {
@@ -184,7 +184,7 @@ impl<'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> {
             vis.visit_body(mir);
             vis.into_map(cx)
         };
-        let maybe_storage_live_result = MaybeStorageLive::new(Cow::Owned(BitSet::new_empty(mir.local_decls.len())))
+        let maybe_storage_live_result = MaybeStorageLive::new(Cow::Owned(DenseBitSet::new_empty(mir.local_decls.len())))
             .iterate_to_fixpoint(cx.tcx, mir, Some("redundant_clone"))
             .into_results_cursor(mir);
         let mut vis = PossibleBorrowerVisitor::new(cx, mir, possible_origin);
diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs b/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs
index 47b93aad20c..3d253fd2bb1 100644
--- a/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs
+++ b/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs
@@ -1,7 +1,7 @@
 use super::transitive_relation::TransitiveRelation;
 use crate::ty::is_copy;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_index::bit_set::BitSet;
+use rustc_index::bit_set::DenseBitSet;
 use rustc_lint::LateContext;
 use rustc_middle::mir;
 
@@ -22,7 +22,7 @@ impl<'a, 'tcx> PossibleOriginVisitor<'a, 'tcx> {
         }
     }
 
-    pub fn into_map(self, cx: &LateContext<'tcx>) -> FxHashMap<mir::Local, BitSet<mir::Local>> {
+    pub fn into_map(self, cx: &LateContext<'tcx>) -> FxHashMap<mir::Local, DenseBitSet<mir::Local>> {
         let mut map = FxHashMap::default();
         for row in (1..self.body.local_decls.len()).map(mir::Local::from_usize) {
             if is_copy(cx, self.body.local_decls[row].ty) {
diff --git a/src/tools/clippy/clippy_utils/src/mir/transitive_relation.rs b/src/tools/clippy/clippy_utils/src/mir/transitive_relation.rs
index 74d1f60af71..da44829a4c8 100644
--- a/src/tools/clippy/clippy_utils/src/mir/transitive_relation.rs
+++ b/src/tools/clippy/clippy_utils/src/mir/transitive_relation.rs
@@ -1,5 +1,5 @@
 use rustc_data_structures::fx::FxHashMap;
-use rustc_index::bit_set::BitSet;
+use rustc_index::bit_set::DenseBitSet;
 use rustc_middle::mir;
 
 #[derive(Default)]
@@ -12,8 +12,8 @@ impl TransitiveRelation {
         self.relations.entry(a).or_default().push(b);
     }
 
-    pub fn reachable_from(&self, a: mir::Local, domain_size: usize) -> BitSet<mir::Local> {
-        let mut seen = BitSet::new_empty(domain_size);
+    pub fn reachable_from(&self, a: mir::Local, domain_size: usize) -> DenseBitSet<mir::Local> {
+        let mut seen = DenseBitSet::new_empty(domain_size);
         let mut stack = vec![a];
         while let Some(u) = stack.pop() {
             if let Some(edges) = self.relations.get(&u) {
diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs
index 98bcedecccc..2169a5fdd63 100644
--- a/src/tools/clippy/clippy_utils/src/msrvs.rs
+++ b/src/tools/clippy/clippy_utils/src/msrvs.rs
@@ -130,7 +130,7 @@ impl Msrv {
         let mut msrv_attrs = attrs.iter().filter(|attr| attr.path_matches(&[sym::clippy, sym_msrv]));
 
         if let Some(msrv_attr) = msrv_attrs.next() {
-            if let Some(duplicate) = msrv_attrs.last() {
+            if let Some(duplicate) = msrv_attrs.next_back() {
                 sess.dcx()
                     .struct_span_err(duplicate.span(), "`clippy::msrv` is defined multiple times")
                     .with_span_note(msrv_attr.span(), "first definition found here")
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index 8cb8cd59014..f15fffc09e8 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -33,6 +33,8 @@ pub const CHILD: [&str; 3] = ["std", "process", "Child"];
 pub const CHILD_ID: [&str; 4] = ["std", "process", "Child", "id"];
 pub const CHILD_KILL: [&str; 4] = ["std", "process", "Child", "kill"];
 pub const PANIC_ANY: [&str; 3] = ["std", "panic", "panic_any"];
+pub const CHAR_IS_ASCII: [&str; 5] = ["core", "char", "methods", "<impl char>", "is_ascii"];
+pub const STDIN: [&str; 4] = ["std", "io", "stdio", "Stdin"];
 
 // Paths in clippy itself
 pub const MSRV: [&str; 3] = ["clippy_utils", "msrvs", "Msrv"];
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 428b40c5771..104ae154e36 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
@@ -109,7 +109,7 @@ fn check_rvalue<'tcx>(
 ) -> McfResult {
     match rvalue {
         Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())),
-        Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::RawPtr(_, place) => {
+        Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::RawPtr(_, place) => {
             check_place(tcx, *place, span, body, msrv)
         },
         Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body, msrv),
diff --git a/src/tools/clippy/lintcheck/src/output.rs b/src/tools/clippy/lintcheck/src/output.rs
index e38036315c2..dcc1ec339ef 100644
--- a/src/tools/clippy/lintcheck/src/output.rs
+++ b/src/tools/clippy/lintcheck/src/output.rs
@@ -94,8 +94,8 @@ impl ClippyWarning {
         Some(Self {
             name,
             diag,
-            url,
             krate: krate.to_string(),
+            url,
         })
     }
 
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 1000d90f52a..b1f0a82b1f4 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,6 +1,6 @@
 [toolchain]
 # begin autogenerated nightly
-channel = "nightly-2024-12-26"
+channel = "nightly-2025-01-09"
 # end autogenerated nightly
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
 profile = "minimal"
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index b8e0413e97b..e2e4d92df79 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -574,12 +574,12 @@ impl LintMetadata {
             id_location: None,
             group: "deprecated",
             level: "none",
-            version,
             docs: format!(
                 "### What it does\n\n\
                 Nothing. This lint has been deprecated\n\n\
                 ### Deprecation reason\n\n{reason}.\n",
             ),
+            version,
             applicability: Applicability::Unspecified,
         }
     }
diff --git a/src/tools/clippy/tests/missing-test-files.rs b/src/tools/clippy/tests/missing-test-files.rs
index a8225d037e8..64eba5e0888 100644
--- a/src/tools/clippy/tests/missing-test-files.rs
+++ b/src/tools/clippy/tests/missing-test-files.rs
@@ -59,7 +59,7 @@ fn explore_directory(dir: &Path) -> Vec<String> {
                             missing_files.push(path.to_str().unwrap().to_string());
                         }
                     },
-                    _ => continue,
+                    _ => {},
                 };
             }
         }
diff --git a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
index b99e8c0e76f..ff178924bd1 100644
--- a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
+++ b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
@@ -1,3 +1,4 @@
+
 thread '<unnamed>' panicked at clippy_lints/src/utils/internal_lints/produce_ice.rs:
 Would you like some help with that?
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/clippy.toml b/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/clippy.toml
new file mode 100644
index 00000000000..f43c9d97e82
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/clippy.toml
@@ -0,0 +1 @@
+lint-inconsistent-struct-field-initializers = true
diff --git a/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.fixed b/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.fixed
new file mode 100644
index 00000000000..8092e40ff9f
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.fixed
@@ -0,0 +1,79 @@
+#![warn(clippy::inconsistent_struct_constructor)]
+#![allow(clippy::redundant_field_names)]
+#![allow(clippy::unnecessary_operation)]
+#![allow(clippy::no_effect)]
+
+#[derive(Default)]
+struct Foo {
+    x: i32,
+    y: i32,
+    z: i32,
+}
+
+fn main() {
+    let x = 1;
+    let y = 1;
+    let z = 1;
+
+    Foo { x, y, z: z };
+
+    Foo {
+        x,
+        z: z,
+        ..Default::default()
+    };
+}
+
+// https://github.com/rust-lang/rust-clippy/pull/13737#discussion_r1859261645
+mod field_attributes {
+    struct HirId;
+    struct BodyVisitor {
+        macro_unsafe_blocks: Vec<HirId>,
+        expn_depth: u32,
+    }
+    fn check_body(condition: bool) {
+        BodyVisitor {
+            macro_unsafe_blocks: Vec::new(),
+            #[expect(clippy::bool_to_int_with_if)] // obfuscates the meaning
+            expn_depth: if condition { 1 } else { 0 },
+        };
+    }
+}
+
+// https://github.com/rust-lang/rust-clippy/pull/13737#discussion_r1874539800
+mod cfgs_between_fields {
+    #[allow(clippy::non_minimal_cfg)]
+    fn cfg_all() {
+        struct S {
+            a: i32,
+            b: i32,
+            #[cfg(all())]
+            c: i32,
+            d: i32,
+        }
+        let s = S {
+            a: 3,
+            b: 2,
+            #[cfg(all())]
+            c: 1,
+            d: 0,
+        };
+    }
+
+    fn cfg_any() {
+        struct S {
+            a: i32,
+            b: i32,
+            #[cfg(any())]
+            c: i32,
+            d: i32,
+        }
+        let s = S {
+            a: 3,
+            #[cfg(any())]
+            c: 1,
+            b: 2,
+            d: 0,
+        };
+    }
+}
diff --git a/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs b/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs
new file mode 100644
index 00000000000..cd1aff96652
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs
@@ -0,0 +1,79 @@
+#![warn(clippy::inconsistent_struct_constructor)]
+#![allow(clippy::redundant_field_names)]
+#![allow(clippy::unnecessary_operation)]
+#![allow(clippy::no_effect)]
+
+#[derive(Default)]
+struct Foo {
+    x: i32,
+    y: i32,
+    z: i32,
+}
+
+fn main() {
+    let x = 1;
+    let y = 1;
+    let z = 1;
+
+    Foo { y, x, z: z };
+
+    Foo {
+        z: z,
+        x,
+        ..Default::default()
+    };
+}
+
+// https://github.com/rust-lang/rust-clippy/pull/13737#discussion_r1859261645
+mod field_attributes {
+    struct HirId;
+    struct BodyVisitor {
+        macro_unsafe_blocks: Vec<HirId>,
+        expn_depth: u32,
+    }
+    fn check_body(condition: bool) {
+        BodyVisitor {
+            #[expect(clippy::bool_to_int_with_if)] // obfuscates the meaning
+            expn_depth: if condition { 1 } else { 0 },
+            macro_unsafe_blocks: Vec::new(),
+        };
+    }
+}
+
+// https://github.com/rust-lang/rust-clippy/pull/13737#discussion_r1874539800
+mod cfgs_between_fields {
+    #[allow(clippy::non_minimal_cfg)]
+    fn cfg_all() {
+        struct S {
+            a: i32,
+            b: i32,
+            #[cfg(all())]
+            c: i32,
+            d: i32,
+        }
+        let s = S {
+            d: 0,
+            #[cfg(all())]
+            c: 1,
+            b: 2,
+            a: 3,
+        };
+    }
+
+    fn cfg_any() {
+        struct S {
+            a: i32,
+            b: i32,
+            #[cfg(any())]
+            c: i32,
+            d: i32,
+        }
+        let s = S {
+            d: 0,
+            #[cfg(any())]
+            c: 1,
+            b: 2,
+            a: 3,
+        };
+    }
+}
diff --git a/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.stderr b/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.stderr
new file mode 100644
index 00000000000..d2533960b84
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.stderr
@@ -0,0 +1,77 @@
+error: struct constructor field order is inconsistent with struct definition field order
+  --> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:18:11
+   |
+LL |     Foo { y, x, z: z };
+   |           ^^^^^^^^^^ help: if the field evaluation order doesn't matter, try: `x, y, z: z`
+   |
+   = note: `-D clippy::inconsistent-struct-constructor` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::inconsistent_struct_constructor)]`
+
+error: struct constructor field order is inconsistent with struct definition field order
+  --> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:21:9
+   |
+LL | /         z: z,
+LL | |         x,
+   | |_________^
+   |
+help: if the field evaluation order doesn't matter, try
+   |
+LL ~         x,
+LL ~         z: z,
+   |
+
+error: struct constructor field order is inconsistent with struct definition field order
+  --> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:36:13
+   |
+LL | /             #[expect(clippy::bool_to_int_with_if)] // obfuscates the meaning
+LL | |             expn_depth: if condition { 1 } else { 0 },
+LL | |             macro_unsafe_blocks: Vec::new(),
+   | |___________________________________________^
+   |
+help: if the field evaluation order doesn't matter, try
+   |
+LL ~             macro_unsafe_blocks: Vec::new(),
+LL +             #[expect(clippy::bool_to_int_with_if)] // obfuscates the meaning
+LL ~             expn_depth: if condition { 1 } else { 0 },
+   |
+
+error: struct constructor field order is inconsistent with struct definition field order
+  --> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:55:13
+   |
+LL | /             d: 0,
+LL | |             #[cfg(all())]
+LL | |             c: 1,
+LL | |             b: 2,
+LL | |             a: 3,
+   | |________________^
+   |
+help: if the field evaluation order doesn't matter, try
+   |
+LL ~             a: 3,
+LL +             b: 2,
+LL +             #[cfg(all())]
+LL +             c: 1,
+LL ~             d: 0,
+   |
+
+error: struct constructor field order is inconsistent with struct definition field order
+  --> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:72:13
+   |
+LL | /             d: 0,
+LL | |             #[cfg(any())]
+LL | |             c: 1,
+LL | |             b: 2,
+LL | |             a: 3,
+   | |________________^
+   |
+help: if the field evaluation order doesn't matter, try
+   |
+LL ~             a: 3,
+LL +             #[cfg(any())]
+LL +             c: 1,
+LL +             b: 2,
+LL ~             d: 0,
+   |
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index 200129da25f..01e9f5c26a3 100644
--- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -46,6 +46,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
            future-size-threshold
            ignore-interior-mutability
            large-error-threshold
+           lint-inconsistent-struct-field-initializers
            literal-representation-threshold
            matches-for-let-else
            max-fn-params-bools
@@ -134,6 +135,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
            future-size-threshold
            ignore-interior-mutability
            large-error-threshold
+           lint-inconsistent-struct-field-initializers
            literal-representation-threshold
            matches-for-let-else
            max-fn-params-bools
@@ -222,6 +224,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni
            future-size-threshold
            ignore-interior-mutability
            large-error-threshold
+           lint-inconsistent-struct-field-initializers
            literal-representation-threshold
            matches-for-let-else
            max-fn-params-bools
diff --git a/src/tools/clippy/tests/ui/author/if.stdout b/src/tools/clippy/tests/ui/author/if.stdout
index a85dcddd331..8ffdf886202 100644
--- a/src/tools/clippy/tests/ui/author/if.stdout
+++ b/src/tools/clippy/tests/ui/author/if.stdout
@@ -30,8 +30,8 @@ if let StmtKind::Let(local) = stmt.kind
 }
 if let ExprKind::If(cond, then, Some(else_expr)) = expr.kind
     && let ExprKind::Let(let_expr) = cond.kind
-    && let PatKind::Lit(lit_expr) = let_expr.pat.kind
-    && let ExprKind::Lit(ref lit) = lit_expr.kind
+    && let PatKind::Expr(lit_expr) = let_expr.pat.kind
+    && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind
     && let LitKind::Bool(true) = lit.node
     && let ExprKind::Path(ref qpath) = let_expr.init.kind
     && match_qpath(qpath, &["a"])
diff --git a/src/tools/clippy/tests/ui/author/loop.stdout b/src/tools/clippy/tests/ui/author/loop.stdout
index 609d2491061..c94eb171f52 100644
--- a/src/tools/clippy/tests/ui/author/loop.stdout
+++ b/src/tools/clippy/tests/ui/author/loop.stdout
@@ -76,8 +76,8 @@ if let Some(higher::While { condition: condition, body: body }) = higher::While:
     // report your lint here
 }
 if let Some(higher::WhileLet { let_pat: let_pat, let_expr: let_expr, if_then: if_then }) = higher::WhileLet::hir(expr)
-    && let PatKind::Lit(lit_expr) = let_pat.kind
-    && let ExprKind::Lit(ref lit) = lit_expr.kind
+    && let PatKind::Expr(lit_expr) = let_pat.kind
+    && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind
     && let LitKind::Bool(true) = lit.node
     && let ExprKind::Path(ref qpath) = let_expr.kind
     && match_qpath(qpath, &["a"])
diff --git a/src/tools/clippy/tests/ui/author/matches.stdout b/src/tools/clippy/tests/ui/author/matches.stdout
index 91b3b6f6877..acb3b140dfa 100644
--- a/src/tools/clippy/tests/ui/author/matches.stdout
+++ b/src/tools/clippy/tests/ui/author/matches.stdout
@@ -4,14 +4,14 @@ if let StmtKind::Let(local) = stmt.kind
     && let ExprKind::Lit(ref lit) = scrutinee.kind
     && let LitKind::Int(42, LitIntType::Unsuffixed) = lit.node
     && arms.len() == 3
-    && let PatKind::Lit(lit_expr) = arms[0].pat.kind
-    && let ExprKind::Lit(ref lit1) = lit_expr.kind
+    && let PatKind::Expr(lit_expr) = arms[0].pat.kind
+    && let PatExprKind::Lit{ref lit1, negated } = lit_expr.kind
     && let LitKind::Int(16, LitIntType::Unsuffixed) = lit1.node
     && arms[0].guard.is_none()
     && let ExprKind::Lit(ref lit2) = arms[0].body.kind
     && let LitKind::Int(5, LitIntType::Unsuffixed) = lit2.node
-    && let PatKind::Lit(lit_expr1) = arms[1].pat.kind
-    && let ExprKind::Lit(ref lit3) = lit_expr1.kind
+    && let PatKind::Expr(lit_expr1) = arms[1].pat.kind
+    && let PatExprKind::Lit{ref lit3, negated1 } = lit_expr1.kind
     && let LitKind::Int(17, LitIntType::Unsuffixed) = lit3.node
     && arms[1].guard.is_none()
     && let ExprKind::Block(block, None) = arms[1].body.kind
diff --git a/src/tools/clippy/tests/ui/author/struct.stdout b/src/tools/clippy/tests/ui/author/struct.stdout
index 0b332d5e7d0..b66bbccb3cf 100644
--- a/src/tools/clippy/tests/ui/author/struct.stdout
+++ b/src/tools/clippy/tests/ui/author/struct.stdout
@@ -23,8 +23,8 @@ if let PatKind::Struct(ref qpath, fields, false) = arm.pat.kind
     && match_qpath(qpath, &["Test"])
     && fields.len() == 1
     && fields[0].ident.as_str() == "field"
-    && let PatKind::Lit(lit_expr) = fields[0].pat.kind
-    && let ExprKind::Lit(ref lit) = lit_expr.kind
+    && let PatKind::Expr(lit_expr) = fields[0].pat.kind
+    && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind
     && let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node
     && arm.guard.is_none()
     && let ExprKind::Block(block, None) = arm.body.kind
@@ -36,8 +36,8 @@ if let PatKind::Struct(ref qpath, fields, false) = arm.pat.kind
 if let PatKind::TupleStruct(ref qpath, fields, None) = arm.pat.kind
     && match_qpath(qpath, &["TestTuple"])
     && fields.len() == 1
-    && let PatKind::Lit(lit_expr) = fields[0].kind
-    && let ExprKind::Lit(ref lit) = lit_expr.kind
+    && let PatKind::Expr(lit_expr) = fields[0].kind
+    && let PatExprKind::Lit{ref lit, negated } = lit_expr.kind
     && let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node
     && arm.guard.is_none()
     && let ExprKind::Block(block, None) = arm.body.kind
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.fixed b/src/tools/clippy/tests/ui/borrow_as_ptr.fixed
index 289a5ef38b8..5365f3dd443 100644
--- a/src/tools/clippy/tests/ui/borrow_as_ptr.fixed
+++ b/src/tools/clippy/tests/ui/borrow_as_ptr.fixed
@@ -16,4 +16,12 @@ fn main() {
 
     let mut val_mut = 1;
     let _p_mut = std::ptr::addr_of_mut!(val_mut);
+
+    let mut x: [i32; 2] = [42, 43];
+    let _raw = std::ptr::addr_of_mut!(x[1]).wrapping_offset(-1);
+}
+
+fn issue_13882() {
+    let mut x: [i32; 2] = [42, 43];
+    let _raw = (&raw mut x[1]).wrapping_offset(-1);
 }
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.rs b/src/tools/clippy/tests/ui/borrow_as_ptr.rs
index b5328cb22dc..261894f1341 100644
--- a/src/tools/clippy/tests/ui/borrow_as_ptr.rs
+++ b/src/tools/clippy/tests/ui/borrow_as_ptr.rs
@@ -16,4 +16,12 @@ fn main() {
 
     let mut val_mut = 1;
     let _p_mut = &mut val_mut as *mut i32;
+
+    let mut x: [i32; 2] = [42, 43];
+    let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1);
+}
+
+fn issue_13882() {
+    let mut x: [i32; 2] = [42, 43];
+    let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1);
 }
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.stderr b/src/tools/clippy/tests/ui/borrow_as_ptr.stderr
index ea618b06e2c..4595fa4f248 100644
--- a/src/tools/clippy/tests/ui/borrow_as_ptr.stderr
+++ b/src/tools/clippy/tests/ui/borrow_as_ptr.stderr
@@ -13,5 +13,17 @@ error: borrow as raw pointer
 LL |     let _p_mut = &mut val_mut as *mut i32;
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of_mut!(val_mut)`
 
-error: aborting due to 2 previous errors
+error: borrow as raw pointer
+  --> tests/ui/borrow_as_ptr.rs:21:16
+   |
+LL |     let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1);
+   |                ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of_mut!(x[1])`
+
+error: borrow as raw pointer
+  --> tests/ui/borrow_as_ptr.rs:26:17
+   |
+LL |     let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1);
+   |                 ^^^^^^^^^^^^^^^^^^^^^ help: try: `&raw mut x[1]`
+
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs
index de220505c3e..a49d53fbbd3 100644
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs
+++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs
@@ -47,6 +47,17 @@ impl<T> std::ops::Deref for StaticRef<T> {
     }
 }
 
+// ICE regression test
+mod issue12979 {
+    use std::cell::UnsafeCell;
+
+    const ATOMIC_TUPLE: (Vec<UnsafeCell<u8>>, ()) = (Vec::new(), ());
+
+    fn main() {
+        let _x = &ATOMIC_TUPLE.0;
+    }
+}
+
 // use a tuple to make sure referencing a field behind a pointer isn't linted.
 const CELL_REF: StaticRef<(UnsafeCell<u32>,)> = unsafe { StaticRef::new(std::ptr::null()) };
 
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr
index 9a9028c8649..4cefcc28008 100644
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr
+++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr
@@ -1,5 +1,5 @@
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:54:5
+  --> tests/ui/borrow_interior_mutable_const/others.rs:65:5
    |
 LL |     ATOMIC.store(1, Ordering::SeqCst);
    |     ^^^^^^
@@ -12,7 +12,7 @@ LL | #![deny(clippy::borrow_interior_mutable_const)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:55:16
+  --> tests/ui/borrow_interior_mutable_const/others.rs:66:16
    |
 LL |     assert_eq!(ATOMIC.load(Ordering::SeqCst), 5);
    |                ^^^^^^
@@ -20,7 +20,7 @@ LL |     assert_eq!(ATOMIC.load(Ordering::SeqCst), 5);
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:58:22
+  --> tests/ui/borrow_interior_mutable_const/others.rs:69:22
    |
 LL |     let _once_ref = &ONCE_INIT;
    |                      ^^^^^^^^^
@@ -28,7 +28,7 @@ LL |     let _once_ref = &ONCE_INIT;
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:59:25
+  --> tests/ui/borrow_interior_mutable_const/others.rs:70:25
    |
 LL |     let _once_ref_2 = &&ONCE_INIT;
    |                         ^^^^^^^^^
@@ -36,7 +36,7 @@ LL |     let _once_ref_2 = &&ONCE_INIT;
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:60:27
+  --> tests/ui/borrow_interior_mutable_const/others.rs:71:27
    |
 LL |     let _once_ref_4 = &&&&ONCE_INIT;
    |                           ^^^^^^^^^
@@ -44,7 +44,7 @@ LL |     let _once_ref_4 = &&&&ONCE_INIT;
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:61:26
+  --> tests/ui/borrow_interior_mutable_const/others.rs:72:26
    |
 LL |     let _once_mut = &mut ONCE_INIT;
    |                          ^^^^^^^^^
@@ -52,7 +52,7 @@ LL |     let _once_mut = &mut ONCE_INIT;
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:72:14
+  --> tests/ui/borrow_interior_mutable_const/others.rs:83:14
    |
 LL |     let _ = &ATOMIC_TUPLE;
    |              ^^^^^^^^^^^^
@@ -60,7 +60,7 @@ LL |     let _ = &ATOMIC_TUPLE;
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:73:14
+  --> tests/ui/borrow_interior_mutable_const/others.rs:84:14
    |
 LL |     let _ = &ATOMIC_TUPLE.0;
    |              ^^^^^^^^^^^^
@@ -68,7 +68,7 @@ LL |     let _ = &ATOMIC_TUPLE.0;
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:74:19
+  --> tests/ui/borrow_interior_mutable_const/others.rs:85:19
    |
 LL |     let _ = &(&&&&ATOMIC_TUPLE).0;
    |                   ^^^^^^^^^^^^
@@ -76,7 +76,7 @@ LL |     let _ = &(&&&&ATOMIC_TUPLE).0;
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:75:14
+  --> tests/ui/borrow_interior_mutable_const/others.rs:86:14
    |
 LL |     let _ = &ATOMIC_TUPLE.0[0];
    |              ^^^^^^^^^^^^
@@ -84,7 +84,7 @@ LL |     let _ = &ATOMIC_TUPLE.0[0];
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:76:13
+  --> tests/ui/borrow_interior_mutable_const/others.rs:87:13
    |
 LL |     let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst);
    |             ^^^^^^^^^^^^
@@ -92,7 +92,7 @@ LL |     let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst);
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:81:13
+  --> tests/ui/borrow_interior_mutable_const/others.rs:92:13
    |
 LL |     let _ = ATOMIC_TUPLE.0[0];
    |             ^^^^^^^^^^^^
@@ -100,7 +100,7 @@ LL |     let _ = ATOMIC_TUPLE.0[0];
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:86:5
+  --> tests/ui/borrow_interior_mutable_const/others.rs:97:5
    |
 LL |     CELL.set(2);
    |     ^^^^
@@ -108,7 +108,7 @@ LL |     CELL.set(2);
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:87:16
+  --> tests/ui/borrow_interior_mutable_const/others.rs:98:16
    |
 LL |     assert_eq!(CELL.get(), 6);
    |                ^^^^
diff --git a/src/tools/clippy/tests/ui/boxed_local.rs b/src/tools/clippy/tests/ui/boxed_local.rs
index e2c27e585fc..4f361f5162b 100644
--- a/src/tools/clippy/tests/ui/boxed_local.rs
+++ b/src/tools/clippy/tests/ui/boxed_local.rs
@@ -173,6 +173,7 @@ mod issue_3739 {
 /// This shouldn't warn for `boxed_local` as it is intended to called from non-Rust code.
 pub extern "C" fn do_not_warn_me(_c_pointer: Box<String>) -> () {}
 
+#[allow(missing_abi)]
 #[rustfmt::skip] // Forces rustfmt to not add ABI
 pub extern fn do_not_warn_me_no_abi(_c_pointer: Box<String>) -> () {}
 
diff --git a/src/tools/clippy/tests/ui/boxed_local.stderr b/src/tools/clippy/tests/ui/boxed_local.stderr
index d3156c820b2..08fe375afb2 100644
--- a/src/tools/clippy/tests/ui/boxed_local.stderr
+++ b/src/tools/clippy/tests/ui/boxed_local.stderr
@@ -14,13 +14,13 @@ LL | pub fn new(_needs_name: Box<PeekableSeekable<&()>>) -> () {}
    |            ^^^^^^^^^^^
 
 error: local variable doesn't need to be boxed here
-  --> tests/ui/boxed_local.rs:188:44
+  --> tests/ui/boxed_local.rs:189:44
    |
 LL |         fn default_impl_x(self: Box<Self>, x: Box<u32>) -> u32 {
    |                                            ^
 
 error: local variable doesn't need to be boxed here
-  --> tests/ui/boxed_local.rs:196:16
+  --> tests/ui/boxed_local.rs:197:16
    |
 LL |         fn foo(x: Box<u32>) {}
    |                ^
diff --git a/src/tools/clippy/tests/ui/crashes/ice-10972-tait.rs b/src/tools/clippy/tests/ui/crashes/ice-10972-tait.rs
new file mode 100644
index 00000000000..f3ab9cebb7c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-10972-tait.rs
@@ -0,0 +1,9 @@
+// ICE: #10972
+// asked to assemble constituent types of unexpected type: Binder(Foo, [])
+#![feature(type_alias_impl_trait)]
+
+use std::fmt::Debug;
+type Foo = impl Debug;
+const FOO2: Foo = 22_u32;
+
+pub fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-13862.rs b/src/tools/clippy/tests/ui/crashes/ice-13862.rs
new file mode 100644
index 00000000000..a5f010054b2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-13862.rs
@@ -0,0 +1,19 @@
+#![crate_type = "lib"]
+#![no_std]
+
+use core::future::Future;
+use core::pin::Pin;
+use core::task::{Context, Poll};
+
+pub struct S<const N: u8>;
+
+impl<const N: u8> Future for S<N> {
+    type Output = ();
+    fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> {
+        todo!()
+    }
+}
+
+pub fn f<const N: u8>() -> S<N> {
+    S
+}
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
index 5cf5c608a85..83574a5cd98 100644
--- a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
+++ b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
@@ -240,7 +240,7 @@ fn parenthesized_word() {}
 /// UXes
 fn plural_acronym_test() {}
 
-extern {
+extern "C" {
     /// `foo()`
     fn in_extern();
 }
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.rs b/src/tools/clippy/tests/ui/doc/doc-fixable.rs
index 420211c6539..20fe89cdc53 100644
--- a/src/tools/clippy/tests/ui/doc/doc-fixable.rs
+++ b/src/tools/clippy/tests/ui/doc/doc-fixable.rs
@@ -240,7 +240,7 @@ fn parenthesized_word() {}
 /// UXes
 fn plural_acronym_test() {}
 
-extern {
+extern "C" {
     /// foo()
     fn in_extern();
 }
diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed b/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed
new file mode 100644
index 00000000000..06c48e33753
--- /dev/null
+++ b/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed
@@ -0,0 +1,53 @@
+#![warn(clippy::double_ended_iterator_last)]
+
+// Typical case
+pub fn last_arg(s: &str) -> Option<&str> {
+    s.split(' ').next_back()
+}
+
+fn main() {
+    // General case
+    struct DeIterator;
+    impl Iterator for DeIterator {
+        type Item = ();
+        fn next(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    impl DoubleEndedIterator for DeIterator {
+        fn next_back(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    let _ = DeIterator.next_back();
+    // Should not apply to other methods of Iterator
+    let _ = DeIterator.count();
+
+    // Should not apply to simple iterators
+    struct SimpleIterator;
+    impl Iterator for SimpleIterator {
+        type Item = ();
+        fn next(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    let _ = SimpleIterator.last();
+
+    // Should not apply to custom implementations of last()
+    struct CustomLast;
+    impl Iterator for CustomLast {
+        type Item = ();
+        fn next(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+        fn last(self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    impl DoubleEndedIterator for CustomLast {
+        fn next_back(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    let _ = CustomLast.last();
+}
diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last.rs b/src/tools/clippy/tests/ui/double_ended_iterator_last.rs
new file mode 100644
index 00000000000..9c13b496d11
--- /dev/null
+++ b/src/tools/clippy/tests/ui/double_ended_iterator_last.rs
@@ -0,0 +1,53 @@
+#![warn(clippy::double_ended_iterator_last)]
+
+// Typical case
+pub fn last_arg(s: &str) -> Option<&str> {
+    s.split(' ').last()
+}
+
+fn main() {
+    // General case
+    struct DeIterator;
+    impl Iterator for DeIterator {
+        type Item = ();
+        fn next(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    impl DoubleEndedIterator for DeIterator {
+        fn next_back(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    let _ = DeIterator.last();
+    // Should not apply to other methods of Iterator
+    let _ = DeIterator.count();
+
+    // Should not apply to simple iterators
+    struct SimpleIterator;
+    impl Iterator for SimpleIterator {
+        type Item = ();
+        fn next(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    let _ = SimpleIterator.last();
+
+    // Should not apply to custom implementations of last()
+    struct CustomLast;
+    impl Iterator for CustomLast {
+        type Item = ();
+        fn next(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+        fn last(self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    impl DoubleEndedIterator for CustomLast {
+        fn next_back(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    let _ = CustomLast.last();
+}
diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr b/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr
new file mode 100644
index 00000000000..b795c18a736
--- /dev/null
+++ b/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr
@@ -0,0 +1,17 @@
+error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator
+  --> tests/ui/double_ended_iterator_last.rs:5:18
+   |
+LL |     s.split(' ').last()
+   |                  ^^^^^^ help: try: `next_back()`
+   |
+   = note: `-D clippy::double-ended-iterator-last` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::double_ended_iterator_last)]`
+
+error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator
+  --> tests/ui/double_ended_iterator_last.rs:22:24
+   |
+LL |     let _ = DeIterator.last();
+   |                        ^^^^^^ help: try: `next_back()`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed
index 4c324587c96..67bd3e4d279 100644
--- a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed
+++ b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed
@@ -60,7 +60,11 @@ mod with_base {
         let z = 1;
 
         // Should lint.
-        Foo { x, z, ..Default::default() };
+        Foo {
+            x,
+            z,
+            ..Default::default()
+        };
 
         // Should NOT lint because the order is consistent with the definition.
         Foo {
diff --git a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr
index 97bb7c789a7..c145eb2a239 100644
--- a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr
+++ b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr
@@ -1,21 +1,24 @@
 error: struct constructor field order is inconsistent with struct definition field order
-  --> tests/ui/inconsistent_struct_constructor.rs:36:9
+  --> tests/ui/inconsistent_struct_constructor.rs:36:15
    |
 LL |         Foo { y, x, z };
-   |         ^^^^^^^^^^^^^^^ help: try: `Foo { x, y, z }`
+   |               ^^^^^^^ help: try: `x, y, z`
    |
    = note: `-D clippy::inconsistent-struct-constructor` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::inconsistent_struct_constructor)]`
 
 error: struct constructor field order is inconsistent with struct definition field order
-  --> tests/ui/inconsistent_struct_constructor.rs:63:9
+  --> tests/ui/inconsistent_struct_constructor.rs:64:13
    |
-LL | /         Foo {
-LL | |             z,
+LL | /             z,
 LL | |             x,
-LL | |             ..Default::default()
-LL | |         };
-   | |_________^ help: try: `Foo { x, z, ..Default::default() }`
+   | |_____________^
+   |
+help: try
+   |
+LL ~             x,
+LL ~             z,
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/infinite_iter.rs b/src/tools/clippy/tests/ui/infinite_iter.rs
index da95ba04b82..178e300ff5b 100644
--- a/src/tools/clippy/tests/ui/infinite_iter.rs
+++ b/src/tools/clippy/tests/ui/infinite_iter.rs
@@ -1,4 +1,4 @@
-#![allow(clippy::uninlined_format_args)]
+#![allow(clippy::uninlined_format_args, clippy::double_ended_iterator_last)]
 
 use std::iter::repeat;
 fn square_is_lower_64(x: &u32) -> bool {
diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed b/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed
index 7d8a584b022..d7d3d299349 100644
--- a/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed
+++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed
@@ -1,5 +1,10 @@
 #![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)]
-#![allow(dead_code, clippy::let_unit_value, clippy::useless_vec)]
+#![allow(
+    dead_code,
+    clippy::let_unit_value,
+    clippy::useless_vec,
+    clippy::double_ended_iterator_last
+)]
 
 fn main() {
     let vec = vec!["1".to_string(), "2".to_string(), "3".to_string()];
diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.rs b/src/tools/clippy/tests/ui/iter_overeager_cloned.rs
index 58c374ab8cd..45e1349febd 100644
--- a/src/tools/clippy/tests/ui/iter_overeager_cloned.rs
+++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.rs
@@ -1,5 +1,10 @@
 #![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)]
-#![allow(dead_code, clippy::let_unit_value, clippy::useless_vec)]
+#![allow(
+    dead_code,
+    clippy::let_unit_value,
+    clippy::useless_vec,
+    clippy::double_ended_iterator_last
+)]
 
 fn main() {
     let vec = vec!["1".to_string(), "2".to_string(), "3".to_string()];
diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr b/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr
index 7a822a79494..e6680266f10 100644
--- a/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr
+++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr
@@ -1,5 +1,5 @@
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:7:29
+  --> tests/ui/iter_overeager_cloned.rs:12:29
    |
 LL |     let _: Option<String> = vec.iter().cloned().last();
    |                             ^^^^^^^^^^----------------
@@ -10,7 +10,7 @@ LL |     let _: Option<String> = vec.iter().cloned().last();
    = help: to override `-D warnings` add `#[allow(clippy::iter_overeager_cloned)]`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:9:29
+  --> tests/ui/iter_overeager_cloned.rs:14:29
    |
 LL |     let _: Option<String> = vec.iter().chain(vec.iter()).cloned().next();
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------
@@ -18,7 +18,7 @@ LL |     let _: Option<String> = vec.iter().chain(vec.iter()).cloned().next();
    |                                                         help: try: `.next().cloned()`
 
 error: unneeded cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:11:20
+  --> tests/ui/iter_overeager_cloned.rs:16:20
    |
 LL |     let _: usize = vec.iter().filter(|x| x == &"2").cloned().count();
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------
@@ -29,7 +29,7 @@ LL |     let _: usize = vec.iter().filter(|x| x == &"2").cloned().count();
    = help: to override `-D warnings` add `#[allow(clippy::redundant_clone)]`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:13:21
+  --> tests/ui/iter_overeager_cloned.rs:18:21
    |
 LL |     let _: Vec<_> = vec.iter().cloned().take(2).collect();
    |                     ^^^^^^^^^^-----------------
@@ -37,7 +37,7 @@ LL |     let _: Vec<_> = vec.iter().cloned().take(2).collect();
    |                               help: try: `.take(2).cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:15:21
+  --> tests/ui/iter_overeager_cloned.rs:20:21
    |
 LL |     let _: Vec<_> = vec.iter().cloned().skip(2).collect();
    |                     ^^^^^^^^^^-----------------
@@ -45,7 +45,7 @@ LL |     let _: Vec<_> = vec.iter().cloned().skip(2).collect();
    |                               help: try: `.skip(2).cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:17:13
+  --> tests/ui/iter_overeager_cloned.rs:22:13
    |
 LL |     let _ = vec.iter().filter(|x| x == &"2").cloned().nth(2);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------
@@ -53,7 +53,7 @@ LL |     let _ = vec.iter().filter(|x| x == &"2").cloned().nth(2);
    |                                             help: try: `.nth(2).cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:19:13
+  --> tests/ui/iter_overeager_cloned.rs:24:13
    |
 LL |       let _ = [Some(Some("str".to_string())), Some(Some("str".to_string()))]
    |  _____________^
@@ -69,7 +69,7 @@ LL ~         .flatten().cloned();
    |
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:24:13
+  --> tests/ui/iter_overeager_cloned.rs:29:13
    |
 LL |     let _ = vec.iter().cloned().filter(|x| x.starts_with('2'));
    |             ^^^^^^^^^^----------------------------------------
@@ -77,7 +77,7 @@ LL |     let _ = vec.iter().cloned().filter(|x| x.starts_with('2'));
    |                       help: try: `.filter(|&x| x.starts_with('2')).cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:26:13
+  --> tests/ui/iter_overeager_cloned.rs:31:13
    |
 LL |     let _ = vec.iter().cloned().find(|x| x == "2");
    |             ^^^^^^^^^^----------------------------
@@ -85,7 +85,7 @@ LL |     let _ = vec.iter().cloned().find(|x| x == "2");
    |                       help: try: `.find(|&x| x == "2").cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:30:17
+  --> tests/ui/iter_overeager_cloned.rs:35:17
    |
 LL |         let _ = vec.iter().cloned().filter(f);
    |                 ^^^^^^^^^^-------------------
@@ -93,7 +93,7 @@ LL |         let _ = vec.iter().cloned().filter(f);
    |                           help: try: `.filter(|&x| f(x)).cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:31:17
+  --> tests/ui/iter_overeager_cloned.rs:36:17
    |
 LL |         let _ = vec.iter().cloned().find(f);
    |                 ^^^^^^^^^^-----------------
@@ -101,7 +101,7 @@ LL |         let _ = vec.iter().cloned().find(f);
    |                           help: try: `.find(|&x| f(x)).cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:37:17
+  --> tests/ui/iter_overeager_cloned.rs:42:17
    |
 LL |         let _ = vec.iter().cloned().filter(f);
    |                 ^^^^^^^^^^-------------------
@@ -109,7 +109,7 @@ LL |         let _ = vec.iter().cloned().filter(f);
    |                           help: try: `.filter(|&x| f(x)).cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:38:17
+  --> tests/ui/iter_overeager_cloned.rs:43:17
    |
 LL |         let _ = vec.iter().cloned().find(f);
    |                 ^^^^^^^^^^-----------------
@@ -117,7 +117,7 @@ LL |         let _ = vec.iter().cloned().find(f);
    |                           help: try: `.find(|&x| f(x)).cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:45:9
+  --> tests/ui/iter_overeager_cloned.rs:50:9
    |
 LL |         iter.cloned().filter(move |(&a, b)| a == 1 && b == &target)
    |         ^^^^-------------------------------------------------------
@@ -125,7 +125,7 @@ LL |         iter.cloned().filter(move |(&a, b)| a == 1 && b == &target)
    |             help: try: `.filter(move |&(&a, b)| a == 1 && b == &target).cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:56:13
+  --> tests/ui/iter_overeager_cloned.rs:61:13
    |
 LL |             iter.cloned().filter(move |S { a, b }| **a == 1 && b == &target)
    |             ^^^^------------------------------------------------------------
@@ -133,7 +133,7 @@ LL |             iter.cloned().filter(move |S { a, b }| **a == 1 && b == &target
    |                 help: try: `.filter(move |&S { a, b }| **a == 1 && b == &target).cloned()`
 
 error: unneeded cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:60:13
+  --> tests/ui/iter_overeager_cloned.rs:65:13
    |
 LL |     let _ = vec.iter().cloned().map(|x| x.len());
    |             ^^^^^^^^^^--------------------------
@@ -141,7 +141,7 @@ LL |     let _ = vec.iter().cloned().map(|x| x.len());
    |                       help: try: `.map(|x| x.len())`
 
 error: unneeded cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:65:13
+  --> tests/ui/iter_overeager_cloned.rs:70:13
    |
 LL |     let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty()));
    |             ^^^^^^^^^^----------------------------------------------
@@ -149,7 +149,7 @@ LL |     let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty()));
    |                       help: try: `.for_each(|x| assert!(!x.is_empty()))`
 
 error: unneeded cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:67:13
+  --> tests/ui/iter_overeager_cloned.rs:72:13
    |
 LL |     let _ = vec.iter().cloned().all(|x| x.len() == 1);
    |             ^^^^^^^^^^-------------------------------
@@ -157,7 +157,7 @@ LL |     let _ = vec.iter().cloned().all(|x| x.len() == 1);
    |                       help: try: `.all(|x| x.len() == 1)`
 
 error: unneeded cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:69:13
+  --> tests/ui/iter_overeager_cloned.rs:74:13
    |
 LL |     let _ = vec.iter().cloned().any(|x| x.len() == 1);
    |             ^^^^^^^^^^-------------------------------
diff --git a/src/tools/clippy/tests/ui/len_zero.fixed b/src/tools/clippy/tests/ui/len_zero.fixed
index 27319d9c20e..c9c476ba421 100644
--- a/src/tools/clippy/tests/ui/len_zero.fixed
+++ b/src/tools/clippy/tests/ui/len_zero.fixed
@@ -108,6 +108,8 @@ fn main() {
     let d2s = DerefToDerefToString {};
     println!("{}", (**d2s).is_empty());
 
+    println!("{}", std::borrow::Cow::Borrowed("").is_empty());
+
     let y = One;
     if y.len() == 0 {
         // No error; `One` does not have `.is_empty()`.
@@ -226,3 +228,23 @@ fn binop_with_macros() {
 
     (!has_is_empty.is_empty()).then(|| println!("This can happen."));
 }
+
+fn no_infinite_recursion() -> bool {
+    struct S;
+
+    impl Deref for S {
+        type Target = Self;
+        fn deref(&self) -> &Self::Target {
+            self
+        }
+    }
+
+    impl PartialEq<&'static str> for S {
+        fn eq(&self, _other: &&'static str) -> bool {
+            false
+        }
+    }
+
+    // Do not crash while checking if S implements `.is_empty()`
+    S == ""
+}
diff --git a/src/tools/clippy/tests/ui/len_zero.rs b/src/tools/clippy/tests/ui/len_zero.rs
index 03c05bc6ed7..610a5448d10 100644
--- a/src/tools/clippy/tests/ui/len_zero.rs
+++ b/src/tools/clippy/tests/ui/len_zero.rs
@@ -108,6 +108,8 @@ fn main() {
     let d2s = DerefToDerefToString {};
     println!("{}", &**d2s == "");
 
+    println!("{}", std::borrow::Cow::Borrowed("") == "");
+
     let y = One;
     if y.len() == 0 {
         // No error; `One` does not have `.is_empty()`.
@@ -226,3 +228,23 @@ fn binop_with_macros() {
 
     (compare_to!(0) < has_is_empty.len()).then(|| println!("This can happen."));
 }
+
+fn no_infinite_recursion() -> bool {
+    struct S;
+
+    impl Deref for S {
+        type Target = Self;
+        fn deref(&self) -> &Self::Target {
+            self
+        }
+    }
+
+    impl PartialEq<&'static str> for S {
+        fn eq(&self, _other: &&'static str) -> bool {
+            false
+        }
+    }
+
+    // Do not crash while checking if S implements `.is_empty()`
+    S == ""
+}
diff --git a/src/tools/clippy/tests/ui/len_zero.stderr b/src/tools/clippy/tests/ui/len_zero.stderr
index 5c849a2aca6..8d6b57e4b6d 100644
--- a/src/tools/clippy/tests/ui/len_zero.stderr
+++ b/src/tools/clippy/tests/ui/len_zero.stderr
@@ -58,107 +58,113 @@ error: comparison to empty slice
 LL |     println!("{}", &**d2s == "");
    |                    ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(**d2s).is_empty()`
 
+error: comparison to empty slice
+  --> tests/ui/len_zero.rs:111:20
+   |
+LL |     println!("{}", std::borrow::Cow::Borrowed("") == "");
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `std::borrow::Cow::Borrowed("").is_empty()`
+
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:124:8
+  --> tests/ui/len_zero.rs:126:8
    |
 LL |     if has_is_empty.len() == 0 {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:127:8
+  --> tests/ui/len_zero.rs:129:8
    |
 LL |     if has_is_empty.len() != 0 {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:130:8
+  --> tests/ui/len_zero.rs:132:8
    |
 LL |     if has_is_empty.len() > 0 {
    |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to one
-  --> tests/ui/len_zero.rs:133:8
+  --> tests/ui/len_zero.rs:135:8
    |
 LL |     if has_is_empty.len() < 1 {
    |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to one
-  --> tests/ui/len_zero.rs:136:8
+  --> tests/ui/len_zero.rs:138:8
    |
 LL |     if has_is_empty.len() >= 1 {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:147:8
+  --> tests/ui/len_zero.rs:149:8
    |
 LL |     if 0 == has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:150:8
+  --> tests/ui/len_zero.rs:152:8
    |
 LL |     if 0 != has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:153:8
+  --> tests/ui/len_zero.rs:155:8
    |
 LL |     if 0 < has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to one
-  --> tests/ui/len_zero.rs:156:8
+  --> tests/ui/len_zero.rs:158:8
    |
 LL |     if 1 <= has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to one
-  --> tests/ui/len_zero.rs:159:8
+  --> tests/ui/len_zero.rs:161:8
    |
 LL |     if 1 > has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:173:8
+  --> tests/ui/len_zero.rs:175:8
    |
 LL |     if with_is_empty.len() == 0 {
    |        ^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `with_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:185:6
+  --> tests/ui/len_zero.rs:187:6
    |
 LL |     (has_is_empty.len() > 0).then(|| println!("This can happen."));
    |      ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:186:6
+  --> tests/ui/len_zero.rs:188:6
    |
 LL |     (has_is_empty.len() == 0).then(|| println!("Or this!"));
    |      ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:190:8
+  --> tests/ui/len_zero.rs:192:8
    |
 LL |     if b.len() != 0 {}
    |        ^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!b.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:224:8
+  --> tests/ui/len_zero.rs:226:8
    |
 LL |     if has_is_empty.len() == compare_to!(0) {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:225:8
+  --> tests/ui/len_zero.rs:227:8
    |
 LL |     if has_is_empty.len() == zero!() {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:227:6
+  --> tests/ui/len_zero.rs:229:6
    |
 LL |     (compare_to!(0) < has_is_empty.len()).then(|| println!("This can happen."));
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
-error: aborting due to 26 previous errors
+error: aborting due to 27 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.fixed b/src/tools/clippy/tests/ui/manual_div_ceil.fixed
index e7801f7376a..1fb1df5b442 100644
--- a/src/tools/clippy/tests/ui/manual_div_ceil.fixed
+++ b/src/tools/clippy/tests/ui/manual_div_ceil.fixed
@@ -28,3 +28,25 @@ fn main() {
     let _ = (7_u32 as i32 + (y_i - 1)) / y_i;
     let _ = (7_u32 as i32 + (4 - 1)) / 4;
 }
+
+fn issue_13843() {
+    let x = 3usize;
+    let _ = 2048_usize.div_ceil(x);
+
+    let x = 5usize;
+    let _ = 2048usize.div_ceil(x);
+
+    let x = 5usize;
+    let _ = 2048_usize.div_ceil(x);
+
+    let x = 2048usize;
+    let _ = x.div_ceil(4);
+
+    let _: u32 = 2048_u32.div_ceil(6);
+    let _: usize = 2048_usize.div_ceil(6);
+    let _: u32 = 0x2048_u32.div_ceil(0x6);
+
+    let _ = 2048_u32.div_ceil(6u32);
+
+    let _ = 1_000_000_u32.div_ceil(6u32);
+}
diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.rs b/src/tools/clippy/tests/ui/manual_div_ceil.rs
index 2de74c7eaa8..4f6d38f0d14 100644
--- a/src/tools/clippy/tests/ui/manual_div_ceil.rs
+++ b/src/tools/clippy/tests/ui/manual_div_ceil.rs
@@ -28,3 +28,25 @@ fn main() {
     let _ = (7_u32 as i32 + (y_i - 1)) / y_i;
     let _ = (7_u32 as i32 + (4 - 1)) / 4;
 }
+
+fn issue_13843() {
+    let x = 3usize;
+    let _ = (2048 + x - 1) / x;
+
+    let x = 5usize;
+    let _ = (2048usize + x - 1) / x;
+
+    let x = 5usize;
+    let _ = (2048_usize + x - 1) / x;
+
+    let x = 2048usize;
+    let _ = (x + 4 - 1) / 4;
+
+    let _: u32 = (2048 + 6 - 1) / 6;
+    let _: usize = (2048 + 6 - 1) / 6;
+    let _: u32 = (0x2048 + 0x6 - 1) / 0x6;
+
+    let _ = (2048 + 6u32 - 1) / 6u32;
+
+    let _ = (1_000_000 + 6u32 - 1) / 6u32;
+}
diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.stderr b/src/tools/clippy/tests/ui/manual_div_ceil.stderr
index dc652dff405..3d87fe8e040 100644
--- a/src/tools/clippy/tests/ui/manual_div_ceil.stderr
+++ b/src/tools/clippy/tests/ui/manual_div_ceil.stderr
@@ -31,5 +31,59 @@ error: manually reimplementing `div_ceil`
 LL |     let _ = (7_i32 as u32 + (4 - 1)) / 4;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `(7_i32 as u32).div_ceil(4)`
 
-error: aborting due to 5 previous errors
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil.rs:34:13
+   |
+LL |     let _ = (2048 + x - 1) / x;
+   |             ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(x)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil.rs:37:13
+   |
+LL |     let _ = (2048usize + x - 1) / x;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048usize.div_ceil(x)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil.rs:40:13
+   |
+LL |     let _ = (2048_usize + x - 1) / x;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(x)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil.rs:43:13
+   |
+LL |     let _ = (x + 4 - 1) / 4;
+   |             ^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(4)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil.rs:45:18
+   |
+LL |     let _: u32 = (2048 + 6 - 1) / 6;
+   |                  ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_u32.div_ceil(6)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil.rs:46:20
+   |
+LL |     let _: usize = (2048 + 6 - 1) / 6;
+   |                    ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(6)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil.rs:47:18
+   |
+LL |     let _: u32 = (0x2048 + 0x6 - 1) / 0x6;
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `0x2048_u32.div_ceil(0x6)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil.rs:49:13
+   |
+LL |     let _ = (2048 + 6u32 - 1) / 6u32;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_u32.div_ceil(6u32)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil.rs:51:13
+   |
+LL |     let _ = (1_000_000 + 6u32 - 1) / 6u32;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `1_000_000_u32.div_ceil(6u32)`
+
+error: aborting due to 14 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.fixed b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.fixed
index a1d678c6689..f32b78aa14d 100644
--- a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.fixed
+++ b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.fixed
@@ -23,3 +23,30 @@ fn main() {
 
     let _ = (x + (y - 1)) / z;
 }
+
+fn issue_13843() {
+    let x = 3usize;
+    let _ = 2048_usize.div_ceil(x);
+
+    let x = 5usize;
+    let _ = 2048usize.div_ceil(x);
+
+    let x = 5usize;
+    let _ = 2048_usize.div_ceil(x);
+
+    let x = 2048usize;
+    let _ = x.div_ceil(4);
+
+    let _ = 2048_i32.div_ceil(4);
+
+    let _: u32 = 2048_u32.div_ceil(6);
+    let _: usize = 2048_usize.div_ceil(6);
+    let _: u32 = 0x2048_u32.div_ceil(0x6);
+
+    let _ = 2048_u32.div_ceil(6u32);
+
+    let x = -2;
+    let _ = (-2048_i32).div_ceil(x);
+
+    let _ = 1_000_000_u32.div_ceil(6u32);
+}
diff --git a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.rs b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.rs
index 58cb1dbe34d..54d89fcbd46 100644
--- a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.rs
+++ b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.rs
@@ -23,3 +23,30 @@ fn main() {
 
     let _ = (x + (y - 1)) / z;
 }
+
+fn issue_13843() {
+    let x = 3usize;
+    let _ = (2048 + x - 1) / x;
+
+    let x = 5usize;
+    let _ = (2048usize + x - 1) / x;
+
+    let x = 5usize;
+    let _ = (2048_usize + x - 1) / x;
+
+    let x = 2048usize;
+    let _ = (x + 4 - 1) / 4;
+
+    let _ = (2048 + 4 - 1) / 4;
+
+    let _: u32 = (2048 + 6 - 1) / 6;
+    let _: usize = (2048 + 6 - 1) / 6;
+    let _: u32 = (0x2048 + 0x6 - 1) / 0x6;
+
+    let _ = (2048 + 6u32 - 1) / 6u32;
+
+    let x = -2;
+    let _ = (-2048 + x - 1) / x;
+
+    let _ = (1_000_000 + 6u32 - 1) / 6u32;
+}
diff --git a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.stderr b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.stderr
index 361ef9bd9f4..c5e8c1a687c 100644
--- a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.stderr
+++ b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.stderr
@@ -43,5 +43,71 @@ error: manually reimplementing `div_ceil`
 LL |     let _ = (z_u + (4 - 1)) / 4;
    |             ^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `z_u.div_ceil(4)`
 
-error: aborting due to 7 previous errors
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil_with_feature.rs:29:13
+   |
+LL |     let _ = (2048 + x - 1) / x;
+   |             ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(x)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil_with_feature.rs:32:13
+   |
+LL |     let _ = (2048usize + x - 1) / x;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048usize.div_ceil(x)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil_with_feature.rs:35:13
+   |
+LL |     let _ = (2048_usize + x - 1) / x;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(x)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil_with_feature.rs:38:13
+   |
+LL |     let _ = (x + 4 - 1) / 4;
+   |             ^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(4)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil_with_feature.rs:40:13
+   |
+LL |     let _ = (2048 + 4 - 1) / 4;
+   |             ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_i32.div_ceil(4)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil_with_feature.rs:42:18
+   |
+LL |     let _: u32 = (2048 + 6 - 1) / 6;
+   |                  ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_u32.div_ceil(6)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil_with_feature.rs:43:20
+   |
+LL |     let _: usize = (2048 + 6 - 1) / 6;
+   |                    ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(6)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil_with_feature.rs:44:18
+   |
+LL |     let _: u32 = (0x2048 + 0x6 - 1) / 0x6;
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `0x2048_u32.div_ceil(0x6)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil_with_feature.rs:46:13
+   |
+LL |     let _ = (2048 + 6u32 - 1) / 6u32;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_u32.div_ceil(6u32)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil_with_feature.rs:49:13
+   |
+LL |     let _ = (-2048 + x - 1) / x;
+   |             ^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `(-2048_i32).div_ceil(x)`
+
+error: manually reimplementing `div_ceil`
+  --> tests/ui/manual_div_ceil_with_feature.rs:51:13
+   |
+LL |     let _ = (1_000_000 + 6u32 - 1) / 6u32;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `1_000_000_u32.div_ceil(6u32)`
+
+error: aborting due to 18 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed b/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed
index a72caa3a37e..179149f697d 100644
--- a/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed
+++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed
@@ -82,3 +82,8 @@ fn generics() {
     take_while(|c: u8| c.is_ascii_uppercase());
     take_while(|c: char| c.is_ascii_uppercase());
 }
+
+fn adds_type_reference() {
+    let digits: Vec<&char> = ['1', 'A'].iter().take_while(|c: &&char| c.is_ascii_digit()).collect();
+    let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c: &&mut char| c.is_ascii_digit()).collect();
+}
diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.rs b/src/tools/clippy/tests/ui/manual_is_ascii_check.rs
index bb6e2a317da..74f35ce94e8 100644
--- a/src/tools/clippy/tests/ui/manual_is_ascii_check.rs
+++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.rs
@@ -82,3 +82,8 @@ fn generics() {
     take_while(|c| (b'A'..=b'Z').contains(&c));
     take_while(|c: char| ('A'..='Z').contains(&c));
 }
+
+fn adds_type_reference() {
+    let digits: Vec<&char> = ['1', 'A'].iter().take_while(|c| ('0'..='9').contains(c)).collect();
+    let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c| ('0'..='9').contains(c)).collect();
+}
diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr b/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr
index a93ccace28a..92d93208006 100644
--- a/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr
+++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr
@@ -173,5 +173,27 @@ error: manual check for common ascii range
 LL |     take_while(|c: char| ('A'..='Z').contains(&c));
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `c.is_ascii_uppercase()`
 
-error: aborting due to 27 previous errors
+error: manual check for common ascii range
+  --> tests/ui/manual_is_ascii_check.rs:87:63
+   |
+LL |     let digits: Vec<&char> = ['1', 'A'].iter().take_while(|c| ('0'..='9').contains(c)).collect();
+   |                                                               ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL |     let digits: Vec<&char> = ['1', 'A'].iter().take_while(|c: &&char| c.is_ascii_digit()).collect();
+   |                                                            ~~~~~~~~~  ~~~~~~~~~~~~~~~~~~
+
+error: manual check for common ascii range
+  --> tests/ui/manual_is_ascii_check.rs:88:71
+   |
+LL |     let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c| ('0'..='9').contains(c)).collect();
+   |                                                                       ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL |     let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c: &&mut char| c.is_ascii_digit()).collect();
+   |                                                                    ~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 29 previous errors
 
diff --git a/src/tools/clippy/tests/ui/map_flatten.rs b/src/tools/clippy/tests/ui/map_flatten.rs
index 76916d46591..eafc8b6e81c 100644
--- a/src/tools/clippy/tests/ui/map_flatten.rs
+++ b/src/tools/clippy/tests/ui/map_flatten.rs
@@ -55,6 +55,18 @@ fn long_span() {
         .collect();
 }
 
+#[allow(clippy::useless_vec)]
+fn no_suggestion_if_comments_present() {
+    let vec = vec![vec![1, 2, 3]];
+    let _ = vec
+        .iter()
+        // a lovely comment explaining the code in very detail
+        .map(|x| x.iter())
+        //~^ ERROR: called `map(..).flatten()` on `Iterator`
+        // the answer to life, the universe and everything could be here
+        .flatten();
+}
+
 fn main() {
     long_span();
 }
diff --git a/src/tools/clippy/tests/ui/map_flatten.stderr b/src/tools/clippy/tests/ui/map_flatten.stderr
index a5837b97617..34bd174d7dd 100644
--- a/src/tools/clippy/tests/ui/map_flatten.stderr
+++ b/src/tools/clippy/tests/ui/map_flatten.stderr
@@ -102,5 +102,14 @@ LL +             }
 LL +         })
    |
 
-error: aborting due to 4 previous errors
+error: called `map(..).flatten()` on `Iterator`
+  --> tests/ui/map_flatten.rs:64:10
+   |
+LL |           .map(|x| x.iter())
+   |  __________^
+...  |
+LL | |         .flatten();
+   | |__________________^ help: try replacing `map` with `flat_map` and remove the `.flatten()`: `flat_map(|x| x.iter())`
+
+error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/map_identity.fixed b/src/tools/clippy/tests/ui/map_identity.fixed
index 53ebfb40ba0..3257ddc6f72 100644
--- a/src/tools/clippy/tests/ui/map_identity.fixed
+++ b/src/tools/clippy/tests/ui/map_identity.fixed
@@ -61,3 +61,18 @@ fn issue11764() {
     // no match ergonomics for `(i32, i32)`
     let _ = x.iter().copied();
 }
+
+fn issue13904() {
+    // don't lint: `it.next()` would not be legal as `it` is immutable
+    let it = [1, 2, 3].into_iter();
+    let _ = it.map(|x| x).next();
+
+    // lint
+    #[allow(unused_mut)]
+    let mut it = [1, 2, 3].into_iter();
+    let _ = it.next();
+
+    // lint
+    let it = [1, 2, 3].into_iter();
+    let _ = { it }.next();
+}
diff --git a/src/tools/clippy/tests/ui/map_identity.rs b/src/tools/clippy/tests/ui/map_identity.rs
index c646c056859..be3bb9a4f10 100644
--- a/src/tools/clippy/tests/ui/map_identity.rs
+++ b/src/tools/clippy/tests/ui/map_identity.rs
@@ -65,3 +65,18 @@ fn issue11764() {
     // no match ergonomics for `(i32, i32)`
     let _ = x.iter().copied().map(|(x, y)| (x, y));
 }
+
+fn issue13904() {
+    // don't lint: `it.next()` would not be legal as `it` is immutable
+    let it = [1, 2, 3].into_iter();
+    let _ = it.map(|x| x).next();
+
+    // lint
+    #[allow(unused_mut)]
+    let mut it = [1, 2, 3].into_iter();
+    let _ = it.map(|x| x).next();
+
+    // lint
+    let it = [1, 2, 3].into_iter();
+    let _ = { it }.map(|x| x).next();
+}
diff --git a/src/tools/clippy/tests/ui/map_identity.stderr b/src/tools/clippy/tests/ui/map_identity.stderr
index 0a0dc9c8f07..aa3fc4ae0b5 100644
--- a/src/tools/clippy/tests/ui/map_identity.stderr
+++ b/src/tools/clippy/tests/ui/map_identity.stderr
@@ -73,5 +73,17 @@ error: unnecessary map of the identity function
 LL |     let _ = x.iter().copied().map(|(x, y)| (x, y));
    |                              ^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
 
-error: aborting due to 11 previous errors
+error: unnecessary map of the identity function
+  --> tests/ui/map_identity.rs:77:15
+   |
+LL |     let _ = it.map(|x| x).next();
+   |               ^^^^^^^^^^^ help: remove the call to `map`
+
+error: unnecessary map of the identity function
+  --> tests/ui/map_identity.rs:81:19
+   |
+LL |     let _ = { it }.map(|x| x).next();
+   |                   ^^^^^^^^^^^ help: remove the call to `map`
+
+error: aborting due to 13 previous errors
 
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
index ca323dcf173..d2f9e34a5ce 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
@@ -47,7 +47,34 @@ fn get_y() -> u32 {
     Y
 }
 
-// Don't lint entrypoint functions
+#[cfg(test)]
+mod with_test_fn {
+    #[derive(Clone, Copy)]
+    pub struct Foo {
+        pub n: u32,
+    }
+
+    impl Foo {
+        #[must_use]
+        pub const fn new(n: u32) -> Foo {
+            Foo { n }
+        }
+    }
+
+    #[test]
+    fn foo_is_copy() {
+        let foo = Foo::new(42);
+        let one = foo;
+        let two = foo;
+        _ = one;
+        _ = two;
+    }
+}
+
+// Allowing on this function, because it would lint, which we don't want in this case.
+// if we have `#[start]` and `#[test]` check `is_entrypoint_fn(cx, def_id.to_def_id())` is stopped
+// working
+#[allow(clippy::missing_const_for_fn)]
 #[start]
 fn init(num: isize, something: *const *const u8) -> isize {
     1
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed
index 014fbb85c7a..dd9dedcdd04 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed
@@ -149,6 +149,7 @@ mod msrv {
         //~^ ERROR: this could be a `const fn`
 
         #[rustfmt::skip]
+        #[allow(missing_abi)]
         const extern fn implicit_c() {}
         //~^ ERROR: this could be a `const fn`
 
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
index 4f7c2cbcf0b..f974478540c 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
@@ -149,6 +149,7 @@ mod msrv {
         //~^ ERROR: this could be a `const fn`
 
         #[rustfmt::skip]
+        #[allow(missing_abi)]
         extern fn implicit_c() {}
         //~^ ERROR: this could be a `const fn`
 
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
index cc7dfd0888d..33836bdfe9f 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
@@ -222,7 +222,7 @@ LL |         const extern "C" fn c() {}
    |         +++++
 
 error: this could be a `const fn`
-  --> tests/ui/missing_const_for_fn/could_be_const.rs:152:9
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:153:9
    |
 LL |         extern fn implicit_c() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -233,7 +233,7 @@ LL |         const extern fn implicit_c() {}
    |         +++++
 
 error: this could be a `const fn`
-  --> tests/ui/missing_const_for_fn/could_be_const.rs:169:9
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:170:9
    |
 LL | /         pub fn new(strings: Vec<String>) -> Self {
 LL | |             Self { strings }
@@ -246,7 +246,7 @@ LL |         pub const fn new(strings: Vec<String>) -> Self {
    |             +++++
 
 error: this could be a `const fn`
-  --> tests/ui/missing_const_for_fn/could_be_const.rs:174:9
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:175:9
    |
 LL | /         pub fn empty() -> Self {
 LL | |             Self { strings: Vec::new() }
@@ -259,7 +259,7 @@ LL |         pub const fn empty() -> Self {
    |             +++++
 
 error: this could be a `const fn`
-  --> tests/ui/missing_const_for_fn/could_be_const.rs:185:9
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:186:9
    |
 LL | /         pub fn new(text: String) -> Self {
 LL | |             let vec = Vec::new();
@@ -273,7 +273,7 @@ LL |         pub const fn new(text: String) -> Self {
    |             +++++
 
 error: this could be a `const fn`
-  --> tests/ui/missing_const_for_fn/could_be_const.rs:204:5
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:205:5
    |
 LL |     fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -284,7 +284,7 @@ LL |     const fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {}
    |     +++++
 
 error: this could be a `const fn`
-  --> tests/ui/missing_const_for_fn/could_be_const.rs:208:5
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:209:5
    |
 LL |     extern "C-unwind" fn c_unwind() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -295,7 +295,7 @@ LL |     const extern "C-unwind" fn c_unwind() {}
    |     +++++
 
 error: this could be a `const fn`
-  --> tests/ui/missing_const_for_fn/could_be_const.rs:210:5
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:211:5
    |
 LL |     extern "system" fn system() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -306,7 +306,7 @@ LL |     const extern "system" fn system() {}
    |     +++++
 
 error: this could be a `const fn`
-  --> tests/ui/missing_const_for_fn/could_be_const.rs:212:5
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:213:5
    |
 LL |     extern "system-unwind" fn system_unwind() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.fixed b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.fixed
index 9da60c687d4..530eb77d83d 100644
--- a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.fixed
+++ b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.fixed
@@ -64,4 +64,9 @@ impl ValType {
     }
 }
 
+trait Foo<'r#struct> {
+    fn f1(&'r#struct self) {}
+    fn f2(&'r#struct mut self) {}
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.rs b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.rs
index fc4ec5cb0b3..5a1ff96a11c 100644
--- a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.rs
+++ b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.rs
@@ -64,4 +64,9 @@ impl ValType {
     }
 }
 
+trait Foo<'r#struct> {
+    fn f1(self: &'r#struct Self) {}
+    fn f2(self: &'r#struct mut Self) {}
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.stderr b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.stderr
index c653267f752..7ebbbaa122f 100644
--- a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.stderr
+++ b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.stderr
@@ -37,5 +37,17 @@ error: the type of the `self` parameter does not need to be arbitrary
 LL |     pub fn mut_ref_bad_with_lifetime<'a>(self: &'a mut Self) {
    |                                          ^^^^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'a mut self`
 
-error: aborting due to 6 previous errors
+error: the type of the `self` parameter does not need to be arbitrary
+  --> tests/ui/needless_arbitrary_self_type.rs:68:11
+   |
+LL |     fn f1(self: &'r#struct Self) {}
+   |           ^^^^^^^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'r#struct self`
+
+error: the type of the `self` parameter does not need to be arbitrary
+  --> tests/ui/needless_arbitrary_self_type.rs:69:11
+   |
+LL |     fn f2(self: &'r#struct mut Self) {}
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'r#struct mut self`
+
+error: aborting due to 8 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_continue.rs b/src/tools/clippy/tests/ui/needless_continue.rs
index b6d8a8f61ae..334a2b32775 100644
--- a/src/tools/clippy/tests/ui/needless_continue.rs
+++ b/src/tools/clippy/tests/ui/needless_continue.rs
@@ -87,6 +87,14 @@ fn simple_loop4() {
     }
 }
 
+fn simple_loop5() {
+    loop {
+        println!("bleh");
+        { continue }
+        //~^ ERROR: this `continue` expression is redundant
+    }
+}
+
 mod issue_2329 {
     fn condition() -> bool {
         unimplemented!()
@@ -168,3 +176,60 @@ fn issue_13641() {
         }
     }
 }
+
+mod issue_4077 {
+    fn main() {
+        'outer: loop {
+            'inner: loop {
+                do_something();
+                if some_expr() {
+                    println!("bar-7");
+                    continue 'outer;
+                } else if !some_expr() {
+                    println!("bar-8");
+                    continue 'inner;
+                } else {
+                    println!("bar-9");
+                    continue 'inner;
+                }
+            }
+        }
+
+        for _ in 0..10 {
+            match "foo".parse::<i32>() {
+                Ok(_) => do_something(),
+                Err(_) => {
+                    println!("bar-10");
+                    continue;
+                },
+            }
+        }
+
+        loop {
+            if true {
+            } else {
+                // redundant `else`
+                continue; // redundant `continue`
+            }
+        }
+
+        loop {
+            if some_expr() {
+                continue;
+            } else {
+                do_something();
+            }
+        }
+    }
+
+    // The contents of these functions are irrelevant, the purpose of this file is
+    // shown in main.
+
+    fn do_something() {
+        std::process::exit(0);
+    }
+
+    fn some_expr() -> bool {
+        true
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_continue.stderr b/src/tools/clippy/tests/ui/needless_continue.stderr
index 0741ba69248..ec39d623419 100644
--- a/src/tools/clippy/tests/ui/needless_continue.stderr
+++ b/src/tools/clippy/tests/ui/needless_continue.stderr
@@ -63,7 +63,7 @@ error: this `continue` expression is redundant
   --> tests/ui/needless_continue.rs:60:9
    |
 LL |         continue;
-   |         ^^^^^^^^^
+   |         ^^^^^^^^
    |
    = help: consider dropping the `continue` expression
 
@@ -71,7 +71,7 @@ error: this `continue` expression is redundant
   --> tests/ui/needless_continue.rs:68:9
    |
 LL |         continue;
-   |         ^^^^^^^^^
+   |         ^^^^^^^^
    |
    = help: consider dropping the `continue` expression
 
@@ -91,8 +91,16 @@ LL |         continue
    |
    = help: consider dropping the `continue` expression
 
+error: this `continue` expression is redundant
+  --> tests/ui/needless_continue.rs:93:11
+   |
+LL |         { continue }
+   |           ^^^^^^^^
+   |
+   = help: consider dropping the `continue` expression
+
 error: this `else` block is redundant
-  --> tests/ui/needless_continue.rs:136:24
+  --> tests/ui/needless_continue.rs:144:24
    |
 LL |                   } else {
    |  ________________________^
@@ -117,7 +125,7 @@ LL | |                 }
                            }
 
 error: there is no need for an explicit `else` block for this `if` expression
-  --> tests/ui/needless_continue.rs:143:17
+  --> tests/ui/needless_continue.rs:151:17
    |
 LL | /                 if condition() {
 LL | |
@@ -137,12 +145,70 @@ LL | |                 }
                            }
 
 error: this `continue` expression is redundant
-  --> tests/ui/needless_continue.rs:166:13
+  --> tests/ui/needless_continue.rs:174:13
    |
 LL |             continue 'b;
-   |             ^^^^^^^^^^^^
+   |             ^^^^^^^^^^^
    |
    = help: consider dropping the `continue` expression
 
-error: aborting due to 9 previous errors
+error: this `continue` expression is redundant
+  --> tests/ui/needless_continue.rs:190:21
+   |
+LL |                     continue 'inner;
+   |                     ^^^^^^^^^^^^^^^
+   |
+   = help: consider dropping the `continue` expression
+
+error: this `continue` expression is redundant
+  --> tests/ui/needless_continue.rs:193:21
+   |
+LL |                     continue 'inner;
+   |                     ^^^^^^^^^^^^^^^
+   |
+   = help: consider dropping the `continue` expression
+
+error: this `continue` expression is redundant
+  --> tests/ui/needless_continue.rs:203:21
+   |
+LL |                     continue;
+   |                     ^^^^^^^^
+   |
+   = help: consider dropping the `continue` expression
+
+error: this `else` block is redundant
+  --> tests/ui/needless_continue.rs:210:20
+   |
+LL |               } else {
+   |  ____________________^
+LL | |                 // redundant `else`
+LL | |                 continue; // redundant `continue`
+LL | |             }
+   | |_____________^
+   |
+   = help: consider dropping the `else` clause and merging the code that follows (in the loop) with the `if` block
+                       if true {
+           // merged code follows:
+           
+                       }
+
+error: there is no need for an explicit `else` block for this `if` expression
+  --> tests/ui/needless_continue.rs:217:13
+   |
+LL | /             if some_expr() {
+LL | |                 continue;
+LL | |             } else {
+LL | |                 do_something();
+LL | |             }
+   | |_____________^
+   |
+   = help: consider dropping the `else` clause
+                       if some_expr() {
+                           continue;
+                       }
+                       {
+                           do_something();
+                       }
+
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
index c9b76262d70..c7e0cd2610f 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
@@ -137,3 +137,11 @@ fn issue10803() {
     // Don't lint
     let _ = matches!(x, Some(16));
 }
+
+fn issue13902() {
+    let x = Some(0);
+    let p = &raw const x;
+    unsafe {
+        let _ = (*p).is_none();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
index a5f9caf659c..6d9a9f7f942 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
@@ -164,3 +164,11 @@ fn issue10803() {
     // Don't lint
     let _ = matches!(x, Some(16));
 }
+
+fn issue13902() {
+    let x = Some(0);
+    let p = &raw const x;
+    unsafe {
+        let _ = matches!(*p, None);
+    }
+}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
index 575f199be42..34d80f5ca78 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
@@ -209,5 +209,11 @@ error: redundant pattern matching, consider using `is_none()`
 LL |     let _ = matches!(x, None);
    |             ^^^^^^^^^^^^^^^^^ help: try: `x.is_none()`
 
-error: aborting due to 30 previous errors
+error: redundant pattern matching, consider using `is_none()`
+  --> tests/ui/redundant_pattern_matching_option.rs:172:17
+   |
+LL |         let _ = matches!(*p, None);
+   |                 ^^^^^^^^^^^^^^^^^^ help: try: `(*p).is_none()`
+
+error: aborting due to 31 previous errors
 
diff --git a/src/tools/clippy/tests/ui/slow_vector_initialization.rs b/src/tools/clippy/tests/ui/slow_vector_initialization.rs
index 16f81019574..2ba87f41250 100644
--- a/src/tools/clippy/tests/ui/slow_vector_initialization.rs
+++ b/src/tools/clippy/tests/ui/slow_vector_initialization.rs
@@ -11,22 +11,22 @@ fn extend_vector() {
     // Extend with constant expression
     let len = 300;
     let mut vec1 = Vec::with_capacity(len);
-    vec1.extend(repeat(0).take(len));
     //~^ ERROR: slow zero-filling initialization
     //~| NOTE: `-D clippy::slow-vector-initialization` implied by `-D warnings`
+    vec1.extend(repeat(0).take(len));
 
     // Extend with len expression
     let mut vec2 = Vec::with_capacity(len - 10);
-    vec2.extend(repeat(0).take(len - 10));
     //~^ ERROR: slow zero-filling initialization
+    vec2.extend(repeat(0).take(len - 10));
 
     // Extend with mismatching expression should not be warned
     let mut vec3 = Vec::with_capacity(24322);
     vec3.extend(repeat(0).take(2));
 
     let mut vec4 = Vec::with_capacity(len);
-    vec4.extend(repeat(0).take(vec4.capacity()));
     //~^ ERROR: slow zero-filling initialization
+    vec4.extend(repeat(0).take(vec4.capacity()));
 }
 
 fn mixed_extend_resize_vector() {
@@ -36,20 +36,20 @@ fn mixed_extend_resize_vector() {
 
     // Slow initialization
     let mut resized_vec = Vec::with_capacity(30);
-    resized_vec.resize(30, 0);
     //~^ ERROR: slow zero-filling initialization
+    resized_vec.resize(30, 0);
 
     let mut extend_vec = Vec::with_capacity(30);
-    extend_vec.extend(repeat(0).take(30));
     //~^ ERROR: slow zero-filling initialization
+    extend_vec.extend(repeat(0).take(30));
 }
 
 fn resize_vector() {
     // Resize with constant expression
     let len = 300;
     let mut vec1 = Vec::with_capacity(len);
-    vec1.resize(len, 0);
     //~^ ERROR: slow zero-filling initialization
+    vec1.resize(len, 0);
 
     // Resize mismatch len
     let mut vec2 = Vec::with_capacity(200);
@@ -57,39 +57,39 @@ fn resize_vector() {
 
     // Resize with len expression
     let mut vec3 = Vec::with_capacity(len - 10);
-    vec3.resize(len - 10, 0);
     //~^ ERROR: slow zero-filling initialization
+    vec3.resize(len - 10, 0);
 
     let mut vec4 = Vec::with_capacity(len);
-    vec4.resize(vec4.capacity(), 0);
     //~^ ERROR: slow zero-filling initialization
+    vec4.resize(vec4.capacity(), 0);
 
     // Reinitialization should be warned
     vec1 = Vec::with_capacity(10);
-    vec1.resize(10, 0);
     //~^ ERROR: slow zero-filling initialization
+    vec1.resize(10, 0);
 }
 
 fn from_empty_vec() {
     // Resize with constant expression
     let len = 300;
     let mut vec1 = Vec::new();
-    vec1.resize(len, 0);
     //~^ ERROR: slow zero-filling initialization
+    vec1.resize(len, 0);
 
     // Resize with len expression
     let mut vec3 = Vec::new();
-    vec3.resize(len - 10, 0);
     //~^ ERROR: slow zero-filling initialization
+    vec3.resize(len - 10, 0);
 
     // Reinitialization should be warned
     vec1 = Vec::new();
-    vec1.resize(10, 0);
     //~^ ERROR: slow zero-filling initialization
+    vec1.resize(10, 0);
 
     vec1 = vec![];
-    vec1.resize(10, 0);
     //~^ ERROR: slow zero-filling initialization
+    vec1.resize(10, 0);
 
     macro_rules! x {
         () => {
diff --git a/src/tools/clippy/tests/ui/slow_vector_initialization.stderr b/src/tools/clippy/tests/ui/slow_vector_initialization.stderr
index 353c677097b..7f4b9f7b67a 100644
--- a/src/tools/clippy/tests/ui/slow_vector_initialization.stderr
+++ b/src/tools/clippy/tests/ui/slow_vector_initialization.stderr
@@ -1,109 +1,122 @@
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:14:5
+  --> tests/ui/slow_vector_initialization.rs:13:20
    |
-LL |     let mut vec1 = Vec::with_capacity(len);
-   |                    ----------------------- help: consider replacing this with: `vec![0; len]`
-LL |     vec1.extend(repeat(0).take(len));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       let mut vec1 = Vec::with_capacity(len);
+   |  ____________________^
+...  |
+LL | |     vec1.extend(repeat(0).take(len));
+   | |____________________________________^ help: consider replacing this with: `vec![0; len]`
    |
    = note: `-D clippy::slow-vector-initialization` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::slow_vector_initialization)]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:20:5
+  --> tests/ui/slow_vector_initialization.rs:19:20
    |
-LL |     let mut vec2 = Vec::with_capacity(len - 10);
-   |                    ---------------------------- help: consider replacing this with: `vec![0; len - 10]`
-LL |     vec2.extend(repeat(0).take(len - 10));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       let mut vec2 = Vec::with_capacity(len - 10);
+   |  ____________________^
+LL | |
+LL | |     vec2.extend(repeat(0).take(len - 10));
+   | |_________________________________________^ help: consider replacing this with: `vec![0; len - 10]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:28:5
+  --> tests/ui/slow_vector_initialization.rs:27:20
    |
-LL |     let mut vec4 = Vec::with_capacity(len);
-   |                    ----------------------- help: consider replacing this with: `vec![0; len]`
-LL |     vec4.extend(repeat(0).take(vec4.capacity()));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       let mut vec4 = Vec::with_capacity(len);
+   |  ____________________^
+LL | |
+LL | |     vec4.extend(repeat(0).take(vec4.capacity()));
+   | |________________________________________________^ help: consider replacing this with: `vec![0; len]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:39:5
+  --> tests/ui/slow_vector_initialization.rs:38:27
    |
-LL |     let mut resized_vec = Vec::with_capacity(30);
-   |                           ---------------------- help: consider replacing this with: `vec![0; 30]`
-LL |     resized_vec.resize(30, 0);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       let mut resized_vec = Vec::with_capacity(30);
+   |  ___________________________^
+LL | |
+LL | |     resized_vec.resize(30, 0);
+   | |_____________________________^ help: consider replacing this with: `vec![0; 30]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:43:5
+  --> tests/ui/slow_vector_initialization.rs:42:26
    |
-LL |     let mut extend_vec = Vec::with_capacity(30);
-   |                          ---------------------- help: consider replacing this with: `vec![0; 30]`
-LL |     extend_vec.extend(repeat(0).take(30));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       let mut extend_vec = Vec::with_capacity(30);
+   |  __________________________^
+LL | |
+LL | |     extend_vec.extend(repeat(0).take(30));
+   | |_________________________________________^ help: consider replacing this with: `vec![0; 30]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:51:5
+  --> tests/ui/slow_vector_initialization.rs:50:20
    |
-LL |     let mut vec1 = Vec::with_capacity(len);
-   |                    ----------------------- help: consider replacing this with: `vec![0; len]`
-LL |     vec1.resize(len, 0);
-   |     ^^^^^^^^^^^^^^^^^^^
+LL |       let mut vec1 = Vec::with_capacity(len);
+   |  ____________________^
+LL | |
+LL | |     vec1.resize(len, 0);
+   | |_______________________^ help: consider replacing this with: `vec![0; len]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:60:5
+  --> tests/ui/slow_vector_initialization.rs:59:20
    |
-LL |     let mut vec3 = Vec::with_capacity(len - 10);
-   |                    ---------------------------- help: consider replacing this with: `vec![0; len - 10]`
-LL |     vec3.resize(len - 10, 0);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       let mut vec3 = Vec::with_capacity(len - 10);
+   |  ____________________^
+LL | |
+LL | |     vec3.resize(len - 10, 0);
+   | |____________________________^ help: consider replacing this with: `vec![0; len - 10]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:64:5
+  --> tests/ui/slow_vector_initialization.rs:63:20
    |
-LL |     let mut vec4 = Vec::with_capacity(len);
-   |                    ----------------------- help: consider replacing this with: `vec![0; len]`
-LL |     vec4.resize(vec4.capacity(), 0);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       let mut vec4 = Vec::with_capacity(len);
+   |  ____________________^
+LL | |
+LL | |     vec4.resize(vec4.capacity(), 0);
+   | |___________________________________^ help: consider replacing this with: `vec![0; len]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:69:5
+  --> tests/ui/slow_vector_initialization.rs:68:12
    |
-LL |     vec1 = Vec::with_capacity(10);
-   |            ---------------------- help: consider replacing this with: `vec![0; 10]`
-LL |     vec1.resize(10, 0);
-   |     ^^^^^^^^^^^^^^^^^^
+LL |       vec1 = Vec::with_capacity(10);
+   |  ____________^
+LL | |
+LL | |     vec1.resize(10, 0);
+   | |______________________^ help: consider replacing this with: `vec![0; 10]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:77:5
+  --> tests/ui/slow_vector_initialization.rs:76:20
    |
-LL |     let mut vec1 = Vec::new();
-   |                    ---------- help: consider replacing this with: `vec![0; len]`
-LL |     vec1.resize(len, 0);
-   |     ^^^^^^^^^^^^^^^^^^^
+LL |       let mut vec1 = Vec::new();
+   |  ____________________^
+LL | |
+LL | |     vec1.resize(len, 0);
+   | |_______________________^ help: consider replacing this with: `vec![0; len]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:82:5
+  --> tests/ui/slow_vector_initialization.rs:81:20
    |
-LL |     let mut vec3 = Vec::new();
-   |                    ---------- help: consider replacing this with: `vec![0; len - 10]`
-LL |     vec3.resize(len - 10, 0);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       let mut vec3 = Vec::new();
+   |  ____________________^
+LL | |
+LL | |     vec3.resize(len - 10, 0);
+   | |____________________________^ help: consider replacing this with: `vec![0; len - 10]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:87:5
+  --> tests/ui/slow_vector_initialization.rs:86:12
    |
-LL |     vec1 = Vec::new();
-   |            ---------- help: consider replacing this with: `vec![0; 10]`
-LL |     vec1.resize(10, 0);
-   |     ^^^^^^^^^^^^^^^^^^
+LL |       vec1 = Vec::new();
+   |  ____________^
+LL | |
+LL | |     vec1.resize(10, 0);
+   | |______________________^ help: consider replacing this with: `vec![0; 10]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:91:5
+  --> tests/ui/slow_vector_initialization.rs:90:12
    |
-LL |     vec1 = vec![];
-   |            ------ help: consider replacing this with: `vec![0; 10]`
-LL |     vec1.resize(10, 0);
-   |     ^^^^^^^^^^^^^^^^^^
+LL |       vec1 = vec![];
+   |  ____________^
+LL | |
+LL | |     vec1.resize(10, 0);
+   | |______________________^ help: consider replacing this with: `vec![0; 10]`
 
 error: aborting due to 13 previous errors
 
diff --git a/src/tools/clippy/tests/ui/starts_ends_with.fixed b/src/tools/clippy/tests/ui/starts_ends_with.fixed
index 4a66ca7ec91..252b6e5a98c 100644
--- a/src/tools/clippy/tests/ui/starts_ends_with.fixed
+++ b/src/tools/clippy/tests/ui/starts_ends_with.fixed
@@ -1,4 +1,4 @@
-#![allow(clippy::needless_if, dead_code, unused_must_use)]
+#![allow(clippy::needless_if, dead_code, unused_must_use, clippy::double_ended_iterator_last)]
 
 fn main() {}
 
diff --git a/src/tools/clippy/tests/ui/starts_ends_with.rs b/src/tools/clippy/tests/ui/starts_ends_with.rs
index 16a68e02d66..6c5655f3178 100644
--- a/src/tools/clippy/tests/ui/starts_ends_with.rs
+++ b/src/tools/clippy/tests/ui/starts_ends_with.rs
@@ -1,4 +1,4 @@
-#![allow(clippy::needless_if, dead_code, unused_must_use)]
+#![allow(clippy::needless_if, dead_code, unused_must_use, clippy::double_ended_iterator_last)]
 
 fn main() {}
 
diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.fixed b/src/tools/clippy/tests/ui/std_instead_of_core.fixed
index 227b98c683e..ec158ee02de 100644
--- a/src/tools/clippy/tests/ui/std_instead_of_core.fixed
+++ b/src/tools/clippy/tests/ui/std_instead_of_core.fixed
@@ -1,7 +1,7 @@
 //@aux-build:proc_macro_derive.rs
 
 #![warn(clippy::std_instead_of_core)]
-#![allow(unused_imports)]
+#![allow(unused_imports, deprecated)]
 
 extern crate alloc;
 
diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.rs b/src/tools/clippy/tests/ui/std_instead_of_core.rs
index 01bb78dd3bf..9c3c1658d8f 100644
--- a/src/tools/clippy/tests/ui/std_instead_of_core.rs
+++ b/src/tools/clippy/tests/ui/std_instead_of_core.rs
@@ -1,7 +1,7 @@
 //@aux-build:proc_macro_derive.rs
 
 #![warn(clippy::std_instead_of_core)]
-#![allow(unused_imports)]
+#![allow(unused_imports, deprecated)]
 
 extern crate alloc;
 
diff --git a/src/tools/clippy/tests/ui/trailing_empty_array.rs b/src/tools/clippy/tests/ui/trailing_empty_array.rs
index 309a5920dfd..ea3b8ff01af 100644
--- a/src/tools/clippy/tests/ui/trailing_empty_array.rs
+++ b/src/tools/clippy/tests/ui/trailing_empty_array.rs
@@ -193,3 +193,17 @@ type C = ConstParamNoDefault<0>;
 type D = ConstParamNonZeroDefault<0>;
 
 fn main() {}
+
+#[cfg(test)]
+mod tests {
+    pub struct Friend {
+        age: u8,
+    }
+
+    #[test]
+    fn oldest_empty_is_none() {
+        struct Michael {
+            friends: [Friend; 0],
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/transmute.rs b/src/tools/clippy/tests/ui/transmute.rs
index eeea3f080b1..7f5bdea4acf 100644
--- a/src/tools/clippy/tests/ui/transmute.rs
+++ b/src/tools/clippy/tests/ui/transmute.rs
@@ -24,31 +24,31 @@ fn my_vec() -> MyVec<i32> {
 #[warn(clippy::useless_transmute)]
 unsafe fn _generic<'a, T, U: 'a>(t: &'a T) {
     // FIXME: should lint
-    // let _: &'a T = core::intrinsics::transmute(t);
+    // let _: &'a T = core::mem::transmute(t);
 
-    let _: &'a U = core::intrinsics::transmute(t);
+    let _: &'a U = core::mem::transmute(t);
 
-    let _: *const T = core::intrinsics::transmute(t);
+    let _: *const T = core::mem::transmute(t);
     //~^ ERROR: transmute from a reference to a pointer
     //~| NOTE: `-D clippy::useless-transmute` implied by `-D warnings`
 
-    let _: *mut T = core::intrinsics::transmute(t);
+    let _: *mut T = core::mem::transmute(t);
     //~^ ERROR: transmute from a reference to a pointer
 
-    let _: *const U = core::intrinsics::transmute(t);
+    let _: *const U = core::mem::transmute(t);
     //~^ ERROR: transmute from a reference to a pointer
 }
 
 #[warn(clippy::useless_transmute)]
 fn useless() {
     unsafe {
-        let _: Vec<i32> = core::intrinsics::transmute(my_vec());
+        let _: Vec<i32> = core::mem::transmute(my_vec());
         //~^ ERROR: transmute from a type (`std::vec::Vec<i32>`) to itself
 
         let _: Vec<i32> = core::mem::transmute(my_vec());
         //~^ ERROR: transmute from a type (`std::vec::Vec<i32>`) to itself
 
-        let _: Vec<i32> = std::intrinsics::transmute(my_vec());
+        let _: Vec<i32> = std::mem::transmute(my_vec());
         //~^ ERROR: transmute from a type (`std::vec::Vec<i32>`) to itself
 
         let _: Vec<i32> = std::mem::transmute(my_vec());
@@ -94,17 +94,17 @@ fn crosspointer() {
     let int_mut_ptr: *mut Usize = &mut int as *mut Usize;
 
     unsafe {
-        let _: Usize = core::intrinsics::transmute(int_const_ptr);
+        let _: Usize = core::mem::transmute(int_const_ptr);
         //~^ ERROR: transmute from a type (`*const Usize`) to the type that it points to (
         //~| NOTE: `-D clippy::crosspointer-transmute` implied by `-D warnings`
 
-        let _: Usize = core::intrinsics::transmute(int_mut_ptr);
+        let _: Usize = core::mem::transmute(int_mut_ptr);
         //~^ ERROR: transmute from a type (`*mut Usize`) to the type that it points to (`U
 
-        let _: *const Usize = core::intrinsics::transmute(my_int());
+        let _: *const Usize = core::mem::transmute(my_int());
         //~^ ERROR: transmute from a type (`Usize`) to a pointer to that type (`*const Usi
 
-        let _: *mut Usize = core::intrinsics::transmute(my_int());
+        let _: *mut Usize = core::mem::transmute(my_int());
         //~^ ERROR: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize
     }
 }
diff --git a/src/tools/clippy/tests/ui/transmute.stderr b/src/tools/clippy/tests/ui/transmute.stderr
index 41a10f381dc..b5032772856 100644
--- a/src/tools/clippy/tests/ui/transmute.stderr
+++ b/src/tools/clippy/tests/ui/transmute.stderr
@@ -1,8 +1,8 @@
 error: transmute from a reference to a pointer
   --> tests/ui/transmute.rs:31:23
    |
-LL |     let _: *const T = core::intrinsics::transmute(t);
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T`
+LL |     let _: *const T = core::mem::transmute(t);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T`
    |
    = note: `-D clippy::useless-transmute` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]`
@@ -10,20 +10,20 @@ LL |     let _: *const T = core::intrinsics::transmute(t);
 error: transmute from a reference to a pointer
   --> tests/ui/transmute.rs:35:21
    |
-LL |     let _: *mut T = core::intrinsics::transmute(t);
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *mut T`
+LL |     let _: *mut T = core::mem::transmute(t);
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *mut T`
 
 error: transmute from a reference to a pointer
   --> tests/ui/transmute.rs:38:23
    |
-LL |     let _: *const U = core::intrinsics::transmute(t);
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U`
+LL |     let _: *const U = core::mem::transmute(t);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U`
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
   --> tests/ui/transmute.rs:45:27
    |
-LL |         let _: Vec<i32> = core::intrinsics::transmute(my_vec());
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         let _: Vec<i32> = core::mem::transmute(my_vec());
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
   --> tests/ui/transmute.rs:48:27
@@ -34,8 +34,8 @@ LL |         let _: Vec<i32> = core::mem::transmute(my_vec());
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
   --> tests/ui/transmute.rs:51:27
    |
-LL |         let _: Vec<i32> = std::intrinsics::transmute(my_vec());
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         let _: Vec<i32> = std::mem::transmute(my_vec());
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
   --> tests/ui/transmute.rs:54:27
@@ -64,8 +64,8 @@ LL |         let _: *const usize = std::mem::transmute(1 + 1usize);
 error: transmute from a type (`*const Usize`) to the type that it points to (`Usize`)
   --> tests/ui/transmute.rs:97:24
    |
-LL |         let _: Usize = core::intrinsics::transmute(int_const_ptr);
-   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         let _: Usize = core::mem::transmute(int_const_ptr);
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::crosspointer-transmute` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::crosspointer_transmute)]`
@@ -73,20 +73,20 @@ LL |         let _: Usize = core::intrinsics::transmute(int_const_ptr);
 error: transmute from a type (`*mut Usize`) to the type that it points to (`Usize`)
   --> tests/ui/transmute.rs:101:24
    |
-LL |         let _: Usize = core::intrinsics::transmute(int_mut_ptr);
-   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         let _: Usize = core::mem::transmute(int_mut_ptr);
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`Usize`) to a pointer to that type (`*const Usize`)
   --> tests/ui/transmute.rs:104:31
    |
-LL |         let _: *const Usize = core::intrinsics::transmute(my_int());
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         let _: *const Usize = core::mem::transmute(my_int());
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`)
   --> tests/ui/transmute.rs:107:29
    |
-LL |         let _: *mut Usize = core::intrinsics::transmute(my_int());
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         let _: *mut Usize = core::mem::transmute(my_int());
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a `u8` to a `bool`
   --> tests/ui/transmute.rs:114:28
diff --git a/src/tools/clippy/tests/ui/unnecessary_map_or.fixed b/src/tools/clippy/tests/ui/unnecessary_map_or.fixed
index 70b78ceca50..efea28e7045 100644
--- a/src/tools/clippy/tests/ui/unnecessary_map_or.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_map_or.fixed
@@ -3,15 +3,16 @@
 #![allow(clippy::no_effect)]
 #![allow(clippy::eq_op)]
 #![allow(clippy::unnecessary_lazy_evaluations)]
+#![allow(clippy::nonminimal_bool)]
 #[clippy::msrv = "1.70.0"]
 #[macro_use]
 extern crate proc_macros;
 
 fn main() {
     // should trigger
-    let _ = (Some(5) == Some(5));
-    let _ = (Some(5) != Some(5));
-    let _ = (Some(5) == Some(5));
+    let _ = Some(5) == Some(5);
+    let _ = Some(5) != Some(5);
+    let _ = Some(5) == Some(5);
     let _ = Some(5).is_some_and(|n| {
         let _ = n;
         6 >= 5
@@ -21,10 +22,13 @@ fn main() {
     let _ = Some(5).is_some_and(|n| n == n);
     let _ = Some(5).is_some_and(|n| n == if 2 > 1 { n } else { 0 });
     let _ = Ok::<Vec<i32>, i32>(vec![5]).is_ok_and(|n| n == [5]);
-    let _ = (Ok::<i32, i32>(5) == Ok(5));
+    let _ = Ok::<i32, i32>(5) == Ok(5);
     let _ = (Some(5) == Some(5)).then(|| 1);
     let _ = Some(5).is_none_or(|n| n == 5);
     let _ = Some(5).is_none_or(|n| 5 == n);
+    let _ = !(Some(5) == Some(5));
+    let _ = (Some(5) == Some(5)) || false;
+    let _ = (Some(5) == Some(5)) as usize;
 
     macro_rules! x {
         () => {
@@ -60,7 +64,7 @@ fn main() {
     #[derive(PartialEq)]
     struct S2;
     let r: Result<i32, S2> = Ok(4);
-    let _ = (r == Ok(8));
+    let _ = r == Ok(8);
 
     // do not lint `Result::map_or(true, …)`
     let r: Result<i32, S2> = Ok(4);
diff --git a/src/tools/clippy/tests/ui/unnecessary_map_or.rs b/src/tools/clippy/tests/ui/unnecessary_map_or.rs
index 50757715977..05a0ca816ef 100644
--- a/src/tools/clippy/tests/ui/unnecessary_map_or.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_map_or.rs
@@ -3,6 +3,7 @@
 #![allow(clippy::no_effect)]
 #![allow(clippy::eq_op)]
 #![allow(clippy::unnecessary_lazy_evaluations)]
+#![allow(clippy::nonminimal_bool)]
 #[clippy::msrv = "1.70.0"]
 #[macro_use]
 extern crate proc_macros;
@@ -28,6 +29,9 @@ fn main() {
     let _ = Some(5).map_or(false, |n| n == 5).then(|| 1);
     let _ = Some(5).map_or(true, |n| n == 5);
     let _ = Some(5).map_or(true, |n| 5 == n);
+    let _ = !Some(5).map_or(false, |n| n == 5);
+    let _ = Some(5).map_or(false, |n| n == 5) || false;
+    let _ = Some(5).map_or(false, |n| n == 5) as usize;
 
     macro_rules! x {
         () => {
diff --git a/src/tools/clippy/tests/ui/unnecessary_map_or.stderr b/src/tools/clippy/tests/ui/unnecessary_map_or.stderr
index 890abb01228..2b78996d5f3 100644
--- a/src/tools/clippy/tests/ui/unnecessary_map_or.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_map_or.stderr
@@ -1,30 +1,30 @@
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:12:13
+  --> tests/ui/unnecessary_map_or.rs:13:13
    |
 LL |     let _ = Some(5).map_or(false, |n| n == 5);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `Some(5) == Some(5)`
    |
    = note: `-D clippy::unnecessary-map-or` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::unnecessary_map_or)]`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:13:13
+  --> tests/ui/unnecessary_map_or.rs:14:13
    |
 LL |     let _ = Some(5).map_or(true, |n| n != 5);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) != Some(5))`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `Some(5) != Some(5)`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:14:13
+  --> tests/ui/unnecessary_map_or.rs:15:13
    |
 LL |       let _ = Some(5).map_or(false, |n| {
    |  _____________^
 LL | |         let _ = 1;
 LL | |         n == 5
 LL | |     });
-   | |______^ help: use a standard comparison instead: `(Some(5) == Some(5))`
+   | |______^ help: use a standard comparison instead: `Some(5) == Some(5)`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:18:13
+  --> tests/ui/unnecessary_map_or.rs:19:13
    |
 LL |       let _ = Some(5).map_or(false, |n| {
    |  _____________^
@@ -42,88 +42,106 @@ LL ~     });
    |
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:22:13
+  --> tests/ui/unnecessary_map_or.rs:23:13
    |
 LL |     let _ = Some(vec![5]).map_or(false, |n| n == [5]);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(vec![5]).is_some_and(|n| n == [5])`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:23:13
+  --> tests/ui/unnecessary_map_or.rs:24:13
    |
 LL |     let _ = Some(vec![1]).map_or(false, |n| vec![2] == n);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(vec![1]).is_some_and(|n| vec![2] == n)`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:24:13
+  --> tests/ui/unnecessary_map_or.rs:25:13
    |
 LL |     let _ = Some(5).map_or(false, |n| n == n);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(5).is_some_and(|n| n == n)`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:25:13
+  --> tests/ui/unnecessary_map_or.rs:26:13
    |
 LL |     let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 });
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(5).is_some_and(|n| n == if 2 > 1 { n } else { 0 })`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:26:13
+  --> tests/ui/unnecessary_map_or.rs:27:13
    |
 LL |     let _ = Ok::<Vec<i32>, i32>(vec![5]).map_or(false, |n| n == [5]);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_ok_and instead: `Ok::<Vec<i32>, i32>(vec![5]).is_ok_and(|n| n == [5])`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:27:13
+  --> tests/ui/unnecessary_map_or.rs:28:13
    |
 LL |     let _ = Ok::<i32, i32>(5).map_or(false, |n| n == 5);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Ok::<i32, i32>(5) == Ok(5))`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `Ok::<i32, i32>(5) == Ok(5)`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:28:13
+  --> tests/ui/unnecessary_map_or.rs:29:13
    |
 LL |     let _ = Some(5).map_or(false, |n| n == 5).then(|| 1);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:29:13
+  --> tests/ui/unnecessary_map_or.rs:30:13
    |
 LL |     let _ = Some(5).map_or(true, |n| n == 5);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_none_or instead: `Some(5).is_none_or(|n| n == 5)`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:30:13
+  --> tests/ui/unnecessary_map_or.rs:31:13
    |
 LL |     let _ = Some(5).map_or(true, |n| 5 == n);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_none_or instead: `Some(5).is_none_or(|n| 5 == n)`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:54:13
+  --> tests/ui/unnecessary_map_or.rs:32:14
+   |
+LL |     let _ = !Some(5).map_or(false, |n| n == 5);
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))`
+
+error: this `map_or` can be simplified
+  --> tests/ui/unnecessary_map_or.rs:33:13
+   |
+LL |     let _ = Some(5).map_or(false, |n| n == 5) || false;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))`
+
+error: this `map_or` can be simplified
+  --> tests/ui/unnecessary_map_or.rs:34:13
+   |
+LL |     let _ = Some(5).map_or(false, |n| n == 5) as usize;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))`
+
+error: this `map_or` can be simplified
+  --> tests/ui/unnecessary_map_or.rs:58:13
    |
 LL |     let _ = r.map_or(false, |x| x == 7);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_ok_and instead: `r.is_ok_and(|x| x == 7)`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:59:13
+  --> tests/ui/unnecessary_map_or.rs:63:13
    |
 LL |     let _ = r.map_or(false, func);
    |             ^^^^^^^^^^^^^^^^^^^^^ help: use is_ok_and instead: `r.is_ok_and(func)`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:60:13
+  --> tests/ui/unnecessary_map_or.rs:64:13
    |
 LL |     let _ = Some(5).map_or(false, func);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(5).is_some_and(func)`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:61:13
+  --> tests/ui/unnecessary_map_or.rs:65:13
    |
 LL |     let _ = Some(5).map_or(true, func);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_none_or instead: `Some(5).is_none_or(func)`
 
 error: this `map_or` can be simplified
-  --> tests/ui/unnecessary_map_or.rs:66:13
+  --> tests/ui/unnecessary_map_or.rs:70:13
    |
 LL |     let _ = r.map_or(false, |x| x == 8);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(r == Ok(8))`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `r == Ok(8)`
 
-error: aborting due to 18 previous errors
+error: aborting due to 21 previous errors
 
diff --git a/src/tools/clippy/tests/ui/useless_vec.rs b/src/tools/clippy/tests/ui/useless_vec.rs
new file mode 100644
index 00000000000..880809f81d7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/useless_vec.rs
@@ -0,0 +1,15 @@
+//@no-rustfix: no suggestions
+
+#![warn(clippy::useless_vec)]
+
+// Regression test for <https://github.com/rust-lang/rust-clippy/issues/13692>.
+fn foo() {
+    // There should be no suggestion in this case.
+    let _some_variable = vec![
+        //~^ useless_vec
+        1, 2, // i'm here to stay
+        3, 4, // but this one going away ;-;
+    ]; // that is life anyways
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/useless_vec.stderr b/src/tools/clippy/tests/ui/useless_vec.stderr
new file mode 100644
index 00000000000..e47364fb06d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/useless_vec.stderr
@@ -0,0 +1,21 @@
+error: useless use of `vec!`
+  --> tests/ui/useless_vec.rs:8:26
+   |
+LL |       let _some_variable = vec![
+   |  __________________________^
+LL | |
+LL | |         1, 2, // i'm here to stay
+LL | |         3, 4, // but this one going away ;-;
+LL | |     ]; // that is life anyways
+   | |_____^
+   |
+   = note: `-D clippy::useless-vec` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::useless_vec)]`
+help: you can use an array directly
+   |
+LL ~     let _some_variable = [1, 2, // i'm here to stay
+LL ~         3, 4]; // that is life anyways
+   |
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index 36f876bcdc6..c6f3d7c0d10 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -39,18 +39,22 @@ macro_rules! string_enum {
         }
 
         impl FromStr for $name {
-            type Err = ();
+            type Err = String;
 
-            fn from_str(s: &str) -> Result<Self, ()> {
+            fn from_str(s: &str) -> Result<Self, Self::Err> {
                 match s {
                     $($repr => Ok(Self::$variant),)*
-                    _ => Err(()),
+                    _ => Err(format!(concat!("unknown `", stringify!($name), "` variant: `{}`"), s)),
                 }
             }
         }
     }
 }
 
+// Make the macro visible outside of this module, for tests.
+#[cfg(test)]
+pub(crate) use string_enum;
+
 string_enum! {
     #[derive(Clone, Copy, PartialEq, Debug)]
     pub enum Mode {
@@ -63,7 +67,7 @@ string_enum! {
         Incremental => "incremental",
         RunMake => "run-make",
         Ui => "ui",
-        JsDocTest => "js-doc-test",
+        RustdocJs => "rustdoc-js",
         MirOpt => "mir-opt",
         Assembly => "assembly",
         CoverageMap => "coverage-map",
diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs
index 25bb1a5f428..ebba16d41f9 100644
--- a/src/tools/compiletest/src/header/tests.rs
+++ b/src/tools/compiletest/src/header/tests.rs
@@ -591,7 +591,7 @@ fn test_forbidden_revisions_allowed_in_non_filecheck_dir() {
         "codegen-units",
         "incremental",
         "ui",
-        "js-doc-test",
+        "rustdoc-js",
         "coverage-map",
         "coverage-run",
         "crashes",
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index 74d1f5637a8..27a046ba5bc 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -71,7 +71,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
             "which sort of compile tests to run",
             "pretty | debug-info | codegen | rustdoc \
             | rustdoc-json | codegen-units | incremental | run-make | ui \
-            | js-doc-test | mir-opt | assembly | crashes",
+            | rustdoc-js | mir-opt | assembly | crashes",
         )
         .reqopt(
             "",
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 9e8443cd13c..84f2149dbdf 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -17,8 +17,8 @@ use tracing::*;
 
 use crate::common::{
     Assembly, Codegen, CodegenUnits, CompareMode, Config, CoverageMap, CoverageRun, Crashes,
-    DebugInfo, Debugger, FailMode, Incremental, JsDocTest, MirOpt, PassMode, Pretty, RunMake,
-    Rustdoc, RustdocJson, TestPaths, UI_EXTENSIONS, UI_FIXED, UI_RUN_STDERR, UI_RUN_STDOUT,
+    DebugInfo, Debugger, FailMode, Incremental, MirOpt, PassMode, Pretty, RunMake, Rustdoc,
+    RustdocJs, RustdocJson, TestPaths, UI_EXTENSIONS, UI_FIXED, UI_RUN_STDERR, UI_RUN_STDOUT,
     UI_STDERR, UI_STDOUT, UI_SVG, UI_WINDOWS_SVG, Ui, expected_output_path, incremental_dir,
     output_base_dir, output_base_name, output_testname_unique,
 };
@@ -32,7 +32,7 @@ use crate::{ColorConfig, json, stamp_file_path};
 mod debugger;
 
 // Helper modules that implement test running logic for each test suite.
-// tidy-alphabet-start
+// tidy-alphabetical-start
 mod assembly;
 mod codegen;
 mod codegen_units;
@@ -47,7 +47,7 @@ mod run_make;
 mod rustdoc;
 mod rustdoc_json;
 mod ui;
-// tidy-alphabet-end
+// tidy-alphabetical-end
 
 #[cfg(test)]
 mod tests;
@@ -269,7 +269,7 @@ impl<'test> TestCx<'test> {
             Ui => self.run_ui_test(),
             MirOpt => self.run_mir_opt_test(),
             Assembly => self.run_assembly_test(),
-            JsDocTest => self.run_js_doc_test(),
+            RustdocJs => self.run_rustdoc_js_test(),
             CoverageMap => self.run_coverage_map_test(), // see self::coverage
             CoverageRun => self.run_coverage_run_test(), // see self::coverage
             Crashes => self.run_crash_test(),
@@ -303,7 +303,7 @@ impl<'test> TestCx<'test> {
 
     fn should_compile_successfully(&self, pm: Option<PassMode>) -> bool {
         match self.config.mode {
-            JsDocTest => true,
+            RustdocJs => true,
             Ui => pm.is_some() || self.props.fail_mode > Some(FailMode::Build),
             Crashes => false,
             Incremental => {
@@ -1627,7 +1627,7 @@ impl<'test> TestCx<'test> {
             Crashes => {
                 set_mir_dump_dir(&mut rustc);
             }
-            Pretty | DebugInfo | Rustdoc | RustdocJson | RunMake | CodegenUnits | JsDocTest => {
+            Pretty | DebugInfo | Rustdoc | RustdocJson | RunMake | CodegenUnits | RustdocJs => {
                 // do not use JSON output
             }
         }
diff --git a/src/tools/compiletest/src/runtest/js_doc.rs b/src/tools/compiletest/src/runtest/js_doc.rs
index 68c74cd155c..a83bcd70c87 100644
--- a/src/tools/compiletest/src/runtest/js_doc.rs
+++ b/src/tools/compiletest/src/runtest/js_doc.rs
@@ -3,7 +3,7 @@ use std::process::Command;
 use super::TestCx;
 
 impl TestCx<'_> {
-    pub(super) fn run_js_doc_test(&self) {
+    pub(super) fn run_rustdoc_js_test(&self) {
         if let Some(nodejs) = &self.config.nodejs {
             let out_dir = self.output_base_dir();
 
diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs
index ee7aed2a39c..8a49d630535 100644
--- a/src/tools/compiletest/src/runtest/run_make.rs
+++ b/src/tools/compiletest/src/runtest/run_make.rs
@@ -353,8 +353,8 @@ impl TestCx<'_> {
         // to work correctly.
         //
         // See <https://github.com/rust-lang/rust/pull/122248> for more background.
+        let stage0_sysroot = build_root.join("stage0-sysroot");
         if std::env::var_os("COMPILETEST_FORCE_STAGE0").is_some() {
-            let stage0_sysroot = build_root.join("stage0-sysroot");
             rustc.arg("--sysroot").arg(&stage0_sysroot);
         }
 
@@ -373,6 +373,15 @@ impl TestCx<'_> {
         // Compute dynamic library search paths for recipes.
         let recipe_dylib_search_paths = {
             let mut paths = base_dylib_search_paths.clone();
+
+            // For stage 0, we need to explicitly include the stage0-sysroot libstd dylib.
+            // See <https://github.com/rust-lang/rust/issues/135373>.
+            if std::env::var_os("COMPILETEST_FORCE_STAGE0").is_some() {
+                paths.push(
+                    stage0_sysroot.join("lib").join("rustlib").join(&self.config.host).join("lib"),
+                );
+            }
+
             paths.push(support_lib_path.parent().unwrap().to_path_buf());
             paths.push(stage_std_path.join("rustlib").join(&self.config.host).join("lib"));
             paths
diff --git a/src/tools/compiletest/src/tests.rs b/src/tools/compiletest/src/tests.rs
index fec746904de..43c6dc0a67e 100644
--- a/src/tools/compiletest/src/tests.rs
+++ b/src/tools/compiletest/src/tests.rs
@@ -66,3 +66,30 @@ fn is_test_test() {
     assert!(!is_test(&OsString::from("#a_dog_gif")));
     assert!(!is_test(&OsString::from("~a_temp_file")));
 }
+
+#[test]
+fn string_enums() {
+    // These imports are needed for the macro-generated code
+    use std::fmt;
+    use std::str::FromStr;
+
+    crate::common::string_enum! {
+        #[derive(Clone, Copy, Debug, PartialEq)]
+        enum Animal {
+            Cat => "meow",
+            Dog => "woof",
+        }
+    }
+
+    // General assertions, mostly to silence the dead code warnings
+    assert_eq!(Animal::VARIANTS.len(), 2);
+    assert_eq!(Animal::STR_VARIANTS.len(), 2);
+
+    // Correct string conversions
+    assert_eq!(Animal::Cat, "meow".parse().unwrap());
+    assert_eq!(Animal::Dog, "woof".parse().unwrap());
+
+    // Invalid conversions
+    let animal = "nya".parse::<Animal>();
+    assert_eq!("unknown `Animal` variant: `nya`", animal.unwrap_err());
+}
diff --git a/src/tools/generate-copyright/src/main.rs b/src/tools/generate-copyright/src/main.rs
index f83d16d0cab..0a446ecff5b 100644
--- a/src/tools/generate-copyright/src/main.rs
+++ b/src/tools/generate-copyright/src/main.rs
@@ -8,7 +8,10 @@ mod cargo_metadata;
 
 /// The entry point to the binary.
 ///
-/// You should probably let `bootstrap` execute this program instead of running it directly.
+/// You should probably let `bootstrap` execute this program instead of running
+/// it directly. It assumes that the current working directory is the root of a
+/// Rust git repository checkout, and constructs a bunch of relative paths based
+/// on that assumption.
 ///
 /// Run `x.py run generate-copyright`
 fn main() -> Result<(), Error> {
diff --git a/src/tools/generate-copyright/templates/COPYRIGHT-library.html b/src/tools/generate-copyright/templates/COPYRIGHT-library.html
index 2c1eba741db..590a84dd931 100644
--- a/src/tools/generate-copyright/templates/COPYRIGHT-library.html
+++ b/src/tools/generate-copyright/templates/COPYRIGHT-library.html
@@ -8,20 +8,31 @@
 
 <h1>Copyright notices for The Rust Standard Library</h1>
 
-<p>This file describes the copyright and licensing information for the Rust
-Standard Library source code within The Rust Project git tree, and the
-third-party dependencies used when building the Rust Standard Library.</p>
-
 <h2>Table of Contents</h2>
 <ul>
+    <li><a href="#short-version">Short version for non-lawyers</a></li>
+    <li><a href="#longer-version">Longer version</a></li>
     <li><a href="#in-tree-files">In-tree files</a></li>
     <li><a href="#out-of-tree-dependencies">Out-of-tree dependencies</a></li>
 </ul>
 
+<h2 id="short-version">Short version for non-lawyers</h2>
+
+The Rust Standard Library is dual-licensed under Apache 2.0 and MIT terms.
+
+<h2 id="longer-version">Longer version</h2>
+
+<p>Copyrights in the Rust Standard Library are retained by their contributors. No copyright assignment is required to contribute to the Rust project.</p>
+
+<p>Some files include explicit copyright notices and/or license notices. For full authorship information, see the version control history or <a href="https://thanks.rust-lang.org">https://thanks.rust-lang.org</a>.</p>
+
+<p>Except as otherwise noted (below and/or in individual files), the Rust Standard Library is licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a> or the <a href="http://opensource.org/licenses/MIT">MIT</a> license, at your option.</p>
+
+<p>This file describes the copyright and licensing information for the source code within The Rust Project git tree related to the Rust Standard Library, and the third-party dependencies used when building the Rust Standard Library.</p>
+
 <h2 id="in-tree-files">In-tree files</h2>
 
-<p>The following licenses cover the in-tree source files that were used in this
-release:</p>
+<p>The following licenses cover the in-tree source files that were used in this release:</p>
 
 {{ in_tree|safe }}
 
diff --git a/src/tools/generate-copyright/templates/COPYRIGHT.html b/src/tools/generate-copyright/templates/COPYRIGHT.html
index ccb177a54d4..a0ed7bfb8d0 100644
--- a/src/tools/generate-copyright/templates/COPYRIGHT.html
+++ b/src/tools/generate-copyright/templates/COPYRIGHT.html
@@ -8,27 +8,37 @@
 
 <h1>Copyright notices for The Rust Toolchain</h1>
 
-<p>This file describes the copyright and licensing information for the source
-code within The Rust Project git tree, and the third-party dependencies used
-when building the Rust toolchain (including the Rust Standard Library).</p>
-
 <h2>Table of Contents</h2>
 <ul>
+    <li><a href="#short-version">Short version for non-lawyers</a></li>
+    <li><a href="#longer-version">Longer version</a></li>
     <li><a href="#in-tree-files">In-tree files</a></li>
     <li><a href="#out-of-tree-dependencies">Out-of-tree dependencies</a></li>
 </ul>
 
+<h2 id="short-version">Short version for non-lawyers</h2>
+
+The Rust Project is dual-licensed under Apache 2.0 and MIT terms.
+
+<h2 id="longer-version">Longer version</h2>
+
+<p>Copyrights in the Rust project are retained by their contributors. No copyright assignment is required to contribute to the Rust project.</p>
+
+<p>Some files include explicit copyright notices and/or license notices. For full authorship information, see the version control history or <a href="https://thanks.rust-lang.org">https://thanks.rust-lang.org</a>.</p>
+
+<p>Except as otherwise noted (below and/or in individual files), Rust is licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a> or the <a href="http://opensource.org/licenses/MIT">MIT</a> license, at your option.</p>
+
+<p>This file describes the copyright and licensing information for the source code within The Rust Project git tree, and the third-party dependencies used when building the Rust toolchain (including the Rust Standard Library).</p>
+
 <h2 id="in-tree-files">In-tree files</h2>
 
-<p>The following licenses cover the in-tree source files that were used in this
-release:</p>
+<p>The following licenses cover the in-tree source files that were used in this release:</p>
 
 {{ in_tree|safe }}
 
 <h2 id="out-of-tree-dependencies">Out-of-tree dependencies</h2>
 
-<p>The following licenses cover the out-of-tree crates that were used in this
-release:</p>
+<p>The following licenses cover the out-of-tree crates that were used in this release:</p>
 
 {% for (key, value) in dependencies %}
     <h3>📦 {{key.name}}-{{key.version}}</h3>
diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs
index b6a1d7dfa7a..7bfa7e3355d 100644
--- a/src/tools/jsondocck/src/main.rs
+++ b/src/tools/jsondocck/src/main.rs
@@ -65,6 +65,11 @@ enum CommandKind {
     /// Checks the path doesn't exist.
     HasNotPath,
 
+    /// `//@ !has <path> <value>`
+    ///
+    /// Checks the path exists, but doesn't have the given value.
+    HasNotValue { value: String },
+
     /// `//@ is <path> <value>`
     ///
     /// Check the path is the given value.
@@ -128,10 +133,11 @@ impl CommandKind {
                 [_path, value] => Self::HasValue { value: value.clone() },
                 _ => panic!("`//@ has` must have 2 or 3 arguments, but got {args:?}"),
             },
-            ("has", true) => {
-                assert_eq!(args.len(), 1, "args={args:?}");
-                Self::HasNotPath
-            }
+            ("has", true) => match args {
+                [_path] => Self::HasNotPath,
+                [_path, value] => Self::HasNotValue { value: value.clone() },
+                _ => panic!("`//@ !has` must have 2 or 3 arguments, but got {args:?}"),
+            },
 
             (_, false) if KNOWN_DIRECTIVE_NAMES.contains(&command_name) => {
                 return None;
@@ -223,6 +229,19 @@ fn check_command(command: &Command, cache: &mut Cache) -> Result<(), String> {
                 return Err(format!("matched to {matches:?}, which didn't contain {want_value:?}"));
             }
         }
+        CommandKind::HasNotValue { value } => {
+            let wantnt_value = string_to_value(value, cache);
+            if matches.contains(&wantnt_value.as_ref()) {
+                return Err(format!(
+                    "matched to {matches:?}, which contains unwanted {wantnt_value:?}"
+                ));
+            } else if matches.is_empty() {
+                return Err(format!(
+                    "got no matches, but expected some matched (not containing {wantnt_value:?}"
+                ));
+            }
+        }
+
         CommandKind::Is { value } => {
             let want_value = string_to_value(value, cache);
             let matched = get_one(&matches)?;
diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs
index f7c752033c5..791b231c27a 100644
--- a/src/tools/jsondoclint/src/validator.rs
+++ b/src/tools/jsondoclint/src/validator.rs
@@ -303,6 +303,12 @@ impl<'a> Validator<'a> {
             PathKind::Trait => self.add_trait_or_alias_id(&x.id),
             PathKind::Type => self.add_type_id(&x.id),
         }
+
+        // FIXME: More robust support for checking things in $.index also exist in $.paths
+        if !self.krate.paths.contains_key(&x.id) {
+            self.fail(&x.id, ErrorKind::Custom(format!("No entry in '$.paths' for {x:?}")));
+        }
+
         if let Some(args) = &x.args {
             self.check_generic_args(&**args);
         }
diff --git a/src/tools/jsondoclint/src/validator/tests.rs b/src/tools/jsondoclint/src/validator/tests.rs
index e842e1318db..7fcb8ffd1f9 100644
--- a/src/tools/jsondoclint/src/validator/tests.rs
+++ b/src/tools/jsondoclint/src/validator/tests.rs
@@ -1,5 +1,5 @@
 use rustc_hash::FxHashMap;
-use rustdoc_json_types::{FORMAT_VERSION, Item, ItemKind, Visibility};
+use rustdoc_json_types::{Abi, FORMAT_VERSION, FunctionHeader, Item, ItemKind, Visibility};
 
 use super::*;
 use crate::json_find::SelectorPart;
@@ -103,6 +103,101 @@ fn errors_on_local_in_paths_and_not_index() {
 }
 
 #[test]
+fn errors_on_missing_path() {
+    // crate-name=foo
+    // ```
+    // pub struct Bar;
+    // pub fn mk_bar() -> Bar { ... }
+    // ```
+
+    let generics = Generics { params: vec![], where_predicates: vec![] };
+
+    let krate = Crate {
+        root: Id(0),
+        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 {
+                            name: "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,
+        })]),
+        external_crates: FxHashMap::default(),
+        format_version: rustdoc_json_types::FORMAT_VERSION,
+    };
+
+    check(&krate, &[Error {
+        kind: ErrorKind::Custom(
+            r#"No entry in '$.paths' for Path { name: "Bar", id: Id(1), args: None }"#.to_owned(),
+        ),
+        id: Id(1),
+    }]);
+}
+
+#[test]
 #[should_panic = "LOCAL_CRATE_ID is wrong"]
 fn checks_local_crate_id_is_correct() {
     let krate = Crate {
diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs
index 8c7ff08ccd7..f6e84465780 100644
--- a/src/tools/lint-docs/src/lib.rs
+++ b/src/tools/lint-docs/src/lib.rs
@@ -473,37 +473,64 @@ impl<'a> LintExtractor<'a> {
             .filter(|line| line.starts_with('{'))
             .map(serde_json::from_str)
             .collect::<Result<Vec<serde_json::Value>, _>>()?;
+
         // First try to find the messages with the `code` field set to our lint.
         let matches: Vec<_> = msgs
             .iter()
             .filter(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s==name))
             .map(|msg| msg["rendered"].as_str().expect("rendered field should exist").to_string())
             .collect();
-        if matches.is_empty() {
-            // Some lints override their code to something else (E0566).
-            // Try to find something that looks like it could be our lint.
-            let matches: Vec<_> = msgs.iter().filter(|msg|
-                matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name)))
-                .map(|msg| msg["rendered"].as_str().expect("rendered field should exist").to_string())
-                .collect();
-            if matches.is_empty() {
-                let rendered: Vec<&str> =
-                    msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect();
-                let non_json: Vec<&str> =
-                    stderr.lines().filter(|line| !line.starts_with('{')).collect();
-                Err(format!(
-                    "did not find lint `{}` in output of example, got:\n{}\n{}",
-                    name,
-                    non_json.join("\n"),
-                    rendered.join("\n")
-                )
-                .into())
-            } else {
-                Ok(matches.join("\n"))
-            }
-        } else {
-            Ok(matches.join("\n"))
+        if !matches.is_empty() {
+            return Ok(matches.join("\n"));
+        }
+
+        // Try to detect if an unstable lint forgot to enable a `#![feature(..)]`.
+        // Specifically exclude `test_unstable_lint` which exercises this on purpose.
+        if name != "test_unstable_lint"
+            && msgs.iter().any(|msg| {
+                matches!(&msg["code"]["code"], serde_json::Value::String(s) if s=="unknown_lints")
+                    && matches!(&msg["message"], serde_json::Value::String(s) if s.contains(name))
+            })
+        {
+            let rendered: Vec<&str> =
+                msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect();
+            let non_json: Vec<&str> =
+                stderr.lines().filter(|line| !line.starts_with('{')).collect();
+            return Err(format!(
+                "did not find lint `{}` in output of example (got unknown_lints)\n\
+                Is the lint possibly misspelled, or does it need a `#![feature(...)]`?\n\
+                Output was:\n\
+                {}\n{}",
+                name,
+                rendered.join("\n"),
+                non_json.join("\n"),
+            )
+            .into());
         }
+
+        // Some lints override their code to something else (E0566).
+        // Try to find something that looks like it could be our lint.
+        let matches: Vec<_> = msgs
+            .iter()
+            .filter(
+                |msg| matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name)),
+            )
+            .map(|msg| msg["rendered"].as_str().expect("rendered field should exist").to_string())
+            .collect();
+        if !matches.is_empty() {
+            return Ok(matches.join("\n"));
+        }
+
+        // Otherwise, give a descriptive error.
+        let rendered: Vec<&str> = msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect();
+        let non_json: Vec<&str> = stderr.lines().filter(|line| !line.starts_with('{')).collect();
+        Err(format!(
+            "did not find lint `{}` in output of example, got:\n{}\n{}",
+            name,
+            non_json.join("\n"),
+            rendered.join("\n")
+        )
+        .into())
     }
 
     /// Saves the mdbook lint chapters at the given path.
diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml
index 209fd622202..81df0964d59 100644
--- a/src/tools/miri/.github/workflows/ci.yml
+++ b/src/tools/miri/.github/workflows/ci.yml
@@ -126,7 +126,7 @@ jobs:
         with:
           fetch-depth: 256 # get a bit more of the history
       - name: install josh-proxy
-        run: RUSTFLAGS="--cap-lints warn" cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r23.12.04
+        run: cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r24.10.04
       - name: setup bot git name and email
         run: |
           git config --global user.name 'The Miri Cronjob Bot'
diff --git a/src/tools/miri/CONTRIBUTING.md b/src/tools/miri/CONTRIBUTING.md
index dd283b7c0a8..5a08ac9af60 100644
--- a/src/tools/miri/CONTRIBUTING.md
+++ b/src/tools/miri/CONTRIBUTING.md
@@ -290,7 +290,7 @@ We use the [`josh` proxy](https://github.com/josh-project/josh) to transmit chan
 rustc and Miri repositories. You can install it as follows:
 
 ```sh
-RUSTFLAGS="--cap-lints=warn" cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r23.12.04
+cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r24.10.04
 ```
 
 Josh will automatically be started and stopped by `./miri`.
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index 9042c5da577..4ae901be9b4 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -217,8 +217,8 @@ degree documented below):
 - For every other target with OS `linux`, `macos`, or `windows`, Miri should generally work, but we
   make no promises and we don't run tests for such targets.
 - We have unofficial support (not maintained by the Miri team itself) for some further operating systems.
-  - `solaris` / `illumos`: maintained by @devnexen. Supports `std::{env, thread, sync}`, but not `std::fs`.
-  - `freebsd`: **maintainer wanted**. Supports `std::env` and parts of `std::{thread, fs}`, but not `std::sync`.
+  - `solaris` / `illumos`: maintained by @devnexen. Supports the entire test suite.
+  - `freebsd`: maintained by @YohDeadfall. Supports `std::env` and parts of `std::{thread, fs}`, but not `std::sync`.
   - `android`: **maintainer wanted**. Support very incomplete, but a basic "hello world" works.
   - `wasi`: **maintainer wanted**. Support very incomplete, not even standard output works, but an empty `main` function works.
 - For targets on other operating systems, Miri might fail before even reaching the `main` function.
diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh
index 0751f86da85..5583030b490 100755
--- a/src/tools/miri/ci/ci.sh
+++ b/src/tools/miri/ci/ci.sh
@@ -147,13 +147,14 @@ case $HOST_TARGET in
     # Extra tier 2
     TEST_TARGET=arm-unknown-linux-gnueabi run_tests
     TEST_TARGET=s390x-unknown-linux-gnu run_tests # big-endian architecture of choice
+    # Not officially supported tier 2
+    TEST_TARGET=x86_64-unknown-illumos run_tests
+    TEST_TARGET=x86_64-pc-solaris run_tests
     # Partially supported targets (tier 2)
     BASIC="empty_main integer heap_alloc libc-mem vec string btreemap" # ensures we have the basics: pre-main code, system allocator
     UNIX="hello panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there
     TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs libc-pipe
     TEST_TARGET=i686-unknown-freebsd   run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs libc-pipe
-    TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX time hashmap random thread sync available-parallelism tls libc-pipe fs
-    TEST_TARGET=x86_64-pc-solaris      run_tests_minimal $BASIC $UNIX time hashmap random thread sync available-parallelism tls libc-pipe fs
     TEST_TARGET=aarch64-linux-android  run_tests_minimal $BASIC $UNIX time hashmap random sync threadname pthread epoll eventfd
     TEST_TARGET=wasm32-wasip2          run_tests_minimal $BASIC wasm
     TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std
diff --git a/src/tools/miri/etc/rust_analyzer_vscode.json b/src/tools/miri/etc/rust_analyzer_vscode.json
index 5e51c3e8880..c646953e92b 100644
--- a/src/tools/miri/etc/rust_analyzer_vscode.json
+++ b/src/tools/miri/etc/rust_analyzer_vscode.json
@@ -5,21 +5,19 @@
         "cargo-miri/Cargo.toml",
         "miri-script/Cargo.toml",
     ],
-    "rust-analyzer.check.invocationLocation": "root",
     "rust-analyzer.check.invocationStrategy": "once",
     "rust-analyzer.check.overrideCommand": [
-        "env",
-        "MIRI_AUTO_OPS=no",
         "./miri",
         "clippy", // make this `check` when working with a locally built rustc
         "--message-format=json",
     ],
+    "rust-analyzer.cargo.extraEnv": {
+        "MIRI_AUTO_OPS": "no",
+        "MIRI_IN_RA": "1",
+    },
     // Contrary to what the name suggests, this also affects proc macros.
-    "rust-analyzer.cargo.buildScripts.invocationLocation": "root",
     "rust-analyzer.cargo.buildScripts.invocationStrategy": "once",
     "rust-analyzer.cargo.buildScripts.overrideCommand": [
-        "env",
-        "MIRI_AUTO_OPS=no",
         "./miri",
         "check",
         "--message-format=json",
diff --git a/src/tools/miri/miri b/src/tools/miri/miri
index ac1a7211c4e..b1b146d7990 100755
--- a/src/tools/miri/miri
+++ b/src/tools/miri/miri
@@ -3,12 +3,16 @@ set -e
 # We want to call the binary directly, so we need to know where it ends up.
 ROOT_DIR="$(dirname "$0")"
 MIRI_SCRIPT_TARGET_DIR="$ROOT_DIR"/miri-script/target
-# If stdout is not a terminal and we are not on CI, assume that we are being invoked by RA, and use JSON output.
-if ! [ -t 1 ] && [ -z "$CI" ]; then
+TOOLCHAIN="+nightly"
+# If we are being invoked for RA, use JSON output and the default toolchain (to make proc-macros
+# work in RA). This needs a different target dir to avoid mixing up the builds.
+if [ -n "$MIRI_IN_RA" ]; then
   MESSAGE_FORMAT="--message-format=json"
+  TOOLCHAIN=""
+  MIRI_SCRIPT_TARGET_DIR="$MIRI_SCRIPT_TARGET_DIR"/ra
 fi
 # We need a nightly toolchain, for `-Zroot-dir`.
-cargo +nightly build $CARGO_EXTRA_FLAGS --manifest-path "$ROOT_DIR"/miri-script/Cargo.toml \
+cargo $TOOLCHAIN build $CARGO_EXTRA_FLAGS --manifest-path "$ROOT_DIR"/miri-script/Cargo.toml \
   -Zroot-dir="$ROOT_DIR" \
   -q --target-dir "$MIRI_SCRIPT_TARGET_DIR" $MESSAGE_FORMAT || \
   ( echo "Failed to build miri-script. Is the 'nightly' toolchain installed?"; exit 1 )
diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs
index 75ac999e8be..17a7c06b525 100644
--- a/src/tools/miri/miri-script/src/commands.rs
+++ b/src/tools/miri/miri-script/src/commands.rs
@@ -423,7 +423,7 @@ impl Command {
                 .map(|path| path.into_os_string().into_string().unwrap())
                 .collect()
         } else {
-            benches.into_iter().map(Into::into).collect()
+            benches.into_iter().collect()
         };
         let target_flag = if let Some(target) = target {
             let mut flag = OsString::from("--target=");
@@ -564,6 +564,10 @@ impl Command {
         if bless {
             e.sh.set_var("RUSTC_BLESS", "Gesundheit");
         }
+        if e.sh.var("MIRI_TEST_TARGET").is_ok() {
+            // Avoid trouble due to an incorrectly set env var.
+            bail!("MIRI_TEST_TARGET must not be set when invoking `./miri test`");
+        }
         if let Some(target) = target {
             // Tell the harness which target to test.
             e.sh.set_var("MIRI_TEST_TARGET", target);
diff --git a/src/tools/miri/miri-script/src/main.rs b/src/tools/miri/miri-script/src/main.rs
index a80fed8fcb6..279bdf8cc3f 100644
--- a/src/tools/miri/miri-script/src/main.rs
+++ b/src/tools/miri/miri-script/src/main.rs
@@ -111,6 +111,7 @@ pub enum Command {
     /// `rustup-toolchain-install-master` must be installed for this to work.
     Toolchain {
         /// Flags that are passed through to `rustup-toolchain-install-master`.
+        #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
         flags: Vec<String>,
     },
     /// Pull and merge Miri changes from the rustc repo.
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 24bef6026d4..fa5dbb99e81 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-13170cd787cb733ed24842ee825bcbd98dc01476
+01706e1a34c87656fcbfce198608f4cd2ac6461a
diff --git a/src/tools/miri/src/concurrency/cpu_affinity.rs b/src/tools/miri/src/concurrency/cpu_affinity.rs
index 4e6bca93c5a..b47b614cf5f 100644
--- a/src/tools/miri/src/concurrency/cpu_affinity.rs
+++ b/src/tools/miri/src/concurrency/cpu_affinity.rs
@@ -54,8 +54,8 @@ impl CpuAffinityMask {
                 let chunk = self.0[start..].first_chunk_mut::<4>().unwrap();
                 let offset = cpu % 32;
                 *chunk = match target.options.endian {
-                    Endian::Little => (u32::from_le_bytes(*chunk) | 1 << offset).to_le_bytes(),
-                    Endian::Big => (u32::from_be_bytes(*chunk) | 1 << offset).to_be_bytes(),
+                    Endian::Little => (u32::from_le_bytes(*chunk) | (1 << offset)).to_le_bytes(),
+                    Endian::Big => (u32::from_be_bytes(*chunk) | (1 << offset)).to_be_bytes(),
                 };
             }
             8 => {
@@ -63,8 +63,8 @@ impl CpuAffinityMask {
                 let chunk = self.0[start..].first_chunk_mut::<8>().unwrap();
                 let offset = cpu % 64;
                 *chunk = match target.options.endian {
-                    Endian::Little => (u64::from_le_bytes(*chunk) | 1 << offset).to_le_bytes(),
-                    Endian::Big => (u64::from_be_bytes(*chunk) | 1 << offset).to_be_bytes(),
+                    Endian::Little => (u64::from_le_bytes(*chunk) | (1 << offset)).to_le_bytes(),
+                    Endian::Big => (u64::from_be_bytes(*chunk) | (1 << offset)).to_be_bytes(),
                 };
             }
             other => bug!("chunk size not supported: {other}"),
diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs
index ef4034cc0c1..14c72e9398a 100644
--- a/src/tools/miri/src/concurrency/sync.rs
+++ b/src/tools/miri/src/concurrency/sync.rs
@@ -422,7 +422,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     mutex_ref: MutexRef,
                     retval_dest: Option<(Scalar, MPlaceTy<'tcx>)>,
                 }
-                @unblock = |this| {
+                |this, unblock: UnblockKind| {
+                    assert_eq!(unblock, UnblockKind::Ready);
+
                     assert!(!this.mutex_is_locked(&mutex_ref));
                     this.mutex_lock(&mutex_ref);
 
@@ -538,7 +540,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     retval: Scalar,
                     dest: MPlaceTy<'tcx>,
                 }
-                @unblock = |this| {
+                |this, unblock: UnblockKind| {
+                    assert_eq!(unblock, UnblockKind::Ready);
                     this.rwlock_reader_lock(id);
                     this.write_scalar(retval, &dest)?;
                     interp_ok(())
@@ -623,7 +626,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     retval: Scalar,
                     dest: MPlaceTy<'tcx>,
                 }
-                @unblock = |this| {
+                |this, unblock: UnblockKind| {
+                    assert_eq!(unblock, UnblockKind::Ready);
                     this.rwlock_writer_lock(id);
                     this.write_scalar(retval, &dest)?;
                     interp_ok(())
@@ -677,25 +681,29 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     retval_timeout: Scalar,
                     dest: MPlaceTy<'tcx>,
                 }
-                @unblock = |this| {
-                    // The condvar was signaled. Make sure we get the clock for that.
-                    if let Some(data_race) = &this.machine.data_race {
-                        data_race.acquire_clock(
-                            &this.machine.sync.condvars[condvar].clock,
-                            &this.machine.threads,
-                        );
+                |this, unblock: UnblockKind| {
+                    match unblock {
+                        UnblockKind::Ready => {
+                            // The condvar was signaled. Make sure we get the clock for that.
+                            if let Some(data_race) = &this.machine.data_race {
+                                data_race.acquire_clock(
+                                    &this.machine.sync.condvars[condvar].clock,
+                                    &this.machine.threads,
+                                );
+                            }
+                            // Try to acquire the mutex.
+                            // The timeout only applies to the first wait (until the signal), not for mutex acquisition.
+                            this.condvar_reacquire_mutex(&mutex_ref, retval_succ, dest)
+                        }
+                        UnblockKind::TimedOut => {
+                            // We have to remove the waiter from the queue again.
+                            let thread = this.active_thread();
+                            let waiters = &mut this.machine.sync.condvars[condvar].waiters;
+                            waiters.retain(|waiter| *waiter != thread);
+                            // Now get back the lock.
+                            this.condvar_reacquire_mutex(&mutex_ref, retval_timeout, dest)
+                        }
                     }
-                    // Try to acquire the mutex.
-                    // The timeout only applies to the first wait (until the signal), not for mutex acquisition.
-                    this.condvar_reacquire_mutex(&mutex_ref, retval_succ, dest)
-                }
-                @timeout = |this| {
-                    // We have to remove the waiter from the queue again.
-                    let thread = this.active_thread();
-                    let waiters = &mut this.machine.sync.condvars[condvar].waiters;
-                    waiters.retain(|waiter| *waiter != thread);
-                    // Now get back the lock.
-                    this.condvar_reacquire_mutex(&mutex_ref, retval_timeout, dest)
                 }
             ),
         );
@@ -752,25 +760,29 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     dest: MPlaceTy<'tcx>,
                     errno_timeout: IoError,
                 }
-                @unblock = |this| {
-                    let futex = futex_ref.0.borrow();
-                    // Acquire the clock of the futex.
-                    if let Some(data_race) = &this.machine.data_race {
-                        data_race.acquire_clock(&futex.clock, &this.machine.threads);
+                |this, unblock: UnblockKind| {
+                    match unblock {
+                        UnblockKind::Ready => {
+                            let futex = futex_ref.0.borrow();
+                            // Acquire the clock of the futex.
+                            if let Some(data_race) = &this.machine.data_race {
+                                data_race.acquire_clock(&futex.clock, &this.machine.threads);
+                            }
+                            // Write the return value.
+                            this.write_scalar(retval_succ, &dest)?;
+                            interp_ok(())
+                        },
+                        UnblockKind::TimedOut => {
+                            // Remove the waiter from the futex.
+                            let thread = this.active_thread();
+                            let mut futex = futex_ref.0.borrow_mut();
+                            futex.waiters.retain(|waiter| waiter.thread != thread);
+                            // Set errno and write return value.
+                            this.set_last_error(errno_timeout)?;
+                            this.write_scalar(retval_timeout, &dest)?;
+                            interp_ok(())
+                        },
                     }
-                    // Write the return value.
-                    this.write_scalar(retval_succ, &dest)?;
-                    interp_ok(())
-                }
-                @timeout = |this| {
-                    // Remove the waiter from the futex.
-                    let thread = this.active_thread();
-                    let mut futex = futex_ref.0.borrow_mut();
-                    futex.waiters.retain(|waiter| waiter.thread != thread);
-                    // Set errno and write return value.
-                    this.set_last_error(errno_timeout)?;
-                    this.write_scalar(retval_timeout, &dest)?;
-                    interp_ok(())
                 }
             ),
         );
diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs
index 730c27d0160..6d22dd8d68d 100644
--- a/src/tools/miri/src/concurrency/thread.rs
+++ b/src/tools/miri/src/concurrency/thread.rs
@@ -19,7 +19,7 @@ use crate::concurrency::data_race;
 use crate::shims::tls;
 use crate::*;
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[derive(Clone, Copy, Debug, PartialEq)]
 enum SchedulingAction {
     /// Execute step on the active thread.
     ExecuteStep,
@@ -30,6 +30,7 @@ enum SchedulingAction {
 }
 
 /// What to do with TLS allocations from terminated threads
+#[derive(Clone, Copy, Debug, PartialEq)]
 pub enum TlsAllocAction {
     /// Deallocate backing memory of thread-local statics as usual
     Deallocate,
@@ -38,71 +39,18 @@ pub enum TlsAllocAction {
     Leak,
 }
 
-/// Trait for callbacks that are executed when a thread gets unblocked.
-pub trait UnblockCallback<'tcx>: VisitProvenance {
-    /// Will be invoked when the thread was unblocked the "regular" way,
-    /// i.e. whatever event it was blocking on has happened.
-    fn unblock(self: Box<Self>, ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>) -> InterpResult<'tcx>;
-
-    /// Will be invoked when the timeout ellapsed without the event the
-    /// thread was blocking on having occurred.
-    fn timeout(self: Box<Self>, _ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>)
-    -> InterpResult<'tcx>;
+/// The argument type for the "unblock" callback, indicating why the thread got unblocked.
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum UnblockKind {
+    /// Operation completed successfully, thread continues normal execution.
+    Ready,
+    /// The operation did not complete within its specified duration.
+    TimedOut,
 }
-pub type DynUnblockCallback<'tcx> = Box<dyn UnblockCallback<'tcx> + 'tcx>;
-
-#[macro_export]
-macro_rules! callback {
-    (
-        @capture<$tcx:lifetime $(,)? $($lft:lifetime),*> { $($name:ident: $type:ty),* $(,)? }
-        @unblock = |$this:ident| $unblock:block
-    ) => {
-        callback!(
-            @capture<$tcx, $($lft),*> { $($name: $type),* }
-            @unblock = |$this| $unblock
-            @timeout = |_this| {
-                unreachable!(
-                    "timeout on a thread that was blocked without a timeout (or someone forgot to overwrite this method)"
-                )
-            }
-        )
-    };
-    (
-        @capture<$tcx:lifetime $(,)? $($lft:lifetime),*> { $($name:ident: $type:ty),* $(,)? }
-        @unblock = |$this:ident| $unblock:block
-        @timeout = |$this_timeout:ident| $timeout:block
-    ) => {{
-        struct Callback<$tcx, $($lft),*> {
-            $($name: $type,)*
-            _phantom: std::marker::PhantomData<&$tcx ()>,
-        }
-
-        impl<$tcx, $($lft),*> VisitProvenance for Callback<$tcx, $($lft),*> {
-            #[allow(unused_variables)]
-            fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
-                $(
-                    self.$name.visit_provenance(visit);
-                )*
-            }
-        }
-
-        impl<$tcx, $($lft),*> UnblockCallback<$tcx> for Callback<$tcx, $($lft),*> {
-            fn unblock(self: Box<Self>, $this: &mut MiriInterpCx<$tcx>) -> InterpResult<$tcx> {
-                #[allow(unused_variables)]
-                let Callback { $($name,)* _phantom } = *self;
-                $unblock
-            }
 
-            fn timeout(self: Box<Self>, $this_timeout: &mut MiriInterpCx<$tcx>) -> InterpResult<$tcx> {
-                #[allow(unused_variables)]
-                let Callback { $($name,)* _phantom } = *self;
-                $timeout
-            }
-        }
-
-        Box::new(Callback { $($name,)* _phantom: std::marker::PhantomData })
-    }}
-}
+/// Type alias for unblock callbacks, i.e. machine callbacks invoked when
+/// a thread gets unblocked.
+pub type DynUnblockCallback<'tcx> = DynMachineCallback<'tcx, UnblockKind>;
 
 /// A thread identifier.
 #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
@@ -656,7 +604,8 @@ impl<'tcx> ThreadManager<'tcx> {
                     @capture<'tcx> {
                         joined_thread_id: ThreadId,
                     }
-                    @unblock = |this| {
+                    |this, unblock: UnblockKind| {
+                        assert_eq!(unblock, UnblockKind::Ready);
                         if let Some(data_race) = &mut this.machine.data_race {
                             data_race.thread_joined(&this.machine.threads, joined_thread_id);
                         }
@@ -842,7 +791,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
             // 2. Make the scheduler the only place that can change the active
             //    thread.
             let old_thread = this.machine.threads.set_active_thread_id(thread);
-            callback.timeout(this)?;
+            callback.call(this, UnblockKind::TimedOut)?;
             this.machine.threads.set_active_thread_id(old_thread);
         }
         // found_callback can remain None if the computer's clock
@@ -1084,7 +1033,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         };
         // The callback must be executed in the previously blocked thread.
         let old_thread = this.machine.threads.set_active_thread_id(thread);
-        callback.unblock(this)?;
+        callback.call(this, UnblockKind::Ready)?;
         this.machine.threads.set_active_thread_id(old_thread);
         interp_ok(())
     }
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index adfec33beac..ca8dbdac125 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -262,6 +262,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         })
     }
 
+    /// Helper function to get a `libc` constant as an `u64`.
+    fn eval_libc_u64(&self, name: &str) -> u64 {
+        // TODO: Cache the result.
+        self.eval_libc(name).to_u64().unwrap_or_else(|_err| {
+            panic!("required libc item has unexpected type (not `u64`): {name}")
+        })
+    }
+
     /// Helper function to get a `windows` constant as a `Scalar`.
     fn eval_windows(&self, module: &str, name: &str) -> Scalar {
         self.eval_context_ref().eval_path_scalar(&["std", "sys", "pal", "windows", module, name])
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index e02d51afcef..a53b22c8041 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -13,6 +13,8 @@
 #![feature(strict_overflow_ops)]
 #![feature(pointer_is_aligned_to)]
 #![feature(unqualified_local_imports)]
+#![feature(derive_coerce_pointee)]
+#![feature(arbitrary_self_types)]
 // Configure clippy and other lints
 #![allow(
     clippy::collapsible_else_if,
@@ -126,8 +128,8 @@ pub use crate::concurrency::sync::{
     CondvarId, EvalContextExt as _, MutexRef, RwLockId, SynchronizationObjects,
 };
 pub use crate::concurrency::thread::{
-    BlockReason, EvalContextExt as _, StackEmptyCallback, ThreadId, ThreadManager, TimeoutAnchor,
-    TimeoutClock, UnblockCallback,
+    BlockReason, DynUnblockCallback, EvalContextExt as _, StackEmptyCallback, ThreadId,
+    ThreadManager, TimeoutAnchor, TimeoutClock, UnblockKind,
 };
 pub use crate::diagnostics::{
     EvalContextExt as _, NonHaltingDiagnostic, TerminationInfo, report_error,
@@ -139,8 +141,8 @@ pub use crate::eval::{
 pub use crate::helpers::{AccessKind, EvalContextExt as _};
 pub use crate::intrinsics::EvalContextExt as _;
 pub use crate::machine::{
-    AllocExtra, FrameExtra, MemoryKind, MiriInterpCx, MiriInterpCxExt, MiriMachine, MiriMemoryKind,
-    PrimitiveLayouts, Provenance, ProvenanceExtra,
+    AllocExtra, DynMachineCallback, FrameExtra, MachineCallback, MemoryKind, MiriInterpCx,
+    MiriInterpCxExt, MiriMachine, MiriMemoryKind, PrimitiveLayouts, Provenance, ProvenanceExtra,
 };
 pub use crate::mono_hash_map::MonoHashMap;
 pub use crate::operator::EvalContextExt as _;
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 5e8f616a37e..845ba484326 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -1723,3 +1723,69 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         Cow::Borrowed(ecx.machine.union_data_ranges.entry(ty).or_insert_with(compute_range))
     }
 }
+
+/// Trait for callbacks handling asynchronous machine operations.
+pub trait MachineCallback<'tcx, T>: VisitProvenance {
+    /// The function to be invoked when the callback is fired.
+    fn call(
+        self: Box<Self>,
+        ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>,
+        arg: T,
+    ) -> InterpResult<'tcx>;
+}
+
+/// Type alias for boxed machine callbacks with generic argument type.
+pub type DynMachineCallback<'tcx, T> = Box<dyn MachineCallback<'tcx, T> + 'tcx>;
+
+/// Creates a `DynMachineCallback`:
+///
+/// ```rust
+/// callback!(
+///     @capture<'tcx> {
+///         var1: Ty1,
+///         var2: Ty2<'tcx>,
+///     }
+///     |this, arg: ArgTy| {
+///         // Implement the callback here.
+///         todo!()
+///     }
+/// )
+/// ```
+///
+/// All the argument types must implement `VisitProvenance`.
+#[macro_export]
+macro_rules! callback {
+    (@capture<$tcx:lifetime $(,)? $($lft:lifetime),*>
+        { $($name:ident: $type:ty),* $(,)? }
+     |$this:ident, $arg:ident: $arg_ty:ty| $body:expr $(,)?) => {{
+        struct Callback<$tcx, $($lft),*> {
+            $($name: $type,)*
+            _phantom: std::marker::PhantomData<&$tcx ()>,
+        }
+
+        impl<$tcx, $($lft),*> VisitProvenance for Callback<$tcx, $($lft),*> {
+            fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
+                $(
+                    self.$name.visit_provenance(_visit);
+                )*
+            }
+        }
+
+        impl<$tcx, $($lft),*> MachineCallback<$tcx, $arg_ty> for Callback<$tcx, $($lft),*> {
+            fn call(
+                self: Box<Self>,
+                $this: &mut MiriInterpCx<$tcx>,
+                $arg: $arg_ty
+            ) -> InterpResult<$tcx> {
+                #[allow(unused_variables)]
+                let Callback { $($name,)* _phantom } = *self;
+                $body
+            }
+        }
+
+        Box::new(Callback {
+            $($name,)*
+            _phantom: std::marker::PhantomData
+        })
+    }};
+}
diff --git a/src/tools/miri/src/shims/files.rs b/src/tools/miri/src/shims/files.rs
index f673b834be2..73425eee515 100644
--- a/src/tools/miri/src/shims/files.rs
+++ b/src/tools/miri/src/shims/files.rs
@@ -1,6 +1,7 @@
 use std::any::Any;
 use std::collections::BTreeMap;
 use std::io::{IsTerminal, Read, SeekFrom, Write};
+use std::marker::CoercePointee;
 use std::ops::Deref;
 use std::rc::{Rc, Weak};
 use std::{fs, io};
@@ -10,16 +11,132 @@ use rustc_abi::Size;
 use crate::shims::unix::UnixFileDescription;
 use crate::*;
 
+/// A unique id for file descriptions. While we could use the address, considering that
+/// is definitely unique, the address would expose interpreter internal state when used
+/// for sorting things. So instead we generate a unique id per file description is the name
+/// for all `dup`licates and is never reused.
+#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
+pub struct FdId(usize);
+
+#[derive(Debug, Clone)]
+struct FdIdWith<T: ?Sized> {
+    id: FdId,
+    inner: T,
+}
+
+/// A refcounted pointer to a file description, also tracking the
+/// globally unique ID of this file description.
+#[repr(transparent)]
+#[derive(CoercePointee, Debug)]
+pub struct FileDescriptionRef<T: ?Sized>(Rc<FdIdWith<T>>);
+
+impl<T: ?Sized> Clone for FileDescriptionRef<T> {
+    fn clone(&self) -> Self {
+        FileDescriptionRef(self.0.clone())
+    }
+}
+
+impl<T: ?Sized> Deref for FileDescriptionRef<T> {
+    type Target = T;
+    fn deref(&self) -> &T {
+        &self.0.inner
+    }
+}
+
+impl<T: ?Sized> FileDescriptionRef<T> {
+    pub fn id(&self) -> FdId {
+        self.0.id
+    }
+}
+
+/// Holds a weak reference to the actual file description.
+#[derive(Debug)]
+pub struct WeakFileDescriptionRef<T: ?Sized>(Weak<FdIdWith<T>>);
+
+impl<T: ?Sized> Clone for WeakFileDescriptionRef<T> {
+    fn clone(&self) -> Self {
+        WeakFileDescriptionRef(self.0.clone())
+    }
+}
+
+impl<T: ?Sized> FileDescriptionRef<T> {
+    pub fn downgrade(this: &Self) -> WeakFileDescriptionRef<T> {
+        WeakFileDescriptionRef(Rc::downgrade(&this.0))
+    }
+}
+
+impl<T: ?Sized> WeakFileDescriptionRef<T> {
+    pub fn upgrade(&self) -> Option<FileDescriptionRef<T>> {
+        self.0.upgrade().map(FileDescriptionRef)
+    }
+}
+
+impl<T> VisitProvenance for WeakFileDescriptionRef<T> {
+    fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
+        // A weak reference can never be the only reference to some pointer or place.
+        // Since the actual file description is tracked by strong ref somewhere,
+        // it is ok to make this a NOP operation.
+    }
+}
+
+/// A helper trait to indirectly allow downcasting on `Rc<FdIdWith<dyn _>>`.
+/// Ideally we'd just add a `FdIdWith<Self>: Any` bound to the `FileDescription` trait,
+/// but that does not allow upcasting.
+pub trait FileDescriptionExt: 'static {
+    fn into_rc_any(self: FileDescriptionRef<Self>) -> Rc<dyn Any>;
+
+    /// We wrap the regular `close` function generically, so both handle `Rc::into_inner`
+    /// and epoll interest management.
+    fn close_ref<'tcx>(
+        self: FileDescriptionRef<Self>,
+        communicate_allowed: bool,
+        ecx: &mut MiriInterpCx<'tcx>,
+    ) -> InterpResult<'tcx, io::Result<()>>;
+}
+
+impl<T: FileDescription + 'static> FileDescriptionExt for T {
+    fn into_rc_any(self: FileDescriptionRef<Self>) -> Rc<dyn Any> {
+        self.0
+    }
+
+    fn close_ref<'tcx>(
+        self: FileDescriptionRef<Self>,
+        communicate_allowed: bool,
+        ecx: &mut MiriInterpCx<'tcx>,
+    ) -> InterpResult<'tcx, io::Result<()>> {
+        match Rc::into_inner(self.0) {
+            Some(fd) => {
+                // Remove entry from the global epoll_event_interest table.
+                ecx.machine.epoll_interests.remove(fd.id);
+
+                fd.inner.close(communicate_allowed, ecx)
+            }
+            None => {
+                // Not the last reference.
+                interp_ok(Ok(()))
+            }
+        }
+    }
+}
+
+pub type DynFileDescriptionRef = FileDescriptionRef<dyn FileDescription>;
+
+impl FileDescriptionRef<dyn FileDescription> {
+    pub fn downcast<T: FileDescription + 'static>(self) -> Option<FileDescriptionRef<T>> {
+        let inner = self.into_rc_any().downcast::<FdIdWith<T>>().ok()?;
+        Some(FileDescriptionRef(inner))
+    }
+}
+
 /// Represents an open file description.
-pub trait FileDescription: std::fmt::Debug + Any {
+pub trait FileDescription: std::fmt::Debug + FileDescriptionExt {
     fn name(&self) -> &'static str;
 
     /// Reads as much as possible into the given buffer `ptr`.
     /// `len` indicates how many bytes we should try to read.
     /// `dest` is where the return value should be stored: number of bytes read, or `-1` in case of error.
     fn read<'tcx>(
-        &self,
-        _self_ref: &FileDescriptionRef,
+        self: FileDescriptionRef<Self>,
         _communicate_allowed: bool,
         _ptr: Pointer,
         _len: usize,
@@ -33,8 +150,7 @@ pub trait FileDescription: std::fmt::Debug + Any {
     /// `len` indicates how many bytes we should try to write.
     /// `dest` is where the return value should be stored: number of bytes written, or `-1` in case of error.
     fn write<'tcx>(
-        &self,
-        _self_ref: &FileDescriptionRef,
+        self: FileDescriptionRef<Self>,
         _communicate_allowed: bool,
         _ptr: Pointer,
         _len: usize,
@@ -54,11 +170,15 @@ pub trait FileDescription: std::fmt::Debug + Any {
         throw_unsup_format!("cannot seek on {}", self.name());
     }
 
+    /// Close the file descriptor.
     fn close<'tcx>(
-        self: Box<Self>,
+        self,
         _communicate_allowed: bool,
         _ecx: &mut MiriInterpCx<'tcx>,
-    ) -> InterpResult<'tcx, io::Result<()>> {
+    ) -> InterpResult<'tcx, io::Result<()>>
+    where
+        Self: Sized,
+    {
         throw_unsup_format!("cannot close {}", self.name());
     }
 
@@ -77,21 +197,13 @@ pub trait FileDescription: std::fmt::Debug + Any {
     }
 }
 
-impl dyn FileDescription {
-    #[inline(always)]
-    pub fn downcast<T: Any>(&self) -> Option<&T> {
-        (self as &dyn Any).downcast_ref()
-    }
-}
-
 impl FileDescription for io::Stdin {
     fn name(&self) -> &'static str {
         "stdin"
     }
 
     fn read<'tcx>(
-        &self,
-        _self_ref: &FileDescriptionRef,
+        self: FileDescriptionRef<Self>,
         communicate_allowed: bool,
         ptr: Pointer,
         len: usize,
@@ -103,7 +215,7 @@ impl FileDescription for io::Stdin {
             // We want isolation mode to be deterministic, so we have to disallow all reads, even stdin.
             helpers::isolation_abort_error("`read` from stdin")?;
         }
-        let result = Read::read(&mut { self }, &mut bytes);
+        let result = Read::read(&mut &*self, &mut bytes);
         match result {
             Ok(read_size) => ecx.return_read_success(ptr, &bytes, read_size, dest),
             Err(e) => ecx.set_last_error_and_return(e, dest),
@@ -121,8 +233,7 @@ impl FileDescription for io::Stdout {
     }
 
     fn write<'tcx>(
-        &self,
-        _self_ref: &FileDescriptionRef,
+        self: FileDescriptionRef<Self>,
         _communicate_allowed: bool,
         ptr: Pointer,
         len: usize,
@@ -131,7 +242,7 @@ impl FileDescription for io::Stdout {
     ) -> InterpResult<'tcx> {
         let bytes = ecx.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?;
         // We allow writing to stderr even with isolation enabled.
-        let result = Write::write(&mut { self }, bytes);
+        let result = Write::write(&mut &*self, bytes);
         // Stdout is buffered, flush to make sure it appears on the
         // screen.  This is the write() syscall of the interpreted
         // program, we want it to correspond to a write() syscall on
@@ -155,8 +266,7 @@ impl FileDescription for io::Stderr {
     }
 
     fn write<'tcx>(
-        &self,
-        _self_ref: &FileDescriptionRef,
+        self: FileDescriptionRef<Self>,
         _communicate_allowed: bool,
         ptr: Pointer,
         len: usize,
@@ -166,7 +276,7 @@ impl FileDescription for io::Stderr {
         let bytes = ecx.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?;
         // We allow writing to stderr even with isolation enabled.
         // No need to flush, stderr is not buffered.
-        let result = Write::write(&mut { self }, bytes);
+        let result = Write::write(&mut &*self, bytes);
         match result {
             Ok(write_size) => ecx.return_write_success(write_size, dest),
             Err(e) => ecx.set_last_error_and_return(e, dest),
@@ -188,8 +298,7 @@ impl FileDescription for NullOutput {
     }
 
     fn write<'tcx>(
-        &self,
-        _self_ref: &FileDescriptionRef,
+        self: FileDescriptionRef<Self>,
         _communicate_allowed: bool,
         _ptr: Pointer,
         len: usize,
@@ -201,91 +310,10 @@ impl FileDescription for NullOutput {
     }
 }
 
-/// Structure contains both the file description and its unique identifier.
-#[derive(Clone, Debug)]
-pub struct FileDescWithId<T: FileDescription + ?Sized> {
-    id: FdId,
-    file_description: Box<T>,
-}
-
-#[derive(Clone, Debug)]
-pub struct FileDescriptionRef(Rc<FileDescWithId<dyn FileDescription>>);
-
-impl Deref for FileDescriptionRef {
-    type Target = dyn FileDescription;
-
-    fn deref(&self) -> &Self::Target {
-        &*self.0.file_description
-    }
-}
-
-impl FileDescriptionRef {
-    fn new(fd: impl FileDescription, id: FdId) -> Self {
-        FileDescriptionRef(Rc::new(FileDescWithId { id, file_description: Box::new(fd) }))
-    }
-
-    pub fn close<'tcx>(
-        self,
-        communicate_allowed: bool,
-        ecx: &mut MiriInterpCx<'tcx>,
-    ) -> InterpResult<'tcx, io::Result<()>> {
-        // Destroy this `Rc` using `into_inner` so we can call `close` instead of
-        // implicitly running the destructor of the file description.
-        let id = self.get_id();
-        match Rc::into_inner(self.0) {
-            Some(fd) => {
-                // Remove entry from the global epoll_event_interest table.
-                ecx.machine.epoll_interests.remove(id);
-
-                fd.file_description.close(communicate_allowed, ecx)
-            }
-            None => interp_ok(Ok(())),
-        }
-    }
-
-    pub fn downgrade(&self) -> WeakFileDescriptionRef {
-        WeakFileDescriptionRef { weak_ref: Rc::downgrade(&self.0) }
-    }
-
-    pub fn get_id(&self) -> FdId {
-        self.0.id
-    }
-}
-
-/// Holds a weak reference to the actual file description.
-#[derive(Clone, Debug, Default)]
-pub struct WeakFileDescriptionRef {
-    weak_ref: Weak<FileDescWithId<dyn FileDescription>>,
-}
-
-impl WeakFileDescriptionRef {
-    pub fn upgrade(&self) -> Option<FileDescriptionRef> {
-        if let Some(file_desc_with_id) = self.weak_ref.upgrade() {
-            return Some(FileDescriptionRef(file_desc_with_id));
-        }
-        None
-    }
-}
-
-impl VisitProvenance for WeakFileDescriptionRef {
-    fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
-        // A weak reference can never be the only reference to some pointer or place.
-        // Since the actual file description is tracked by strong ref somewhere,
-        // it is ok to make this a NOP operation.
-    }
-}
-
-/// A unique id for file descriptions. While we could use the address, considering that
-/// is definitely unique, the address would expose interpreter internal state when used
-/// for sorting things. So instead we generate a unique id per file description is the name
-/// for all `dup`licates and is never reused.
-#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
-pub struct FdId(usize);
-
 /// The file descriptor table
 #[derive(Debug)]
 pub struct FdTable {
-    pub fds: BTreeMap<i32, FileDescriptionRef>,
+    pub fds: BTreeMap<i32, DynFileDescriptionRef>,
     /// Unique identifier for file description, used to differentiate between various file description.
     next_file_description_id: FdId,
 }
@@ -313,8 +341,9 @@ impl FdTable {
         fds
     }
 
-    pub fn new_ref(&mut self, fd: impl FileDescription) -> FileDescriptionRef {
-        let file_handle = FileDescriptionRef::new(fd, self.next_file_description_id);
+    pub fn new_ref<T: FileDescription>(&mut self, fd: T) -> FileDescriptionRef<T> {
+        let file_handle =
+            FileDescriptionRef(Rc::new(FdIdWith { id: self.next_file_description_id, inner: fd }));
         self.next_file_description_id = FdId(self.next_file_description_id.0.strict_add(1));
         file_handle
     }
@@ -325,12 +354,16 @@ impl FdTable {
         self.insert(fd_ref)
     }
 
-    pub fn insert(&mut self, fd_ref: FileDescriptionRef) -> i32 {
+    pub fn insert(&mut self, fd_ref: DynFileDescriptionRef) -> i32 {
         self.insert_with_min_num(fd_ref, 0)
     }
 
     /// Insert a file description, giving it a file descriptor that is at least `min_fd_num`.
-    pub fn insert_with_min_num(&mut self, file_handle: FileDescriptionRef, min_fd_num: i32) -> i32 {
+    pub fn insert_with_min_num(
+        &mut self,
+        file_handle: DynFileDescriptionRef,
+        min_fd_num: i32,
+    ) -> i32 {
         // Find the lowest unused FD, starting from min_fd. If the first such unused FD is in
         // between used FDs, the find_map combinator will return it. If the first such unused FD
         // is after all other used FDs, the find_map combinator will return None, and we will use
@@ -356,12 +389,12 @@ impl FdTable {
         new_fd_num
     }
 
-    pub fn get(&self, fd_num: i32) -> Option<FileDescriptionRef> {
+    pub fn get(&self, fd_num: i32) -> Option<DynFileDescriptionRef> {
         let fd = self.fds.get(&fd_num)?;
         Some(fd.clone())
     }
 
-    pub fn remove(&mut self, fd_num: i32) -> Option<FileDescriptionRef> {
+    pub fn remove(&mut self, fd_num: i32) -> Option<DynFileDescriptionRef> {
         self.fds.remove(&fd_num)
     }
 
diff --git a/src/tools/miri/src/shims/native_lib.rs b/src/tools/miri/src/shims/native_lib.rs
index 87be5a521d1..8c9e1860f31 100644
--- a/src/tools/miri/src/shims/native_lib.rs
+++ b/src/tools/miri/src/shims/native_lib.rs
@@ -72,7 +72,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             // Functions with no declared return type (i.e., the default return)
             // have the output_type `Tuple([])`.
-            ty::Tuple(t_list) if t_list.len() == 0 => {
+            ty::Tuple(t_list) if t_list.is_empty() => {
                 unsafe { ffi::call::<()>(ptr, libffi_args.as_slice()) };
                 return interp_ok(ImmTy::uninit(dest.layout));
             }
diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs
index 72d98bc1c48..d6c77d9c4d9 100644
--- a/src/tools/miri/src/shims/time.rs
+++ b/src/tools/miri/src/shims/time.rs
@@ -331,8 +331,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             Some((TimeoutClock::Monotonic, TimeoutAnchor::Relative, duration)),
             callback!(
                 @capture<'tcx> {}
-                @unblock = |_this| { panic!("sleeping thread unblocked before time is up") }
-                @timeout = |_this| { interp_ok(()) }
+                |_this, unblock: UnblockKind| {
+                    assert_eq!(unblock, UnblockKind::TimedOut);
+                    interp_ok(())
+                }
             ),
         );
         interp_ok(Scalar::from_i32(0))
@@ -353,8 +355,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             Some((TimeoutClock::Monotonic, TimeoutAnchor::Relative, duration)),
             callback!(
                 @capture<'tcx> {}
-                @unblock = |_this| { panic!("sleeping thread unblocked before time is up") }
-                @timeout = |_this| { interp_ok(()) }
+                |_this, unblock: UnblockKind| {
+                    assert_eq!(unblock, UnblockKind::TimedOut);
+                    interp_ok(())
+                }
             ),
         );
         interp_ok(())
diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs
index e5dead1a263..0b59490308b 100644
--- a/src/tools/miri/src/shims/unix/fd.rs
+++ b/src/tools/miri/src/shims/unix/fd.rs
@@ -88,7 +88,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // If old_fd and new_fd point to the same description, then `dup_fd` ensures we keep the underlying file description alive.
             if let Some(old_new_fd) = this.machine.fds.fds.insert(new_fd_num, fd) {
                 // Ignore close error (not interpreter's) according to dup2() doc.
-                old_new_fd.close(this.machine.communicate(), this)?.ok();
+                old_new_fd.close_ref(this.machine.communicate(), this)?.ok();
             }
         }
         interp_ok(Scalar::from_i32(new_fd_num))
@@ -122,7 +122,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         };
 
         let result = fd.as_unix().flock(this.machine.communicate(), parsed_op)?;
-        drop(fd);
         // return `0` if flock is successful
         let result = result.map(|()| 0i32);
         interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
@@ -198,7 +197,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let Some(fd) = this.machine.fds.remove(fd_num) else {
             return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
-        let result = fd.close(this.machine.communicate(), this)?;
+        let result = fd.close_ref(this.machine.communicate(), this)?;
         // return `0` if close is successful
         let result = result.map(|()| 0i32);
         interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
@@ -246,7 +245,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // `usize::MAX` because it is bounded by the host's `isize`.
 
         match offset {
-            None => fd.read(&fd, communicate, buf, count, dest, this)?,
+            None => fd.read(communicate, buf, count, dest, this)?,
             Some(offset) => {
                 let Ok(offset) = u64::try_from(offset) else {
                     return this.set_last_error_and_return(LibcError("EINVAL"), dest);
@@ -286,7 +285,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         };
 
         match offset {
-            None => fd.write(&fd, communicate, buf, count, dest, this)?,
+            None => fd.write(communicate, buf, count, dest, this)?,
             Some(offset) => {
                 let Ok(offset) = u64::try_from(offset) else {
                     return this.set_last_error_and_return(LibcError("EINVAL"), dest);
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index f47a96b10fe..3353cf2cc59 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -109,56 +109,54 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
 
         // See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern.
-        #[rustfmt::skip]
         match link_name.as_str() {
             // Environment related shims
             "getenv" => {
-                let [name] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [name] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.getenv(name)?;
                 this.write_pointer(result, dest)?;
             }
             "unsetenv" => {
-                let [name] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [name] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.unsetenv(name)?;
                 this.write_scalar(result, dest)?;
             }
             "setenv" => {
-                let [name, value, overwrite] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [name, value, overwrite] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.read_scalar(overwrite)?.to_i32()?;
                 let result = this.setenv(name, value)?;
                 this.write_scalar(result, dest)?;
             }
             "getcwd" => {
-                let [buf, size] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [buf, size] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.getcwd(buf, size)?;
                 this.write_pointer(result, dest)?;
             }
             "chdir" => {
-                let [path] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [path] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.chdir(path)?;
                 this.write_scalar(result, dest)?;
             }
             "getpid" => {
-                let [] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.getpid()?;
                 this.write_scalar(result, dest)?;
             }
             "sysconf" => {
-                let [val] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                let [val] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.sysconf(val)?;
                 this.write_scalar(result, dest)?;
             }
             // File descriptors
             "read" => {
-                let [fd, buf, count] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd, buf, count] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let buf = this.read_pointer(buf)?;
                 let count = this.read_target_usize(count)?;
                 this.read(fd, buf, count, None, dest)?;
             }
             "write" => {
-                let [fd, buf, n] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd, buf, n] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let buf = this.read_pointer(buf)?;
                 let count = this.read_target_usize(n)?;
@@ -166,7 +164,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write(fd, buf, count, None, dest)?;
             }
             "pread" => {
-                let [fd, buf, count, offset] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd, buf, count, offset] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let buf = this.read_pointer(buf)?;
                 let count = this.read_target_usize(count)?;
@@ -174,7 +172,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.read(fd, buf, count, Some(offset), dest)?;
             }
             "pwrite" => {
-                let [fd, buf, n, offset] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd, buf, n, offset] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let buf = this.read_pointer(buf)?;
                 let count = this.read_target_usize(n)?;
@@ -183,49 +181,51 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write(fd, buf, count, Some(offset), dest)?;
             }
             "pread64" => {
-                let [fd, buf, count, offset] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd, buf, count, offset] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let buf = this.read_pointer(buf)?;
                 let count = this.read_target_usize(count)?;
-                let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off64_t").size)?;
+                let offset =
+                    this.read_scalar(offset)?.to_int(this.libc_ty_layout("off64_t").size)?;
                 this.read(fd, buf, count, Some(offset), dest)?;
             }
             "pwrite64" => {
-                let [fd, buf, n, offset] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd, buf, n, offset] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let buf = this.read_pointer(buf)?;
                 let count = this.read_target_usize(n)?;
-                let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off64_t").size)?;
+                let offset =
+                    this.read_scalar(offset)?.to_int(this.libc_ty_layout("off64_t").size)?;
                 trace!("Called pwrite64({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
                 this.write(fd, buf, count, Some(offset), dest)?;
             }
             "close" => {
-                let [fd] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.close(fd)?;
                 this.write_scalar(result, dest)?;
             }
             "fcntl" => {
                 // `fcntl` is variadic. The argument count is checked based on the first argument
                 // in `this.fcntl()`, so we do not use `check_shim` here.
-                this.check_abi_and_shim_symbol_clash(abi, Conv::C , link_name)?;
+                this.check_abi_and_shim_symbol_clash(abi, Conv::C, link_name)?;
                 let result = this.fcntl(args)?;
                 this.write_scalar(result, dest)?;
             }
             "dup" => {
-                let [old_fd] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [old_fd] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let old_fd = this.read_scalar(old_fd)?.to_i32()?;
                 let new_fd = this.dup(old_fd)?;
                 this.write_scalar(new_fd, dest)?;
             }
             "dup2" => {
-                let [old_fd, new_fd] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [old_fd, new_fd] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let old_fd = this.read_scalar(old_fd)?.to_i32()?;
                 let new_fd = this.read_scalar(new_fd)?.to_i32()?;
                 let result = this.dup2(old_fd, new_fd)?;
                 this.write_scalar(result, dest)?;
             }
             "flock" => {
-                let [fd, op] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd, op] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let op = this.read_scalar(op)?.to_i32()?;
                 let result = this.flock(fd, op)?;
@@ -234,48 +234,49 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // File and file system access
             "open" | "open64" => {
-                // `open` is variadic, the third argument is only present when the second argument has O_CREAT (or on linux O_TMPFILE, but miri doesn't support that) set
-                this.check_abi_and_shim_symbol_clash(abi, Conv::C , link_name)?;
+                // `open` is variadic, the third argument is only present when the second argument
+                // has O_CREAT (or on linux O_TMPFILE, but miri doesn't support that) set
+                this.check_abi_and_shim_symbol_clash(abi, Conv::C, link_name)?;
                 let result = this.open(args)?;
                 this.write_scalar(result, dest)?;
             }
             "unlink" => {
-                let [path] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [path] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.unlink(path)?;
                 this.write_scalar(result, dest)?;
             }
             "symlink" => {
-                let [target, linkpath] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [target, linkpath] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.symlink(target, linkpath)?;
                 this.write_scalar(result, dest)?;
             }
             "rename" => {
-                let [oldpath, newpath] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [oldpath, newpath] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.rename(oldpath, newpath)?;
                 this.write_scalar(result, dest)?;
             }
             "mkdir" => {
-                let [path, mode] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [path, mode] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.mkdir(path, mode)?;
                 this.write_scalar(result, dest)?;
             }
             "rmdir" => {
-                let [path] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [path] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.rmdir(path)?;
                 this.write_scalar(result, dest)?;
             }
             "opendir" => {
-                let [name] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [name] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.opendir(name)?;
                 this.write_scalar(result, dest)?;
             }
             "closedir" => {
-                let [dirp] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [dirp] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.closedir(dirp)?;
                 this.write_scalar(result, dest)?;
             }
             "lseek64" => {
-                let [fd, offset, whence] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd, offset, whence] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let offset = this.read_scalar(offset)?.to_i64()?;
                 let whence = this.read_scalar(whence)?.to_i32()?;
@@ -283,7 +284,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(result, dest)?;
             }
             "lseek" => {
-                let [fd, offset, whence] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd, offset, whence] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
                 let whence = this.read_scalar(whence)?.to_i32()?;
@@ -291,39 +292,36 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(result, dest)?;
             }
             "ftruncate64" => {
-                let [fd, length] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd, length] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let length = this.read_scalar(length)?.to_i64()?;
                 let result = this.ftruncate64(fd, length.into())?;
                 this.write_scalar(result, dest)?;
             }
             "ftruncate" => {
-                let [fd, length] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd, length] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let fd = this.read_scalar(fd)?.to_i32()?;
                 let length = this.read_scalar(length)?.to_int(this.libc_ty_layout("off_t").size)?;
                 let result = this.ftruncate64(fd, length)?;
                 this.write_scalar(result, dest)?;
             }
             "fsync" => {
-                let [fd] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.fsync(fd)?;
                 this.write_scalar(result, dest)?;
             }
             "fdatasync" => {
-                let [fd] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.fdatasync(fd)?;
                 this.write_scalar(result, dest)?;
             }
             "readlink" => {
-                let [pathname, buf, bufsize] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [pathname, buf, bufsize] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.readlink(pathname, buf, bufsize)?;
                 this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
             }
             "posix_fadvise" => {
-                let [fd, offset, len, advice] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd, offset, len, advice] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.read_scalar(fd)?.to_i32()?;
                 this.read_target_isize(offset)?;
                 this.read_target_isize(len)?;
@@ -332,12 +330,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_null(dest)?;
             }
             "realpath" => {
-                let [path, resolved_path] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [path, resolved_path] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.realpath(path, resolved_path)?;
                 this.write_scalar(result, dest)?;
             }
             "mkstemp" => {
-                let [template] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [template] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.mkstemp(template)?;
                 this.write_scalar(result, dest)?;
             }
@@ -345,63 +343,59 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Unnamed sockets and pipes
             "socketpair" => {
                 let [domain, type_, protocol, sv] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                    this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.socketpair(domain, type_, protocol, sv)?;
                 this.write_scalar(result, dest)?;
             }
             "pipe" => {
-                let [pipefd] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                let [pipefd] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.pipe2(pipefd, /*flags*/ None)?;
                 this.write_scalar(result, dest)?;
             }
             "pipe2" => {
                 // Currently this function does not exist on all Unixes, e.g. on macOS.
-                if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "solaris" | "illumos") {
-                    throw_unsup_format!(
-                        "`pipe2` is not supported on {}",
-                        this.tcx.sess.target.os
-                    );
+                if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "solaris" | "illumos")
+                {
+                    throw_unsup_format!("`pipe2` is not supported on {}", this.tcx.sess.target.os);
                 }
-                let [pipefd, flags] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                let [pipefd, flags] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.pipe2(pipefd, Some(flags))?;
                 this.write_scalar(result, dest)?;
             }
 
             // Time
             "gettimeofday" => {
-                let [tv, tz] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [tv, tz] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.gettimeofday(tv, tz)?;
                 this.write_scalar(result, dest)?;
             }
             "localtime_r" => {
-                let [timep, result_op] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [timep, result_op] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.localtime_r(timep, result_op)?;
                 this.write_pointer(result, dest)?;
             }
             "clock_gettime" => {
-                let [clk_id, tp] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                let [clk_id, tp] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.clock_gettime(clk_id, tp)?;
                 this.write_scalar(result, dest)?;
             }
 
             // Allocation
             "posix_memalign" => {
-                let [memptr, align, size] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [memptr, align, size] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.posix_memalign(memptr, align, size)?;
                 this.write_scalar(result, dest)?;
             }
 
             "mmap" => {
-                let [addr, length, prot, flags, fd, offset] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [addr, length, prot, flags, fd, offset] =
+                    this.check_shim(abi, Conv::C, link_name, args)?;
                 let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
                 let ptr = this.mmap(addr, length, prot, flags, fd, offset)?;
                 this.write_scalar(ptr, dest)?;
             }
             "munmap" => {
-                let [addr, length] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [addr, length] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.munmap(addr, length)?;
                 this.write_scalar(result, dest)?;
             }
@@ -414,8 +408,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         this.tcx.sess.target.os
                     );
                 }
-                let [ptr, nmemb, size] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                let [ptr, nmemb, size] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let nmemb = this.read_target_usize(nmemb)?;
                 let size = this.read_target_usize(size)?;
@@ -438,19 +431,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "aligned_alloc" => {
                 // This is a C11 function, we assume all Unixes have it.
                 // (MSVC explicitly does not support this.)
-                let [align, size] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                let [align, size] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let res = this.aligned_alloc(align, size)?;
                 this.write_pointer(res, dest)?;
             }
 
             // Dynamic symbol loading
             "dlsym" => {
-                let [handle, symbol] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [handle, symbol] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.read_target_usize(handle)?;
                 let symbol = this.read_pointer(symbol)?;
                 let name = this.read_c_str(symbol)?;
-                if let Ok(name) = str::from_utf8(name) && is_dyn_sym(name, &this.tcx.sess.target.os) {
+                if let Ok(name) = str::from_utf8(name)
+                    && is_dyn_sym(name, &this.tcx.sess.target.os)
+                {
                     let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name)));
                     this.write_pointer(ptr, dest)?;
                 } else {
@@ -460,7 +454,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // Thread-local storage
             "pthread_key_create" => {
-                let [key, dtor] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [key, dtor] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let key_place = this.deref_pointer_as(key, this.libc_ty_layout("pthread_key_t"))?;
                 let dtor = this.read_pointer(dtor)?;
 
@@ -488,21 +482,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_null(dest)?;
             }
             "pthread_key_delete" => {
-                let [key] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [key] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
                 this.machine.tls.delete_tls_key(key)?;
                 // Return success (0)
                 this.write_null(dest)?;
             }
             "pthread_getspecific" => {
-                let [key] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [key] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
                 let active_thread = this.active_thread();
                 let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
                 this.write_scalar(ptr, dest)?;
             }
             "pthread_setspecific" => {
-                let [key, new_ptr] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [key, new_ptr] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
                 let active_thread = this.active_thread();
                 let new_data = this.read_scalar(new_ptr)?;
@@ -514,151 +508,149 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // Synchronization primitives
             "pthread_mutexattr_init" => {
-                let [attr] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [attr] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_mutexattr_init(attr)?;
                 this.write_null(dest)?;
             }
             "pthread_mutexattr_settype" => {
-                let [attr, kind] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [attr, kind] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.pthread_mutexattr_settype(attr, kind)?;
                 this.write_scalar(result, dest)?;
             }
             "pthread_mutexattr_destroy" => {
-                let [attr] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [attr] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_mutexattr_destroy(attr)?;
                 this.write_null(dest)?;
             }
             "pthread_mutex_init" => {
-                let [mutex, attr] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [mutex, attr] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_mutex_init(mutex, attr)?;
                 this.write_null(dest)?;
             }
             "pthread_mutex_lock" => {
-                let [mutex] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [mutex] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_mutex_lock(mutex, dest)?;
             }
             "pthread_mutex_trylock" => {
-                let [mutex] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [mutex] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.pthread_mutex_trylock(mutex)?;
                 this.write_scalar(result, dest)?;
             }
             "pthread_mutex_unlock" => {
-                let [mutex] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [mutex] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.pthread_mutex_unlock(mutex)?;
                 this.write_scalar(result, dest)?;
             }
             "pthread_mutex_destroy" => {
-                let [mutex] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [mutex] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_mutex_destroy(mutex)?;
                 this.write_int(0, dest)?;
             }
             "pthread_rwlock_rdlock" => {
-                let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_rwlock_rdlock(rwlock, dest)?;
             }
             "pthread_rwlock_tryrdlock" => {
-                let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.pthread_rwlock_tryrdlock(rwlock)?;
                 this.write_scalar(result, dest)?;
             }
             "pthread_rwlock_wrlock" => {
-                let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_rwlock_wrlock(rwlock, dest)?;
             }
             "pthread_rwlock_trywrlock" => {
-                let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.pthread_rwlock_trywrlock(rwlock)?;
                 this.write_scalar(result, dest)?;
             }
             "pthread_rwlock_unlock" => {
-                let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_rwlock_unlock(rwlock)?;
                 this.write_null(dest)?;
             }
             "pthread_rwlock_destroy" => {
-                let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_rwlock_destroy(rwlock)?;
                 this.write_null(dest)?;
             }
             "pthread_condattr_init" => {
-                let [attr] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [attr] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_condattr_init(attr)?;
                 this.write_null(dest)?;
             }
             "pthread_condattr_setclock" => {
-                let [attr, clock_id] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                let [attr, clock_id] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.pthread_condattr_setclock(attr, clock_id)?;
                 this.write_scalar(result, dest)?;
             }
             "pthread_condattr_getclock" => {
-                let [attr, clock_id] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                let [attr, clock_id] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_condattr_getclock(attr, clock_id)?;
                 this.write_null(dest)?;
             }
             "pthread_condattr_destroy" => {
-                let [attr] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [attr] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_condattr_destroy(attr)?;
                 this.write_null(dest)?;
             }
             "pthread_cond_init" => {
-                let [cond, attr] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [cond, attr] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_cond_init(cond, attr)?;
                 this.write_null(dest)?;
             }
             "pthread_cond_signal" => {
-                let [cond] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [cond] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_cond_signal(cond)?;
                 this.write_null(dest)?;
             }
             "pthread_cond_broadcast" => {
-                let [cond] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [cond] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_cond_broadcast(cond)?;
                 this.write_null(dest)?;
             }
             "pthread_cond_wait" => {
-                let [cond, mutex] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [cond, mutex] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_cond_wait(cond, mutex, dest)?;
             }
             "pthread_cond_timedwait" => {
-                let [cond, mutex, abstime] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [cond, mutex, abstime] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_cond_timedwait(cond, mutex, abstime, dest)?;
             }
             "pthread_cond_destroy" => {
-                let [cond] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [cond] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_cond_destroy(cond)?;
                 this.write_null(dest)?;
             }
 
             // Threading
             "pthread_create" => {
-                let [thread, attr, start, arg] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [thread, attr, start, arg] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.pthread_create(thread, attr, start, arg)?;
                 this.write_null(dest)?;
             }
             "pthread_join" => {
-                let [thread, retval] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [thread, retval] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let res = this.pthread_join(thread, retval)?;
                 this.write_scalar(res, dest)?;
             }
             "pthread_detach" => {
-                let [thread] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [thread] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let res = this.pthread_detach(thread)?;
                 this.write_scalar(res, dest)?;
             }
             "pthread_self" => {
-                let [] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let res = this.pthread_self()?;
                 this.write_scalar(res, dest)?;
             }
             "sched_yield" => {
-                let [] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.sched_yield()?;
                 this.write_null(dest)?;
             }
             "nanosleep" => {
-                let [req, rem] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [req, rem] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.nanosleep(req, rem)?;
                 this.write_scalar(result, dest)?;
             }
@@ -671,8 +663,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     );
                 }
 
-                let [pid, cpusetsize, mask] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                let [pid, cpusetsize, mask] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let pid = this.read_scalar(pid)?.to_u32()?;
                 let cpusetsize = this.read_target_usize(cpusetsize)?;
                 let mask = this.read_pointer(mask)?;
@@ -680,7 +671,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // TODO: when https://github.com/rust-lang/miri/issues/3730 is fixed this should use its notion of tid/pid
                 let thread_id = match pid {
                     0 => this.active_thread(),
-                    _ => throw_unsup_format!("`sched_getaffinity` is only supported with a pid of 0 (indicating the current thread)"),
+                    _ =>
+                        throw_unsup_format!(
+                            "`sched_getaffinity` is only supported with a pid of 0 (indicating the current thread)"
+                        ),
                 };
 
                 // The mask is stored in chunks, and the size must be a whole number of chunks.
@@ -694,7 +688,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 } else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&thread_id) {
                     let cpuset = cpuset.clone();
                     // we only copy whole chunks of size_of::<c_ulong>()
-                    let byte_count = Ord::min(cpuset.as_slice().len(), cpusetsize.try_into().unwrap());
+                    let byte_count =
+                        Ord::min(cpuset.as_slice().len(), cpusetsize.try_into().unwrap());
                     this.write_bytes_ptr(mask, cpuset.as_slice()[..byte_count].iter().copied())?;
                     this.write_null(dest)?;
                 } else {
@@ -711,8 +706,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     );
                 }
 
-                let [pid, cpusetsize, mask] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                let [pid, cpusetsize, mask] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let pid = this.read_scalar(pid)?.to_u32()?;
                 let cpusetsize = this.read_target_usize(cpusetsize)?;
                 let mask = this.read_pointer(mask)?;
@@ -720,7 +714,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // TODO: when https://github.com/rust-lang/miri/issues/3730 is fixed this should use its notion of tid/pid
                 let thread_id = match pid {
                     0 => this.active_thread(),
-                    _ => throw_unsup_format!("`sched_setaffinity` is only supported with a pid of 0 (indicating the current thread)"),
+                    _ =>
+                        throw_unsup_format!(
+                            "`sched_setaffinity` is only supported with a pid of 0 (indicating the current thread)"
+                        ),
                 };
 
                 if this.ptr_is_null(mask)? {
@@ -729,7 +726,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     // NOTE: cpusetsize might be smaller than `CpuAffinityMask::CPU_MASK_BYTES`.
                     // Any unspecified bytes are treated as zero here (none of the CPUs are configured).
                     // This is not exactly documented, so we assume that this is the behavior in practice.
-                    let bits_slice = this.read_bytes_ptr_strip_provenance(mask, Size::from_bytes(cpusetsize))?;
+                    let bits_slice =
+                        this.read_bytes_ptr_strip_provenance(mask, Size::from_bytes(cpusetsize))?;
                     // This ignores the bytes beyond `CpuAffinityMask::CPU_MASK_BYTES`
                     let bits_array: [u8; CpuAffinityMask::CPU_MASK_BYTES] =
                         std::array::from_fn(|i| bits_slice.get(i).copied().unwrap_or(0));
@@ -748,12 +746,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // Miscellaneous
             "isatty" => {
-                let [fd] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [fd] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.isatty(fd)?;
                 this.write_scalar(result, dest)?;
             }
             "pthread_atfork" => {
-                let [prepare, parent, child] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [prepare, parent, child] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.read_pointer(prepare)?;
                 this.read_pointer(parent)?;
                 this.read_pointer(child)?;
@@ -763,15 +761,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "getentropy" => {
                 // This function is non-standard but exists with the same signature and behavior on
                 // Linux, macOS, FreeBSD and Solaris/Illumos.
-                if !matches!(&*this.tcx.sess.target.os, "linux" | "macos" | "freebsd" | "illumos" | "solaris" | "android") {
+                if !matches!(
+                    &*this.tcx.sess.target.os,
+                    "linux" | "macos" | "freebsd" | "illumos" | "solaris" | "android"
+                ) {
                     throw_unsup_format!(
                         "`getentropy` is not supported on {}",
                         this.tcx.sess.target.os
                     );
                 }
 
-                let [buf, bufsize] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                let [buf, bufsize] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let buf = this.read_pointer(buf)?;
                 let bufsize = this.read_target_usize(bufsize)?;
 
@@ -789,8 +789,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
 
             "strerror_r" => {
-                let [errnum, buf, buflen] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                let [errnum, buf, buflen] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let result = this.strerror_r(errnum, buf, buflen)?;
                 this.write_scalar(result, dest)?;
             }
@@ -798,14 +797,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "getrandom" => {
                 // This function is non-standard but exists with the same signature and behavior on
                 // Linux, FreeBSD and Solaris/Illumos.
-                if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "illumos" | "solaris" | "android") {
+                if !matches!(
+                    &*this.tcx.sess.target.os,
+                    "linux" | "freebsd" | "illumos" | "solaris" | "android"
+                ) {
                     throw_unsup_format!(
                         "`getrandom` is not supported on {}",
                         this.tcx.sess.target.os
                     );
                 }
-                let [ptr, len, flags] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                let [ptr, len, flags] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let len = this.read_target_usize(len)?;
                 let _flags = this.read_scalar(flags)?.to_i32()?;
@@ -822,7 +823,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         this.tcx.sess.target.os
                     );
                 }
-                let [ptr, len] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [ptr, len] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let len = this.read_target_usize(len)?;
                 this.gen_random(ptr, len)?;
@@ -841,7 +842,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // For arm32 they did something custom, but similar enough that the same
                 // `_Unwind_RaiseException` impl in miri should work:
                 // https://github.com/ARM-software/abi-aa/blob/main/ehabi32/ehabi32.rst
-                if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "illumos" | "solaris" | "android" | "macos") {
+                if !matches!(
+                    &*this.tcx.sess.target.os,
+                    "linux" | "freebsd" | "illumos" | "solaris" | "android" | "macos"
+                ) {
                     throw_unsup_format!(
                         "`_Unwind_RaiseException` is not supported on {}",
                         this.tcx.sess.target.os
@@ -853,43 +857,42 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 return interp_ok(EmulateItemResult::NeedsUnwind);
             }
             "getuid" => {
-                let [] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
                 // For now, just pretend we always have this fixed UID.
                 this.write_int(UID, dest)?;
             }
 
             // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
             // These shims are enabled only when the caller is in the standard library.
-            "pthread_attr_getguardsize"
-            if this.frame_in_std() => {
-                let [_attr, guard_size] = this.check_shim(abi, Conv::C , link_name, args)?;
+            "pthread_attr_getguardsize" if this.frame_in_std() => {
+                let [_attr, guard_size] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let guard_size = this.deref_pointer(guard_size)?;
                 let guard_size_layout = this.libc_ty_layout("size_t");
-                this.write_scalar(Scalar::from_uint(this.machine.page_size, guard_size_layout.size), &guard_size)?;
+                this.write_scalar(
+                    Scalar::from_uint(this.machine.page_size, guard_size_layout.size),
+                    &guard_size,
+                )?;
 
                 // Return success (`0`).
                 this.write_null(dest)?;
             }
 
-            | "pthread_attr_init"
-            | "pthread_attr_destroy"
-            if this.frame_in_std() => {
-                let [_] = this.check_shim(abi, Conv::C , link_name, args)?;
+            "pthread_attr_init" | "pthread_attr_destroy" if this.frame_in_std() => {
+                let [_] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.write_null(dest)?;
             }
-            | "pthread_attr_setstacksize"
-            if this.frame_in_std() => {
-                let [_, _] = this.check_shim(abi, Conv::C , link_name, args)?;
+            "pthread_attr_setstacksize" if this.frame_in_std() => {
+                let [_, _] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.write_null(dest)?;
             }
 
-            "pthread_attr_getstack"
-            if this.frame_in_std() => {
+            "pthread_attr_getstack" if this.frame_in_std() => {
                 // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here.
                 // Hence we can mostly ignore the input `attr_place`.
                 let [attr_place, addr_place, size_place] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
-                let _attr_place = this.deref_pointer_as(attr_place, this.libc_ty_layout("pthread_attr_t"))?;
+                    this.check_shim(abi, Conv::C, link_name, args)?;
+                let _attr_place =
+                    this.deref_pointer_as(attr_place, this.libc_ty_layout("pthread_attr_t"))?;
                 let addr_place = this.deref_pointer(addr_place)?;
                 let size_place = this.deref_pointer(size_place)?;
 
@@ -906,24 +909,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_null(dest)?;
             }
 
-            | "signal"
-            | "sigaltstack"
-            if this.frame_in_std() => {
-                let [_, _] = this.check_shim(abi, Conv::C , link_name, args)?;
+            "signal" | "sigaltstack" if this.frame_in_std() => {
+                let [_, _] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.write_null(dest)?;
             }
-            | "sigaction"
-            | "mprotect"
-            if this.frame_in_std() => {
-                let [_, _, _] = this.check_shim(abi, Conv::C , link_name, args)?;
+            "sigaction" | "mprotect" if this.frame_in_std() => {
+                let [_, _, _] = this.check_shim(abi, Conv::C, link_name, args)?;
                 this.write_null(dest)?;
             }
 
-            "getpwuid_r" | "__posix_getpwuid_r"
-            if this.frame_in_std() => {
+            "getpwuid_r" | "__posix_getpwuid_r" if this.frame_in_std() => {
                 // getpwuid_r is the standard name, __posix_getpwuid_r is used on solarish
                 let [uid, pwd, buf, buflen, result] =
-                    this.check_shim(abi, Conv::C , link_name, args)?;
+                    this.check_shim(abi, Conv::C, link_name, args)?;
                 this.check_no_isolation("`getpwuid_r`")?;
 
                 let uid = this.read_scalar(uid)?.to_u32()?;
@@ -961,11 +959,26 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             _ => {
                 let target_os = &*this.tcx.sess.target.os;
                 return match target_os {
-                    "android" => android::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
-                    "freebsd" => freebsd::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
-                    "linux" => linux::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
-                    "macos" => macos::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
-                    "solaris" | "illumos" => solarish::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
+                    "android" =>
+                        android::EvalContextExt::emulate_foreign_item_inner(
+                            this, link_name, abi, args, dest,
+                        ),
+                    "freebsd" =>
+                        freebsd::EvalContextExt::emulate_foreign_item_inner(
+                            this, link_name, abi, args, dest,
+                        ),
+                    "linux" =>
+                        linux::EvalContextExt::emulate_foreign_item_inner(
+                            this, link_name, abi, args, dest,
+                        ),
+                    "macos" =>
+                        macos::EvalContextExt::emulate_foreign_item_inner(
+                            this, link_name, abi, args, dest,
+                        ),
+                    "solaris" | "illumos" =>
+                        solarish::EvalContextExt::emulate_foreign_item_inner(
+                            this, link_name, abi, args, dest,
+                        ),
                     _ => interp_ok(EmulateItemResult::NotSupported),
                 };
             }
diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
index 5381234e28c..03dbd931329 100644
--- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
@@ -21,29 +21,38 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
         match link_name.as_str() {
             // Threading
-            "pthread_set_name_np" => {
+            "pthread_setname_np" => {
                 let [thread, name] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let max_len = usize::MAX; // FreeBSD does not seem to have a limit.
-                // FreeBSD's pthread_set_name_np does not return anything.
-                this.pthread_setname_np(
+                let res = match this.pthread_setname_np(
                     this.read_scalar(thread)?,
                     this.read_scalar(name)?,
                     max_len,
                     /* truncate */ false,
-                )?;
+                )? {
+                    ThreadNameResult::Ok => Scalar::from_u32(0),
+                    ThreadNameResult::NameTooLong => unreachable!(),
+                    ThreadNameResult::ThreadNotFound => this.eval_libc("ESRCH"),
+                };
+                this.write_scalar(res, dest)?;
             }
-            "pthread_get_name_np" => {
+            "pthread_getname_np" => {
                 let [thread, name, len] = this.check_shim(abi, Conv::C, link_name, args)?;
-                // FreeBSD's pthread_get_name_np does not return anything
-                // and uses strlcpy, which truncates the resulting value,
+                // FreeBSD's pthread_getname_np uses strlcpy, which truncates the resulting value,
                 // but always adds a null terminator (except for zero-sized buffers).
                 // https://github.com/freebsd/freebsd-src/blob/c2d93a803acef634bd0eede6673aeea59e90c277/lib/libthr/thread/thr_info.c#L119-L144
-                this.pthread_getname_np(
+                let res = match this.pthread_getname_np(
                     this.read_scalar(thread)?,
                     this.read_scalar(name)?,
                     this.read_scalar(len)?,
                     /* truncate */ true,
-                )?;
+                )? {
+                    ThreadNameResult::Ok => Scalar::from_u32(0),
+                    // `NameTooLong` is possible when the buffer is zero sized,
+                    ThreadNameResult::NameTooLong => Scalar::from_u32(0),
+                    ThreadNameResult::ThreadNotFound => this.eval_libc("ESRCH"),
+                };
+                this.write_scalar(res, dest)?;
             }
 
             // File related shims
diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs
index 5682fb659e7..25594b78031 100644
--- a/src/tools/miri/src/shims/unix/fs.rs
+++ b/src/tools/miri/src/shims/unix/fs.rs
@@ -31,8 +31,7 @@ impl FileDescription for FileHandle {
     }
 
     fn read<'tcx>(
-        &self,
-        _self_ref: &FileDescriptionRef,
+        self: FileDescriptionRef<Self>,
         communicate_allowed: bool,
         ptr: Pointer,
         len: usize,
@@ -49,8 +48,7 @@ impl FileDescription for FileHandle {
     }
 
     fn write<'tcx>(
-        &self,
-        _self_ref: &FileDescriptionRef,
+        self: FileDescriptionRef<Self>,
         communicate_allowed: bool,
         ptr: Pointer,
         len: usize,
@@ -76,7 +74,7 @@ impl FileDescription for FileHandle {
     }
 
     fn close<'tcx>(
-        self: Box<Self>,
+        self,
         communicate_allowed: bool,
         _ecx: &mut MiriInterpCx<'tcx>,
     ) -> InterpResult<'tcx, io::Result<()>> {
@@ -87,7 +85,7 @@ impl FileDescription for FileHandle {
             // to handle possible errors correctly.
             let result = self.file.sync_all();
             // Now we actually close the file and return the result.
-            drop(*self);
+            drop(self.file);
             interp_ok(result)
         } else {
             // We drop the file, this closes it but ignores any errors
@@ -96,7 +94,7 @@ impl FileDescription for FileHandle {
             // `/dev/urandom` which are read-only. Check
             // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439
             // for a deeper discussion.
-            drop(*self);
+            drop(self.file);
             interp_ok(Ok(()))
         }
     }
@@ -1311,22 +1309,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         };
 
         // FIXME: Support ftruncate64 for all FDs
-        let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| {
+        let file = fd.downcast::<FileHandle>().ok_or_else(|| {
             err_unsup_format!("`ftruncate64` is only supported on file-backed file descriptors")
         })?;
 
-        if *writable {
+        if file.writable {
             if let Ok(length) = length.try_into() {
-                let result = file.set_len(length);
-                drop(fd);
+                let result = file.file.set_len(length);
                 let result = this.try_unwrap_io_result(result.map(|_| 0i32))?;
                 interp_ok(Scalar::from_i32(result))
             } else {
-                drop(fd);
                 this.set_last_error_and_return_i32(LibcError("EINVAL"))
             }
         } else {
-            drop(fd);
             // The file is not writable
             this.set_last_error_and_return_i32(LibcError("EINVAL"))
         }
@@ -1358,11 +1353,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
         // Only regular files support synchronization.
-        let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| {
+        let file = fd.downcast::<FileHandle>().ok_or_else(|| {
             err_unsup_format!("`fsync` is only supported on file-backed file descriptors")
         })?;
-        let io_result = maybe_sync_file(file, *writable, File::sync_all);
-        drop(fd);
+        let io_result = maybe_sync_file(&file.file, file.writable, File::sync_all);
         interp_ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?))
     }
 
@@ -1382,11 +1376,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
         // Only regular files support synchronization.
-        let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| {
+        let file = fd.downcast::<FileHandle>().ok_or_else(|| {
             err_unsup_format!("`fdatasync` is only supported on file-backed file descriptors")
         })?;
-        let io_result = maybe_sync_file(file, *writable, File::sync_data);
-        drop(fd);
+        let io_result = maybe_sync_file(&file.file, file.writable, File::sync_data);
         interp_ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?))
     }
 
@@ -1425,11 +1418,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
         // Only regular files support synchronization.
-        let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| {
+        let file = fd.downcast::<FileHandle>().ok_or_else(|| {
             err_unsup_format!("`sync_data_range` is only supported on file-backed file descriptors")
         })?;
-        let io_result = maybe_sync_file(file, *writable, File::sync_data);
-        drop(fd);
+        let io_result = maybe_sync_file(&file.file, file.writable, File::sync_data);
         interp_ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?))
     }
 
diff --git a/src/tools/miri/src/shims/unix/linux_like/epoll.rs b/src/tools/miri/src/shims/unix/linux_like/epoll.rs
index 5b240351c20..de8bcb54aef 100644
--- a/src/tools/miri/src/shims/unix/linux_like/epoll.rs
+++ b/src/tools/miri/src/shims/unix/linux_like/epoll.rs
@@ -5,12 +5,14 @@ use std::rc::{Rc, Weak};
 use std::time::Duration;
 
 use crate::concurrency::VClock;
-use crate::shims::files::{FdId, FileDescription, FileDescriptionRef, WeakFileDescriptionRef};
+use crate::shims::files::{
+    DynFileDescriptionRef, FdId, FileDescription, FileDescriptionRef, WeakFileDescriptionRef,
+};
 use crate::shims::unix::UnixFileDescription;
 use crate::*;
 
 /// An `Epoll` file descriptor connects file handles and epoll events
-#[derive(Clone, Debug, Default)]
+#[derive(Debug, Default)]
 struct Epoll {
     /// A map of EpollEventInterests registered under this epoll instance.
     /// Each entry is differentiated using FdId and file descriptor value.
@@ -18,11 +20,15 @@ struct Epoll {
     /// A map of EpollEventInstance that will be returned when `epoll_wait` is called.
     /// Similar to interest_list, the entry is also differentiated using FdId
     /// and file descriptor value.
-    // This is an Rc because EpollInterest need to hold a reference to update
-    // it.
-    ready_list: Rc<ReadyList>,
+    ready_list: ReadyList,
     /// A list of thread ids blocked on this epoll instance.
-    thread_id: RefCell<Vec<ThreadId>>,
+    blocked_tid: RefCell<Vec<ThreadId>>,
+}
+
+impl VisitProvenance for Epoll {
+    fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {
+        // No provenance anywhere in this type.
+    }
 }
 
 /// EpollEventInstance contains information that will be returned by epoll_wait.
@@ -51,7 +57,7 @@ impl EpollEventInstance {
 /// see the man page:
 ///
 /// <https://man7.org/linux/man-pages/man2/epoll_ctl.2.html>
-#[derive(Clone, Debug)]
+#[derive(Debug)]
 pub struct EpollEventInterest {
     /// The file descriptor value of the file description registered.
     /// This is only used for ready_list, to inform userspace which FD triggered an event.
@@ -65,10 +71,10 @@ pub struct EpollEventInterest {
     /// but only u64 is supported for now.
     /// <https://man7.org/linux/man-pages/man3/epoll_event.3type.html>
     data: u64,
-    /// Ready list of the epoll instance under which this EpollEventInterest is registered.
-    ready_list: Rc<ReadyList>,
     /// The epoll file description that this EpollEventInterest is registered under.
-    weak_epfd: WeakFileDescriptionRef,
+    /// This is weak to avoid cycles, but an upgrade is always guaranteed to succeed
+    /// because only the `Epoll` holds a strong ref to a `EpollEventInterest`.
+    weak_epfd: WeakFileDescriptionRef<Epoll>,
 }
 
 /// EpollReadyEvents reflects the readiness of a file description.
@@ -134,19 +140,13 @@ impl EpollReadyEvents {
     }
 }
 
-impl Epoll {
-    fn get_ready_list(&self) -> Rc<ReadyList> {
-        Rc::clone(&self.ready_list)
-    }
-}
-
 impl FileDescription for Epoll {
     fn name(&self) -> &'static str {
         "epoll"
     }
 
     fn close<'tcx>(
-        self: Box<Self>,
+        self,
         _communicate_allowed: bool,
         _ecx: &mut MiriInterpCx<'tcx>,
     ) -> InterpResult<'tcx, io::Result<()>> {
@@ -271,17 +271,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let Some(epfd) = this.machine.fds.get(epfd_value) else {
             return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
-        let epoll_file_description = epfd
+        let epfd = epfd
             .downcast::<Epoll>()
             .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_ctl`"))?;
 
-        let mut interest_list = epoll_file_description.interest_list.borrow_mut();
-        let ready_list = &epoll_file_description.ready_list;
+        let mut interest_list = epfd.interest_list.borrow_mut();
 
         let Some(fd_ref) = this.machine.fds.get(fd) else {
             return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
-        let id = fd_ref.get_id();
+        let id = fd_ref.id();
 
         if op == epoll_ctl_add || op == epoll_ctl_mod {
             // Read event bitmask and data from epoll_event passed by caller.
@@ -337,30 +336,33 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 }
             }
 
-            // Create an epoll_interest.
-            let interest = Rc::new(RefCell::new(EpollEventInterest {
-                fd_num: fd,
-                events,
-                data,
-                ready_list: Rc::clone(ready_list),
-                weak_epfd: epfd.downgrade(),
-            }));
-
             if op == epoll_ctl_add {
+                // Create an epoll_interest.
+                let interest = Rc::new(RefCell::new(EpollEventInterest {
+                    fd_num: fd,
+                    events,
+                    data,
+                    weak_epfd: FileDescriptionRef::downgrade(&epfd),
+                }));
+                // Notification will be returned for current epfd if there is event in the file
+                // descriptor we registered.
+                check_and_update_one_event_interest(&fd_ref, &interest, id, this)?;
+
                 // Insert an epoll_interest to global epoll_interest list.
                 this.machine.epoll_interests.insert_epoll_interest(id, Rc::downgrade(&interest));
-                interest_list.insert(epoll_key, Rc::clone(&interest));
+                interest_list.insert(epoll_key, interest);
             } else {
-                // Directly modify the epoll_interest so the global epoll_event_interest table
-                // will be updated too.
-                let mut epoll_interest = interest_list.get_mut(&epoll_key).unwrap().borrow_mut();
-                epoll_interest.events = events;
-                epoll_interest.data = data;
+                // Modify the existing interest.
+                let epoll_interest = interest_list.get_mut(&epoll_key).unwrap();
+                {
+                    let mut epoll_interest = epoll_interest.borrow_mut();
+                    epoll_interest.events = events;
+                    epoll_interest.data = data;
+                }
+                // Updating an FD interest triggers events.
+                check_and_update_one_event_interest(&fd_ref, epoll_interest, id, this)?;
             }
 
-            // Notification will be returned for current epfd if there is event in the file
-            // descriptor we registered.
-            check_and_update_one_event_interest(&fd_ref, interest, id, this)?;
             interp_ok(Scalar::from_i32(0))
         } else if op == epoll_ctl_del {
             let epoll_key = (id, fd);
@@ -373,7 +375,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             drop(epoll_interest);
 
             // Remove related epoll_interest from ready list.
-            ready_list.mapping.borrow_mut().remove(&epoll_key);
+            epfd.ready_list.mapping.borrow_mut().remove(&epoll_key);
 
             // Remove dangling EpollEventInterest from its global table.
             // .unwrap() below should succeed because the file description id must have registered
@@ -452,24 +454,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let Some(epfd) = this.machine.fds.get(epfd_value) else {
             return this.set_last_error_and_return(LibcError("EBADF"), dest);
         };
-        // Create a weak ref of epfd and pass it to callback so we will make sure that epfd
-        // is not close after the thread unblocks.
-        let weak_epfd = epfd.downgrade();
+        let Some(epfd) = epfd.downcast::<Epoll>() else {
+            return this.set_last_error_and_return(LibcError("EBADF"), dest);
+        };
 
         // We just need to know if the ready list is empty and borrow the thread_ids out.
-        // The whole logic is wrapped inside a block so we don't need to manually drop epfd later.
-        let ready_list_empty;
-        let mut thread_ids;
-        {
-            let epoll_file_description = epfd
-                .downcast::<Epoll>()
-                .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_wait`"))?;
-            ready_list_empty = epoll_file_description.ready_list.mapping.borrow().is_empty();
-            thread_ids = epoll_file_description.thread_id.borrow_mut();
-        }
+        let ready_list_empty = epfd.ready_list.mapping.borrow().is_empty();
         if timeout == 0 || !ready_list_empty {
             // If the ready list is not empty, or the timeout is 0, we can return immediately.
-            return_ready_list(epfd_value, weak_epfd, dest, &event, this)?;
+            return_ready_list(&epfd, dest, &event, this)?;
         } else {
             // Blocking
             let timeout = match timeout {
@@ -484,34 +477,37 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     );
                 }
             };
-            thread_ids.push(this.active_thread());
+            // Record this thread as blocked.
+            epfd.blocked_tid.borrow_mut().push(this.active_thread());
+            // And block it.
             let dest = dest.clone();
+            // We keep a strong ref to the underlying `Epoll` to make sure it sticks around.
+            // This means there'll be a leak if we never wake up, but that anyway would imply
+            // a thread is permanently blocked so this is fine.
             this.block_thread(
                 BlockReason::Epoll,
                 timeout,
                 callback!(
                     @capture<'tcx> {
-                        epfd_value: i32,
-                        weak_epfd: WeakFileDescriptionRef,
+                        epfd: FileDescriptionRef<Epoll>,
                         dest: MPlaceTy<'tcx>,
                         event: MPlaceTy<'tcx>,
                     }
-                    @unblock = |this| {
-                        return_ready_list(epfd_value, weak_epfd, &dest, &event, this)?;
-                        interp_ok(())
-                    }
-                    @timeout = |this| {
-                        // No notification after blocking timeout.
-                        let Some(epfd) = weak_epfd.upgrade() else {
-                            throw_unsup_format!("epoll FD {epfd_value} got closed while blocking.")
-                        };
-                        // Remove the current active thread_id from the blocked thread_id list.
-                        epfd.downcast::<Epoll>()
-                            .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_wait`"))?
-                            .thread_id.borrow_mut()
-                            .retain(|&id| id != this.active_thread());
-                        this.write_int(0, &dest)?;
-                        interp_ok(())
+                    |this, unblock: UnblockKind| {
+                        match unblock {
+                            UnblockKind::Ready => {
+                                return_ready_list(&epfd, &dest, &event, this)?;
+                                interp_ok(())
+                            },
+                            UnblockKind::TimedOut => {
+                                // Remove the current active thread_id from the blocked thread_id list.
+                                epfd
+                                    .blocked_tid.borrow_mut()
+                                    .retain(|&id| id != this.active_thread());
+                                this.write_int(0, &dest)?;
+                                interp_ok(())
+                            },
+                        }
                     }
                 ),
             );
@@ -528,21 +524,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     /// do not call this function when an FD didn't have anything happen to it!
     fn check_and_update_readiness(
         &mut self,
-        fd_ref: &FileDescriptionRef,
+        fd_ref: DynFileDescriptionRef,
     ) -> InterpResult<'tcx, ()> {
         let this = self.eval_context_mut();
-        let id = fd_ref.get_id();
+        let id = fd_ref.id();
         let mut waiter = Vec::new();
         // Get a list of EpollEventInterest that is associated to a specific file description.
         if let Some(epoll_interests) = this.machine.epoll_interests.get_epoll_interest(id) {
             for weak_epoll_interest in epoll_interests {
                 if let Some(epoll_interest) = weak_epoll_interest.upgrade() {
-                    let is_updated = check_and_update_one_event_interest(
-                        fd_ref,
-                        epoll_interest.clone(),
-                        id,
-                        this,
-                    )?;
+                    let is_updated =
+                        check_and_update_one_event_interest(&fd_ref, &epoll_interest, id, this)?;
                     if is_updated {
                         // Edge-triggered notification only notify one thread even if there are
                         // multiple threads blocked on the same epfd.
@@ -553,10 +545,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         // holds a strong ref to epoll_interest.
                         let epfd = epoll_interest.borrow().weak_epfd.upgrade().unwrap();
                         // FIXME: We can randomly pick a thread to unblock.
-
-                        let epoll = epfd.downcast::<Epoll>().unwrap();
-
-                        if let Some(thread_id) = epoll.thread_id.borrow_mut().pop() {
+                        if let Some(thread_id) = epfd.blocked_tid.borrow_mut().pop() {
                             waiter.push(thread_id);
                         };
                     }
@@ -595,14 +584,15 @@ fn ready_list_next(
 /// notification was added/updated. Unlike check_and_update_readiness, this function sends a
 /// notification to only one epoll instance.
 fn check_and_update_one_event_interest<'tcx>(
-    fd_ref: &FileDescriptionRef,
-    interest: Rc<RefCell<EpollEventInterest>>,
+    fd_ref: &DynFileDescriptionRef,
+    interest: &RefCell<EpollEventInterest>,
     id: FdId,
     ecx: &MiriInterpCx<'tcx>,
 ) -> InterpResult<'tcx, bool> {
     // Get the bitmask of ready events for a file description.
     let ready_events_bitmask = fd_ref.as_unix().get_epoll_ready_events()?.get_event_bitmask(ecx);
     let epoll_event_interest = interest.borrow();
+    let epfd = epoll_event_interest.weak_epfd.upgrade().unwrap();
     // This checks if any of the events specified in epoll_event_interest.events
     // match those in ready_events.
     let flags = epoll_event_interest.events & ready_events_bitmask;
@@ -610,7 +600,7 @@ fn check_and_update_one_event_interest<'tcx>(
     // insert an epoll_return to the ready list.
     if flags != 0 {
         let epoll_key = (id, epoll_event_interest.fd_num);
-        let ready_list = &mut epoll_event_interest.ready_list.mapping.borrow_mut();
+        let mut ready_list = epfd.ready_list.mapping.borrow_mut();
         let mut event_instance = EpollEventInstance::new(flags, epoll_event_interest.data);
         // If we are tracking data races, remember the current clock so we can sync with it later.
         ecx.release_clock(|clock| {
@@ -627,23 +617,12 @@ fn check_and_update_one_event_interest<'tcx>(
 /// Stores the ready list of the `epfd` epoll instance into `events` (which must be an array),
 /// and the number of returned events into `dest`.
 fn return_ready_list<'tcx>(
-    epfd_value: i32,
-    weak_epfd: WeakFileDescriptionRef,
+    epfd: &FileDescriptionRef<Epoll>,
     dest: &MPlaceTy<'tcx>,
     events: &MPlaceTy<'tcx>,
     ecx: &mut MiriInterpCx<'tcx>,
 ) -> InterpResult<'tcx> {
-    let Some(epfd) = weak_epfd.upgrade() else {
-        throw_unsup_format!("epoll FD {epfd_value} got closed while blocking.")
-    };
-
-    let epoll_file_description = epfd
-        .downcast::<Epoll>()
-        .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_wait`"))?;
-
-    let ready_list = epoll_file_description.get_ready_list();
-
-    let mut ready_list = ready_list.mapping.borrow_mut();
+    let mut ready_list = epfd.ready_list.mapping.borrow_mut();
     let mut num_of_events: i32 = 0;
     let mut array_iter = ecx.project_array_fields(events)?;
 
diff --git a/src/tools/miri/src/shims/unix/linux_like/eventfd.rs b/src/tools/miri/src/shims/unix/linux_like/eventfd.rs
index 4bbe417ea8d..4b76bbb2b4d 100644
--- a/src/tools/miri/src/shims/unix/linux_like/eventfd.rs
+++ b/src/tools/miri/src/shims/unix/linux_like/eventfd.rs
@@ -20,7 +20,7 @@ const MAX_COUNTER: u64 = u64::MAX - 1;
 ///
 /// <https://man.netbsd.org/eventfd.2>
 #[derive(Debug)]
-struct Event {
+struct EventFd {
     /// The object contains an unsigned 64-bit integer (uint64_t) counter that is maintained by the
     /// kernel. This counter is initialized with the value specified in the argument initval.
     counter: Cell<u64>,
@@ -32,13 +32,13 @@ struct Event {
     blocked_write_tid: RefCell<Vec<ThreadId>>,
 }
 
-impl FileDescription for Event {
+impl FileDescription for EventFd {
     fn name(&self) -> &'static str {
         "event"
     }
 
     fn close<'tcx>(
-        self: Box<Self>,
+        self,
         _communicate_allowed: bool,
         _ecx: &mut MiriInterpCx<'tcx>,
     ) -> InterpResult<'tcx, io::Result<()>> {
@@ -47,8 +47,7 @@ impl FileDescription for Event {
 
     /// Read the counter in the buffer and return the counter if succeeded.
     fn read<'tcx>(
-        &self,
-        self_ref: &FileDescriptionRef,
+        self: FileDescriptionRef<Self>,
         _communicate_allowed: bool,
         ptr: Pointer,
         len: usize,
@@ -62,11 +61,10 @@ impl FileDescription for Event {
             return ecx.set_last_error_and_return(ErrorKind::InvalidInput, dest);
         }
 
-        // eventfd read at the size of u64.
+        // Turn the pointer into a place at the right type.
         let buf_place = ecx.ptr_to_mplace_unaligned(ptr, ty);
 
-        let weak_eventfd = self_ref.downgrade();
-        eventfd_read(buf_place, dest, weak_eventfd, ecx)
+        eventfd_read(buf_place, dest, self, ecx)
     }
 
     /// A write call adds the 8-byte integer value supplied in
@@ -82,8 +80,7 @@ impl FileDescription for Event {
     /// supplied buffer is less than 8 bytes, or if an attempt is
     /// made to write the value 0xffffffffffffffff.
     fn write<'tcx>(
-        &self,
-        self_ref: &FileDescriptionRef,
+        self: FileDescriptionRef<Self>,
         _communicate_allowed: bool,
         ptr: Pointer,
         len: usize,
@@ -97,18 +94,10 @@ impl FileDescription for Event {
             return ecx.set_last_error_and_return(ErrorKind::InvalidInput, dest);
         }
 
-        // Read the user-supplied value from the pointer.
+        // Turn the pointer into a place at the right type.
         let buf_place = ecx.ptr_to_mplace_unaligned(ptr, ty);
-        let num = ecx.read_scalar(&buf_place)?.to_u64()?;
 
-        // u64::MAX as input is invalid because the maximum value of counter is u64::MAX - 1.
-        if num == u64::MAX {
-            return ecx.set_last_error_and_return(ErrorKind::InvalidInput, dest);
-        }
-        // If the addition does not let the counter to exceed the maximum value, update the counter.
-        // Else, block.
-        let weak_eventfd = self_ref.downgrade();
-        eventfd_write(num, buf_place, dest, weak_eventfd, ecx)
+        eventfd_write(buf_place, dest, self, ecx)
     }
 
     fn as_unix(&self) -> &dyn UnixFileDescription {
@@ -116,7 +105,7 @@ impl FileDescription for Event {
     }
 }
 
-impl UnixFileDescription for Event {
+impl UnixFileDescription for EventFd {
     fn get_epoll_ready_events<'tcx>(&self) -> InterpResult<'tcx, EpollReadyEvents> {
         // We only check the status of EPOLLIN and EPOLLOUT flags for eventfd. If other event flags
         // need to be supported in the future, the check should be added here.
@@ -178,7 +167,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let fds = &mut this.machine.fds;
 
-        let fd_value = fds.insert_new(Event {
+        let fd_value = fds.insert_new(EventFd {
             counter: Cell::new(val.into()),
             is_nonblock,
             clock: RefCell::new(VClock::default()),
@@ -193,19 +182,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 /// Block thread if the value addition will exceed u64::MAX -1,
 /// else just add the user-supplied value to current counter.
 fn eventfd_write<'tcx>(
-    num: u64,
     buf_place: MPlaceTy<'tcx>,
     dest: &MPlaceTy<'tcx>,
-    weak_eventfd: WeakFileDescriptionRef,
+    eventfd: FileDescriptionRef<EventFd>,
     ecx: &mut MiriInterpCx<'tcx>,
 ) -> InterpResult<'tcx> {
-    let Some(eventfd_ref) = weak_eventfd.upgrade() else {
-        throw_unsup_format!("eventfd FD got closed while blocking.")
-    };
-
-    // Since we pass the weak file description ref, it is guaranteed to be
-    // an eventfd file description.
-    let eventfd = eventfd_ref.downcast::<Event>().unwrap();
+    // Figure out which value we should add.
+    let num = ecx.read_scalar(&buf_place)?.to_u64()?;
+    // u64::MAX as input is invalid because the maximum value of counter is u64::MAX - 1.
+    if num == u64::MAX {
+        return ecx.set_last_error_and_return(ErrorKind::InvalidInput, dest);
+    }
 
     match eventfd.counter.get().checked_add(num) {
         Some(new_count @ 0..=MAX_COUNTER) => {
@@ -217,10 +204,6 @@ fn eventfd_write<'tcx>(
             // Store new counter value.
             eventfd.counter.set(new_count);
 
-            // The state changed; we check and update the status of all supported event
-            // types for current file description.
-            ecx.check_and_update_readiness(&eventfd_ref)?;
-
             // Unblock *all* threads previously blocked on `read`.
             // We need to take out the blocked thread ids and unblock them together,
             // because `unblock_threads` may block them again and end up re-adding the
@@ -231,6 +214,10 @@ fn eventfd_write<'tcx>(
                 ecx.unblock_thread(thread_id, BlockReason::Eventfd)?;
             }
 
+            // The state changed; we check and update the status of all supported event
+            // types for current file description.
+            ecx.check_and_update_readiness(eventfd)?;
+
             // Return how many bytes we consumed from the user-provided buffer.
             return ecx.write_int(buf_place.layout.size.bytes(), dest);
         }
@@ -244,6 +231,7 @@ fn eventfd_write<'tcx>(
 
             eventfd.blocked_write_tid.borrow_mut().push(ecx.active_thread());
 
+            let weak_eventfd = FileDescriptionRef::downgrade(&eventfd);
             ecx.block_thread(
                 BlockReason::Eventfd,
                 None,
@@ -252,11 +240,14 @@ fn eventfd_write<'tcx>(
                         num: u64,
                         buf_place: MPlaceTy<'tcx>,
                         dest: MPlaceTy<'tcx>,
-                        weak_eventfd: WeakFileDescriptionRef,
+                        weak_eventfd: WeakFileDescriptionRef<EventFd>,
                     }
-                    @unblock = |this| {
-                        // When we get unblocked, try again.
-                        eventfd_write(num, buf_place, &dest, weak_eventfd, this)
+                    |this, unblock: UnblockKind| {
+                        assert_eq!(unblock, UnblockKind::Ready);
+                        // When we get unblocked, try again. We know the ref is still valid,
+                        // otherwise there couldn't be a `write` that unblocks us.
+                        let eventfd_ref = weak_eventfd.upgrade().unwrap();
+                        eventfd_write(buf_place, &dest, eventfd_ref, this)
                     }
                 ),
             );
@@ -270,17 +261,9 @@ fn eventfd_write<'tcx>(
 fn eventfd_read<'tcx>(
     buf_place: MPlaceTy<'tcx>,
     dest: &MPlaceTy<'tcx>,
-    weak_eventfd: WeakFileDescriptionRef,
+    eventfd: FileDescriptionRef<EventFd>,
     ecx: &mut MiriInterpCx<'tcx>,
 ) -> InterpResult<'tcx> {
-    let Some(eventfd_ref) = weak_eventfd.upgrade() else {
-        throw_unsup_format!("eventfd FD got closed while blocking.")
-    };
-
-    // Since we pass the weak file description ref to the callback function, it is guaranteed to be
-    // an eventfd file description.
-    let eventfd = eventfd_ref.downcast::<Event>().unwrap();
-
     // Set counter to 0, get old value.
     let counter = eventfd.counter.replace(0);
 
@@ -293,6 +276,7 @@ fn eventfd_read<'tcx>(
 
         eventfd.blocked_read_tid.borrow_mut().push(ecx.active_thread());
 
+        let weak_eventfd = FileDescriptionRef::downgrade(&eventfd);
         ecx.block_thread(
             BlockReason::Eventfd,
             None,
@@ -300,11 +284,14 @@ fn eventfd_read<'tcx>(
                 @capture<'tcx> {
                     buf_place: MPlaceTy<'tcx>,
                     dest: MPlaceTy<'tcx>,
-                    weak_eventfd: WeakFileDescriptionRef,
+                    weak_eventfd: WeakFileDescriptionRef<EventFd>,
                 }
-                @unblock = |this| {
-                    // When we get unblocked, try again.
-                    eventfd_read(buf_place, &dest, weak_eventfd, this)
+                |this, unblock: UnblockKind| {
+                    assert_eq!(unblock, UnblockKind::Ready);
+                    // When we get unblocked, try again. We know the ref is still valid,
+                    // otherwise there couldn't be a `write` that unblocks us.
+                    let eventfd_ref = weak_eventfd.upgrade().unwrap();
+                    eventfd_read(buf_place, &dest, eventfd_ref, this)
                 }
             ),
         );
@@ -315,10 +302,6 @@ fn eventfd_read<'tcx>(
         // Return old counter value into user-space buffer.
         ecx.write_int(counter, &buf_place)?;
 
-        // The state changed; we check and update the status of all supported event
-        // types for current file description.
-        ecx.check_and_update_readiness(&eventfd_ref)?;
-
         // Unblock *all* threads previously blocked on `write`.
         // We need to take out the blocked thread ids and unblock them together,
         // because `unblock_threads` may block them again and end up re-adding the
@@ -329,6 +312,10 @@ fn eventfd_read<'tcx>(
             ecx.unblock_thread(thread_id, BlockReason::Eventfd)?;
         }
 
+        // The state changed; we check and update the status of all supported event
+        // types for current file description.
+        ecx.check_and_update_readiness(eventfd)?;
+
         // Tell userspace how many bytes we put into the buffer.
         return ecx.write_int(buf_place.layout.size.bytes(), dest);
     }
diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
index aa291639a6d..85c963774a1 100644
--- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
@@ -3,6 +3,7 @@ use rustc_span::Symbol;
 use rustc_target::callconv::{Conv, FnAbi};
 
 use super::sync::EvalContextExt as _;
+use crate::helpers::check_min_arg_count;
 use crate::shims::unix::*;
 use crate::*;
 
@@ -67,6 +68,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let result = this.realpath(path, resolved_path)?;
                 this.write_scalar(result, dest)?;
             }
+            "ioctl" => {
+                // `ioctl` is variadic. The argument count is checked based on the first argument
+                // in `this.ioctl()`, so we do not use `check_shim` here.
+                this.check_abi_and_shim_symbol_clash(abi, Conv::C, link_name)?;
+                let result = this.ioctl(args)?;
+                this.write_scalar(result, dest)?;
+            }
 
             // Environment related shims
             "_NSGetEnviron" => {
@@ -112,7 +120,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.check_no_isolation("`_NSGetExecutablePath`")?;
 
                 let buf_ptr = this.read_pointer(buf)?;
-                let bufsize = this.deref_pointer(bufsize)?;
+                let bufsize = this.deref_pointer_as(bufsize, this.machine.layouts.u32)?;
 
                 // Using the host current_exe is a bit off, but consistent with Linux
                 // (where stdlib reads /proc/self/exe).
@@ -234,4 +242,26 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         interp_ok(EmulateItemResult::NeedsReturn)
     }
+
+    fn ioctl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, Scalar> {
+        let this = self.eval_context_mut();
+
+        let fioclex = this.eval_libc_u64("FIOCLEX");
+
+        let [fd_num, cmd] = check_min_arg_count("ioctl", args)?;
+        let fd_num = this.read_scalar(fd_num)?.to_i32()?;
+        let cmd = this.read_scalar(cmd)?.to_u64()?;
+
+        if cmd == fioclex {
+            // Since we don't support `exec`, this is a NOP. However, we want to
+            // return EBADF if the FD is invalid.
+            if this.machine.fds.is_fd_num(fd_num) {
+                interp_ok(Scalar::from_i32(0))
+            } else {
+                this.set_last_error_and_return_i32(LibcError("EBADF"))
+            }
+        } else {
+            throw_unsup_format!("ioctl: unsupported command {cmd:#x}");
+        }
+    }
 }
diff --git a/src/tools/miri/src/shims/unix/macos/sync.rs b/src/tools/miri/src/shims/unix/macos/sync.rs
index f66a57ae706..330c64f06a3 100644
--- a/src/tools/miri/src/shims/unix/macos/sync.rs
+++ b/src/tools/miri/src/shims/unix/macos/sync.rs
@@ -64,7 +64,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 None,
                 callback!(
                     @capture<'tcx> {}
-                    @unblock = |_this| {
+                    |_this, _unblock: UnblockKind| {
                         panic!("we shouldn't wake up ever")
                     }
                 ),
diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
index c99e8ae7c6e..f94783a3907 100644
--- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
@@ -3,6 +3,8 @@ use rustc_span::Symbol;
 use rustc_target::callconv::{Conv, FnAbi};
 
 use crate::shims::unix::foreign_items::EvalContextExt as _;
+use crate::shims::unix::linux_like::epoll::EvalContextExt as _;
+use crate::shims::unix::linux_like::eventfd::EvalContextExt as _;
 use crate::shims::unix::*;
 use crate::*;
 
@@ -21,6 +23,32 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx, EmulateItemResult> {
         let this = self.eval_context_mut();
         match link_name.as_str() {
+            // epoll, eventfd (NOT available on Solaris!)
+            "epoll_create1" => {
+                this.assert_target_os("illumos", "epoll_create1");
+                let [flag] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let result = this.epoll_create1(flag)?;
+                this.write_scalar(result, dest)?;
+            }
+            "epoll_ctl" => {
+                this.assert_target_os("illumos", "epoll_ctl");
+                let [epfd, op, fd, event] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let result = this.epoll_ctl(epfd, op, fd, event)?;
+                this.write_scalar(result, dest)?;
+            }
+            "epoll_wait" => {
+                this.assert_target_os("illumos", "epoll_wait");
+                let [epfd, events, maxevents, timeout] =
+                    this.check_shim(abi, Conv::C, link_name, args)?;
+                this.epoll_wait(epfd, events, maxevents, timeout, dest)?;
+            }
+            "eventfd" => {
+                this.assert_target_os("illumos", "eventfd");
+                let [val, flag] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let result = this.eventfd(val, flag)?;
+                this.write_scalar(result, dest)?;
+            }
+
             // Threading
             "pthread_setname_np" => {
                 let [thread, name] = this.check_shim(abi, Conv::C, link_name, args)?;
@@ -78,6 +106,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(result, dest)?;
             }
 
+            // Sockets and pipes
+            "__xnet_socketpair" => {
+                let [domain, type_, protocol, sv] =
+                    this.check_shim(abi, Conv::C, link_name, args)?;
+                let result = this.socketpair(domain, type_, protocol, sv)?;
+                this.write_scalar(result, dest)?;
+            }
+
             // Miscellaneous
             "___errno" => {
                 let [] = this.check_shim(abi, Conv::C, link_name, args)?;
diff --git a/src/tools/miri/src/shims/unix/unnamed_socket.rs b/src/tools/miri/src/shims/unix/unnamed_socket.rs
index 86ebe95762a..08515b815a9 100644
--- a/src/tools/miri/src/shims/unix/unnamed_socket.rs
+++ b/src/tools/miri/src/shims/unix/unnamed_socket.rs
@@ -31,7 +31,7 @@ struct AnonSocket {
     /// The `AnonSocket` file descriptor that is our "peer", and that holds the buffer we are
     /// writing to. This is a weak reference because the other side may be closed before us; all
     /// future writes will then trigger EPIPE.
-    peer_fd: OnceCell<WeakFileDescriptionRef>,
+    peer_fd: OnceCell<WeakFileDescriptionRef<AnonSocket>>,
     /// Indicates whether the peer has lost data when the file description is closed.
     /// This flag is set to `true` if the peer's `readbuf` is non-empty at the time
     /// of closure.
@@ -58,7 +58,7 @@ impl Buffer {
 }
 
 impl AnonSocket {
-    fn peer_fd(&self) -> &WeakFileDescriptionRef {
+    fn peer_fd(&self) -> &WeakFileDescriptionRef<AnonSocket> {
         self.peer_fd.get().unwrap()
     }
 }
@@ -69,7 +69,7 @@ impl FileDescription for AnonSocket {
     }
 
     fn close<'tcx>(
-        self: Box<Self>,
+        self,
         _communicate_allowed: bool,
         ecx: &mut MiriInterpCx<'tcx>,
     ) -> InterpResult<'tcx, io::Result<()>> {
@@ -78,80 +78,35 @@ impl FileDescription for AnonSocket {
             // notify the peer that data lost has happened in current file description.
             if let Some(readbuf) = &self.readbuf {
                 if !readbuf.borrow().buf.is_empty() {
-                    peer_fd.downcast::<AnonSocket>().unwrap().peer_lost_data.set(true);
+                    peer_fd.peer_lost_data.set(true);
                 }
             }
             // Notify peer fd that close has happened, since that can unblock reads and writes.
-            ecx.check_and_update_readiness(&peer_fd)?;
+            ecx.check_and_update_readiness(peer_fd)?;
         }
         interp_ok(Ok(()))
     }
 
     fn read<'tcx>(
-        &self,
-        self_ref: &FileDescriptionRef,
+        self: FileDescriptionRef<Self>,
         _communicate_allowed: bool,
         ptr: Pointer,
         len: usize,
         dest: &MPlaceTy<'tcx>,
         ecx: &mut MiriInterpCx<'tcx>,
     ) -> InterpResult<'tcx> {
-        // Always succeed on read size 0.
-        if len == 0 {
-            return ecx.return_read_success(ptr, &[], 0, dest);
-        }
-
-        let Some(readbuf) = &self.readbuf else {
-            // FIXME: This should return EBADF, but there's no nice way to do that as there's no
-            // corresponding ErrorKind variant.
-            throw_unsup_format!("reading from the write end of a pipe");
-        };
-
-        if readbuf.borrow().buf.is_empty() && self.is_nonblock {
-            // Non-blocking socketpair with writer and empty buffer.
-            // https://linux.die.net/man/2/read
-            // EAGAIN or EWOULDBLOCK can be returned for socket,
-            // POSIX.1-2001 allows either error to be returned for this case.
-            // Since there is no ErrorKind for EAGAIN, WouldBlock is used.
-            return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest);
-        }
-        anonsocket_read(self_ref.downgrade(), len, ptr, dest.clone(), ecx)
+        anonsocket_read(self, len, ptr, dest, ecx)
     }
 
     fn write<'tcx>(
-        &self,
-        self_ref: &FileDescriptionRef,
+        self: FileDescriptionRef<Self>,
         _communicate_allowed: bool,
         ptr: Pointer,
         len: usize,
         dest: &MPlaceTy<'tcx>,
         ecx: &mut MiriInterpCx<'tcx>,
     ) -> InterpResult<'tcx> {
-        // Always succeed on write size 0.
-        // ("If count is zero and fd refers to a file other than a regular file, the results are not specified.")
-        if len == 0 {
-            return ecx.return_write_success(0, dest);
-        }
-
-        // We are writing to our peer's readbuf.
-        let Some(peer_fd) = self.peer_fd().upgrade() else {
-            // If the upgrade from Weak to Rc fails, it indicates that all read ends have been
-            // closed.
-            return ecx.set_last_error_and_return(ErrorKind::BrokenPipe, dest);
-        };
-
-        let Some(writebuf) = &peer_fd.downcast::<AnonSocket>().unwrap().readbuf else {
-            // FIXME: This should return EBADF, but there's no nice way to do that as there's no
-            // corresponding ErrorKind variant.
-            throw_unsup_format!("writing to the reading end of a pipe");
-        };
-        let available_space =
-            MAX_SOCKETPAIR_BUFFER_CAPACITY.strict_sub(writebuf.borrow().buf.len());
-        if available_space == 0 && self.is_nonblock {
-            // Non-blocking socketpair with a full buffer.
-            return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest);
-        }
-        anonsocket_write(self_ref.downgrade(), ptr, len, dest.clone(), ecx)
+        anonsocket_write(self, ptr, len, dest, ecx)
     }
 
     fn as_unix(&self) -> &dyn UnixFileDescription {
@@ -161,50 +116,64 @@ impl FileDescription for AnonSocket {
 
 /// Write to AnonSocket based on the space available and return the written byte size.
 fn anonsocket_write<'tcx>(
-    weak_self_ref: WeakFileDescriptionRef,
+    self_ref: FileDescriptionRef<AnonSocket>,
     ptr: Pointer,
     len: usize,
-    dest: MPlaceTy<'tcx>,
+    dest: &MPlaceTy<'tcx>,
     ecx: &mut MiriInterpCx<'tcx>,
 ) -> InterpResult<'tcx> {
-    let Some(self_ref) = weak_self_ref.upgrade() else {
-        // FIXME:  We should raise a deadlock error if the self_ref upgrade failed.
-        throw_unsup_format!("This will be a deadlock error in future")
-    };
-    let self_anonsocket = self_ref.downcast::<AnonSocket>().unwrap();
-    let Some(peer_fd) = self_anonsocket.peer_fd().upgrade() else {
+    // Always succeed on write size 0.
+    // ("If count is zero and fd refers to a file other than a regular file, the results are not specified.")
+    if len == 0 {
+        return ecx.return_write_success(0, dest);
+    }
+
+    // We are writing to our peer's readbuf.
+    let Some(peer_fd) = self_ref.peer_fd().upgrade() else {
         // If the upgrade from Weak to Rc fails, it indicates that all read ends have been
-        // closed.
-        return ecx.set_last_error_and_return(ErrorKind::BrokenPipe, &dest);
+        // closed. It is an error to write even if there would be space.
+        return ecx.set_last_error_and_return(ErrorKind::BrokenPipe, dest);
     };
-    let Some(writebuf) = &peer_fd.downcast::<AnonSocket>().unwrap().readbuf else {
-        // FIXME: This should return EBADF, but there's no nice way to do that as there's no
-        // corresponding ErrorKind variant.
-        throw_unsup_format!("writing to the reading end of a pipe")
+
+    let Some(writebuf) = &peer_fd.readbuf else {
+        // Writing to the read end of a pipe.
+        return ecx.set_last_error_and_return(IoError::LibcError("EBADF"), dest);
     };
 
+    // Let's see if we can write.
     let available_space = MAX_SOCKETPAIR_BUFFER_CAPACITY.strict_sub(writebuf.borrow().buf.len());
-
     if available_space == 0 {
-        // Blocking socketpair with a full buffer.
-        let dest = dest.clone();
-        self_anonsocket.blocked_write_tid.borrow_mut().push(ecx.active_thread());
-        ecx.block_thread(
-            BlockReason::UnnamedSocket,
-            None,
-            callback!(
-                @capture<'tcx> {
-                    weak_self_ref: WeakFileDescriptionRef,
-                    ptr: Pointer,
-                    len: usize,
-                    dest: MPlaceTy<'tcx>,
-                }
-                @unblock = |this| {
-                    anonsocket_write(weak_self_ref, ptr, len, dest, this)
-                }
-            ),
-        );
+        if self_ref.is_nonblock {
+            // Non-blocking socketpair with a full buffer.
+            return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest);
+        } else {
+            self_ref.blocked_write_tid.borrow_mut().push(ecx.active_thread());
+            // Blocking socketpair with a full buffer.
+            // Block the current thread; only keep a weak ref for this.
+            let weak_self_ref = FileDescriptionRef::downgrade(&self_ref);
+            let dest = dest.clone();
+            ecx.block_thread(
+                BlockReason::UnnamedSocket,
+                None,
+                callback!(
+                    @capture<'tcx> {
+                        weak_self_ref: WeakFileDescriptionRef<AnonSocket>,
+                        ptr: Pointer,
+                        len: usize,
+                        dest: MPlaceTy<'tcx>,
+                    }
+                    |this, unblock: UnblockKind| {
+                        assert_eq!(unblock, UnblockKind::Ready);
+                        // If we got unblocked, then our peer successfully upgraded its weak
+                        // ref to us. That means we can also upgrade our weak ref.
+                        let self_ref = weak_self_ref.upgrade().unwrap();
+                        anonsocket_write(self_ref, ptr, len, &dest, this)
+                    }
+                ),
+            );
+        }
     } else {
+        // There is space to write!
         let mut writebuf = writebuf.borrow_mut();
         // Remember this clock so `read` can synchronize with us.
         ecx.release_clock(|clock| {
@@ -218,68 +187,80 @@ fn anonsocket_write<'tcx>(
         // Need to stop accessing peer_fd so that it can be notified.
         drop(writebuf);
 
-        // Notification should be provided for peer fd as it became readable.
-        // The kernel does this even if the fd was already readable before, so we follow suit.
-        ecx.check_and_update_readiness(&peer_fd)?;
-        let peer_anonsocket = peer_fd.downcast::<AnonSocket>().unwrap();
         // Unblock all threads that are currently blocked on peer_fd's read.
-        let waiting_threads = std::mem::take(&mut *peer_anonsocket.blocked_read_tid.borrow_mut());
+        let waiting_threads = std::mem::take(&mut *peer_fd.blocked_read_tid.borrow_mut());
         // FIXME: We can randomize the order of unblocking.
         for thread_id in waiting_threads {
             ecx.unblock_thread(thread_id, BlockReason::UnnamedSocket)?;
         }
+        // Notification should be provided for peer fd as it became readable.
+        // The kernel does this even if the fd was already readable before, so we follow suit.
+        ecx.check_and_update_readiness(peer_fd)?;
 
-        return ecx.return_write_success(actual_write_size, &dest);
+        return ecx.return_write_success(actual_write_size, dest);
     }
     interp_ok(())
 }
 
 /// Read from AnonSocket and return the number of bytes read.
 fn anonsocket_read<'tcx>(
-    weak_self_ref: WeakFileDescriptionRef,
+    self_ref: FileDescriptionRef<AnonSocket>,
     len: usize,
     ptr: Pointer,
-    dest: MPlaceTy<'tcx>,
+    dest: &MPlaceTy<'tcx>,
     ecx: &mut MiriInterpCx<'tcx>,
 ) -> InterpResult<'tcx> {
-    let Some(self_ref) = weak_self_ref.upgrade() else {
-        // FIXME:  We should raise a deadlock error if the self_ref upgrade failed.
-        throw_unsup_format!("This will be a deadlock error in future")
-    };
-    let self_anonsocket = self_ref.downcast::<AnonSocket>().unwrap();
+    // Always succeed on read size 0.
+    if len == 0 {
+        return ecx.return_read_success(ptr, &[], 0, dest);
+    }
 
-    let Some(readbuf) = &self_anonsocket.readbuf else {
+    let Some(readbuf) = &self_ref.readbuf else {
         // FIXME: This should return EBADF, but there's no nice way to do that as there's no
         // corresponding ErrorKind variant.
         throw_unsup_format!("reading from the write end of a pipe")
     };
 
     if readbuf.borrow_mut().buf.is_empty() {
-        if self_anonsocket.peer_fd().upgrade().is_none() {
+        if self_ref.peer_fd().upgrade().is_none() {
             // Socketpair with no peer and empty buffer.
             // 0 bytes successfully read indicates end-of-file.
-            return ecx.return_read_success(ptr, &[], 0, &dest);
+            return ecx.return_read_success(ptr, &[], 0, dest);
+        } else if self_ref.is_nonblock {
+            // Non-blocking socketpair with writer and empty buffer.
+            // https://linux.die.net/man/2/read
+            // EAGAIN or EWOULDBLOCK can be returned for socket,
+            // POSIX.1-2001 allows either error to be returned for this case.
+            // Since there is no ErrorKind for EAGAIN, WouldBlock is used.
+            return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest);
         } else {
+            self_ref.blocked_read_tid.borrow_mut().push(ecx.active_thread());
             // Blocking socketpair with writer and empty buffer.
-            let weak_self_ref = weak_self_ref.clone();
-            self_anonsocket.blocked_read_tid.borrow_mut().push(ecx.active_thread());
+            // Block the current thread; only keep a weak ref for this.
+            let weak_self_ref = FileDescriptionRef::downgrade(&self_ref);
+            let dest = dest.clone();
             ecx.block_thread(
                 BlockReason::UnnamedSocket,
                 None,
                 callback!(
                     @capture<'tcx> {
-                        weak_self_ref: WeakFileDescriptionRef,
+                        weak_self_ref: WeakFileDescriptionRef<AnonSocket>,
                         len: usize,
                         ptr: Pointer,
                         dest: MPlaceTy<'tcx>,
                     }
-                    @unblock = |this| {
-                        anonsocket_read(weak_self_ref, len, ptr, dest, this)
+                    |this, unblock: UnblockKind| {
+                        assert_eq!(unblock, UnblockKind::Ready);
+                        // If we got unblocked, then our peer successfully upgraded its weak
+                        // ref to us. That means we can also upgrade our weak ref.
+                        let self_ref = weak_self_ref.upgrade().unwrap();
+                        anonsocket_read(self_ref, len, ptr, &dest, this)
                     }
                 ),
             );
         }
     } else {
+        // There's data to be read!
         let mut bytes = vec![0; len];
         let mut readbuf = readbuf.borrow_mut();
         // Synchronize with all previous writes to this buffer.
@@ -301,19 +282,18 @@ fn anonsocket_read<'tcx>(
         // don't know what that *certain number* is, we will provide a notification every time
         // a read is successful. This might result in our epoll emulation providing more
         // notifications than the real system.
-        if let Some(peer_fd) = self_anonsocket.peer_fd().upgrade() {
-            ecx.check_and_update_readiness(&peer_fd)?;
-            let peer_anonsocket = peer_fd.downcast::<AnonSocket>().unwrap();
+        if let Some(peer_fd) = self_ref.peer_fd().upgrade() {
             // Unblock all threads that are currently blocked on peer_fd's write.
-            let waiting_threads =
-                std::mem::take(&mut *peer_anonsocket.blocked_write_tid.borrow_mut());
+            let waiting_threads = std::mem::take(&mut *peer_fd.blocked_write_tid.borrow_mut());
             // FIXME: We can randomize the order of unblocking.
             for thread_id in waiting_threads {
                 ecx.unblock_thread(thread_id, BlockReason::UnnamedSocket)?;
             }
+            // Notify epoll waiters.
+            ecx.check_and_update_readiness(peer_fd)?;
         };
 
-        return ecx.return_read_success(ptr, &bytes, actual_read_size, &dest);
+        return ecx.return_read_success(ptr, &bytes, actual_read_size, dest);
     }
     interp_ok(())
 }
@@ -337,7 +317,7 @@ impl UnixFileDescription for AnonSocket {
 
         // Check if is writable.
         if let Some(peer_fd) = self.peer_fd().upgrade() {
-            if let Some(writebuf) = &peer_fd.downcast::<AnonSocket>().unwrap().readbuf {
+            if let Some(writebuf) = &peer_fd.readbuf {
                 let data_size = writebuf.borrow().buf.len();
                 let available_space = MAX_SOCKETPAIR_BUFFER_CAPACITY.strict_sub(data_size);
                 if available_space != 0 {
@@ -443,8 +423,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         });
 
         // Make the file descriptions point to each other.
-        fd0.downcast::<AnonSocket>().unwrap().peer_fd.set(fd1.downgrade()).unwrap();
-        fd1.downcast::<AnonSocket>().unwrap().peer_fd.set(fd0.downgrade()).unwrap();
+        fd0.peer_fd.set(FileDescriptionRef::downgrade(&fd1)).unwrap();
+        fd1.peer_fd.set(FileDescriptionRef::downgrade(&fd0)).unwrap();
 
         // Insert the file description to the fd table, generating the file descriptors.
         let sv0 = fds.insert(fd0);
@@ -511,8 +491,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         });
 
         // Make the file descriptions point to each other.
-        fd0.downcast::<AnonSocket>().unwrap().peer_fd.set(fd1.downgrade()).unwrap();
-        fd1.downcast::<AnonSocket>().unwrap().peer_fd.set(fd0.downgrade()).unwrap();
+        fd0.peer_fd.set(FileDescriptionRef::downgrade(&fd1)).unwrap();
+        fd1.peer_fd.set(FileDescriptionRef::downgrade(&fd0)).unwrap();
 
         // Insert the file description to the fd table, generating the file descriptors.
         let pipefd0 = fds.insert(fd0);
diff --git a/src/tools/miri/src/shims/windows/handle.rs b/src/tools/miri/src/shims/windows/handle.rs
index 3d872b65a63..c4eb11fbd3f 100644
--- a/src/tools/miri/src/shims/windows/handle.rs
+++ b/src/tools/miri/src/shims/windows/handle.rs
@@ -97,7 +97,7 @@ impl Handle {
 
         // packs the data into the lower `data_size` bits
         // and packs the discriminant right above the data
-        discriminant << data_size | data
+        (discriminant << data_size) | data
     }
 
     fn new(discriminant: u32, data: u32) -> Option<Self> {
diff --git a/src/tools/miri/src/shims/windows/sync.rs b/src/tools/miri/src/shims/windows/sync.rs
index a394e0430bc..4001201bf67 100644
--- a/src/tools/miri/src/shims/windows/sync.rs
+++ b/src/tools/miri/src/shims/windows/sync.rs
@@ -111,7 +111,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     pending_place: MPlaceTy<'tcx>,
                     dest: MPlaceTy<'tcx>,
                 }
-                @unblock = |this| {
+                |this, unblock: UnblockKind| {
+                    assert_eq!(unblock, UnblockKind::Ready);
                     let ret = this.init_once_try_begin(id, &pending_place, &dest)?;
                     assert!(ret, "we were woken up but init_once_try_begin still failed");
                     interp_ok(())
diff --git a/src/tools/miri/tests/fail-dep/libc/affinity.rs b/src/tools/miri/tests/fail-dep/libc/affinity.rs
index 09f096e46f1..3acbd83d0e5 100644
--- a/src/tools/miri/tests/fail-dep/libc/affinity.rs
+++ b/src/tools/miri/tests/fail-dep/libc/affinity.rs
@@ -1,5 +1,4 @@
-//@ignore-target: windows # only very limited libc on Windows
-//@ignore-target: apple # `sched_setaffinity` is not supported on macOS
+//@only-target: linux # these are Linux-specific APIs
 //@compile-flags: -Zmiri-disable-isolation -Zmiri-num-cpus=4
 
 fn main() {
diff --git a/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs b/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs
index 81a96103db4..0d893663fd6 100644
--- a/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs
+++ b/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs
@@ -1,4 +1,4 @@
-//@only-target: linux
+//@only-target: linux android illumos
 //~^ERROR: deadlocked
 //~^^ERROR: deadlocked
 //@compile-flags: -Zmiri-preemption-rate=0
diff --git a/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs b/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs
index 7a2a6f4eb1a..9fed47c17d4 100644
--- a/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs
+++ b/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs
@@ -1,4 +1,4 @@
-//@only-target: linux
+//@only-target: linux android illumos
 //~^ERROR: deadlocked
 //~^^ERROR: deadlocked
 //@compile-flags: -Zmiri-preemption-rate=0
diff --git a/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs b/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs
index 7bef687e339..45f6bf6da09 100644
--- a/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs
+++ b/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs
@@ -2,7 +2,7 @@
 //! and we only read one of them, we do not synchronize with the other events
 //! and therefore still report a data race for things that need to see the second event
 //! to be considered synchronized.
-//@only-target: linux android
+//@only-target: linux android illumos
 // ensure deterministic schedule
 //@compile-flags: -Zmiri-preemption-rate=0
 
diff --git a/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs
index 1c6c2f70c1d..059b24cb8c0 100644
--- a/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs
+++ b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs
@@ -1,7 +1,7 @@
 //@compile-flags: -Zmiri-preemption-rate=0
 //~^ERROR: deadlocked
 //~^^ERROR: deadlocked
-//@only-target: linux
+//@only-target: linux android illumos
 //@error-in-other-file: deadlock
 
 use std::convert::TryInto;
diff --git a/src/tools/miri/tests/fail-dep/libc/libc_epoll_unsupported_fd.rs b/src/tools/miri/tests/fail-dep/libc/libc_epoll_unsupported_fd.rs
index 03d4b2d6633..59cf0fc2ba0 100644
--- a/src/tools/miri/tests/fail-dep/libc/libc_epoll_unsupported_fd.rs
+++ b/src/tools/miri/tests/fail-dep/libc/libc_epoll_unsupported_fd.rs
@@ -1,4 +1,4 @@
-//@only-target: linux
+//@only-target: linux android illumos
 
 // This is a test for registering unsupported fd with epoll.
 // Register epoll fd with epoll is allowed in real system, but we do not support this.
diff --git a/src/tools/miri/tests/fail-dep/libc/memrchr_null.rs b/src/tools/miri/tests/fail-dep/libc/memrchr_null.rs
index 8b34ff4ac2e..a1d8fd663f8 100644
--- a/src/tools/miri/tests/fail-dep/libc/memrchr_null.rs
+++ b/src/tools/miri/tests/fail-dep/libc/memrchr_null.rs
@@ -1,9 +1,8 @@
-//@ignore-target: windows # No `memrchr` on Windows
-//@ignore-target: apple # No `memrchr` on some apple targets
+//@only-target: linux # `memrchr` is a GNU extension
 
 use std::ptr;
 
-// null is explicitly called out as UB in the C docs.
+// null is explicitly called out as UB in the C docs for `memchr`.
 fn main() {
     unsafe {
         libc::memrchr(ptr::null(), 0, 0); //~ERROR: null pointer
diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs
new file mode 100644
index 00000000000..8413e118819
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs
@@ -0,0 +1,37 @@
+//! This is a regression test for <https://github.com/rust-lang/miri/issues/3947>: we had some
+//! faulty logic around `release_clock` that led to this code not reporting a data race.
+//~^^ERROR: deadlock
+//@ignore-target: windows # no libc socketpair on Windows
+//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-address-reuse-rate=0
+//@error-in-other-file: deadlock
+use std::thread;
+
+fn main() {
+    let mut fds = [-1, -1];
+    let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) };
+    assert_eq!(res, 0);
+
+    let thread1 = thread::spawn(move || {
+        let mut buf: [u8; 1] = [0; 1];
+        let _res: i32 = unsafe {
+            libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) //~ERROR: deadlock
+                .try_into()
+                .unwrap()
+        };
+    });
+    let thread2 = thread::spawn(move || {
+        // Close the FD that the other thread is blocked on.
+        unsafe { libc::close(fds[1]) };
+    });
+
+    // Run the other threads.
+    thread::yield_now();
+
+    // When they are both done, continue here.
+    let data = "a".as_bytes().as_ptr();
+    let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 1) };
+    assert_eq!(res, -1);
+
+    thread1.join().unwrap();
+    thread2.join().unwrap();
+}
diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr
new file mode 100644
index 00000000000..fe196f5d7d7
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr
@@ -0,0 +1,35 @@
+error: deadlock: the evaluated program deadlocked
+  --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   |
+LL |         let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
+   |                                                                  ^ the evaluated program deadlocked
+   |
+   = note: BACKTRACE:
+   = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
+   = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
+note: inside `main`
+  --> tests/fail-dep/libc/socketpair-close-while-blocked.rs:LL:CC
+   |
+LL |     thread1.join().unwrap();
+   |     ^^^^^^^^^^^^^^
+
+error: deadlock: the evaluated program deadlocked
+  --> tests/fail-dep/libc/socketpair-close-while-blocked.rs:LL:CC
+   |
+LL |             libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t)
+   |                                                                                  ^ the evaluated program deadlocked
+   |
+   = note: BACKTRACE on thread `unnamed-ID`:
+   = note: inside closure at tests/fail-dep/libc/socketpair-close-while-blocked.rs:LL:CC
+
+error: deadlock: the evaluated program deadlocked
+   |
+   = note: the evaluated program deadlocked
+   = note: (no span available)
+   = note: BACKTRACE on thread `unnamed-ID`:
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr
index b416f0eb689..5061c9e8dc3 100644
--- a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr
+++ b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr
@@ -15,9 +15,9 @@ LL |     extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
    = note: inside `std::panicking::r#try::<i32, &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>` at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside `std::panic::catch_unwind::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at RUSTLIB/std/src/panic.rs:LL:CC
    = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC
-   = note: inside `std::panicking::r#try::do_call::<{closure@std::rt::lang_start_internal::{closure#1}}, isize>` at RUSTLIB/std/src/panicking.rs:LL:CC
-   = note: inside `std::panicking::r#try::<isize, {closure@std::rt::lang_start_internal::{closure#1}}>` at RUSTLIB/std/src/panicking.rs:LL:CC
-   = note: inside `std::panic::catch_unwind::<{closure@std::rt::lang_start_internal::{closure#1}}, isize>` at RUSTLIB/std/src/panic.rs:LL:CC
+   = note: inside `std::panicking::r#try::do_call::<{closure@std::rt::lang_start_internal::{closure#0}}, isize>` at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside `std::panicking::r#try::<isize, {closure@std::rt::lang_start_internal::{closure#0}}>` at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside `std::panic::catch_unwind::<{closure@std::rt::lang_start_internal::{closure#0}}, isize>` at RUSTLIB/std/src/panic.rs:LL:CC
    = note: inside `std::rt::lang_start_internal` at RUSTLIB/std/src/rt.rs:LL:CC
    = note: inside `std::rt::lang_start::<()>` at RUSTLIB/std/src/rt.rs:LL:CC
 
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs b/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs
index 3c4311efc4c..400e3ca3d7d 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs
@@ -1,5 +1,4 @@
-//@ignore-target: windows # only very limited libc on Windows
-//@ignore-target: apple # `sched_{g, s}etaffinity` are not supported on macOS
+//@only-target: linux # these are Linux-specific APIs
 //@compile-flags: -Zmiri-disable-isolation -Zmiri-num-cpus=4
 #![feature(io_error_more)]
 #![feature(pointer_is_aligned_to)]
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs b/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs
index e3c42b2701c..825e1355848 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs
@@ -1,4 +1,4 @@
-//@only-target: linux android
+//@only-target: linux android illumos
 // test_epoll_block_then_unblock and test_epoll_race depend on a deterministic schedule.
 //@compile-flags: -Zmiri-preemption-rate=0
 
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs b/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs
index 111e639c864..23e2122ee50 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs
@@ -1,4 +1,4 @@
-//@only-target: linux android
+//@only-target: linux android illumos
 
 use std::convert::TryInto;
 
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs b/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs
index 2e453215ec9..30e1bbb8fa1 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs
@@ -1,4 +1,4 @@
-//@only-target: linux android
+//@only-target: linux android illumos
 // test_race, test_blocking_read and test_blocking_write depend on a deterministic schedule.
 //@compile-flags: -Zmiri-preemption-rate=0
 
@@ -10,7 +10,10 @@ use std::thread;
 fn main() {
     test_read_write();
     test_race();
+
+    #[cfg(not(target_os = "illumos"))]
     test_syscall();
+
     test_blocking_read();
     test_blocking_write();
     test_two_threads_blocked_on_eventfd();
@@ -115,6 +118,8 @@ fn test_race() {
 }
 
 // This is a test for calling eventfd2 through a syscall.
+// Illumos supports eventfd, but it has no entry to call it through syscall.
+#[cfg(not(target_os = "illumos"))]
 fn test_syscall() {
     let initval = 0 as libc::c_uint;
     let flags = (libc::EFD_CLOEXEC | libc::EFD_NONBLOCK) as libc::c_int;
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs
index f85abe2cc43..129b18d8e59 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs
@@ -38,6 +38,8 @@ fn main() {
     test_isatty();
     test_read_and_uninit();
     test_nofollow_not_symlink();
+    #[cfg(target_os = "macos")]
+    test_ioctl();
 }
 
 fn test_file_open_unix_allow_two_args() {
@@ -431,3 +433,21 @@ fn test_nofollow_not_symlink() {
     let ret = unsafe { libc::open(cpath.as_ptr(), libc::O_NOFOLLOW | libc::O_CLOEXEC) };
     assert!(ret >= 0);
 }
+
+#[cfg(target_os = "macos")]
+fn test_ioctl() {
+    let path = utils::prepare_with_content("miri_test_libc_ioctl.txt", &[]);
+
+    let mut name = path.into_os_string();
+    name.push("\0");
+    let name_ptr = name.as_bytes().as_ptr().cast::<libc::c_char>();
+    unsafe {
+        // 100 surely is an invalid FD.
+        assert_eq!(libc::ioctl(100, libc::FIOCLEX), -1);
+        let errno = std::io::Error::last_os_error().raw_os_error().unwrap();
+        assert_eq!(errno, libc::EBADF);
+
+        let fd = libc::open(name_ptr, libc::O_RDONLY);
+        assert_eq!(libc::ioctl(fd, libc::FIOCLEX), 0);
+    }
+}
diff --git a/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs b/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs
index cf634bc6890..6ac71b5ad1e 100644
--- a/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs
+++ b/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs
@@ -29,12 +29,13 @@ fn main() {
 
     fn set_thread_name(name: &CStr) -> i32 {
         cfg_if::cfg_if! {
-            if #[cfg(any(target_os = "linux", target_os = "illumos", target_os = "solaris"))] {
+            if #[cfg(any(
+                target_os = "linux",
+                target_os = "freebsd",
+                target_os = "illumos",
+                target_os = "solaris"
+            ))] {
                 unsafe { libc::pthread_setname_np(libc::pthread_self(), name.as_ptr().cast()) }
-            } else if #[cfg(target_os = "freebsd")] {
-                // pthread_set_name_np does not return anything
-                unsafe { libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr().cast()) };
-                0
             } else if #[cfg(target_os = "macos")] {
                 unsafe { libc::pthread_setname_np(name.as_ptr().cast()) }
             } else {
@@ -47,6 +48,7 @@ fn main() {
         cfg_if::cfg_if! {
             if #[cfg(any(
                 target_os = "linux",
+                target_os = "freebsd",
                 target_os = "illumos",
                 target_os = "solaris",
                 target_os = "macos"
@@ -54,12 +56,6 @@ fn main() {
                 unsafe {
                     libc::pthread_getname_np(libc::pthread_self(), name.as_mut_ptr().cast(), name.len())
                 }
-            } else if #[cfg(target_os = "freebsd")] {
-                // pthread_get_name_np does not return anything
-                unsafe {
-                    libc::pthread_get_name_np(libc::pthread_self(), name.as_mut_ptr().cast(), name.len())
-                };
-                0
             } else {
                 compile_error!("get_thread_name not supported for this OS")
             }
@@ -201,27 +197,25 @@ fn main() {
         .unwrap();
 
     // Now set the name for a non-existing thread and verify error codes.
-    // (FreeBSD doesn't return an error code.)
-    #[cfg(not(target_os = "freebsd"))]
-    {
-        let invalid_thread = 0xdeadbeef;
-        let error = {
-            cfg_if::cfg_if! {
-                if #[cfg(target_os = "linux")] {
-                    libc::ENOENT
-                } else {
-                    libc::ESRCH
-                }
+    let invalid_thread = 0xdeadbeef;
+    let error = {
+        cfg_if::cfg_if! {
+            if #[cfg(target_os = "linux")] {
+                libc::ENOENT
+            } else {
+                libc::ESRCH
             }
-        };
-        #[cfg(not(target_os = "macos"))]
-        {
-            // macOS has no `setname` function accepting a thread id as the first argument.
-            let res = unsafe { libc::pthread_setname_np(invalid_thread, [0].as_ptr()) };
-            assert_eq!(res, error);
         }
-        let mut buf = [0; 64];
-        let res = unsafe { libc::pthread_getname_np(invalid_thread, buf.as_mut_ptr(), buf.len()) };
+    };
+
+    #[cfg(not(target_os = "macos"))]
+    {
+        // macOS has no `setname` function accepting a thread id as the first argument.
+        let res = unsafe { libc::pthread_setname_np(invalid_thread, [0].as_ptr()) };
         assert_eq!(res, error);
     }
+
+    let mut buf = [0; 64];
+    let res = unsafe { libc::pthread_getname_np(invalid_thread, buf.as_mut_ptr(), buf.len()) };
+    assert_eq!(res, error);
 }
diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr
index 48d9649c920..1ee5298f17d 100644
--- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr
+++ b/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr
@@ -10,7 +10,7 @@ RUSTLIB/core/src/ops/function.rs:LL:CC (std::ops::function::impls::call_once)
 RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try::do_call)
 RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try)
 RUSTLIB/std/src/panic.rs:LL:CC (std::panic::catch_unwind)
-RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start_internal::{closure#1})
+RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start_internal::{closure#0})
 RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try::do_call)
 RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try)
 RUSTLIB/std/src/panic.rs:LL:CC (std::panic::catch_unwind)
diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr
index 667ee04e624..26cdee18e3c 100644
--- a/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr
+++ b/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr
@@ -14,7 +14,7 @@
  at RUSTLIB/std/src/panicking.rs:LL:CC
    7: std::panic::catch_unwind
  at RUSTLIB/std/src/panic.rs:LL:CC
-   8: std::rt::lang_start_internal::{closure#1}
+   8: std::rt::lang_start_internal::{closure#0}
  at RUSTLIB/std/src/rt.rs:LL:CC
    9: std::panicking::r#try::do_call
  at RUSTLIB/std/src/panicking.rs:LL:CC
diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr
index b3a3a9d654a..d89ae3837b9 100644
--- a/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr
+++ b/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr
@@ -22,7 +22,7 @@
  at RUSTLIB/std/src/panicking.rs:LL:CC
   11: std::panic::catch_unwind
  at RUSTLIB/std/src/panic.rs:LL:CC
-  12: std::rt::lang_start_internal::{closure#1}
+  12: std::rt::lang_start_internal::{closure#0}
  at RUSTLIB/std/src/rt.rs:LL:CC
   13: std::panicking::r#try::do_call
  at RUSTLIB/std/src/panicking.rs:LL:CC
diff --git a/src/tools/miri/tests/pass/shims/pipe.rs b/src/tools/miri/tests/pass/shims/pipe.rs
new file mode 100644
index 00000000000..1be29886d2d
--- /dev/null
+++ b/src/tools/miri/tests/pass/shims/pipe.rs
@@ -0,0 +1,13 @@
+//@ignore-target: windows
+
+#![feature(anonymous_pipe)]
+
+use std::io::{Read, Write, pipe};
+
+fn main() {
+    let (mut ping_rx, mut ping_tx) = pipe().unwrap();
+    ping_tx.write(b"hello").unwrap();
+    let mut buf: [u8; 5] = [0; 5];
+    ping_rx.read(&mut buf).unwrap();
+    assert_eq!(&buf, "hello".as_bytes());
+}
diff --git a/src/tools/miri/triagebot.toml b/src/tools/miri/triagebot.toml
index 3192882dff6..4e013764d87 100644
--- a/src/tools/miri/triagebot.toml
+++ b/src/tools/miri/triagebot.toml
@@ -1,3 +1,6 @@
+## See <https://forge.rust-lang.org/triagebot/index.html> for documentation
+## of these options.
+
 [relabel]
 allow-unauthenticated = [
     "A-*",
@@ -30,5 +33,10 @@ remove_labels = ["S-waiting-on-author"]
 # Those labels are added when PR author requests a review from an assignee
 add_labels = ["S-waiting-on-review"]
 
+[merge-conflicts]
+remove = []
+add = ["S-waiting-on-author"]
+unless = ["S-blocked", "S-waiting-on-team", "S-waiting-on-review"]
+
 # Automatically close and reopen PRs made by bots to run CI on them
 [bot-pull-requests]
diff --git a/src/tools/opt-dist/src/bolt.rs b/src/tools/opt-dist/src/bolt.rs
index d9efbb8d880..0f1fda38115 100644
--- a/src/tools/opt-dist/src/bolt.rs
+++ b/src/tools/opt-dist/src/bolt.rs
@@ -1,6 +1,7 @@
 use anyhow::Context;
 use camino::{Utf8Path, Utf8PathBuf};
 
+use crate::environment::Environment;
 use crate::exec::cmd;
 use crate::training::BoltProfile;
 use crate::utils::io::copy_file;
@@ -45,13 +46,21 @@ pub fn with_bolt_instrumented<F: FnOnce(&Utf8Path) -> anyhow::Result<R>, R>(
 }
 
 /// Optimizes the file at `path` with BOLT in-place using the given `profile`.
-pub fn bolt_optimize(path: &Utf8Path, profile: &BoltProfile) -> anyhow::Result<()> {
+pub fn bolt_optimize(
+    path: &Utf8Path,
+    profile: &BoltProfile,
+    env: &Environment,
+) -> anyhow::Result<()> {
     // Copy the artifact to a new location, so that we do not use the same input and output file.
     // BOLT cannot handle optimizing when the input and output is the same file, because it performs
     // in-place patching.
     let temp_path = tempfile::NamedTempFile::new()?.into_temp_path();
     copy_file(path, &temp_path)?;
 
+    // FIXME: cdsplit in llvm-bolt is currently broken on AArch64, drop this once it's fixed upstream
+    let split_strategy =
+        if env.host_tuple().starts_with("aarch64") { "profile2" } else { "cdsplit" };
+
     cmd(&["llvm-bolt"])
         .arg(temp_path.display())
         .arg("-data")
@@ -65,7 +74,7 @@ pub fn bolt_optimize(path: &Utf8Path, profile: &BoltProfile) -> anyhow::Result<(
         // Split function code into hot and code regions
         .arg("-split-functions")
         // Split using best available strategy (three-way splitting, Cache-Directed Sort)
-        .arg("-split-strategy=cdsplit")
+        .arg(format!("-split-strategy={split_strategy}"))
         // Split as many basic blocks as possible
         .arg("-split-all-cold")
         // Move jump tables to a separate section
diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs
index c871200f3cf..aa05b5f0e76 100644
--- a/src/tools/opt-dist/src/main.rs
+++ b/src/tools/opt-dist/src/main.rs
@@ -146,6 +146,21 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)>
             let target_triple =
                 std::env::var("PGO_HOST").expect("PGO_HOST environment variable missing");
 
+            let is_aarch64 = target_triple.starts_with("aarch64");
+
+            let mut skip_tests = vec![
+                // Fails because of linker errors, as of June 2023.
+                "tests/ui/process/nofile-limit.rs".to_string(),
+            ];
+
+            if is_aarch64 {
+                skip_tests.extend([
+                    // Those tests fail only inside of Docker on aarch64, as of December 2024
+                    "tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs".to_string(),
+                    "tests/ui/consts/large_const_alloc.rs".to_string(),
+                ]);
+            }
+
             let checkout_dir = Utf8PathBuf::from("/checkout");
             let env = EnvironmentBuilder::default()
                 .host_tuple(target_triple)
@@ -155,11 +170,9 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)>
                 .artifact_dir(Utf8PathBuf::from("/tmp/tmp-multistage/opt-artifacts"))
                 .build_dir(checkout_dir.join("obj"))
                 .shared_llvm(true)
-                .use_bolt(true)
-                .skipped_tests(vec![
-                    // Fails because of linker errors, as of June 2023.
-                    "tests/ui/process/nofile-limit.rs".to_string(),
-                ])
+                // FIXME: Enable bolt for aarch64 once it's fixed upstream. Broken as of December 2024.
+                .use_bolt(!is_aarch64)
+                .skipped_tests(skip_tests)
                 .build()?;
 
             (env, shared.build_args)
@@ -304,7 +317,8 @@ fn execute_pipeline(
             // the final dist build. However, when BOLT optimizes an artifact, it does so *in-place*,
             // therefore it will actually optimize all the hard links, which means that the final
             // packaged `libLLVM.so` file *will* be BOLT optimized.
-            bolt_optimize(&llvm_lib, &llvm_profile).context("Could not optimize LLVM with BOLT")?;
+            bolt_optimize(&llvm_lib, &llvm_profile, env)
+                .context("Could not optimize LLVM with BOLT")?;
 
             let rustc_lib = io::find_file_in_dir(&libdir, "librustc_driver", ".so")?;
 
@@ -319,7 +333,7 @@ fn execute_pipeline(
             print_free_disk_space()?;
 
             // Now optimize the library with BOLT.
-            bolt_optimize(&rustc_lib, &rustc_profile)
+            bolt_optimize(&rustc_lib, &rustc_profile, env)
                 .context("Could not optimize rustc with BOLT")?;
 
             // LLVM is not being cleared here, we want to use the BOLT-optimized LLVM
diff --git a/src/tools/replace-version-placeholder/src/main.rs b/src/tools/replace-version-placeholder/src/main.rs
index 88118cab235..fb2838a4ea0 100644
--- a/src/tools/replace-version-placeholder/src/main.rs
+++ b/src/tools/replace-version-placeholder/src/main.rs
@@ -10,7 +10,12 @@ fn main() {
     let version_str = t!(std::fs::read_to_string(&version_path), version_path);
     let version_str = version_str.trim();
     walk::walk_many(
-        &[&root_path.join("compiler"), &root_path.join("library")],
+        &[
+            &root_path.join("compiler"),
+            &root_path.join("library"),
+            &root_path.join("src/doc/rustc"),
+            &root_path.join("src/doc/rustdoc"),
+        ],
         |path, _is_dir| walk::filter_dirs(path),
         &mut |entry, contents| {
             if !contents.contains(VERSION_PLACEHOLDER) {
diff --git a/src/tools/run-make-support/src/external_deps/rustdoc.rs b/src/tools/run-make-support/src/external_deps/rustdoc.rs
index df5e5d8a2e8..3c0e9c82f0b 100644
--- a/src/tools/run-make-support/src/external_deps/rustdoc.rs
+++ b/src/tools/run-make-support/src/external_deps/rustdoc.rs
@@ -45,8 +45,7 @@ impl Rustdoc {
     #[track_caller]
     pub fn new() -> Self {
         let mut cmd = setup_common();
-        let target_rpath_dir = env_var_os("TARGET_RPATH_DIR");
-        cmd.arg(format!("-L{}", target_rpath_dir.to_string_lossy()));
+        cmd.arg("-L").arg(env_var_os("TARGET_RPATH_DIR"));
         Self { cmd }
     }
 
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index 819bbc161e6..ffd4ca22a00 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -6,6 +6,7 @@
 // We want to control use declaration ordering and spacing (and preserve use group comments), so
 // skip rustfmt on this file.
 #![cfg_attr(rustfmt, rustfmt::skip)]
+#![warn(unreachable_pub)]
 
 mod command;
 mod macros;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
index 0c1f63880cd..108171586ea 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
@@ -197,6 +197,7 @@ fn layout_of_simd_ty(
         align,
         max_repr_align: None,
         unadjusted_abi_align: align.abi,
+        randomization_seed: 0,
     }))
 }
 
@@ -313,6 +314,7 @@ pub fn layout_of_ty_query(
                 size,
                 max_repr_align: None,
                 unadjusted_abi_align: element.align.abi,
+                randomization_seed: 0,
             }
         }
         TyKind::Slice(element) => {
@@ -326,6 +328,7 @@ pub fn layout_of_ty_query(
                 size: Size::ZERO,
                 max_repr_align: None,
                 unadjusted_abi_align: element.align.abi,
+                randomization_seed: 0,
             }
         }
         TyKind::Str => Layout {
@@ -337,6 +340,7 @@ pub fn layout_of_ty_query(
             size: Size::ZERO,
             max_repr_align: None,
             unadjusted_abi_align: dl.i8_align.abi,
+            randomization_seed: 0,
         },
         // Potentially-wide pointers.
         TyKind::Ref(_, _, pointee) | TyKind::Raw(_, pointee) => {
diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock
index b5b360db252..86d2abcacb7 100644
--- a/src/tools/rustbook/Cargo.lock
+++ b/src/tools/rustbook/Cargo.lock
@@ -86,11 +86,12 @@ dependencies = [
 
 [[package]]
 name = "anstyle-wincon"
-version = "3.0.6"
+version = "3.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
+checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
 dependencies = [
  "anstyle",
+ "once_cell",
  "windows-sys",
 ]
 
@@ -123,9 +124,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
 name = "bitflags"
-version = "2.6.0"
+version = "2.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
 
 [[package]]
 name = "block-buffer"
@@ -161,9 +162,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
 
 [[package]]
 name = "cc"
-version = "1.2.7"
+version = "1.2.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a012a0df96dd6d06ba9a1b29d6402d1a5d77c6befd2566afdc26e10603dc93d7"
+checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229"
 dependencies = [
  "shlex",
 ]
@@ -190,9 +191,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.5.23"
+version = "4.5.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84"
+checksum = "a8eb5e908ef3a6efbe1ed62520fb7287959888c88485abe072543190ecc66783"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -200,9 +201,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.23"
+version = "4.5.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838"
+checksum = "96b01801b5fc6a0a232407abc821660c9c6d25a1cafc0d4f85f29fb8d9afc121"
 dependencies = [
  "anstream",
  "anstyle",
@@ -213,18 +214,18 @@ dependencies = [
 
 [[package]]
 name = "clap_complete"
-version = "4.5.40"
+version = "4.5.42"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac2e663e3e3bed2d32d065a8404024dad306e699a04263ec59919529f803aee9"
+checksum = "33a7e468e750fa4b6be660e8b5651ad47372e8fb114030b594c2d75d48c5ffd0"
 dependencies = [
  "clap",
 ]
 
 [[package]]
 name = "clap_derive"
-version = "4.5.18"
+version = "4.5.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
+checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c"
 dependencies = [
  "heck",
  "proc-macro2",
@@ -279,6 +280,41 @@ dependencies = [
 ]
 
 [[package]]
+name = "darling"
+version = "0.20.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
+dependencies = [
+ "darling_core",
+ "darling_macro",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.20.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.20.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
+dependencies = [
+ "darling_core",
+ "quote",
+ "syn",
+]
+
+[[package]]
 name = "dateparser"
 version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -302,6 +338,37 @@ dependencies = [
 ]
 
 [[package]]
+name = "derive_builder"
+version = "0.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947"
+dependencies = [
+ "derive_builder_macro",
+]
+
+[[package]]
+name = "derive_builder_core"
+version = "0.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8"
+dependencies = [
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "derive_builder_macro"
+version = "0.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
+dependencies = [
+ "derive_builder_core",
+ "syn",
+]
+
+[[package]]
 name = "digest"
 version = "0.10.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -452,17 +519,18 @@ dependencies = [
 
 [[package]]
 name = "handlebars"
-version = "6.2.0"
+version = "6.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd4ccde012831f9a071a637b0d4e31df31c0f6c525784b35ae76a9ac6bc1e315"
+checksum = "3d6b224b95c1e668ac0270325ad563b2eef1469fbbb8959bc7c692c844b813d9"
 dependencies = [
+ "derive_builder",
  "log",
  "num-order",
  "pest",
  "pest_derive",
  "serde",
  "serde_json",
- "thiserror 1.0.69",
+ "thiserror 2.0.11",
 ]
 
 [[package]]
@@ -654,6 +722,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "ident_case"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+
+[[package]]
 name = "idna"
 version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -698,9 +772,9 @@ checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
 
 [[package]]
 name = "js-sys"
-version = "0.3.76"
+version = "0.3.77"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7"
+checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
 dependencies = [
  "once_cell",
  "wasm-bindgen",
@@ -739,9 +813,9 @@ dependencies = [
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.4.14"
+version = "0.4.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
+checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
 
 [[package]]
 name = "litemap"
@@ -761,9 +835,9 @@ dependencies = [
 
 [[package]]
 name = "log"
-version = "0.4.22"
+version = "0.4.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
+checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
 
 [[package]]
 name = "mac"
@@ -878,9 +952,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
 
 [[package]]
 name = "miniz_oxide"
-version = "0.8.2"
+version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394"
+checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924"
 dependencies = [
  "adler2",
 ]
@@ -1006,7 +1080,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc"
 dependencies = [
  "memchr",
- "thiserror 2.0.9",
+ "thiserror 2.0.11",
  "ucd-trie",
 ]
 
@@ -1046,21 +1120,21 @@ dependencies = [
 
 [[package]]
 name = "phf"
-version = "0.11.2"
+version = "0.11.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
+checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078"
 dependencies = [
- "phf_shared 0.11.2",
+ "phf_shared 0.11.3",
 ]
 
 [[package]]
 name = "phf_codegen"
-version = "0.11.2"
+version = "0.11.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a"
+checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a"
 dependencies = [
- "phf_generator 0.11.2",
- "phf_shared 0.11.2",
+ "phf_generator 0.11.3",
+ "phf_shared 0.11.3",
 ]
 
 [[package]]
@@ -1075,11 +1149,11 @@ dependencies = [
 
 [[package]]
 name = "phf_generator"
-version = "0.11.2"
+version = "0.11.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
+checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
 dependencies = [
- "phf_shared 0.11.2",
+ "phf_shared 0.11.3",
  "rand",
 ]
 
@@ -1089,16 +1163,16 @@ version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096"
 dependencies = [
- "siphasher",
+ "siphasher 0.3.11",
 ]
 
 [[package]]
 name = "phf_shared"
-version = "0.11.2"
+version = "0.11.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
+checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
 dependencies = [
- "siphasher",
+ "siphasher 1.0.1",
 ]
 
 [[package]]
@@ -1133,9 +1207,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.92"
+version = "1.0.93"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
+checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
 dependencies = [
  "unicode-ident",
 ]
@@ -1146,7 +1220,7 @@ version = "0.10.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993"
 dependencies = [
- "bitflags 2.6.0",
+ "bitflags 2.8.0",
  "memchr",
  "pulldown-cmark-escape 0.10.1",
  "unicase",
@@ -1158,7 +1232,7 @@ version = "0.11.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625"
 dependencies = [
- "bitflags 2.6.0",
+ "bitflags 2.8.0",
  "memchr",
  "pulldown-cmark-escape 0.11.0",
  "unicase",
@@ -1170,7 +1244,7 @@ version = "0.12.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f86ba2052aebccc42cbbb3ed234b8b13ce76f75c3551a303cb2bcffcff12bb14"
 dependencies = [
- "bitflags 2.6.0",
+ "bitflags 2.8.0",
  "getopts",
  "memchr",
  "pulldown-cmark-escape 0.11.0",
@@ -1252,7 +1326,7 @@ version = "0.5.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
 dependencies = [
- "bitflags 2.6.0",
+ "bitflags 2.8.0",
 ]
 
 [[package]]
@@ -1298,11 +1372,11 @@ dependencies = [
 
 [[package]]
 name = "rustix"
-version = "0.38.42"
+version = "0.38.43"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85"
+checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6"
 dependencies = [
- "bitflags 2.6.0",
+ "bitflags 2.8.0",
  "errno",
  "libc",
  "linux-raw-sys",
@@ -1310,6 +1384,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "rustversion"
+version = "1.0.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4"
+
+[[package]]
 name = "ryu"
 version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1358,9 +1438,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.134"
+version = "1.0.135"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d"
+checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9"
 dependencies = [
  "itoa",
  "memchr",
@@ -1401,6 +1481,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
 
 [[package]]
+name = "siphasher"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
+
+[[package]]
 name = "smallvec"
 version = "1.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1446,9 +1532,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
 
 [[package]]
 name = "syn"
-version = "2.0.94"
+version = "2.0.96"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "987bc0be1cdea8b10216bd06e2ca407d40b9543468fafd3ddfb02f36e77f71f3"
+checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1538,11 +1624,11 @@ dependencies = [
 
 [[package]]
 name = "thiserror"
-version = "2.0.9"
+version = "2.0.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc"
+checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc"
 dependencies = [
- "thiserror-impl 2.0.9",
+ "thiserror-impl 2.0.11",
 ]
 
 [[package]]
@@ -1558,9 +1644,9 @@ dependencies = [
 
 [[package]]
 name = "thiserror-impl"
-version = "2.0.9"
+version = "2.0.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4"
+checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1715,20 +1801,21 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.99"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396"
+checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
 dependencies = [
  "cfg-if",
  "once_cell",
+ "rustversion",
  "wasm-bindgen-macro",
 ]
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.99"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79"
+checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
 dependencies = [
  "bumpalo",
  "log",
@@ -1740,9 +1827,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.99"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe"
+checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -1750,9 +1837,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.99"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2"
+checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1763,9 +1850,12 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.99"
+version = "0.2.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6"
+checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
+dependencies = [
+ "unicode-ident",
+]
 
 [[package]]
 name = "winapi"
@@ -1882,9 +1972,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
 [[package]]
 name = "winnow"
-version = "0.6.22"
+version = "0.6.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39281189af81c07ec09db316b302a3e67bf9bd7cbf6c820b50e35fee9c2fa980"
+checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a"
 dependencies = [
  "memchr",
 ]
diff --git a/src/tools/rustc-perf b/src/tools/rustc-perf
-Subproject d5055e78042c739deeb3fe0bef83fde0e5cc259
+Subproject e22e08623a349b13a3296971a05394d44f76974
diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js
index 7aa5e102e6d..ea575f27799 100644
--- a/src/tools/rustdoc-js/tester.js
+++ b/src/tools/rustdoc-js/tester.js
@@ -256,7 +256,7 @@ async function runSearch(query, expected, doSearch, loadedFile, queryName) {
                                 JSON.stringify(results[key][index]) + "'");
             } else if (ignore_order === false && entry_pos < prev_pos) {
                 error_text.push(queryName + "==> '" + JSON.stringify(elem) + "' was supposed " +
-                                "to be before '" + JSON.stringify(results[key][entry_pos]) + "'");
+                                "to be before '" + JSON.stringify(results[key][prev_pos]) + "'");
             } else {
                 prev_pos = entry_pos;
             }
diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs
index 7b4730eadc8..1d88726d945 100644
--- a/src/tools/rustfmt/src/patterns.rs
+++ b/src/tools/rustfmt/src/patterns.rs
@@ -31,18 +31,31 @@ use crate::utils::{format_mutability, mk_sp, mk_sp_lo_plus_one, rewrite_ident};
 ///     - `[small, ntp]`
 ///     - unary tuple constructor `([small, ntp])`
 ///     - `&[small]`
-pub(crate) fn is_short_pattern(pat: &ast::Pat, pat_str: &str) -> bool {
+pub(crate) fn is_short_pattern(
+    context: &RewriteContext<'_>,
+    pat: &ast::Pat,
+    pat_str: &str,
+) -> bool {
     // We also require that the pattern is reasonably 'small' with its literal width.
-    pat_str.len() <= 20 && !pat_str.contains('\n') && is_short_pattern_inner(pat)
+    pat_str.len() <= 20 && !pat_str.contains('\n') && is_short_pattern_inner(context, pat)
 }
 
-fn is_short_pattern_inner(pat: &ast::Pat) -> bool {
-    match pat.kind {
-        ast::PatKind::Rest
-        | ast::PatKind::Never
-        | ast::PatKind::Wild
-        | ast::PatKind::Err(_)
-        | ast::PatKind::Lit(_) => true,
+fn is_short_pattern_inner(context: &RewriteContext<'_>, pat: &ast::Pat) -> bool {
+    match &pat.kind {
+        ast::PatKind::Rest | ast::PatKind::Never | ast::PatKind::Wild | ast::PatKind::Err(_) => {
+            true
+        }
+        ast::PatKind::Expr(expr) => match &expr.kind {
+            ast::ExprKind::Lit(_) => true,
+            ast::ExprKind::Unary(ast::UnOp::Neg, expr) => match &expr.kind {
+                ast::ExprKind::Lit(_) => true,
+                _ => unreachable!(),
+            },
+            ast::ExprKind::ConstBlock(_) | ast::ExprKind::Path(..) => {
+                context.config.style_edition() <= StyleEdition::Edition2024
+            }
+            _ => unreachable!(),
+        },
         ast::PatKind::Ident(_, _, ref pat) => pat.is_none(),
         ast::PatKind::Struct(..)
         | ast::PatKind::MacCall(..)
@@ -57,8 +70,8 @@ fn is_short_pattern_inner(pat: &ast::Pat) -> bool {
         ast::PatKind::Box(ref p)
         | PatKind::Deref(ref p)
         | ast::PatKind::Ref(ref p, _)
-        | ast::PatKind::Paren(ref p) => is_short_pattern_inner(&*p),
-        PatKind::Or(ref pats) => pats.iter().all(|p| is_short_pattern_inner(p)),
+        | ast::PatKind::Paren(ref p) => is_short_pattern_inner(context, &*p),
+        PatKind::Or(ref pats) => pats.iter().all(|p| is_short_pattern_inner(context, p)),
     }
 }
 
@@ -96,7 +109,7 @@ impl Rewrite for Pat {
                 let use_mixed_layout = pats
                     .iter()
                     .zip(pat_strs.iter())
-                    .all(|(pat, pat_str)| is_short_pattern(pat, pat_str));
+                    .all(|(pat, pat_str)| is_short_pattern(context, pat, pat_str));
                 let items: Vec<_> = pat_strs.into_iter().map(ListItem::from_str).collect();
                 let tactic = if use_mixed_layout {
                     DefinitiveListTactic::Mixed
@@ -293,7 +306,7 @@ impl Rewrite for Pat {
                 let path_str = rewrite_path(context, PathContext::Expr, q_self, path, shape)?;
                 rewrite_tuple_pat(pat_vec, Some(path_str), self.span, context, shape)
             }
-            PatKind::Lit(ref expr) => expr.rewrite_result(context, shape),
+            PatKind::Expr(ref expr) => expr.rewrite_result(context, shape),
             PatKind::Slice(ref slice_pat)
                 if context.config.style_edition() <= StyleEdition::Edition2021 =>
             {
@@ -530,7 +543,7 @@ pub(crate) fn can_be_overflowed_pat(
             ast::PatKind::Ref(ref p, _) | ast::PatKind::Box(ref p) => {
                 can_be_overflowed_pat(context, &TuplePatField::Pat(p), len)
             }
-            ast::PatKind::Lit(ref expr) => can_be_overflowed_expr(context, expr, len),
+            ast::PatKind::Expr(ref expr) => can_be_overflowed_expr(context, expr, len),
             _ => false,
         },
         TuplePatField::Dotdot(..) => false,
diff --git a/src/tools/rustfmt/tests/source/pattern.rs b/src/tools/rustfmt/tests/source/pattern.rs
index f06d03cadf2..ed6ad690fa9 100644
--- a/src/tools/rustfmt/tests/source/pattern.rs
+++ b/src/tools/rustfmt/tests/source/pattern.rs
@@ -88,3 +88,13 @@ fn issue3728() {
         | c;
     foo((1,));
 }
+
+fn literals() {
+    match 42 {
+        const { 1 + 2 } | 4
+        | 6 => {}
+        10 | 11 | 12
+        | 13 | 14 => {}
+        _ => {}
+    }
+}
\ No newline at end of file
diff --git a/src/tools/rustfmt/tests/target/pattern.rs b/src/tools/rustfmt/tests/target/pattern.rs
index 576018ac623..e867f65929d 100644
--- a/src/tools/rustfmt/tests/target/pattern.rs
+++ b/src/tools/rustfmt/tests/target/pattern.rs
@@ -96,3 +96,11 @@ fn issue3728() {
     let foo = |(c,)| c;
     foo((1,));
 }
+
+fn literals() {
+    match 42 {
+        const { 1 + 2 } | 4 | 6 => {}
+        10 | 11 | 12 | 13 | 14 => {}
+        _ => {}
+    }
+}
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index b20d8678d0e..575716eb6dd 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -1,5 +1,4 @@
 run-make/cat-and-grep-sanity-check/Makefile
-run-make/extern-fn-reachable/Makefile
 run-make/jobserver-error/Makefile
 run-make/split-debuginfo/Makefile
 run-make/symbol-mangling-hashed/Makefile
diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs
index aefcd2bb0cc..21b513629ed 100644
--- a/src/tools/tidy/src/style.rs
+++ b/src/tools/tidy/src/style.rs
@@ -72,6 +72,21 @@ const ANNOTATIONS_TO_IGNORE: &[&str] = &[
     "//@ normalize-stderr",
 ];
 
+// If you edit this, also edit where it gets used in `check` (calling `contains_ignore_directives`)
+const CONFIGURABLE_CHECKS: [&str; 11] = [
+    "cr",
+    "undocumented-unsafe",
+    "tab",
+    "linelength",
+    "filelength",
+    "end-whitespace",
+    "trailing-newlines",
+    "leading-newlines",
+    "copyright",
+    "dbg",
+    "odd-backticks",
+];
+
 fn generate_problems<'a>(
     consts: &'a [u32],
     letter_digit: &'a FxHashMap<char, char>,
@@ -220,6 +235,7 @@ fn long_line_is_ok(extension: &str, is_error_code: bool, max_columns: usize, lin
     }
 }
 
+#[derive(Clone, Copy)]
 enum Directive {
     /// By default, tidy always warns against style issues.
     Deny,
@@ -231,20 +247,28 @@ enum Directive {
     Ignore(bool),
 }
 
-fn contains_ignore_directive(can_contain: bool, contents: &str, check: &str) -> Directive {
+// Use a fixed size array in the return type to catch mistakes with changing `CONFIGURABLE_CHECKS`
+// without changing the code in `check` easier.
+fn contains_ignore_directives<const N: usize>(
+    can_contain: bool,
+    contents: &str,
+    checks: [&str; N],
+) -> [Directive; N] {
     if !can_contain {
-        return Directive::Deny;
-    }
-    // Update `can_contain` when changing this
-    if contents.contains(&format!("// ignore-tidy-{check}"))
-        || contents.contains(&format!("# ignore-tidy-{check}"))
-        || contents.contains(&format!("/* ignore-tidy-{check} */"))
-        || contents.contains(&format!("<!-- ignore-tidy-{check} -->"))
-    {
-        Directive::Ignore(false)
-    } else {
-        Directive::Deny
+        return [Directive::Deny; N];
     }
+    checks.map(|check| {
+        // Update `can_contain` when changing this
+        if contents.contains(&format!("// ignore-tidy-{check}"))
+            || contents.contains(&format!("# ignore-tidy-{check}"))
+            || contents.contains(&format!("/* ignore-tidy-{check} */"))
+            || contents.contains(&format!("<!-- ignore-tidy-{check} -->"))
+        {
+            Directive::Ignore(false)
+        } else {
+            Directive::Deny
+        }
+    })
 }
 
 macro_rules! suppressible_tidy_err {
@@ -370,6 +394,7 @@ pub fn check(path: &Path, bad: &mut bool) {
             COLS
         };
 
+        // When you change this, also change the `directive_line_starts` variable below
         let can_contain = contents.contains("// ignore-tidy-")
             || contents.contains("# ignore-tidy-")
             || contents.contains("/* ignore-tidy-")
@@ -385,22 +410,19 @@ pub fn check(path: &Path, bad: &mut bool) {
                 return;
             }
         }
-        let mut skip_cr = contains_ignore_directive(can_contain, &contents, "cr");
-        let mut skip_undocumented_unsafe =
-            contains_ignore_directive(can_contain, &contents, "undocumented-unsafe");
-        let mut skip_tab = contains_ignore_directive(can_contain, &contents, "tab");
-        let mut skip_line_length = contains_ignore_directive(can_contain, &contents, "linelength");
-        let mut skip_file_length = contains_ignore_directive(can_contain, &contents, "filelength");
-        let mut skip_end_whitespace =
-            contains_ignore_directive(can_contain, &contents, "end-whitespace");
-        let mut skip_trailing_newlines =
-            contains_ignore_directive(can_contain, &contents, "trailing-newlines");
-        let mut skip_leading_newlines =
-            contains_ignore_directive(can_contain, &contents, "leading-newlines");
-        let mut skip_copyright = contains_ignore_directive(can_contain, &contents, "copyright");
-        let mut skip_dbg = contains_ignore_directive(can_contain, &contents, "dbg");
-        let mut skip_odd_backticks =
-            contains_ignore_directive(can_contain, &contents, "odd-backticks");
+        let [
+            mut skip_cr,
+            mut skip_undocumented_unsafe,
+            mut skip_tab,
+            mut skip_line_length,
+            mut skip_file_length,
+            mut skip_end_whitespace,
+            mut skip_trailing_newlines,
+            mut skip_leading_newlines,
+            mut skip_copyright,
+            mut skip_dbg,
+            mut skip_odd_backticks,
+        ] = contains_ignore_directives(can_contain, &contents, CONFIGURABLE_CHECKS);
         let mut leading_new_lines = false;
         let mut trailing_new_lines = 0;
         let mut lines = 0;
@@ -474,6 +496,22 @@ pub fn check(path: &Path, bad: &mut bool) {
                 suppressible_tidy_err!(err, skip_cr, "CR character");
             }
             if !is_this_file {
+                let directive_line_starts = ["// ", "# ", "/* ", "<!-- "];
+                let possible_line_start =
+                    directive_line_starts.into_iter().any(|s| line.starts_with(s));
+                let contains_potential_directive =
+                    possible_line_start && (line.contains("-tidy") || line.contains("tidy-"));
+                let has_recognized_ignore_directive =
+                    contains_ignore_directives(can_contain, line, CONFIGURABLE_CHECKS)
+                        .into_iter()
+                        .any(|directive| matches!(directive, Directive::Ignore(_)));
+                let has_alphabetical_directive = line.contains("tidy-alphabetical-start")
+                    || line.contains("tidy-alphabetical-end");
+                let has_recognized_directive =
+                    has_recognized_ignore_directive || has_alphabetical_directive;
+                if contains_potential_directive && (!has_recognized_directive) {
+                    err("Unrecognized tidy directive")
+                }
                 // Allow using TODO in diagnostic suggestions by marking the
                 // relevant line with `// ignore-tidy-todo`.
                 if trimmed.contains("TODO") && !trimmed.contains("ignore-tidy-todo") {