about summary refs log tree commit diff
path: root/src/tools
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/build-manifest/src/main.rs4
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/CHANGELOG.md1
-rw-r--r--src/tools/clippy/CONTRIBUTING.md6
-rw-r--r--src/tools/clippy/Cargo.toml4
-rw-r--r--src/tools/clippy/book/src/development/basics.md2
-rw-r--r--src/tools/clippy/book/src/development/the_team.md2
-rw-r--r--src/tools/clippy/book/src/development/trait_checking.md4
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md3
-rw-r--r--src/tools/clippy/clippy_config/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_config/src/conf.rs3
-rw-r--r--src/tools/clippy/clippy_dev/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_dev/src/deprecate_lint.rs61
-rw-r--r--src/tools/clippy/clippy_dev/src/fmt.rs278
-rw-r--r--src/tools/clippy/clippy_dev/src/lib.rs10
-rw-r--r--src/tools/clippy/clippy_dev/src/main.rs5
-rw-r--r--src/tools/clippy/clippy_dev/src/release.rs24
-rw-r--r--src/tools/clippy/clippy_dev/src/rename_lint.rs493
-rw-r--r--src/tools/clippy/clippy_dev/src/sync.rs13
-rw-r--r--src/tools/clippy/clippy_dev/src/update_lints.rs163
-rw-r--r--src/tools/clippy/clippy_dev/src/utils.rs426
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs27
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/cognitive_complexity.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/comparison_chain.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/copies.rs27
-rw-r--r--src/tools/clippy/clippy_lints/src/dbg_macro.rs122
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/deprecated_lints.rs166
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs86
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_types.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs88
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/markdown.rs56
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/missing_headers.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/mod.rs27
-rw-r--r--src/tools/clippy/clippy_lints/src/empty_with_brackets.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/enum_clike.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/excessive_bools.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/exhaustive_items.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/explicit_write.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/fallible_impl_from.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/float_literal.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs54
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/must_use.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/ref_option.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/result.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_hasher.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/index_refutable_slice.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/ineffective_open_options.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/infinite_iter.rs85
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_to_string.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/item_name_repetitions.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/large_const_arrays.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/large_enum_variant.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/let_underscore.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/char_indices_as_byte_indices.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/explicit_into_iter_loop.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_find.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mod.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs103
-rw-r--r--src/tools/clippy/clippy_lints/src/macro_use.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_is_power_of_two.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs25
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_string_new.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/map_unit_fn.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs122
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/needless_match.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_last_cmp.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_next_cmp.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_count.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_nth.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_c_str_literals.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_is_variant_and.rs70
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_identity.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs418
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_as_bytes.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_collect.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_option_take.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/search_is_some.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/str_split.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/str_splitn.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/useless_asref.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/min_ident_chars.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_key.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_reference.rs32
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_bool.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_for_each.rs32
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/no_effect.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs1153
-rw-r--r--src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs45
-rw-r--r--src/tools/clippy/clippy_lints/src/option_env_unwrap.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/panic_unimplemented.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/partial_pub_fields.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs27
-rw-r--r--src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/string_patterns.rs52
-rw-r--r--src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/trailing_empty_array.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/types/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs126
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_peekable.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_rounding.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_trait_names.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap_in_result.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/use_self.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/useless_concat.rs104
-rw-r--r--src/tools/clippy/clippy_lints/src/useless_conversion.rs35
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/dump_hir.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/vec.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/wildcard_imports.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs8
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/almost_standard_lint_formulation.rs3
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/collapsible_calls.rs3
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs3
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/msrv_attr_impl.rs5
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/outer_expn_data_pass.rs6
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/produce_ice.rs3
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/symbols.rs3
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs8
-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.rs12
-rw-r--r--src/tools/clippy/clippy_utils/src/attrs.rs40
-rw-r--r--src/tools/clippy/clippy_utils/src/check_proc_macro.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs10
-rw-r--r--src/tools/clippy/clippy_utils/src/eager_or_lazy.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/higher.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs85
-rw-r--r--src/tools/clippy/clippy_utils/src/macros.rs20
-rw-r--r--src/tools/clippy/clippy_utils/src/msrvs.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs12
-rw-r--r--src/tools/clippy/clippy_utils/src/ptr.rs12
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs7
-rw-r--r--src/tools/clippy/clippy_utils/src/source.rs86
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/sym.rs254
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/mod.rs21
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs2
-rw-r--r--src/tools/clippy/lintcheck/src/input.rs21
-rw-r--r--src/tools/clippy/lintcheck/src/main.rs20
-rw-r--r--src/tools/clippy/lintcheck/src/output.rs6
-rw-r--r--src/tools/clippy/rust-toolchain.toml2
-rw-r--r--src/tools/clippy/rustfmt.toml6
-rw-r--r--src/tools/clippy/src/driver.rs15
-rw-r--r--src/tools/clippy/tests/headers.rs34
-rw-r--r--src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default.stderr70
-rw-r--r--src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default_exp.stderr70
-rw-r--r--src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.ord_within.stderr94
-rw-r--r--src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs16
-rw-r--r--src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if.fixed4
-rw-r--r--src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if.stderr4
-rw-r--r--src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs2
-rw-r--r--src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr12
-rw-r--r--src/tools/clippy/tests/ui/assign_ops.fixed69
-rw-r--r--src/tools/clippy/tests/ui/assign_ops.rs69
-rw-r--r--src/tools/clippy/tests/ui/assign_ops.stderr30
-rw-r--r--src/tools/clippy/tests/ui/assign_ops2.rs77
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/interior_mutable_const.rs (renamed from src/tools/clippy/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs)0
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs3
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs3
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs221
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const.stderr247
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.rs101
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.stderr79
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs128
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr119
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/projections.rs42
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/projections.stderr44
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.rs219
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.stderr143
-rw-r--r--src/tools/clippy/tests/ui/cast.rs4
-rw-r--r--src/tools/clippy/tests/ui/cast.stderr184
-rw-r--r--src/tools/clippy/tests/ui/cast_size.rs2
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.rs2
-rw-r--r--src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs2
-rw-r--r--src/tools/clippy/tests/ui/comparison_chain.rs12
-rw-r--r--src/tools/clippy/tests/ui/comparison_chain.stderr42
-rw-r--r--src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs3
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-12491.fixed2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-12491.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-12491.stderr8
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-12979.1.fixed2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-12979.2.fixed3
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-12979.rs3
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-12979.stderr19
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6840.rs1
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-9445.rs4
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-9445.stderr12
-rw-r--r--src/tools/clippy/tests/ui/dbg_macro/dbg_macro.fixed16
-rw-r--r--src/tools/clippy/tests/ui/dbg_macro/dbg_macro.rs16
-rw-r--r--src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr14
-rw-r--r--src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.rs2
-rw-r--r--src/tools/clippy/tests/ui/declare_interior_mutable_const.rs200
-rw-r--r--src/tools/clippy/tests/ui/declare_interior_mutable_const.stderr197
-rw-r--r--src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.rs135
-rw-r--r--src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.stderr89
-rw-r--r--src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs76
-rw-r--r--src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr50
-rw-r--r--src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.rs162
-rw-r--r--src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr88
-rw-r--r--src/tools/clippy/tests/ui/deprecated.rs20
-rw-r--r--src/tools/clippy/tests/ui/deprecated.stderr80
-rw-r--r--src/tools/clippy/tests/ui/doc/doc_markdown-issue_13097.fixed36
-rw-r--r--src/tools/clippy/tests/ui/doc/doc_markdown-issue_13097.rs36
-rw-r--r--src/tools/clippy/tests/ui/doc/doc_markdown-issue_13097.stderr74
-rw-r--r--src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs2
-rw-r--r--src/tools/clippy/tests/ui/duplicated_attributes.rs2
-rw-r--r--src/tools/clippy/tests/ui/empty_structs_with_brackets.fixed8
-rw-r--r--src/tools/clippy/tests/ui/empty_structs_with_brackets.rs8
-rw-r--r--src/tools/clippy/tests/ui/entry_unfixable.rs3
-rw-r--r--src/tools/clippy/tests/ui/entry_unfixable.stderr6
-rw-r--r--src/tools/clippy/tests/ui/excessive_precision.fixed3
-rw-r--r--src/tools/clippy/tests/ui/excessive_precision.rs3
-rw-r--r--src/tools/clippy/tests/ui/excessive_precision.stderr6
-rw-r--r--src/tools/clippy/tests/ui/explicit_counter_loop.rs2
-rw-r--r--src/tools/clippy/tests/ui/explicit_deref_methods.fixed17
-rw-r--r--src/tools/clippy/tests/ui/explicit_deref_methods.rs13
-rw-r--r--src/tools/clippy/tests/ui/explicit_deref_methods.stderr46
-rw-r--r--src/tools/clippy/tests/ui/explicit_into_iter_loop.fixed13
-rw-r--r--src/tools/clippy/tests/ui/explicit_into_iter_loop.rs13
-rw-r--r--src/tools/clippy/tests/ui/explicit_into_iter_loop.stderr8
-rw-r--r--src/tools/clippy/tests/ui/explicit_iter_loop.fixed17
-rw-r--r--src/tools/clippy/tests/ui/explicit_iter_loop.rs17
-rw-r--r--src/tools/clippy/tests/ui/explicit_iter_loop.stderr8
-rw-r--r--src/tools/clippy/tests/ui/filter_map_bool_then_unfixable.rs3
-rw-r--r--src/tools/clippy/tests/ui/filter_map_bool_then_unfixable.stderr10
-rw-r--r--src/tools/clippy/tests/ui/ifs_same_cond.rs12
-rw-r--r--src/tools/clippy/tests/ui/ifs_same_cond.stderr62
-rw-r--r--src/tools/clippy/tests/ui/impl_trait_in_params.rs2
-rw-r--r--src/tools/clippy/tests/ui/indexing_slicing_index.rs2
-rw-r--r--src/tools/clippy/tests/ui/indexing_slicing_index.stderr4
-rw-r--r--src/tools/clippy/tests/ui/infinite_loop.rs2
-rw-r--r--src/tools/clippy/tests/ui/infinite_loop.stderr22
-rw-r--r--src/tools/clippy/tests/ui/infinite_loops.rs2
-rw-r--r--src/tools/clippy/tests/ui/into_iter_without_iter.rs2
-rw-r--r--src/tools/clippy/tests/ui/iter_next_loop.rs15
-rw-r--r--src/tools/clippy/tests/ui/iter_next_loop.stderr8
-rw-r--r--src/tools/clippy/tests/ui/iter_not_returning_iterator.rs2
-rw-r--r--src/tools/clippy/tests/ui/iter_out_of_bounds.rs2
-rw-r--r--src/tools/clippy/tests/ui/iter_out_of_bounds.stderr30
-rw-r--r--src/tools/clippy/tests/ui/manual_find_fixable.fixed10
-rw-r--r--src/tools/clippy/tests/ui/manual_find_fixable.rs22
-rw-r--r--src/tools/clippy/tests/ui/manual_find_fixable.stderr24
-rw-r--r--src/tools/clippy/tests/ui/manual_flatten.rs7
-rw-r--r--src/tools/clippy/tests/ui/manual_flatten.stderr4
-rw-r--r--src/tools/clippy/tests/ui/manual_inspect.fixed2
-rw-r--r--src/tools/clippy/tests/ui/manual_inspect.stderr2
-rw-r--r--src/tools/clippy/tests/ui/manual_is_variant_and.fixed62
-rw-r--r--src/tools/clippy/tests/ui/manual_is_variant_and.rs62
-rw-r--r--src/tools/clippy/tests/ui/manual_is_variant_and.stderr60
-rw-r--r--src/tools/clippy/tests/ui/manual_slice_size_calculation.fixed25
-rw-r--r--src/tools/clippy/tests/ui/manual_slice_size_calculation.rs25
-rw-r--r--src/tools/clippy/tests/ui/manual_slice_size_calculation.stderr14
-rw-r--r--src/tools/clippy/tests/ui/map_flatten.rs2
-rw-r--r--src/tools/clippy/tests/ui/map_flatten_fixable.fixed1
-rw-r--r--src/tools/clippy/tests/ui/map_flatten_fixable.rs1
-rw-r--r--src/tools/clippy/tests/ui/map_flatten_fixable.stderr18
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms.fixed142
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms.rs20
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms.stderr137
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms2.fixed53
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms2.rs49
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms2.stderr255
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.fixed24
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs19
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr86
-rw-r--r--src/tools/clippy/tests/ui/methods.rs2
-rw-r--r--src/tools/clippy/tests/ui/misrefactored_assign_op.1.fixed40
-rw-r--r--src/tools/clippy/tests/ui/misrefactored_assign_op.2.fixed40
-rw-r--r--src/tools/clippy/tests/ui/misrefactored_assign_op.rs40
-rw-r--r--src/tools/clippy/tests/ui/misrefactored_assign_op.stderr (renamed from src/tools/clippy/tests/ui/assign_ops2.stderr)29
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.fixed15
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.rs15
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.stderr32
-rw-r--r--src/tools/clippy/tests/ui/needless_for_each_fixable.fixed15
-rw-r--r--src/tools/clippy/tests/ui/needless_for_each_fixable.rs15
-rw-r--r--src/tools/clippy/tests/ui/needless_for_each_fixable.stderr14
-rw-r--r--src/tools/clippy/tests/ui/needless_lifetimes.fixed2
-rw-r--r--src/tools/clippy/tests/ui/needless_lifetimes.rs2
-rw-r--r--src/tools/clippy/tests/ui/needless_match.fixed12
-rw-r--r--src/tools/clippy/tests/ui/needless_match.rs15
-rw-r--r--src/tools/clippy/tests/ui/needless_match.stderr12
-rw-r--r--src/tools/clippy/tests/ui/needless_return.fixed83
-rw-r--r--src/tools/clippy/tests/ui/needless_return.rs83
-rw-r--r--src/tools/clippy/tests/ui/needless_return.stderr174
-rw-r--r--src/tools/clippy/tests/ui/no_effect.rs53
-rw-r--r--src/tools/clippy/tests/ui/non_expressive_names_error_recovery.fixed (renamed from src/tools/clippy/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.fixed)0
-rw-r--r--src/tools/clippy/tests/ui/non_expressive_names_error_recovery.rs (renamed from src/tools/clippy/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.rs)0
-rw-r--r--src/tools/clippy/tests/ui/non_expressive_names_error_recovery.stderr (renamed from src/tools/clippy/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.stderr)2
-rw-r--r--src/tools/clippy/tests/ui/ptr_arg.rs2
-rw-r--r--src/tools/clippy/tests/ui/ptr_arg.stderr25
-rw-r--r--src/tools/clippy/tests/ui/question_mark.fixed10
-rw-r--r--src/tools/clippy/tests/ui/question_mark.rs10
-rw-r--r--src/tools/clippy/tests/ui/rename.fixed120
-rw-r--r--src/tools/clippy/tests/ui/rename.rs120
-rw-r--r--src/tools/clippy/tests/ui/rename.stderr400
-rw-r--r--src/tools/clippy/tests/ui/same_functions_in_if_condition.rs12
-rw-r--r--src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr67
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs12
-rw-r--r--src/tools/clippy/tests/ui/single_range_in_vec_init.rs2
-rw-r--r--src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.fixed180
-rw-r--r--src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs61
-rw-r--r--src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr80
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned.fixed6
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned.rs6
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_wraps.stderr71
-rw-r--r--src/tools/clippy/tests/ui/use_self.fixed2
-rw-r--r--src/tools/clippy/tests/ui/use_self.rs2
-rw-r--r--src/tools/clippy/tests/ui/useless_asref.fixed10
-rw-r--r--src/tools/clippy/tests/ui/useless_asref.rs10
-rw-r--r--src/tools/clippy/tests/ui/useless_concat.fixed41
-rw-r--r--src/tools/clippy/tests/ui/useless_concat.rs41
-rw-r--r--src/tools/clippy/tests/ui/useless_concat.stderr89
-rw-r--r--src/tools/clippy/tests/ui/useless_conversion.fixed15
-rw-r--r--src/tools/clippy/tests/ui/useless_conversion.rs15
-rw-r--r--src/tools/clippy/tests/ui/useless_conversion.stderr14
-rw-r--r--src/tools/clippy/tests/ui/while_let_loop.rs86
-rw-r--r--src/tools/clippy/tests/ui/while_let_loop.stderr122
-rw-r--r--src/tools/clippy/tests/ui/zero_sized_hashmap_values.rs21
-rw-r--r--src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr16
-rw-r--r--src/tools/clippy/triagebot.toml3
-rw-r--r--src/tools/clippy/util/gh-pages/index_template.html2
-rw-r--r--src/tools/clippy/util/gh-pages/script.js12
-rw-r--r--src/tools/compiletest/src/common.rs1
-rw-r--r--src/tools/compiletest/src/directive-list.rs2
-rw-r--r--src/tools/generate-copyright/Cargo.toml2
-rw-r--r--src/tools/generate-copyright/src/cargo_metadata.rs11
-rw-r--r--src/tools/generate-copyright/src/main.rs11
-rw-r--r--src/tools/jsondocck/src/config.rs2
-rw-r--r--src/tools/jsondocck/src/directive.rs232
-rw-r--r--src/tools/jsondocck/src/error.rs4
-rw-r--r--src/tools/jsondocck/src/main.rs251
-rw-r--r--src/tools/lint-docs/Cargo.toml1
-rw-r--r--src/tools/lint-docs/src/lib.rs11
-rw-r--r--src/tools/miri/README.md2
-rw-r--r--src/tools/miri/cargo-miri/Cargo.lock4
-rw-r--r--src/tools/miri/cargo-miri/Cargo.toml2
-rw-r--r--src/tools/miri/cargo-miri/src/phases.rs2
-rwxr-xr-xsrc/tools/miri/ci/ci.sh28
-rw-r--r--src/tools/miri/miri-script/src/commands.rs49
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/alloc/alloc_bytes.rs (renamed from src/tools/miri/src/alloc_bytes.rs)67
-rw-r--r--src/tools/miri/src/alloc/isolated_alloc.rs386
-rw-r--r--src/tools/miri/src/alloc/mod.rs5
-rw-r--r--src/tools/miri/src/alloc_addresses/mod.rs15
-rw-r--r--src/tools/miri/src/alloc_addresses/reuse_pool.rs3
-rw-r--r--src/tools/miri/src/bin/miri.rs4
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs2
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs230
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs21
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs144
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs42
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs20
-rw-r--r--src/tools/miri/src/concurrency/cpu_affinity.rs2
-rw-r--r--src/tools/miri/src/concurrency/mod.rs13
-rw-r--r--src/tools/miri/src/concurrency/thread.rs24
-rw-r--r--src/tools/miri/src/concurrency/vector_clock.rs5
-rw-r--r--src/tools/miri/src/diagnostics.rs3
-rw-r--r--src/tools/miri/src/eval.rs27
-rw-r--r--src/tools/miri/src/helpers.rs48
-rw-r--r--src/tools/miri/src/intrinsics/atomic.rs148
-rw-r--r--src/tools/miri/src/intrinsics/mod.rs70
-rw-r--r--src/tools/miri/src/intrinsics/simd.rs2
-rw-r--r--src/tools/miri/src/lib.rs19
-rw-r--r--src/tools/miri/src/machine.rs60
-rw-r--r--src/tools/miri/src/range_map.rs22
-rw-r--r--src/tools/miri/src/shims/aarch64.rs7
-rw-r--r--src/tools/miri/src/shims/alloc.rs5
-rw-r--r--src/tools/miri/src/shims/backtrace.rs30
-rw-r--r--src/tools/miri/src/shims/files.rs24
-rw-r--r--src/tools/miri/src/shims/foreign_items.rs94
-rw-r--r--src/tools/miri/src/shims/io_error.rs24
-rw-r--r--src/tools/miri/src/shims/native_lib.rs17
-rw-r--r--src/tools/miri/src/shims/panic.rs12
-rw-r--r--src/tools/miri/src/shims/unix/android/foreign_items.rs13
-rw-r--r--src/tools/miri/src/shims/unix/android/thread.rs10
-rw-r--r--src/tools/miri/src/shims/unix/env.rs7
-rw-r--r--src/tools/miri/src/shims/unix/fd.rs21
-rw-r--r--src/tools/miri/src/shims/unix/foreign_items.rs124
-rw-r--r--src/tools/miri/src/shims/unix/freebsd/foreign_items.rs87
-rw-r--r--src/tools/miri/src/shims/unix/freebsd/sync.rs8
-rw-r--r--src/tools/miri/src/shims/unix/fs.rs17
-rw-r--r--src/tools/miri/src/shims/unix/linux/foreign_items.rs42
-rw-r--r--src/tools/miri/src/shims/unix/linux_like/epoll.rs6
-rw-r--r--src/tools/miri/src/shims/unix/linux_like/syscall.rs5
-rw-r--r--src/tools/miri/src/shims/unix/macos/foreign_items.rs67
-rw-r--r--src/tools/miri/src/shims/unix/solarish/foreign_items.rs33
-rw-r--r--src/tools/miri/src/shims/unix/thread.rs6
-rw-r--r--src/tools/miri/src/shims/unix/unnamed_socket.rs96
-rw-r--r--src/tools/miri/src/shims/wasi/foreign_items.rs7
-rw-r--r--src/tools/miri/src/shims/windows/env.rs6
-rw-r--r--src/tools/miri/src/shims/windows/foreign_items.rs144
-rw-r--r--src/tools/miri/src/shims/windows/fs.rs264
-rw-r--r--src/tools/miri/src/shims/windows/handle.rs110
-rw-r--r--src/tools/miri/src/shims/x86/aesni.rs13
-rw-r--r--src/tools/miri/src/shims/x86/avx.rs41
-rw-r--r--src/tools/miri/src/shims/x86/avx2.rs43
-rw-r--r--src/tools/miri/src/shims/x86/bmi.rs5
-rw-r--r--src/tools/miri/src/shims/x86/gfni.rs13
-rw-r--r--src/tools/miri/src/shims/x86/mod.rs18
-rw-r--r--src/tools/miri/src/shims/x86/sha.rs11
-rw-r--r--src/tools/miri/src/shims/x86/sse.rs21
-rw-r--r--src/tools/miri/src/shims/x86/sse2.rs31
-rw-r--r--src/tools/miri/src/shims/x86/sse3.rs7
-rw-r--r--src/tools/miri/src/shims/x86/sse41.rs23
-rw-r--r--src/tools/miri/src/shims/x86/sse42.rs16
-rw-r--r--src/tools/miri/src/shims/x86/ssse3.rs15
-rw-r--r--src/tools/miri/test_dependencies/Cargo.toml9
-rw-r--r--src/tools/miri/tests/fail-dep/libc/fcntl_fsetfl_while_blocking.rs20
-rw-r--r--src/tools/miri/tests/fail-dep/libc/fcntl_fsetfl_while_blocking.stderr19
-rw-r--r--src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.rs9
-rw-r--r--src/tools/miri/tests/fail-dep/libc/unsupported_incomplete_function.stderr3
-rw-r--r--src/tools/miri/tests/fail/alloc/no_global_allocator.stderr3
-rw-r--r--src/tools/miri/tests/fail/async-shared-mutable.rs25
-rw-r--r--src/tools/miri/tests/fail/async-shared-mutable.stack.stderr43
-rw-r--r--src/tools/miri/tests/fail/async-shared-mutable.tree.stderr47
-rw-r--r--src/tools/miri/tests/fail/concurrency/read_only_atomic_load_large.rs1
-rw-r--r--src/tools/miri/tests/fail/const-ub-checks.rs2
-rw-r--r--src/tools/miri/tests/fail/const-ub-checks.stderr4
-rw-r--r--src/tools/miri/tests/fail/data_race/stack_pop_race.rs5
-rw-r--r--src/tools/miri/tests/fail/data_race/stack_pop_race.stderr11
-rw-r--r--src/tools/miri/tests/fail/erroneous_const.rs2
-rw-r--r--src/tools/miri/tests/fail/erroneous_const.stderr4
-rw-r--r--src/tools/miri/tests/fail/erroneous_const2.rs2
-rw-r--r--src/tools/miri/tests/fail/erroneous_const2.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/copy_overlapping.rs9
-rw-r--r--src/tools/miri/tests/fail/intrinsics/copy_overlapping.stderr4
-rw-r--r--src/tools/miri/tests/fail/intrinsics/copy_unaligned.rs9
-rw-r--r--src/tools/miri/tests/fail/intrinsics/copy_unaligned.stderr4
-rw-r--r--src/tools/miri/tests/fail/panic/bad_unwind.stderr4
-rw-r--r--src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr5
-rw-r--r--src/tools/miri/tests/fail/shims/isolated_stdin.rs12
-rw-r--r--src/tools/miri/tests/fail/shims/isolated_stdin.stderr (renamed from src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.stderr)11
-rw-r--r--src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr8
-rw-r--r--src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr4
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/cell-inside-struct.rs33
-rw-r--r--src/tools/miri/tests/fail/tree_borrows/cell-inside-struct.stderr26
-rw-r--r--src/tools/miri/tests/fail/unaligned_pointers/atomic_unaligned.rs3
-rw-r--r--src/tools/miri/tests/fail/unaligned_pointers/atomic_unaligned.stderr4
-rw-r--r--src/tools/miri/tests/fail/unsupported_foreign_function.stderr3
-rw-r--r--src/tools/miri/tests/many-seeds/reentrant-lock.rs2
-rw-r--r--src/tools/miri/tests/native-lib/fail/function_not_in_so.stderr3
-rw-r--r--src/tools/miri/tests/native-lib/fail/private_function.stderr3
-rw-r--r--src/tools/miri/tests/panic/transmute_fat2.rs2
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.rs4
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-pipe.rs67
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs33
-rw-r--r--src/tools/miri/tests/pass-dep/shims/freebsd-cpuset-affinity.rs51
-rw-r--r--src/tools/miri/tests/pass-dep/shims/windows-fs.rs97
-rw-r--r--src/tools/miri/tests/pass-dep/tokio/file-io.rs10
-rw-r--r--src/tools/miri/tests/pass/alloc-access-tracking.rs4
-rw-r--r--src/tools/miri/tests/pass/atomic.rs40
-rw-r--r--src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr8
-rw-r--r--src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr8
-rw-r--r--src/tools/miri/tests/pass/backtrace/backtrace-std.stderr8
-rw-r--r--src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs20
-rw-r--r--src/tools/miri/tests/pass/both_borrows/unsafe_pinned.rs16
-rw-r--r--src/tools/miri/tests/pass/btreemap.rs2
-rw-r--r--src/tools/miri/tests/pass/fat_ptr.rs4
-rw-r--r--src/tools/miri/tests/pass/iter_macro.rs22
-rw-r--r--src/tools/miri/tests/pass/shims/fs.rs12
-rw-r--r--src/tools/miri/tests/pass/shims/io.rs8
-rw-r--r--src/tools/miri/tests/pass/shims/io.stderr1
-rw-r--r--src/tools/miri/tests/pass/shims/io.stdout1
-rw-r--r--src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs2
-rw-r--r--src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs2
-rw-r--r--src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs1
-rw-r--r--src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs1
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.stderr4
-rw-r--r--src/tools/miri/tests/pass/tree_borrows/cell-lazy-write-to-surrounding.rs22
-rw-r--r--src/tools/opt-dist/src/training.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs14
-rw-r--r--src/tools/rustbook/Cargo.lock63
-rw-r--r--src/tools/rustbook/Cargo.toml2
m---------src/tools/rustc-perf0
-rw-r--r--src/tools/rustfmt/src/items.rs4
-rw-r--r--src/tools/rustfmt/src/lib.rs1
-rw-r--r--src/tools/rustfmt/src/modules.rs2
-rw-r--r--src/tools/rustfmt/src/parse/macros/asm.rs2
-rw-r--r--src/tools/rustfmt/src/parse/macros/cfg_if.rs2
-rw-r--r--src/tools/rustfmt/src/visitor.rs2
-rw-r--r--src/tools/test-float-parse/Cargo.lock75
-rw-r--r--src/tools/test-float-parse/Cargo.toml22
-rw-r--r--src/tools/test-float-parse/README.md55
-rw-r--r--src/tools/test-float-parse/src/gen_/exhaustive.rs42
-rw-r--r--src/tools/test-float-parse/src/gen_/exponents.rs95
-rw-r--r--src/tools/test-float-parse/src/gen_/fuzz.rs87
-rw-r--r--src/tools/test-float-parse/src/gen_/integers.rs104
-rw-r--r--src/tools/test-float-parse/src/gen_/long_fractions.rs58
-rw-r--r--src/tools/test-float-parse/src/gen_/many_digits.rs84
-rw-r--r--src/tools/test-float-parse/src/gen_/sparse.rs99
-rw-r--r--src/tools/test-float-parse/src/gen_/spot_checks.rs101
-rw-r--r--src/tools/test-float-parse/src/gen_/subnorm.rs108
-rw-r--r--src/tools/test-float-parse/src/lib.rs419
-rw-r--r--src/tools/test-float-parse/src/main.rs129
-rw-r--r--src/tools/test-float-parse/src/traits.rs206
-rw-r--r--src/tools/test-float-parse/src/ui.rs168
-rw-r--r--src/tools/test-float-parse/src/validate.rs394
-rw-r--r--src/tools/test-float-parse/src/validate/tests.rs149
-rw-r--r--src/tools/tidy/Cargo.toml2
-rw-r--r--src/tools/tidy/src/deps.rs4
-rw-r--r--src/tools/tidy/src/features.rs17
-rw-r--r--src/tools/tidy/src/issues.txt1
-rw-r--r--src/tools/tidy/src/lib.rs1
-rw-r--r--src/tools/tidy/src/main.rs2
-rw-r--r--src/tools/tidy/src/pal.rs1
-rw-r--r--src/tools/tidy/src/rustdoc_js.rs99
-rw-r--r--src/tools/tidy/src/walk.rs1
-rw-r--r--src/tools/unstable-book-gen/src/SUMMARY.md2
-rw-r--r--src/tools/unstable-book-gen/src/main.rs28
-rw-r--r--src/tools/unstable-book-gen/src/stub-issue.md2
-rw-r--r--src/tools/unstable-book-gen/src/stub-no-issue.md2
582 files changed, 13901 insertions, 6726 deletions
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index 741d7e3fa16..4c53ea42793 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -40,7 +40,9 @@ static HOSTS: &[&str] = &[
     "powerpc64le-unknown-linux-musl",
     "riscv64gc-unknown-linux-gnu",
     "s390x-unknown-linux-gnu",
+    "sparcv9-sun-solaris",
     "x86_64-apple-darwin",
+    "x86_64-pc-solaris",
     "x86_64-pc-windows-gnu",
     "x86_64-pc-windows-msvc",
     "x86_64-unknown-freebsd",
@@ -111,6 +113,8 @@ static TARGETS: &[&str] = &[
     "i686-unknown-uefi",
     "loongarch64-unknown-linux-gnu",
     "loongarch64-unknown-linux-musl",
+    "loongarch32-unknown-none",
+    "loongarch32-unknown-none-softfloat",
     "loongarch64-unknown-none",
     "loongarch64-unknown-none-softfloat",
     "m68k-unknown-linux-gnu",
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 47c911e9e6f6461f90ce19142031fe16876a3b9
+Subproject 64a12460708cf146e16cc61f28aba5dc2463bbb
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 28147dfbea3..3a98217f625 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6440,6 +6440,7 @@ Released 2018-09-13
 [`used_underscore_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#used_underscore_items
 [`useless_asref`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_asref
 [`useless_attribute`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_attribute
+[`useless_concat`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_concat
 [`useless_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion
 [`useless_format`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_format
 [`useless_let_if_seq`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_let_if_seq
diff --git a/src/tools/clippy/CONTRIBUTING.md b/src/tools/clippy/CONTRIBUTING.md
index 45ba2f078be..72ab08792d3 100644
--- a/src/tools/clippy/CONTRIBUTING.md
+++ b/src/tools/clippy/CONTRIBUTING.md
@@ -51,7 +51,7 @@ Clippy team directly by mentioning them in the issue or over on [Zulip]. All
 currently active team members can be found
 [here](https://github.com/rust-lang/rust-clippy/blob/master/triagebot.toml#L18)
 
-Some issues are easier than others. The [`good-first-issue`] label can be used to find the easy
+Some issues are easier than others. The [`good first issue`] label can be used to find the easy
 issues. You can use `@rustbot claim` to assign the issue to yourself.
 
 There are also some abandoned PRs, marked with [`S-inactive-closed`].
@@ -70,7 +70,7 @@ To figure out how this syntax structure is encoded in the AST, it is recommended
 Usually the lint will end up to be a nested series of matches and ifs, [like so][deep-nesting].
 But we can make it nest-less by using [let chains], [like this][nest-less].
 
-[`E-medium`] issues are generally pretty easy too, though it's recommended you work on an [`good-first-issue`]
+[`E-medium`] issues are generally pretty easy too, though it's recommended you work on an [`good first issue`]
 first. Sometimes they are only somewhat involved code wise, but not difficult per-se.
 Note that [`E-medium`] issues may require some knowledge of Clippy internals or some
 debugging to find the actual problem behind the issue.
@@ -79,7 +79,7 @@ debugging to find the actual problem behind the issue.
 lot of methods that are useful, though one of the most useful would be `expr_ty` (gives the type of
 an AST expression).
 
-[`good-first-issue`]: https://github.com/rust-lang/rust-clippy/labels/good-first-issue
+[`good first issue`]: https://github.com/rust-lang/rust-clippy/labels/good%20first%20issue
 [`S-inactive-closed`]: https://github.com/rust-lang/rust-clippy/pulls?q=is%3Aclosed+label%3AS-inactive-closed
 [`T-AST`]: https://github.com/rust-lang/rust-clippy/labels/T-AST
 [`T-middle`]: https://github.com/rust-lang/rust-clippy/labels/T-middle
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index c7c06afb612..3a76c61489e 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -1,8 +1,6 @@
 [package]
 name = "clippy"
-# begin autogenerated version
 version = "0.1.89"
-# end autogenerated version
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
@@ -44,7 +42,7 @@ walkdir = "2.3"
 filetime = "0.2.9"
 itertools = "0.12"
 pulldown-cmark = { version = "0.11", default-features = false, features = ["html"] }
-askama = { version = "0.13", default-features = false, features = ["alloc", "config", "derive"] }
+askama = { version = "0.14", default-features = false, features = ["alloc", "config", "derive"] }
 
 # UI test dependencies
 if_chain = "1.0"
diff --git a/src/tools/clippy/book/src/development/basics.md b/src/tools/clippy/book/src/development/basics.md
index cdbbe76bdb0..fc405249bcf 100644
--- a/src/tools/clippy/book/src/development/basics.md
+++ b/src/tools/clippy/book/src/development/basics.md
@@ -151,7 +151,7 @@ toolchain called `clippy` by default, see `cargo dev setup toolchain --help`
 for other options.
 
 ```terminal
-cargo dev setup toolcahin
+cargo dev setup toolchain
 ```
 
 Now you may run `cargo +clippy clippy` in any project using the new toolchain.
diff --git a/src/tools/clippy/book/src/development/the_team.md b/src/tools/clippy/book/src/development/the_team.md
index da5d084ed97..d2212323186 100644
--- a/src/tools/clippy/book/src/development/the_team.md
+++ b/src/tools/clippy/book/src/development/the_team.md
@@ -33,7 +33,7 @@ this group to help with triaging, which can include:
 
 1. **Labeling issues**
 
-    For the `good-first-issue` label, it can still be good to use `@rustbot` to
+    For the `good first issue` label, it can still be good to use `@rustbot` to
     subscribe to the issue and help interested parties, if they post questions
     in the comments. 
 
diff --git a/src/tools/clippy/book/src/development/trait_checking.md b/src/tools/clippy/book/src/development/trait_checking.md
index cc4eb966f59..6d01496eebe 100644
--- a/src/tools/clippy/book/src/development/trait_checking.md
+++ b/src/tools/clippy/book/src/development/trait_checking.md
@@ -17,7 +17,7 @@ providing the `LateContext` (`cx`), our expression at hand, and
 the symbol of the trait in question:
 
 ```rust
-use clippy_utils::is_trait_method;
+use clippy_utils::ty::implements_trait;
 use rustc_hir::Expr;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_span::symbol::sym;
@@ -25,7 +25,7 @@ use rustc_span::symbol::sym;
 impl LateLintPass<'_> for CheckIteratorTraitLint {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
 		let implements_iterator = cx.tcx.get_diagnostic_item(sym::Iterator).map_or(false, |id| {
-    		implements_trait(cx, cx.typeck_results().expr_ty(arg), id, &[])
+    		implements_trait(cx, cx.typeck_results().expr_ty(expr), id, &[])
 		});
 		if implements_iterator {
 			// [...]
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index 0db4182dbcd..7c850b4b023 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -836,6 +836,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio
 * [`manual_repeat_n`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_repeat_n)
 * [`manual_retain`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain)
 * [`manual_slice_fill`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_slice_fill)
+* [`manual_slice_size_calculation`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_slice_size_calculation)
 * [`manual_split_once`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once)
 * [`manual_str_repeat`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat)
 * [`manual_strip`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip)
@@ -1025,7 +1026,7 @@ The order of associated items in traits.
 The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by
 reference.
 
-**Default Value:** `target_pointer_width * 2`
+**Default Value:** `target_pointer_width`
 
 ---
 **Affected lints:**
diff --git a/src/tools/clippy/clippy_config/Cargo.toml b/src/tools/clippy/clippy_config/Cargo.toml
index 1134b0e97af..0606245f990 100644
--- a/src/tools/clippy/clippy_config/Cargo.toml
+++ b/src/tools/clippy/clippy_config/Cargo.toml
@@ -1,8 +1,6 @@
 [package]
 name = "clippy_config"
-# begin autogenerated version
 version = "0.1.89"
-# end autogenerated version
 edition = "2024"
 publish = false
 
diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs
index ad0aea39d41..87158cec42b 100644
--- a/src/tools/clippy/clippy_config/src/conf.rs
+++ b/src/tools/clippy/clippy_config/src/conf.rs
@@ -739,6 +739,7 @@ define_Conf! {
         manual_repeat_n,
         manual_retain,
         manual_slice_fill,
+        manual_slice_size_calculation,
         manual_split_once,
         manual_str_repeat,
         manual_strip,
@@ -827,7 +828,7 @@ define_Conf! {
     trait_assoc_item_kinds_order: SourceItemOrderingTraitAssocItemKinds = DEFAULT_TRAIT_ASSOC_ITEM_KINDS_ORDER.into(),
     /// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by
     /// reference.
-    #[default_text = "target_pointer_width * 2"]
+    #[default_text = "target_pointer_width"]
     #[lints(trivially_copy_pass_by_ref)]
     trivial_copy_size_limit: Option<u64> = None,
     /// The maximum complexity a type can have
diff --git a/src/tools/clippy/clippy_dev/Cargo.toml b/src/tools/clippy/clippy_dev/Cargo.toml
index 47b7b375861..10c08dba50b 100644
--- a/src/tools/clippy/clippy_dev/Cargo.toml
+++ b/src/tools/clippy/clippy_dev/Cargo.toml
@@ -5,13 +5,11 @@ version = "0.0.1"
 edition = "2024"
 
 [dependencies]
-aho-corasick = "1.0"
 chrono = { version = "0.4.38", default-features = false, features = ["clock"] }
 clap = { version = "4.4", features = ["derive"] }
 indoc = "1.0"
 itertools = "0.12"
 opener = "0.7"
-shell-escape = "0.1"
 walkdir = "2.3"
 
 [package.metadata.rust-analyzer]
diff --git a/src/tools/clippy/clippy_dev/src/deprecate_lint.rs b/src/tools/clippy/clippy_dev/src/deprecate_lint.rs
index bf0e7771046..3bdc5b27723 100644
--- a/src/tools/clippy/clippy_dev/src/deprecate_lint.rs
+++ b/src/tools/clippy/clippy_dev/src/deprecate_lint.rs
@@ -1,6 +1,4 @@
-use crate::update_lints::{
-    DeprecatedLint, DeprecatedLints, Lint, find_lint_decls, generate_lint_files, read_deprecated_lints,
-};
+use crate::update_lints::{DeprecatedLint, Lint, find_lint_decls, generate_lint_files, read_deprecated_lints};
 use crate::utils::{UpdateMode, Version};
 use std::ffi::OsStr;
 use std::path::{Path, PathBuf};
@@ -16,28 +14,34 @@ use std::{fs, io};
 ///
 /// If a file path could not read from or written to
 pub fn deprecate(clippy_version: Version, name: &str, reason: &str) {
-    let prefixed_name = if name.starts_with("clippy::") {
-        name.to_owned()
-    } else {
-        format!("clippy::{name}")
-    };
-    let stripped_name = &prefixed_name[8..];
+    if let Some((prefix, _)) = name.split_once("::") {
+        panic!("`{name}` should not contain the `{prefix}` prefix");
+    }
 
     let mut lints = find_lint_decls();
-    let DeprecatedLints {
-        renamed: renamed_lints,
-        deprecated: mut deprecated_lints,
-        file: mut deprecated_file,
-        contents: mut deprecated_contents,
-        deprecated_end,
-        ..
-    } = read_deprecated_lints();
-
-    let Some(lint) = lints.iter().find(|l| l.name == stripped_name) else {
+    let (mut deprecated_lints, renamed_lints) = read_deprecated_lints();
+
+    let Some(lint) = lints.iter().find(|l| l.name == name) else {
         eprintln!("error: failed to find lint `{name}`");
         return;
     };
 
+    let prefixed_name = String::from_iter(["clippy::", name]);
+    match deprecated_lints.binary_search_by(|x| x.name.cmp(&prefixed_name)) {
+        Ok(_) => {
+            println!("`{name}` is already deprecated");
+            return;
+        },
+        Err(idx) => deprecated_lints.insert(
+            idx,
+            DeprecatedLint {
+                name: prefixed_name,
+                reason: reason.into(),
+                version: clippy_version.rust_display().to_string(),
+            },
+        ),
+    }
+
     let mod_path = {
         let mut mod_path = PathBuf::from(format!("clippy_lints/src/{}", lint.module));
         if mod_path.is_dir() {
@@ -48,24 +52,7 @@ pub fn deprecate(clippy_version: Version, name: &str, reason: &str) {
         mod_path
     };
 
-    if remove_lint_declaration(stripped_name, &mod_path, &mut lints).unwrap_or(false) {
-        deprecated_contents.insert_str(
-            deprecated_end as usize,
-            &format!(
-                "    #[clippy::version = \"{}\"]\n    (\"{}\", \"{}\"),\n",
-                clippy_version.rust_display(),
-                prefixed_name,
-                reason,
-            ),
-        );
-        deprecated_file.replace_contents(deprecated_contents.as_bytes());
-        drop(deprecated_file);
-
-        deprecated_lints.push(DeprecatedLint {
-            name: prefixed_name,
-            reason: reason.into(),
-        });
-
+    if remove_lint_declaration(name, &mod_path, &mut lints).unwrap_or(false) {
         generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints);
         println!("info: `{name}` has successfully been deprecated");
         println!("note: you must run `cargo uitest` to update the test results");
diff --git a/src/tools/clippy/clippy_dev/src/fmt.rs b/src/tools/clippy/clippy_dev/src/fmt.rs
index b4c13213f55..c1b6b370706 100644
--- a/src/tools/clippy/clippy_dev/src/fmt.rs
+++ b/src/tools/clippy/clippy_dev/src/fmt.rs
@@ -1,19 +1,18 @@
+use crate::utils::{
+    ErrAction, FileUpdater, UpdateMode, UpdateStatus, expect_action, run_with_output, split_args_for_threads,
+    walk_dir_no_dot_or_target,
+};
 use itertools::Itertools;
 use rustc_lexer::{TokenKind, tokenize};
-use shell_escape::escape;
-use std::ffi::{OsStr, OsString};
+use std::fmt::Write;
+use std::fs;
+use std::io::{self, Read};
 use std::ops::ControlFlow;
-use std::path::{Path, PathBuf};
+use std::path::PathBuf;
 use std::process::{self, Command, Stdio};
-use std::{fs, io};
-use walkdir::WalkDir;
 
 pub enum Error {
-    CommandFailed(String, String),
     Io(io::Error),
-    RustfmtNotInstalled,
-    WalkDir(walkdir::Error),
-    IntellijSetupActive,
     Parse(PathBuf, usize, String),
     CheckFailed,
 }
@@ -24,37 +23,15 @@ impl From<io::Error> for Error {
     }
 }
 
-impl From<walkdir::Error> for Error {
-    fn from(error: walkdir::Error) -> Self {
-        Self::WalkDir(error)
-    }
-}
-
 impl Error {
     fn display(&self) {
         match self {
             Self::CheckFailed => {
                 eprintln!("Formatting check failed!\nRun `cargo dev fmt` to update.");
             },
-            Self::CommandFailed(command, stderr) => {
-                eprintln!("error: command `{command}` failed!\nstderr: {stderr}");
-            },
             Self::Io(err) => {
                 eprintln!("error: {err}");
             },
-            Self::RustfmtNotInstalled => {
-                eprintln!("error: rustfmt nightly is not installed.");
-            },
-            Self::WalkDir(err) => {
-                eprintln!("error: {err}");
-            },
-            Self::IntellijSetupActive => {
-                eprintln!(
-                    "error: a local rustc repo is enabled as path dependency via `cargo dev setup intellij`.\n\
-                    Not formatting because that would format the local repo as well!\n\
-                    Please revert the changes to `Cargo.toml`s with `cargo dev remove intellij`."
-                );
-            },
             Self::Parse(path, line, msg) => {
                 eprintln!("error parsing `{}:{line}`: {msg}", path.display());
             },
@@ -62,12 +39,6 @@ impl Error {
     }
 }
 
-struct FmtContext {
-    check: bool,
-    verbose: bool,
-    rustfmt_path: String,
-}
-
 struct ClippyConf<'a> {
     name: &'a str,
     attrs: &'a str,
@@ -257,155 +228,108 @@ fn fmt_conf(check: bool) -> Result<(), Error> {
     Ok(())
 }
 
-fn run_rustfmt(context: &FmtContext) -> Result<(), Error> {
-    // if we added a local rustc repo as path dependency to clippy for rust analyzer, we do NOT want to
-    // format because rustfmt would also format the entire rustc repo as it is a local
-    // dependency
-    if fs::read_to_string("Cargo.toml")
-        .expect("Failed to read clippy Cargo.toml")
-        .contains("[target.'cfg(NOT_A_PLATFORM)'.dependencies]")
-    {
-        return Err(Error::IntellijSetupActive);
-    }
-
-    check_for_rustfmt(context)?;
-
-    cargo_fmt(context, ".".as_ref())?;
-    cargo_fmt(context, "clippy_dev".as_ref())?;
-    cargo_fmt(context, "rustc_tools_util".as_ref())?;
-    cargo_fmt(context, "lintcheck".as_ref())?;
-
-    let chunks = WalkDir::new("tests")
-        .into_iter()
-        .filter_map(|entry| {
-            let entry = entry.expect("failed to find tests");
-            let path = entry.path();
-            if path.extension() != Some("rs".as_ref())
-                || path
-                    .components()
-                    .nth_back(1)
-                    .is_some_and(|c| c.as_os_str() == "syntax-error-recovery")
-                || entry.file_name() == "ice-3891.rs"
-            {
-                None
+/// Format the symbols list
+fn fmt_syms(update_mode: UpdateMode) {
+    FileUpdater::default().update_file_checked(
+        "cargo dev fmt",
+        update_mode,
+        "clippy_utils/src/sym.rs",
+        &mut |_, text: &str, new_text: &mut String| {
+            let (pre, conf) = text.split_once("generate! {\n").expect("can't find generate! call");
+            let (conf, post) = conf.split_once("\n}\n").expect("can't find end of generate! call");
+            let mut lines = conf
+                .lines()
+                .map(|line| {
+                    let line = line.trim();
+                    line.strip_suffix(',').unwrap_or(line).trim_end()
+                })
+                .collect::<Vec<_>>();
+            lines.sort_unstable();
+            write!(
+                new_text,
+                "{pre}generate! {{\n    {},\n}}\n{post}",
+                lines.join(",\n    "),
+            )
+            .unwrap();
+            if text == new_text {
+                UpdateStatus::Unchanged
             } else {
-                Some(entry.into_path().into_os_string())
+                UpdateStatus::Changed
             }
-        })
-        .chunks(250);
-
-    for chunk in &chunks {
-        rustfmt(context, chunk)?;
-    }
-    Ok(())
+        },
+    );
 }
 
-// the "main" function of cargo dev fmt
-pub fn run(check: bool, verbose: bool) {
-    let output = Command::new("rustup")
-        .args(["which", "rustfmt"])
-        .stderr(Stdio::inherit())
-        .output()
-        .expect("error running `rustup which rustfmt`");
-    if !output.status.success() {
-        eprintln!("`rustup which rustfmt` did not execute successfully");
-        process::exit(1);
-    }
-    let mut rustfmt_path = String::from_utf8(output.stdout).expect("invalid rustfmt path");
+fn run_rustfmt(update_mode: UpdateMode) {
+    let mut rustfmt_path = String::from_utf8(run_with_output(
+        "rustup which rustfmt",
+        Command::new("rustup").args(["which", "rustfmt"]),
+    ))
+    .expect("invalid rustfmt path");
     rustfmt_path.truncate(rustfmt_path.trim_end().len());
 
-    let context = FmtContext {
-        check,
-        verbose,
-        rustfmt_path,
-    };
-    if let Err(e) = run_rustfmt(&context).and_then(|()| fmt_conf(check)) {
-        e.display();
-        process::exit(1);
-    }
-}
-
-fn format_command(program: impl AsRef<OsStr>, dir: impl AsRef<Path>, args: &[impl AsRef<OsStr>]) -> String {
-    let arg_display: Vec<_> = args.iter().map(|a| escape(a.as_ref().to_string_lossy())).collect();
-
-    format!(
-        "cd {} && {} {}",
-        escape(dir.as_ref().to_string_lossy()),
-        escape(program.as_ref().to_string_lossy()),
-        arg_display.join(" ")
-    )
-}
-
-fn exec_fmt_command(
-    context: &FmtContext,
-    program: impl AsRef<OsStr>,
-    dir: impl AsRef<Path>,
-    args: &[impl AsRef<OsStr>],
-) -> Result<(), Error> {
-    if context.verbose {
-        println!("{}", format_command(&program, &dir, args));
-    }
-
-    let output = Command::new(&program)
-        .env("RUSTFMT", &context.rustfmt_path)
-        .current_dir(&dir)
-        .args(args.iter())
-        .output()
-        .unwrap();
-    let success = output.status.success();
-
-    match (context.check, success) {
-        (_, true) => Ok(()),
-        (true, false) => Err(Error::CheckFailed),
-        (false, false) => {
-            let stderr = std::str::from_utf8(&output.stderr).unwrap_or("");
-            Err(Error::CommandFailed(
-                format_command(&program, &dir, args),
-                String::from(stderr),
-            ))
+    let args: Vec<_> = walk_dir_no_dot_or_target()
+        .filter_map(|e| {
+            let e = expect_action(e, ErrAction::Read, ".");
+            e.path()
+                .as_os_str()
+                .as_encoded_bytes()
+                .ends_with(b".rs")
+                .then(|| e.into_path().into_os_string())
+        })
+        .collect();
+
+    let mut children: Vec<_> = split_args_for_threads(
+        32,
+        || {
+            let mut cmd = Command::new(&rustfmt_path);
+            if update_mode.is_check() {
+                cmd.arg("--check");
+            }
+            cmd.stdout(Stdio::null())
+                .stdin(Stdio::null())
+                .stderr(Stdio::piped())
+                .args(["--unstable-features", "--skip-children"]);
+            cmd
         },
+        args.iter(),
+    )
+    .map(|mut cmd| expect_action(cmd.spawn(), ErrAction::Run, "rustfmt"))
+    .collect();
+
+    for child in &mut children {
+        let status = expect_action(child.wait(), ErrAction::Run, "rustfmt");
+        match (update_mode, status.exit_ok()) {
+            (UpdateMode::Check | UpdateMode::Change, Ok(())) => {},
+            (UpdateMode::Check, Err(_)) => {
+                let mut s = String::new();
+                if let Some(mut stderr) = child.stderr.take()
+                    && stderr.read_to_string(&mut s).is_ok()
+                {
+                    eprintln!("{s}");
+                }
+                eprintln!("Formatting check failed!\nRun `cargo dev fmt` to update.");
+                process::exit(1);
+            },
+            (UpdateMode::Change, e) => {
+                let mut s = String::new();
+                if let Some(mut stderr) = child.stderr.take()
+                    && stderr.read_to_string(&mut s).is_ok()
+                {
+                    eprintln!("{s}");
+                }
+                expect_action(e, ErrAction::Run, "rustfmt");
+            },
+        }
     }
 }
 
-fn cargo_fmt(context: &FmtContext, path: &Path) -> Result<(), Error> {
-    let mut args = vec!["fmt", "--all"];
-    if context.check {
-        args.push("--check");
-    }
-    exec_fmt_command(context, "cargo", path, &args)
-}
-
-fn check_for_rustfmt(context: &FmtContext) -> Result<(), Error> {
-    let program = "rustfmt";
-    let dir = std::env::current_dir()?;
-    let args = &["--version"];
-
-    if context.verbose {
-        println!("{}", format_command(program, &dir, args));
-    }
-
-    let output = Command::new(program).current_dir(&dir).args(args.iter()).output()?;
-
-    if output.status.success() {
-        Ok(())
-    } else if std::str::from_utf8(&output.stderr)
-        .unwrap_or("")
-        .starts_with("error: 'rustfmt' is not installed")
-    {
-        Err(Error::RustfmtNotInstalled)
-    } else {
-        Err(Error::CommandFailed(
-            format_command(program, &dir, args),
-            std::str::from_utf8(&output.stderr).unwrap_or("").to_string(),
-        ))
-    }
-}
-
-fn rustfmt(context: &FmtContext, paths: impl Iterator<Item = OsString>) -> Result<(), Error> {
-    let mut args = Vec::new();
-    if context.check {
-        args.push(OsString::from("--check"));
+// the "main" function of cargo dev fmt
+pub fn run(update_mode: UpdateMode) {
+    run_rustfmt(update_mode);
+    fmt_syms(update_mode);
+    if let Err(e) = fmt_conf(update_mode.is_check()) {
+        e.display();
+        process::exit(1);
     }
-    args.extend(paths);
-    exec_fmt_command(context, &context.rustfmt_path, std::env::current_dir()?, &args)
 }
diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs
index e237a05b253..3361443196a 100644
--- a/src/tools/clippy/clippy_dev/src/lib.rs
+++ b/src/tools/clippy/clippy_dev/src/lib.rs
@@ -1,4 +1,12 @@
-#![feature(rustc_private, if_let_guard, let_chains)]
+#![feature(
+    rustc_private,
+    exit_status_error,
+    if_let_guard,
+    let_chains,
+    os_str_slice,
+    os_string_truncate,
+    slice_split_once
+)]
 #![warn(
     trivial_casts,
     trivial_numeric_casts,
diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs
index 5dce0be742b..26aa269fb63 100644
--- a/src/tools/clippy/clippy_dev/src/main.rs
+++ b/src/tools/clippy/clippy_dev/src/main.rs
@@ -26,7 +26,7 @@ fn main() {
             allow_staged,
             allow_no_vcs,
         } => dogfood::dogfood(fix, allow_dirty, allow_staged, allow_no_vcs),
-        DevCommand::Fmt { check, verbose } => fmt::run(check, verbose),
+        DevCommand::Fmt { check } => fmt::run(utils::UpdateMode::from_check(check)),
         DevCommand::UpdateLints { check } => update_lints::update(utils::UpdateMode::from_check(check)),
         DevCommand::NewLint {
             pass,
@@ -125,9 +125,6 @@ enum DevCommand {
         #[arg(long)]
         /// Use the rustfmt --check option
         check: bool,
-        #[arg(short, long)]
-        /// Echo commands run
-        verbose: bool,
     },
     #[command(name = "update_lints")]
     /// Updates lint registration and information from the source code
diff --git a/src/tools/clippy/clippy_dev/src/release.rs b/src/tools/clippy/clippy_dev/src/release.rs
index d3b1a7ff320..62c1bee8185 100644
--- a/src/tools/clippy/clippy_dev/src/release.rs
+++ b/src/tools/clippy/clippy_dev/src/release.rs
@@ -1,4 +1,4 @@
-use crate::utils::{FileUpdater, Version, update_text_region_fn};
+use crate::utils::{FileUpdater, UpdateStatus, Version, parse_cargo_package};
 use std::fmt::Write;
 
 static CARGO_TOML_FILES: &[&str] = &[
@@ -13,15 +13,17 @@ pub fn bump_version(mut version: Version) {
 
     let mut updater = FileUpdater::default();
     for file in CARGO_TOML_FILES {
-        updater.update_file(
-            file,
-            &mut update_text_region_fn(
-                "# begin autogenerated version\n",
-                "# end autogenerated version",
-                |dst| {
-                    writeln!(dst, "version = \"{}\"", version.toml_display()).unwrap();
-                },
-            ),
-        );
+        updater.update_file(file, &mut |_, src, dst| {
+            let package = parse_cargo_package(src);
+            if package.version_range.is_empty() {
+                dst.push_str(src);
+                UpdateStatus::Unchanged
+            } else {
+                dst.push_str(&src[..package.version_range.start]);
+                write!(dst, "\"{}\"", version.toml_display()).unwrap();
+                dst.push_str(&src[package.version_range.end..]);
+                UpdateStatus::from_changed(src.get(package.version_range.clone()) != dst.get(package.version_range))
+            }
+        });
     }
 }
diff --git a/src/tools/clippy/clippy_dev/src/rename_lint.rs b/src/tools/clippy/clippy_dev/src/rename_lint.rs
index 9e7e5d97f02..d62597428e2 100644
--- a/src/tools/clippy/clippy_dev/src/rename_lint.rs
+++ b/src/tools/clippy/clippy_dev/src/rename_lint.rs
@@ -1,11 +1,12 @@
-use crate::update_lints::{
-    DeprecatedLints, RenamedLint, find_lint_decls, gen_renamed_lints_test_fn, generate_lint_files,
-    read_deprecated_lints,
+use crate::update_lints::{RenamedLint, find_lint_decls, generate_lint_files, read_deprecated_lints};
+use crate::utils::{
+    ErrAction, FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, Version, delete_dir_if_exists,
+    delete_file_if_exists, expect_action, try_rename_dir, try_rename_file, walk_dir_no_dot_or_target,
 };
-use crate::utils::{FileUpdater, StringReplacer, UpdateMode, Version, try_rename_file};
-use std::ffi::OsStr;
+use rustc_lexer::TokenKind;
+use std::ffi::OsString;
+use std::fs;
 use std::path::Path;
-use walkdir::WalkDir;
 
 /// Runs the `rename_lint` command.
 ///
@@ -22,7 +23,7 @@ use walkdir::WalkDir;
 /// * If either lint name has a prefix
 /// * If `old_name` doesn't name an existing lint.
 /// * If `old_name` names a deprecated or renamed lint.
-#[allow(clippy::too_many_lines)]
+#[expect(clippy::too_many_lines)]
 pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: bool) {
     if let Some((prefix, _)) = old_name.split_once("::") {
         panic!("`{old_name}` should not contain the `{prefix}` prefix");
@@ -33,162 +34,362 @@ pub fn rename(clippy_version: Version, old_name: &str, new_name: &str, uplift: b
 
     let mut updater = FileUpdater::default();
     let mut lints = find_lint_decls();
-    let DeprecatedLints {
-        renamed: mut renamed_lints,
-        deprecated: deprecated_lints,
-        file: mut deprecated_file,
-        contents: mut deprecated_contents,
-        renamed_end,
-        ..
-    } = read_deprecated_lints();
-
-    let mut old_lint_index = None;
-    let mut found_new_name = false;
-    for (i, lint) in lints.iter().enumerate() {
-        if lint.name == old_name {
-            old_lint_index = Some(i);
-        } else if lint.name == new_name {
-            found_new_name = true;
+    let (deprecated_lints, mut renamed_lints) = read_deprecated_lints();
+
+    let Ok(lint_idx) = lints.binary_search_by(|x| x.name.as_str().cmp(old_name)) else {
+        panic!("could not find lint `{old_name}`");
+    };
+    let lint = &lints[lint_idx];
+
+    let old_name_prefixed = String::from_iter(["clippy::", old_name]);
+    let new_name_prefixed = if uplift {
+        new_name.to_owned()
+    } else {
+        String::from_iter(["clippy::", new_name])
+    };
+
+    for lint in &mut renamed_lints {
+        if lint.new_name == old_name_prefixed {
+            lint.new_name.clone_from(&new_name_prefixed);
         }
     }
-    let old_lint_index = old_lint_index.unwrap_or_else(|| panic!("could not find lint `{old_name}`"));
+    match renamed_lints.binary_search_by(|x| x.old_name.cmp(&old_name_prefixed)) {
+        Ok(_) => {
+            println!("`{old_name}` already has a rename registered");
+            return;
+        },
+        Err(idx) => {
+            renamed_lints.insert(
+                idx,
+                RenamedLint {
+                    old_name: old_name_prefixed,
+                    new_name: if uplift {
+                        new_name.to_owned()
+                    } else {
+                        String::from_iter(["clippy::", new_name])
+                    },
+                    version: clippy_version.rust_display().to_string(),
+                },
+            );
+        },
+    }
 
-    let lint = RenamedLint {
-        old_name: format!("clippy::{old_name}"),
-        new_name: if uplift {
-            new_name.into()
+    // Some tests are named `lint_name_suffix` which should also be renamed,
+    // but we can't do that if the renamed lint's name overlaps with another
+    // lint. e.g. renaming 'foo' to 'bar' when a lint 'foo_bar' also exists.
+    let change_prefixed_tests = lints.get(lint_idx + 1).is_none_or(|l| !l.name.starts_with(old_name));
+
+    let mut mod_edit = ModEdit::None;
+    if uplift {
+        let is_unique_mod = lints[..lint_idx].iter().any(|l| l.module == lint.module)
+            || lints[lint_idx + 1..].iter().any(|l| l.module == lint.module);
+        if is_unique_mod {
+            if delete_file_if_exists(lint.path.as_ref()) {
+                mod_edit = ModEdit::Delete;
+            }
         } else {
-            format!("clippy::{new_name}")
-        },
-    };
+            updater.update_file(&lint.path, &mut |_, src, dst| -> UpdateStatus {
+                let mut start = &src[..lint.declaration_range.start];
+                if start.ends_with("\n\n") {
+                    start = &start[..start.len() - 1];
+                }
+                let mut end = &src[lint.declaration_range.end..];
+                if end.starts_with("\n\n") {
+                    end = &end[1..];
+                }
+                dst.push_str(start);
+                dst.push_str(end);
+                UpdateStatus::Changed
+            });
+        }
+        delete_test_files(old_name, change_prefixed_tests);
+        lints.remove(lint_idx);
+    } else if lints.binary_search_by(|x| x.name.as_str().cmp(new_name)).is_err() {
+        let lint = &mut lints[lint_idx];
+        if lint.module.ends_with(old_name)
+            && lint
+                .path
+                .file_stem()
+                .is_some_and(|x| x.as_encoded_bytes() == old_name.as_bytes())
+        {
+            let mut new_path = lint.path.with_file_name(new_name).into_os_string();
+            new_path.push(".rs");
+            if try_rename_file(lint.path.as_ref(), new_path.as_ref()) {
+                mod_edit = ModEdit::Rename;
+            }
 
-    // Renamed lints and deprecated lints shouldn't have been found in the lint list, but check just in
-    // case.
-    assert!(
-        !renamed_lints.iter().any(|l| lint.old_name == l.old_name),
-        "`{old_name}` has already been renamed"
-    );
-    assert!(
-        !deprecated_lints.iter().any(|l| lint.old_name == l.name),
-        "`{old_name}` has already been deprecated"
-    );
-
-    // Update all lint level attributes. (`clippy::lint_name`)
-    let replacements = &[(&*lint.old_name, &*lint.new_name)];
-    let replacer = StringReplacer::new(replacements);
-    for file in WalkDir::new(".").into_iter().map(Result::unwrap).filter(|f| {
-        let name = f.path().file_name();
-        let ext = f.path().extension();
-        (ext == Some(OsStr::new("rs")) || ext == Some(OsStr::new("fixed")))
-            && name != Some(OsStr::new("rename.rs"))
-            && name != Some(OsStr::new("deprecated_lints.rs"))
-    }) {
-        updater.update_file(file.path(), &mut replacer.replace_ident_fn());
+            let mod_len = lint.module.len();
+            lint.module.truncate(mod_len - old_name.len());
+            lint.module.push_str(new_name);
+        }
+        rename_test_files(old_name, new_name, change_prefixed_tests);
+        new_name.clone_into(&mut lints[lint_idx].name);
+        lints.sort_by(|lhs, rhs| lhs.name.cmp(&rhs.name));
+    } else {
+        println!("Renamed `clippy::{old_name}` to `clippy::{new_name}`");
+        println!("Since `{new_name}` already exists the existing code has not been changed");
+        return;
     }
 
-    deprecated_contents.insert_str(
-        renamed_end as usize,
-        &format!(
-            "    #[clippy::version = \"{}\"]\n    (\"{}\", \"{}\"),\n",
-            clippy_version.rust_display(),
-            lint.old_name,
-            lint.new_name,
-        ),
-    );
-    deprecated_file.replace_contents(deprecated_contents.as_bytes());
-    drop(deprecated_file);
-
-    renamed_lints.push(lint);
-    renamed_lints.sort_by(|lhs, rhs| {
-        lhs.new_name
-            .starts_with("clippy::")
-            .cmp(&rhs.new_name.starts_with("clippy::"))
-            .reverse()
-            .then_with(|| lhs.old_name.cmp(&rhs.old_name))
-    });
+    let mut update_fn = file_update_fn(old_name, new_name, mod_edit);
+    for e in walk_dir_no_dot_or_target() {
+        let e = expect_action(e, ErrAction::Read, ".");
+        if e.path().as_os_str().as_encoded_bytes().ends_with(b".rs") {
+            updater.update_file(e.path(), &mut update_fn);
+        }
+    }
+    generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints);
 
     if uplift {
-        updater.update_file("tests/ui/rename.rs", &mut gen_renamed_lints_test_fn(&renamed_lints));
-        println!(
-            "`{old_name}` has be uplifted. All the code inside `clippy_lints` related to it needs to be removed manually."
-        );
-    } else if found_new_name {
-        updater.update_file("tests/ui/rename.rs", &mut gen_renamed_lints_test_fn(&renamed_lints));
-        println!(
-            "`{new_name}` is already defined. The old linting code inside `clippy_lints` needs to be updated/removed manually."
-        );
-    } else {
-        // Rename the lint struct and source files sharing a name with the lint.
-        let lint = &mut lints[old_lint_index];
-        let old_name_upper = old_name.to_uppercase();
-        let new_name_upper = new_name.to_uppercase();
-        lint.name = new_name.into();
-
-        // Rename test files. only rename `.stderr` and `.fixed` files if the new test name doesn't exist.
-        if try_rename_file(
-            Path::new(&format!("tests/ui/{old_name}.rs")),
-            Path::new(&format!("tests/ui/{new_name}.rs")),
-        ) {
-            try_rename_file(
-                Path::new(&format!("tests/ui/{old_name}.stderr")),
-                Path::new(&format!("tests/ui/{new_name}.stderr")),
-            );
-            try_rename_file(
-                Path::new(&format!("tests/ui/{old_name}.fixed")),
-                Path::new(&format!("tests/ui/{new_name}.fixed")),
-            );
+        println!("Uplifted `clippy::{old_name}` as `{new_name}`");
+        if matches!(mod_edit, ModEdit::None) {
+            println!("Only the rename has been registered, the code will need to be edited manually");
+        } else {
+            println!("All the lint's code has been deleted");
+            println!("Make sure to inspect the results as some things may have been missed");
         }
+    } else {
+        println!("Renamed `clippy::{old_name}` to `clippy::{new_name}`");
+        println!("All code referencing the old name has been updated");
+        println!("Make sure to inspect the results as some things may have been missed");
+    }
+    println!("note: `cargo uibless` still needs to be run to update the test results");
+}
+
+#[derive(Clone, Copy)]
+enum ModEdit {
+    None,
+    Delete,
+    Rename,
+}
 
-        // Try to rename the file containing the lint if the file name matches the lint's name.
-        let replacements;
-        let replacements = if lint.module == old_name
-            && try_rename_file(
-                Path::new(&format!("clippy_lints/src/{old_name}.rs")),
-                Path::new(&format!("clippy_lints/src/{new_name}.rs")),
-            ) {
-            // Edit the module name in the lint list. Note there could be multiple lints.
-            for lint in lints.iter_mut().filter(|l| l.module == old_name) {
-                lint.module = new_name.into();
+fn collect_ui_test_names(lint: &str, rename_prefixed: bool, dst: &mut Vec<(OsString, bool)>) {
+    for e in fs::read_dir("tests/ui").expect("error reading `tests/ui`") {
+        let e = e.expect("error reading `tests/ui`");
+        let name = e.file_name();
+        if let Some((name_only, _)) = name.as_encoded_bytes().split_once(|&x| x == b'.') {
+            if name_only.starts_with(lint.as_bytes()) && (rename_prefixed || name_only.len() == lint.len()) {
+                dst.push((name, true));
             }
-            replacements = [(&*old_name_upper, &*new_name_upper), (old_name, new_name)];
-            replacements.as_slice()
-        } else if !lint.module.contains("::")
-            // Catch cases like `methods/lint_name.rs` where the lint is stored in `methods/mod.rs`
-            && try_rename_file(
-                Path::new(&format!("clippy_lints/src/{}/{old_name}.rs", lint.module)),
-                Path::new(&format!("clippy_lints/src/{}/{new_name}.rs", lint.module)),
-            )
+        } else if name.as_encoded_bytes().starts_with(lint.as_bytes()) && (rename_prefixed || name.len() == lint.len())
         {
-            // Edit the module name in the lint list. Note there could be multiple lints, or none.
-            let renamed_mod = format!("{}::{old_name}", lint.module);
-            for lint in lints.iter_mut().filter(|l| l.module == renamed_mod) {
-                lint.module = format!("{}::{new_name}", lint.module);
+            dst.push((name, false));
+        }
+    }
+}
+
+fn collect_ui_toml_test_names(lint: &str, rename_prefixed: bool, dst: &mut Vec<(OsString, bool)>) {
+    if rename_prefixed {
+        for e in fs::read_dir("tests/ui-toml").expect("error reading `tests/ui-toml`") {
+            let e = e.expect("error reading `tests/ui-toml`");
+            let name = e.file_name();
+            if name.as_encoded_bytes().starts_with(lint.as_bytes()) && e.file_type().is_ok_and(|ty| ty.is_dir()) {
+                dst.push((name, false));
             }
-            replacements = [(&*old_name_upper, &*new_name_upper), (old_name, new_name)];
-            replacements.as_slice()
+        }
+    } else {
+        dst.push((lint.into(), false));
+    }
+}
+
+/// Renames all test files for the given lint.
+///
+/// If `rename_prefixed` is `true` this will also rename tests which have the lint name as a prefix.
+fn rename_test_files(old_name: &str, new_name: &str, rename_prefixed: bool) {
+    let mut tests = Vec::new();
+
+    let mut old_buf = OsString::from("tests/ui/");
+    let mut new_buf = OsString::from("tests/ui/");
+    collect_ui_test_names(old_name, rename_prefixed, &mut tests);
+    for &(ref name, is_file) in &tests {
+        old_buf.push(name);
+        new_buf.extend([new_name.as_ref(), name.slice_encoded_bytes(old_name.len()..)]);
+        if is_file {
+            try_rename_file(old_buf.as_ref(), new_buf.as_ref());
         } else {
-            replacements = [(&*old_name_upper, &*new_name_upper), ("", "")];
-            &replacements[0..1]
-        };
-
-        // Don't change `clippy_utils/src/renamed_lints.rs` here as it would try to edit the lint being
-        // renamed.
-        let replacer = StringReplacer::new(replacements);
-        for file in WalkDir::new("clippy_lints/src") {
-            let file = file.expect("error reading `clippy_lints/src`");
-            if file
-                .path()
-                .as_os_str()
-                .to_str()
-                .is_some_and(|x| x.ends_with("*.rs") && x["clippy_lints/src/".len()..] != *"deprecated_lints.rs")
-            {
-                updater.update_file(file.path(), &mut replacer.replace_ident_fn());
-            }
+            try_rename_dir(old_buf.as_ref(), new_buf.as_ref());
         }
+        old_buf.truncate("tests/ui/".len());
+        new_buf.truncate("tests/ui/".len());
+    }
 
-        generate_lint_files(UpdateMode::Change, &lints, &deprecated_lints, &renamed_lints);
-        println!("{old_name} has been successfully renamed");
+    tests.clear();
+    old_buf.truncate("tests/ui".len());
+    new_buf.truncate("tests/ui".len());
+    old_buf.push("-toml/");
+    new_buf.push("-toml/");
+    collect_ui_toml_test_names(old_name, rename_prefixed, &mut tests);
+    for (name, _) in &tests {
+        old_buf.push(name);
+        new_buf.extend([new_name.as_ref(), name.slice_encoded_bytes(old_name.len()..)]);
+        try_rename_dir(old_buf.as_ref(), new_buf.as_ref());
+        old_buf.truncate("tests/ui/".len());
+        new_buf.truncate("tests/ui/".len());
     }
+}
 
-    println!("note: `cargo uitest` still needs to be run to update the test results");
+fn delete_test_files(lint: &str, rename_prefixed: bool) {
+    let mut tests = Vec::new();
+
+    let mut buf = OsString::from("tests/ui/");
+    collect_ui_test_names(lint, rename_prefixed, &mut tests);
+    for &(ref name, is_file) in &tests {
+        buf.push(name);
+        if is_file {
+            delete_file_if_exists(buf.as_ref());
+        } else {
+            delete_dir_if_exists(buf.as_ref());
+        }
+        buf.truncate("tests/ui/".len());
+    }
+
+    buf.truncate("tests/ui".len());
+    buf.push("-toml/");
+
+    tests.clear();
+    collect_ui_toml_test_names(lint, rename_prefixed, &mut tests);
+    for (name, _) in &tests {
+        buf.push(name);
+        delete_dir_if_exists(buf.as_ref());
+        buf.truncate("tests/ui/".len());
+    }
+}
+
+fn snake_to_pascal(s: &str) -> String {
+    let mut dst = Vec::with_capacity(s.len());
+    let mut iter = s.bytes();
+    || -> Option<()> {
+        dst.push(iter.next()?.to_ascii_uppercase());
+        while let Some(c) = iter.next() {
+            if c == b'_' {
+                dst.push(iter.next()?.to_ascii_uppercase());
+            } else {
+                dst.push(c);
+            }
+        }
+        Some(())
+    }();
+    String::from_utf8(dst).unwrap()
+}
+
+#[expect(clippy::too_many_lines)]
+fn file_update_fn<'a, 'b>(
+    old_name: &'a str,
+    new_name: &'b str,
+    mod_edit: ModEdit,
+) -> impl use<'a, 'b> + FnMut(&Path, &str, &mut String) -> UpdateStatus {
+    let old_name_pascal = snake_to_pascal(old_name);
+    let new_name_pascal = snake_to_pascal(new_name);
+    let old_name_upper = old_name.to_ascii_uppercase();
+    let new_name_upper = new_name.to_ascii_uppercase();
+    move |_, src, dst| {
+        let mut copy_pos = 0u32;
+        let mut changed = false;
+        let mut searcher = RustSearcher::new(src);
+        let mut capture = "";
+        loop {
+            match searcher.peek() {
+                TokenKind::Eof => break,
+                TokenKind::Ident => {
+                    let match_start = searcher.pos();
+                    let text = searcher.peek_text();
+                    searcher.step();
+                    match text {
+                        // clippy::line_name or clippy::lint-name
+                        "clippy" => {
+                            if searcher.match_tokens(&[Token::DoubleColon, Token::CaptureIdent], &mut [&mut capture])
+                                && capture == old_name
+                            {
+                                dst.push_str(&src[copy_pos as usize..searcher.pos() as usize - capture.len()]);
+                                dst.push_str(new_name);
+                                copy_pos = searcher.pos();
+                                changed = true;
+                            }
+                        },
+                        // mod lint_name
+                        "mod" => {
+                            if !matches!(mod_edit, ModEdit::None)
+                                && searcher.match_tokens(&[Token::CaptureIdent], &mut [&mut capture])
+                                && capture == old_name
+                            {
+                                match mod_edit {
+                                    ModEdit::Rename => {
+                                        dst.push_str(&src[copy_pos as usize..searcher.pos() as usize - capture.len()]);
+                                        dst.push_str(new_name);
+                                        copy_pos = searcher.pos();
+                                        changed = true;
+                                    },
+                                    ModEdit::Delete if searcher.match_tokens(&[Token::Semi], &mut []) => {
+                                        let mut start = &src[copy_pos as usize..match_start as usize];
+                                        if start.ends_with("\n\n") {
+                                            start = &start[..start.len() - 1];
+                                        }
+                                        dst.push_str(start);
+                                        copy_pos = searcher.pos();
+                                        if src[copy_pos as usize..].starts_with("\n\n") {
+                                            copy_pos += 1;
+                                        }
+                                        changed = true;
+                                    },
+                                    ModEdit::Delete | ModEdit::None => {},
+                                }
+                            }
+                        },
+                        // lint_name::
+                        name if matches!(mod_edit, ModEdit::Rename) && name == old_name => {
+                            let name_end = searcher.pos();
+                            if searcher.match_tokens(&[Token::DoubleColon], &mut []) {
+                                dst.push_str(&src[copy_pos as usize..match_start as usize]);
+                                dst.push_str(new_name);
+                                copy_pos = name_end;
+                                changed = true;
+                            }
+                        },
+                        // LINT_NAME or LintName
+                        name => {
+                            let replacement = if name == old_name_upper {
+                                &new_name_upper
+                            } else if name == old_name_pascal {
+                                &new_name_pascal
+                            } else {
+                                continue;
+                            };
+                            dst.push_str(&src[copy_pos as usize..match_start as usize]);
+                            dst.push_str(replacement);
+                            copy_pos = searcher.pos();
+                            changed = true;
+                        },
+                    }
+                },
+                // //~ lint_name
+                TokenKind::LineComment { doc_style: None } => {
+                    let text = searcher.peek_text();
+                    if text.starts_with("//~")
+                        && let Some(text) = text.strip_suffix(old_name)
+                        && !text.ends_with(|c| matches!(c, 'a'..='z' | 'A'..='Z' | '0'..='9' | '_'))
+                    {
+                        dst.push_str(&src[copy_pos as usize..searcher.pos() as usize + text.len()]);
+                        dst.push_str(new_name);
+                        copy_pos = searcher.pos() + searcher.peek_len();
+                        changed = true;
+                    }
+                    searcher.step();
+                },
+                // ::lint_name
+                TokenKind::Colon
+                    if searcher.match_tokens(&[Token::DoubleColon, Token::CaptureIdent], &mut [&mut capture])
+                        && capture == old_name =>
+                {
+                    dst.push_str(&src[copy_pos as usize..searcher.pos() as usize - capture.len()]);
+                    dst.push_str(new_name);
+                    copy_pos = searcher.pos();
+                    changed = true;
+                },
+                _ => searcher.step(),
+            }
+        }
+
+        dst.push_str(&src[copy_pos as usize..]);
+        UpdateStatus::from_changed(changed)
+    }
 }
diff --git a/src/tools/clippy/clippy_dev/src/sync.rs b/src/tools/clippy/clippy_dev/src/sync.rs
index c699b0d7b95..98fd72fc0bd 100644
--- a/src/tools/clippy/clippy_dev/src/sync.rs
+++ b/src/tools/clippy/clippy_dev/src/sync.rs
@@ -4,15 +4,22 @@ use std::fmt::Write;
 
 pub fn update_nightly() {
     let date = Utc::now().format("%Y-%m-%d").to_string();
-    let update = &mut update_text_region_fn(
+    let toolchain_update = &mut update_text_region_fn(
         "# begin autogenerated nightly\n",
         "# end autogenerated nightly",
         |dst| {
             writeln!(dst, "channel = \"nightly-{date}\"").unwrap();
         },
     );
+    let readme_update = &mut update_text_region_fn(
+        "<!-- begin autogenerated nightly -->\n",
+        "<!-- end autogenerated nightly -->",
+        |dst| {
+            writeln!(dst, "```\nnightly-{date}\n```").unwrap();
+        },
+    );
 
     let mut updater = FileUpdater::default();
-    updater.update_file("rust-toolchain.toml", update);
-    updater.update_file("clippy_utils/README.md", update);
+    updater.update_file("rust-toolchain.toml", toolchain_update);
+    updater.update_file("clippy_utils/README.md", readme_update);
 }
diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs
index 0c861b72935..320462a2c96 100644
--- a/src/tools/clippy/clippy_dev/src/update_lints.rs
+++ b/src/tools/clippy/clippy_dev/src/update_lints.rs
@@ -1,12 +1,11 @@
 use crate::utils::{
-    File, FileAction, FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, panic_file, update_text_region_fn,
+    ErrAction, File, FileUpdater, RustSearcher, Token, UpdateMode, UpdateStatus, expect_action, update_text_region_fn,
 };
 use itertools::Itertools;
 use std::collections::HashSet;
 use std::fmt::Write;
-use std::fs::OpenOptions;
 use std::ops::Range;
-use std::path::Path;
+use std::path::{Path, PathBuf};
 use walkdir::{DirEntry, WalkDir};
 
 const GENERATED_FILE_COMMENT: &str = "// This file was generated by `cargo dev update_lints`.\n\
@@ -26,12 +25,11 @@ const DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.ht
 /// Panics if a file path could not read from or then written to
 pub fn update(update_mode: UpdateMode) {
     let lints = find_lint_decls();
-    let DeprecatedLints {
-        renamed, deprecated, ..
-    } = read_deprecated_lints();
+    let (deprecated, renamed) = read_deprecated_lints();
     generate_lint_files(update_mode, &lints, &deprecated, &renamed);
 }
 
+#[expect(clippy::too_many_lines)]
 pub fn generate_lint_files(
     update_mode: UpdateMode,
     lints: &[Lint],
@@ -93,6 +91,40 @@ pub fn generate_lint_files(
                 dst.push_str("];\n");
                 UpdateStatus::from_changed(src != dst)
             }),
+            ("clippy_lints/src/deprecated_lints.rs", &mut |_, src, dst| {
+                let mut searcher = RustSearcher::new(src);
+                assert!(
+                    searcher.find_token(Token::Ident("declare_with_version"))
+                        && searcher.find_token(Token::Ident("declare_with_version")),
+                    "error reading deprecated lints"
+                );
+                dst.push_str(&src[..searcher.pos() as usize]);
+                dst.push_str("! { DEPRECATED(DEPRECATED_VERSION) = [\n");
+                for lint in deprecated {
+                    write!(
+                        dst,
+                        "    #[clippy::version = \"{}\"]\n    (\"{}\", \"{}\"),\n",
+                        lint.version, lint.name, lint.reason,
+                    )
+                    .unwrap();
+                }
+                dst.push_str(
+                    "]}\n\n\
+                    #[rustfmt::skip]\n\
+                    declare_with_version! { RENAMED(RENAMED_VERSION) = [\n\
+                ",
+                );
+                for lint in renamed {
+                    write!(
+                        dst,
+                        "    #[clippy::version = \"{}\"]\n    (\"{}\", \"{}\"),\n",
+                        lint.version, lint.old_name, lint.new_name,
+                    )
+                    .unwrap();
+                }
+                dst.push_str("]}\n");
+                UpdateStatus::from_changed(src != dst)
+            }),
             ("tests/ui/deprecated.rs", &mut |_, src, dst| {
                 dst.push_str(GENERATED_FILE_COMMENT);
                 for lint in deprecated {
@@ -101,7 +133,24 @@ pub fn generate_lint_files(
                 dst.push_str("\nfn main() {}\n");
                 UpdateStatus::from_changed(src != dst)
             }),
-            ("tests/ui/rename.rs", &mut gen_renamed_lints_test_fn(renamed)),
+            ("tests/ui/rename.rs", &mut move |_, src, dst| {
+                let mut seen_lints = HashSet::new();
+                dst.push_str(GENERATED_FILE_COMMENT);
+                dst.push_str("#![allow(clippy::duplicated_attributes)]\n");
+                for lint in renamed {
+                    if seen_lints.insert(&lint.new_name) {
+                        writeln!(dst, "#![allow({})]", lint.new_name).unwrap();
+                    }
+                }
+                seen_lints.clear();
+                for lint in renamed {
+                    if seen_lints.insert(&lint.old_name) {
+                        writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.old_name, lint.old_name).unwrap();
+                    }
+                }
+                dst.push_str("\nfn main() {}\n");
+                UpdateStatus::from_changed(src != dst)
+            }),
         ],
     );
 }
@@ -111,44 +160,25 @@ fn round_to_fifty(count: usize) -> usize {
 }
 
 /// Lint data parsed from the Clippy source code.
-#[derive(Clone, PartialEq, Eq, Debug)]
+#[derive(PartialEq, Eq, Debug)]
 pub struct Lint {
     pub name: String,
     pub group: String,
     pub module: String,
+    pub path: PathBuf,
     pub declaration_range: Range<usize>,
 }
 
-#[derive(Clone, PartialEq, Eq, Debug)]
 pub struct DeprecatedLint {
     pub name: String,
     pub reason: String,
+    pub version: String,
 }
 
 pub struct RenamedLint {
     pub old_name: String,
     pub new_name: String,
-}
-
-pub fn gen_renamed_lints_test_fn(lints: &[RenamedLint]) -> impl Fn(&Path, &str, &mut String) -> UpdateStatus {
-    move |_, src, dst| {
-        let mut seen_lints = HashSet::new();
-        dst.push_str(GENERATED_FILE_COMMENT);
-        dst.push_str("#![allow(clippy::duplicated_attributes)]\n");
-        for lint in lints {
-            if seen_lints.insert(&lint.new_name) {
-                writeln!(dst, "#![allow({})]", lint.new_name).unwrap();
-            }
-        }
-        seen_lints.clear();
-        for lint in lints {
-            if seen_lints.insert(&lint.old_name) {
-                writeln!(dst, "#![warn({})] //~ ERROR: lint `{}`", lint.old_name, lint.old_name).unwrap();
-            }
-        }
-        dst.push_str("\nfn main() {}\n");
-        UpdateStatus::from_changed(src != dst)
-    }
+    pub version: String,
 }
 
 /// Finds all lint declarations (`declare_clippy_lint!`)
@@ -158,6 +188,7 @@ pub fn find_lint_decls() -> Vec<Lint> {
     let mut contents = String::new();
     for (file, module) in read_src_with_module("clippy_lints/src".as_ref()) {
         parse_clippy_lint_decls(
+            file.path(),
             File::open_read_to_cleared_string(file.path(), &mut contents),
             &module,
             &mut lints,
@@ -170,10 +201,7 @@ pub fn find_lint_decls() -> Vec<Lint> {
 /// Reads the source files from the given root directory
 fn read_src_with_module(src_root: &Path) -> impl use<'_> + Iterator<Item = (DirEntry, String)> {
     WalkDir::new(src_root).into_iter().filter_map(move |e| {
-        let e = match e {
-            Ok(e) => e,
-            Err(ref e) => panic_file(e, FileAction::Read, src_root),
-        };
+        let e = expect_action(e, ErrAction::Read, src_root);
         let path = e.path().as_os_str().as_encoded_bytes();
         if let Some(path) = path.strip_suffix(b".rs")
             && let Some(path) = path.get("clippy_lints/src/".len()..)
@@ -202,17 +230,17 @@ fn read_src_with_module(src_root: &Path) -> impl use<'_> + Iterator<Item = (DirE
 }
 
 /// Parse a source file looking for `declare_clippy_lint` macro invocations.
-fn parse_clippy_lint_decls(contents: &str, module: &str, lints: &mut Vec<Lint>) {
+fn parse_clippy_lint_decls(path: &Path, contents: &str, module: &str, lints: &mut Vec<Lint>) {
     #[allow(clippy::enum_glob_use)]
     use Token::*;
     #[rustfmt::skip]
-    static DECL_TOKENS: &[Token] = &[
+    static DECL_TOKENS: &[Token<'_>] = &[
         // !{ /// docs
-        Bang, OpenBrace, AnyDoc,
+        Bang, OpenBrace, AnyComment,
         // #[clippy::version = "version"]
         Pound, OpenBracket, Ident("clippy"), DoubleColon, Ident("version"), Eq, LitStr, CloseBracket,
         // pub NAME, GROUP,
-        Ident("pub"), CaptureIdent, Comma, CaptureIdent, Comma,
+        Ident("pub"), CaptureIdent, Comma, AnyComment, CaptureIdent, Comma,
     ];
 
     let mut searcher = RustSearcher::new(contents);
@@ -224,55 +252,42 @@ fn parse_clippy_lint_decls(contents: &str, module: &str, lints: &mut Vec<Lint>)
                 name: name.to_lowercase(),
                 group: group.into(),
                 module: module.into(),
+                path: path.into(),
                 declaration_range: start..searcher.pos() as usize,
             });
         }
     }
 }
 
-pub struct DeprecatedLints {
-    pub file: File<'static>,
-    pub contents: String,
-    pub deprecated: Vec<DeprecatedLint>,
-    pub renamed: Vec<RenamedLint>,
-    pub deprecated_end: u32,
-    pub renamed_end: u32,
-}
-
 #[must_use]
-pub fn read_deprecated_lints() -> DeprecatedLints {
+pub fn read_deprecated_lints() -> (Vec<DeprecatedLint>, Vec<RenamedLint>) {
     #[allow(clippy::enum_glob_use)]
     use Token::*;
     #[rustfmt::skip]
-    static DECL_TOKENS: &[Token] = &[
+    static DECL_TOKENS: &[Token<'_>] = &[
         // #[clippy::version = "version"]
-        Pound, OpenBracket, Ident("clippy"), DoubleColon, Ident("version"), Eq, LitStr, CloseBracket,
+        Pound, OpenBracket, Ident("clippy"), DoubleColon, Ident("version"), Eq, CaptureLitStr, CloseBracket,
         // ("first", "second"),
         OpenParen, CaptureLitStr, Comma, CaptureLitStr, CloseParen, Comma,
     ];
     #[rustfmt::skip]
-    static DEPRECATED_TOKENS: &[Token] = &[
+    static DEPRECATED_TOKENS: &[Token<'_>] = &[
         // !{ DEPRECATED(DEPRECATED_VERSION) = [
         Bang, OpenBrace, Ident("DEPRECATED"), OpenParen, Ident("DEPRECATED_VERSION"), CloseParen, Eq, OpenBracket,
     ];
     #[rustfmt::skip]
-    static RENAMED_TOKENS: &[Token] = &[
+    static RENAMED_TOKENS: &[Token<'_>] = &[
         // !{ RENAMED(RENAMED_VERSION) = [
         Bang, OpenBrace, Ident("RENAMED"), OpenParen, Ident("RENAMED_VERSION"), CloseParen, Eq, OpenBracket,
     ];
 
     let path = "clippy_lints/src/deprecated_lints.rs";
-    let mut res = DeprecatedLints {
-        file: File::open(path, OpenOptions::new().read(true).write(true)),
-        contents: String::new(),
-        deprecated: Vec::with_capacity(30),
-        renamed: Vec::with_capacity(80),
-        deprecated_end: 0,
-        renamed_end: 0,
-    };
+    let mut deprecated = Vec::with_capacity(30);
+    let mut renamed = Vec::with_capacity(80);
+    let mut contents = String::new();
+    File::open_read_to_cleared_string(path, &mut contents);
 
-    res.file.read_append_to_string(&mut res.contents);
-    let mut searcher = RustSearcher::new(&res.contents);
+    let mut searcher = RustSearcher::new(&contents);
 
     // First instance is the macro definition.
     assert!(
@@ -281,36 +296,38 @@ pub fn read_deprecated_lints() -> DeprecatedLints {
     );
 
     if searcher.find_token(Ident("declare_with_version")) && searcher.match_tokens(DEPRECATED_TOKENS, &mut []) {
+        let mut version = "";
         let mut name = "";
         let mut reason = "";
-        while searcher.match_tokens(DECL_TOKENS, &mut [&mut name, &mut reason]) {
-            res.deprecated.push(DeprecatedLint {
+        while searcher.match_tokens(DECL_TOKENS, &mut [&mut version, &mut name, &mut reason]) {
+            deprecated.push(DeprecatedLint {
                 name: parse_str_single_line(path.as_ref(), name),
                 reason: parse_str_single_line(path.as_ref(), reason),
+                version: parse_str_single_line(path.as_ref(), version),
             });
         }
     } else {
         panic!("error reading deprecated lints");
     }
-    // position of the closing `]}` of `declare_with_version`
-    res.deprecated_end = searcher.pos();
 
     if searcher.find_token(Ident("declare_with_version")) && searcher.match_tokens(RENAMED_TOKENS, &mut []) {
+        let mut version = "";
         let mut old_name = "";
         let mut new_name = "";
-        while searcher.match_tokens(DECL_TOKENS, &mut [&mut old_name, &mut new_name]) {
-            res.renamed.push(RenamedLint {
+        while searcher.match_tokens(DECL_TOKENS, &mut [&mut version, &mut old_name, &mut new_name]) {
+            renamed.push(RenamedLint {
                 old_name: parse_str_single_line(path.as_ref(), old_name),
                 new_name: parse_str_single_line(path.as_ref(), new_name),
+                version: parse_str_single_line(path.as_ref(), version),
             });
         }
     } else {
         panic!("error reading renamed lints");
     }
-    // position of the closing `]}` of `declare_with_version`
-    res.renamed_end = searcher.pos();
 
-    res
+    deprecated.sort_by(|lhs, rhs| lhs.name.cmp(&rhs.name));
+    renamed.sort_by(|lhs, rhs| lhs.old_name.cmp(&rhs.old_name));
+    (deprecated, renamed)
 }
 
 /// Removes the line splices and surrounding quotes from a string literal
@@ -366,7 +383,7 @@ mod tests {
             }
         "#;
         let mut result = Vec::new();
-        parse_clippy_lint_decls(CONTENTS, "module_name", &mut result);
+        parse_clippy_lint_decls("".as_ref(), CONTENTS, "module_name", &mut result);
         for r in &mut result {
             r.declaration_range = Range::default();
         }
@@ -376,12 +393,14 @@ mod tests {
                 name: "ptr_arg".into(),
                 group: "style".into(),
                 module: "module_name".into(),
+                path: PathBuf::new(),
                 declaration_range: Range::default(),
             },
             Lint {
                 name: "doc_markdown".into(),
                 group: "pedantic".into(),
                 module: "module_name".into(),
+                path: PathBuf::new(),
                 declaration_range: Range::default(),
             },
         ];
diff --git a/src/tools/clippy/clippy_dev/src/utils.rs b/src/tools/clippy/clippy_dev/src/utils.rs
index ae2eabc45dd..c4808b7048b 100644
--- a/src/tools/clippy/clippy_dev/src/utils.rs
+++ b/src/tools/clippy/clippy_dev/src/utils.rs
@@ -1,13 +1,16 @@
-use aho_corasick::{AhoCorasick, AhoCorasickBuilder};
 use core::fmt::{self, Display};
+use core::num::NonZero;
+use core::ops::Range;
 use core::slice;
 use core::str::FromStr;
 use rustc_lexer::{self as lexer, FrontmatterAllowed};
-use std::env;
+use std::ffi::OsStr;
 use std::fs::{self, OpenOptions};
 use std::io::{self, Read as _, Seek as _, SeekFrom, Write};
 use std::path::{Path, PathBuf};
-use std::process::{self, ExitStatus};
+use std::process::{self, Command, ExitStatus, Stdio};
+use std::{env, thread};
+use walkdir::WalkDir;
 
 #[cfg(not(windows))]
 static CARGO_CLIPPY_EXE: &str = "cargo-clippy";
@@ -15,14 +18,16 @@ static CARGO_CLIPPY_EXE: &str = "cargo-clippy";
 static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe";
 
 #[derive(Clone, Copy)]
-pub enum FileAction {
+pub enum ErrAction {
     Open,
     Read,
     Write,
     Create,
     Rename,
+    Delete,
+    Run,
 }
-impl FileAction {
+impl ErrAction {
     fn as_str(self) -> &'static str {
         match self {
             Self::Open => "opening",
@@ -30,16 +35,26 @@ impl FileAction {
             Self::Write => "writing",
             Self::Create => "creating",
             Self::Rename => "renaming",
+            Self::Delete => "deleting",
+            Self::Run => "running",
         }
     }
 }
 
 #[cold]
 #[track_caller]
-pub fn panic_file(err: &impl Display, action: FileAction, path: &Path) -> ! {
+pub fn panic_action(err: &impl Display, action: ErrAction, path: &Path) -> ! {
     panic!("error {} `{}`: {}", action.as_str(), path.display(), *err)
 }
 
+#[track_caller]
+pub fn expect_action<T>(res: Result<T, impl Display>, action: ErrAction, path: impl AsRef<Path>) -> T {
+    match res {
+        Ok(x) => x,
+        Err(ref e) => panic_action(e, action, path.as_ref()),
+    }
+}
+
 /// Wrapper around `std::fs::File` which panics with a path on failure.
 pub struct File<'a> {
     pub inner: fs::File,
@@ -50,9 +65,9 @@ impl<'a> File<'a> {
     #[track_caller]
     pub fn open(path: &'a (impl AsRef<Path> + ?Sized), options: &mut OpenOptions) -> Self {
         let path = path.as_ref();
-        match options.open(path) {
-            Ok(inner) => Self { inner, path },
-            Err(e) => panic_file(&e, FileAction::Open, path),
+        Self {
+            inner: expect_action(options.open(path), ErrAction::Open, path),
+            path,
         }
     }
 
@@ -63,7 +78,7 @@ impl<'a> File<'a> {
         match options.open(path) {
             Ok(inner) => Some(Self { inner, path }),
             Err(e) if e.kind() == io::ErrorKind::NotFound => None,
-            Err(e) => panic_file(&e, FileAction::Open, path),
+            Err(e) => panic_action(&e, ErrAction::Open, path),
         }
     }
 
@@ -79,10 +94,7 @@ impl<'a> File<'a> {
     /// Read the entire contents of a file to the given buffer.
     #[track_caller]
     pub fn read_append_to_string<'dst>(&mut self, dst: &'dst mut String) -> &'dst mut String {
-        match self.inner.read_to_string(dst) {
-            Ok(_) => {},
-            Err(e) => panic_file(&e, FileAction::Read, self.path),
-        }
+        expect_action(self.inner.read_to_string(dst), ErrAction::Read, self.path);
         dst
     }
 
@@ -102,9 +114,7 @@ impl<'a> File<'a> {
             },
             Err(e) => Err(e),
         };
-        if let Err(e) = res {
-            panic_file(&e, FileAction::Write, self.path);
-        }
+        expect_action(res, ErrAction::Write, self.path);
     }
 }
 
@@ -165,9 +175,83 @@ impl Version {
     }
 }
 
+enum TomlPart<'a> {
+    Table(&'a str),
+    Value(&'a str, &'a str),
+}
+
+fn toml_iter(s: &str) -> impl Iterator<Item = (usize, TomlPart<'_>)> {
+    let mut pos = 0;
+    s.split('\n')
+        .map(move |s| {
+            let x = pos;
+            pos += s.len() + 1;
+            (x, s)
+        })
+        .filter_map(|(pos, s)| {
+            if let Some(s) = s.strip_prefix('[') {
+                s.split_once(']').map(|(name, _)| (pos, TomlPart::Table(name)))
+            } else if matches!(s.bytes().next(), Some(b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_')) {
+                s.split_once('=').map(|(key, value)| (pos, TomlPart::Value(key, value)))
+            } else {
+                None
+            }
+        })
+}
+
+pub struct CargoPackage<'a> {
+    pub name: &'a str,
+    pub version_range: Range<usize>,
+    pub not_a_platform_range: Range<usize>,
+}
+
+#[must_use]
+pub fn parse_cargo_package(s: &str) -> CargoPackage<'_> {
+    let mut in_package = false;
+    let mut in_platform_deps = false;
+    let mut name = "";
+    let mut version_range = 0..0;
+    let mut not_a_platform_range = 0..0;
+    for (offset, part) in toml_iter(s) {
+        match part {
+            TomlPart::Table(name) => {
+                if in_platform_deps {
+                    not_a_platform_range.end = offset;
+                }
+                in_package = false;
+                in_platform_deps = false;
+
+                match name.trim() {
+                    "package" => in_package = true,
+                    "target.'cfg(NOT_A_PLATFORM)'.dependencies" => {
+                        in_platform_deps = true;
+                        not_a_platform_range.start = offset;
+                    },
+                    _ => {},
+                }
+            },
+            TomlPart::Value(key, value) if in_package => match key.trim_end() {
+                "name" => name = value.trim(),
+                "version" => {
+                    version_range.start = offset + (value.len() - value.trim().len()) + key.len() + 1;
+                    version_range.end = offset + key.len() + value.trim_end().len() + 1;
+                },
+                _ => {},
+            },
+            TomlPart::Value(..) => {},
+        }
+    }
+    CargoPackage {
+        name,
+        version_range,
+        not_a_platform_range,
+    }
+}
+
 pub struct ClippyInfo {
     pub path: PathBuf,
     pub version: Version,
+    pub has_intellij_hook: bool,
 }
 impl ClippyInfo {
     #[must_use]
@@ -177,35 +261,21 @@ impl ClippyInfo {
         loop {
             path.push("Cargo.toml");
             if let Some(mut file) = File::open_if_exists(&path, OpenOptions::new().read(true)) {
-                let mut in_package = false;
-                let mut is_clippy = false;
-                let mut version: Option<Version> = None;
-
-                // Ad-hoc parsing to avoid dependencies. We control all the file so this
-                // isn't actually a problem
-                for line in file.read_to_cleared_string(&mut buf).lines() {
-                    if line.starts_with('[') {
-                        in_package = line.starts_with("[package]");
-                    } else if in_package && let Some((name, value)) = line.split_once('=') {
-                        match name.trim() {
-                            "name" => is_clippy = value.trim() == "\"clippy\"",
-                            "version"
-                                if let Some(value) = value.trim().strip_prefix('"')
-                                    && let Some(value) = value.strip_suffix('"') =>
-                            {
-                                version = value.parse().ok();
-                            },
-                            _ => {},
-                        }
+                file.read_to_cleared_string(&mut buf);
+                let package = parse_cargo_package(&buf);
+                if package.name == "\"clippy\"" {
+                    if let Some(version) = buf[package.version_range].strip_prefix('"')
+                        && let Some(version) = version.strip_suffix('"')
+                        && let Ok(version) = version.parse()
+                    {
+                        path.pop();
+                        return ClippyInfo {
+                            path,
+                            version,
+                            has_intellij_hook: !package.not_a_platform_range.is_empty(),
+                        };
                     }
-                }
-
-                if is_clippy {
-                    let Some(version) = version else {
-                        panic!("error reading clippy version from {}", file.path.display());
-                    };
-                    path.pop();
-                    return ClippyInfo { path, version };
+                    panic!("error reading clippy version from `{}`", file.path.display());
                 }
             }
 
@@ -258,6 +328,11 @@ impl UpdateMode {
     pub fn from_check(check: bool) -> Self {
         if check { Self::Check } else { Self::Change }
     }
+
+    #[must_use]
+    pub fn is_check(self) -> bool {
+        matches!(self, Self::Check)
+    }
 }
 
 #[derive(Default)]
@@ -366,53 +441,11 @@ pub fn update_text_region_fn(
     move |path, src, dst| update_text_region(path, start, end, src, dst, &mut insert)
 }
 
-#[must_use]
-pub fn is_ident_char(c: u8) -> bool {
-    matches!(c, b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_')
-}
-
-pub struct StringReplacer<'a> {
-    searcher: AhoCorasick,
-    replacements: &'a [(&'a str, &'a str)],
-}
-impl<'a> StringReplacer<'a> {
-    #[must_use]
-    pub fn new(replacements: &'a [(&'a str, &'a str)]) -> Self {
-        Self {
-            searcher: AhoCorasickBuilder::new()
-                .match_kind(aho_corasick::MatchKind::LeftmostLongest)
-                .build(replacements.iter().map(|&(x, _)| x))
-                .unwrap(),
-            replacements,
-        }
-    }
-
-    /// Replace substrings if they aren't bordered by identifier characters.
-    pub fn replace_ident_fn(&self) -> impl Fn(&Path, &str, &mut String) -> UpdateStatus {
-        move |_, src, dst| {
-            let mut pos = 0;
-            let mut changed = false;
-            for m in self.searcher.find_iter(src) {
-                if !is_ident_char(src.as_bytes().get(m.start().wrapping_sub(1)).copied().unwrap_or(0))
-                    && !is_ident_char(src.as_bytes().get(m.end()).copied().unwrap_or(0))
-                {
-                    changed = true;
-                    dst.push_str(&src[pos..m.start()]);
-                    dst.push_str(self.replacements[m.pattern()].1);
-                    pos = m.end();
-                }
-            }
-            dst.push_str(&src[pos..]);
-            UpdateStatus::from_changed(changed)
-        }
-    }
-}
-
 #[derive(Clone, Copy)]
-pub enum Token {
-    /// Matches any number of doc comments.
-    AnyDoc,
-    Ident(&'static str),
+pub enum Token<'a> {
+    /// Matches any number of comments / doc comments.
+    AnyComment,
+    Ident(&'a str),
     CaptureIdent,
     LitStr,
     CaptureLitStr,
@@ -431,29 +464,26 @@ pub enum Token {
     OpenBracket,
     OpenParen,
     Pound,
+    Semi,
+    Slash,
 }
 
 pub struct RustSearcher<'txt> {
     text: &'txt str,
     cursor: lexer::Cursor<'txt>,
     pos: u32,
-
-    // Either the next token or a zero-sized whitespace sentinel.
     next_token: lexer::Token,
 }
 impl<'txt> RustSearcher<'txt> {
     #[must_use]
+    #[expect(clippy::inconsistent_struct_constructor)]
     pub fn new(text: &'txt str) -> Self {
+        let mut cursor = lexer::Cursor::new(text, FrontmatterAllowed::Yes);
         Self {
             text,
-            cursor: lexer::Cursor::new(text, FrontmatterAllowed::Yes),
             pos: 0,
-
-            // Sentinel value indicating there is no read token.
-            next_token: lexer::Token {
-                len: 0,
-                kind: lexer::TokenKind::Whitespace,
-            },
+            next_token: cursor.advance_token(),
+            cursor,
         }
     }
 
@@ -463,6 +493,11 @@ impl<'txt> RustSearcher<'txt> {
     }
 
     #[must_use]
+    pub fn peek_len(&self) -> u32 {
+        self.next_token.len
+    }
+
+    #[must_use]
     pub fn peek(&self) -> lexer::TokenKind {
         self.next_token.kind
     }
@@ -485,37 +520,15 @@ impl<'txt> RustSearcher<'txt> {
 
     /// Consumes the next token if it matches the requested value and captures the value if
     /// requested. Returns true if a token was matched.
-    fn read_token(&mut self, token: Token, captures: &mut slice::IterMut<'_, &mut &'txt str>) -> bool {
+    fn read_token(&mut self, token: Token<'_>, captures: &mut slice::IterMut<'_, &mut &'txt str>) -> bool {
         loop {
             match (token, self.next_token.kind) {
-                // Has to be the first match arm so the empty sentinel token will be handled.
-                // This will also skip all whitespace/comments preceding any tokens.
-                (
-                    _,
-                    lexer::TokenKind::Whitespace
-                    | lexer::TokenKind::LineComment { doc_style: None }
-                    | lexer::TokenKind::BlockComment {
-                        doc_style: None,
-                        terminated: true,
-                    },
-                ) => {
-                    self.step();
-                    if self.at_end() {
-                        // `AnyDoc` always matches.
-                        return matches!(token, Token::AnyDoc);
-                    }
-                },
-                (
-                    Token::AnyDoc,
+                (_, lexer::TokenKind::Whitespace)
+                | (
+                    Token::AnyComment,
                     lexer::TokenKind::BlockComment { terminated: true, .. } | lexer::TokenKind::LineComment { .. },
-                ) => {
-                    self.step();
-                    if self.at_end() {
-                        // `AnyDoc` always matches.
-                        return true;
-                    }
-                },
-                (Token::AnyDoc, _) => return true,
+                ) => self.step(),
+                (Token::AnyComment, _) => return true,
                 (Token::Bang, lexer::TokenKind::Bang)
                 | (Token::CloseBrace, lexer::TokenKind::CloseBrace)
                 | (Token::CloseBracket, lexer::TokenKind::CloseBracket)
@@ -529,6 +542,8 @@ impl<'txt> RustSearcher<'txt> {
                 | (Token::OpenBracket, lexer::TokenKind::OpenBracket)
                 | (Token::OpenParen, lexer::TokenKind::OpenParen)
                 | (Token::Pound, lexer::TokenKind::Pound)
+                | (Token::Semi, lexer::TokenKind::Semi)
+                | (Token::Slash, lexer::TokenKind::Slash)
                 | (
                     Token::LitStr,
                     lexer::TokenKind::Literal {
@@ -569,7 +584,7 @@ impl<'txt> RustSearcher<'txt> {
     }
 
     #[must_use]
-    pub fn find_token(&mut self, token: Token) -> bool {
+    pub fn find_token(&mut self, token: Token<'_>) -> bool {
         let mut capture = [].iter_mut();
         while !self.read_token(token, &mut capture) {
             self.step();
@@ -581,7 +596,7 @@ impl<'txt> RustSearcher<'txt> {
     }
 
     #[must_use]
-    pub fn find_capture_token(&mut self, token: Token) -> Option<&'txt str> {
+    pub fn find_capture_token(&mut self, token: Token<'_>) -> Option<&'txt str> {
         let mut res = "";
         let mut capture = &mut res;
         let mut capture = slice::from_mut(&mut capture).iter_mut();
@@ -595,7 +610,7 @@ impl<'txt> RustSearcher<'txt> {
     }
 
     #[must_use]
-    pub fn match_tokens(&mut self, tokens: &[Token], captures: &mut [&mut &'txt str]) -> bool {
+    pub fn match_tokens(&mut self, tokens: &[Token<'_>], captures: &mut [&mut &'txt str]) -> bool {
         let mut captures = captures.iter_mut();
         tokens.iter().all(|&t| self.read_token(t, &mut captures))
     }
@@ -606,21 +621,160 @@ pub fn try_rename_file(old_name: &Path, new_name: &Path) -> bool {
     match OpenOptions::new().create_new(true).write(true).open(new_name) {
         Ok(file) => drop(file),
         Err(e) if matches!(e.kind(), io::ErrorKind::AlreadyExists | io::ErrorKind::NotFound) => return false,
-        Err(e) => panic_file(&e, FileAction::Create, new_name),
+        Err(ref e) => panic_action(e, ErrAction::Create, new_name),
     }
     match fs::rename(old_name, new_name) {
         Ok(()) => true,
-        Err(e) => {
+        Err(ref e) => {
             drop(fs::remove_file(new_name));
-            if e.kind() == io::ErrorKind::NotFound {
+            // `NotADirectory` happens on posix when renaming a directory to an existing file.
+            // Windows will ignore this and rename anyways.
+            if matches!(e.kind(), io::ErrorKind::NotFound | io::ErrorKind::NotADirectory) {
                 false
             } else {
-                panic_file(&e, FileAction::Rename, old_name);
+                panic_action(e, ErrAction::Rename, old_name);
+            }
+        },
+    }
+}
+
+#[expect(clippy::must_use_candidate)]
+pub fn try_rename_dir(old_name: &Path, new_name: &Path) -> bool {
+    match fs::create_dir(new_name) {
+        Ok(()) => {},
+        Err(e) if matches!(e.kind(), io::ErrorKind::AlreadyExists | io::ErrorKind::NotFound) => return false,
+        Err(ref e) => panic_action(e, ErrAction::Create, new_name),
+    }
+    // Windows can't reliably rename to an empty directory.
+    #[cfg(windows)]
+    drop(fs::remove_dir(new_name));
+    match fs::rename(old_name, new_name) {
+        Ok(()) => true,
+        Err(ref e) => {
+            // Already dropped earlier on windows.
+            #[cfg(not(windows))]
+            drop(fs::remove_dir(new_name));
+            // `NotADirectory` happens on posix when renaming a file to an existing directory.
+            if matches!(e.kind(), io::ErrorKind::NotFound | io::ErrorKind::NotADirectory) {
+                false
+            } else {
+                panic_action(e, ErrAction::Rename, old_name);
             }
         },
     }
 }
 
 pub fn write_file(path: &Path, contents: &str) {
-    fs::write(path, contents).unwrap_or_else(|e| panic_file(&e, FileAction::Write, path));
+    expect_action(fs::write(path, contents), ErrAction::Write, path);
+}
+
+#[must_use]
+pub fn run_with_output(path: &(impl AsRef<Path> + ?Sized), cmd: &mut Command) -> Vec<u8> {
+    fn f(path: &Path, cmd: &mut Command) -> Vec<u8> {
+        let output = expect_action(
+            cmd.stdin(Stdio::null())
+                .stdout(Stdio::piped())
+                .stderr(Stdio::inherit())
+                .output(),
+            ErrAction::Run,
+            path,
+        );
+        expect_action(output.status.exit_ok(), ErrAction::Run, path);
+        output.stdout
+    }
+    f(path.as_ref(), cmd)
+}
+
+/// Splits an argument list across multiple `Command` invocations.
+///
+/// The argument list will be split into a number of batches based on
+/// `thread::available_parallelism`, with `min_batch_size` setting a lower bound on the size of each
+/// batch.
+///
+/// If the size of the arguments would exceed the system limit additional batches will be created.
+pub fn split_args_for_threads(
+    min_batch_size: usize,
+    make_cmd: impl FnMut() -> Command,
+    args: impl ExactSizeIterator<Item: AsRef<OsStr>>,
+) -> impl Iterator<Item = Command> {
+    struct Iter<F, I> {
+        make_cmd: F,
+        args: I,
+        min_batch_size: usize,
+        batch_size: usize,
+        thread_count: usize,
+    }
+    impl<F, I> Iterator for Iter<F, I>
+    where
+        F: FnMut() -> Command,
+        I: ExactSizeIterator<Item: AsRef<OsStr>>,
+    {
+        type Item = Command;
+        fn next(&mut self) -> Option<Self::Item> {
+            if self.thread_count > 1 {
+                self.thread_count -= 1;
+            }
+            let mut cmd = (self.make_cmd)();
+            let mut cmd_len = 0usize;
+            for arg in self.args.by_ref().take(self.batch_size) {
+                cmd.arg(arg.as_ref());
+                // `+ 8` to account for the `argv` pointer on unix.
+                // Windows is complicated since the arguments are first converted to UTF-16ish,
+                // but this needs to account for the space between arguments and whatever additional
+                // is needed to escape within an argument.
+                cmd_len += arg.as_ref().len() + 8;
+                cmd_len += 8;
+
+                // Windows has a command length limit of 32767. For unix systems this is more
+                // complicated since the limit includes environment variables and room needs to be
+                // left to edit them once the program starts, but the total size comes from
+                // `getconf ARG_MAX`.
+                //
+                // For simplicity we use 30000 here under a few assumptions.
+                // * Individual arguments aren't super long (the final argument is still added)
+                // * `ARG_MAX` is set to a reasonable amount. Basically every system will be configured way above
+                //   what windows supports, but POSIX only requires `4096`.
+                if cmd_len > 30000 {
+                    self.batch_size = self.args.len().div_ceil(self.thread_count).max(self.min_batch_size);
+                    break;
+                }
+            }
+            (cmd_len != 0).then_some(cmd)
+        }
+    }
+    let thread_count = thread::available_parallelism().map_or(1, NonZero::get);
+    let batch_size = args.len().div_ceil(thread_count).max(min_batch_size);
+    Iter {
+        make_cmd,
+        args,
+        min_batch_size,
+        batch_size,
+        thread_count,
+    }
+}
+
+#[expect(clippy::must_use_candidate)]
+pub fn delete_file_if_exists(path: &Path) -> bool {
+    match fs::remove_file(path) {
+        Ok(()) => true,
+        Err(e) if matches!(e.kind(), io::ErrorKind::NotFound | io::ErrorKind::IsADirectory) => false,
+        Err(ref e) => panic_action(e, ErrAction::Delete, path),
+    }
+}
+
+pub fn delete_dir_if_exists(path: &Path) {
+    match fs::remove_dir_all(path) {
+        Ok(()) => {},
+        Err(e) if matches!(e.kind(), io::ErrorKind::NotFound | io::ErrorKind::NotADirectory) => {},
+        Err(ref e) => panic_action(e, ErrAction::Delete, path),
+    }
+}
+
+/// Walks all items excluding top-level dot files/directories and any target directories.
+pub fn walk_dir_no_dot_or_target() -> impl Iterator<Item = ::walkdir::Result<::walkdir::DirEntry>> {
+    WalkDir::new(".").into_iter().filter_entry(|e| {
+        e.path()
+            .file_name()
+            .is_none_or(|x| x != "target" && x.as_encoded_bytes().first().copied() != Some(b'.'))
+    })
 }
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index 7e3cb404247..39e4e2e365e 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -1,8 +1,6 @@
 [package]
 name = "clippy_lints"
-# begin autogenerated version
 version = "0.1.89"
-# end autogenerated version
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
diff --git a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
index 272444475c0..59a0c7c8868 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
@@ -6,9 +6,10 @@ use clippy_config::types::{
 };
 use clippy_utils::diagnostics::span_lint_and_note;
 use clippy_utils::is_cfg_test;
+use rustc_attr_data_structures::AttributeKind;
 use rustc_hir::{
-    AssocItemKind, FieldDef, HirId, ImplItemRef, IsAuto, Item, ItemKind, Mod, QPath, TraitItemRef, TyKind, Variant,
-    VariantData,
+    AssocItemKind, Attribute, FieldDef, HirId, ImplItemRef, IsAuto, Item, ItemKind, Mod, QPath, TraitItemRef, TyKind,
+    Variant, VariantData,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::impl_lint_pass;
@@ -28,6 +29,11 @@ declare_clippy_lint! {
     /// implemented in the code. Sometimes this will be referred to as
     /// "bikeshedding".
     ///
+    /// The content of items with a representation clause attribute, such as
+    /// `#[repr(C)]` will not be checked, as the order of their fields or
+    /// variants might be dictated by an external API (application binary
+    /// interface).
+    ///
     /// ### Default Ordering and Configuration
     ///
     /// As there is no generally applicable rule, and each project may have
@@ -256,8 +262,17 @@ impl ArbitrarySourceItemOrdering {
 
 impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+        if cx
+            .tcx
+            .hir_attrs(item.hir_id())
+            .iter()
+            .any(|attr| matches!(attr, Attribute::Parsed(AttributeKind::Repr(..))))
+        {
+            // Do not lint items with a `#[repr]` attribute as their layout may be imposed by an external API.
+            return;
+        }
         match &item.kind {
-            ItemKind::Enum(_, enum_def, _generics) if self.enable_ordering_for_enum => {
+            ItemKind::Enum(_, _generics, enum_def) if self.enable_ordering_for_enum => {
                 let mut cur_v: Option<&Variant<'_>> = None;
                 for variant in enum_def.variants {
                     if variant.span.in_external_macro(cx.sess().source_map()) {
@@ -273,7 +288,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
                     cur_v = Some(variant);
                 }
             },
-            ItemKind::Struct(_, VariantData::Struct { fields, .. }, _generics) if self.enable_ordering_for_struct => {
+            ItemKind::Struct(_, _generics, VariantData::Struct { fields, .. }) if self.enable_ordering_for_struct => {
                 let mut cur_f: Option<&FieldDef<'_>> = None;
                 for field in *fields {
                     if field.span.in_external_macro(cx.sess().source_map()) {
diff --git a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs
index 2643f850879..9e09fb5bb43 100644
--- a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs
+++ b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs
@@ -50,7 +50,7 @@ impl<'tcx> LateLintPass<'tcx> for ArcWithNonSendSync {
             && let arg_ty = cx.typeck_results().expr_ty(arg)
             // make sure that the type is not and does not contain any type parameters
             && arg_ty.walk().all(|arg| {
-                !matches!(arg.unpack(), GenericArgKind::Type(ty) if matches!(ty.kind(), ty::Param(_)))
+                !matches!(arg.kind(), GenericArgKind::Type(ty) if matches!(ty.kind(), ty::Param(_)))
             })
             && let Some(send) = cx.tcx.get_diagnostic_item(sym::Send)
             && let Some(sync) = cx.tcx.lang_items().sync_trait()
diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
index c073dee855e..6f2a6a36a38 100644
--- a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
+++ b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
@@ -3,14 +3,13 @@ use clippy_utils::macros::{PanicExpn, find_assert_args, root_macro_call_first_no
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::{has_debug_impl, is_copy, is_type_diagnostic_item};
 use clippy_utils::usage::local_used_after_expr;
-use clippy_utils::{is_expr_final_block_expr, path_res};
+use clippy_utils::{is_expr_final_block_expr, path_res, sym};
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, Ty};
 use rustc_session::declare_lint_pass;
-use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -68,11 +67,11 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
                     return;
                 }
             }
-            let (message, replacement) = match method_segment.ident.as_str() {
-                "is_ok" if type_suitable_to_unwrap(cx, args.type_at(1)) => {
+            let (message, replacement) = match method_segment.ident.name {
+                sym::is_ok if type_suitable_to_unwrap(cx, args.type_at(1)) => {
                     ("called `assert!` with `Result::is_ok`", "unwrap")
                 },
-                "is_err" if type_suitable_to_unwrap(cx, args.type_at(0)) => {
+                sym::is_err if type_suitable_to_unwrap(cx, args.type_at(0)) => {
                     ("called `assert!` with `Result::is_err`", "unwrap_err")
                 },
                 _ => return,
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
index e92879b853d..4120e5c8cb7 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
@@ -56,7 +56,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
             if signed {
                 return nbits;
             }
-            let max_bits = if method.ident.as_str() == "min" {
+            let max_bits = if method.ident.name == sym::min {
                 get_constant_bits(cx, right)
             } else {
                 None
@@ -64,7 +64,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
             apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::MAX))
         },
         ExprKind::MethodCall(method, _, [lo, hi], _) => {
-            if method.ident.as_str() == "clamp"
+            if method.ident.name == sym::clamp
                 //FIXME: make this a diagnostic item
                 && let (Some(lo_bits), Some(hi_bits)) = (get_constant_bits(cx, lo), get_constant_bits(cx, hi))
             {
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
index c8abf9dac9a..9a1ad8a7473 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
@@ -4,10 +4,11 @@ use std::ops::ControlFlow;
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::visitors::{Descend, for_each_expr_without_closures};
-use clippy_utils::{method_chain_args, sext};
+use clippy_utils::{method_chain_args, sext, sym};
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, Ty};
+use rustc_span::Symbol;
 
 use super::CAST_SIGN_LOSS;
 
@@ -16,24 +17,24 @@ use super::CAST_SIGN_LOSS;
 ///
 /// Methods that can overflow and return a negative value must not be included in this list,
 /// because casting their return values can still result in sign loss.
-const METHODS_RET_POSITIVE: &[&str] = &[
-    "checked_abs",
-    "saturating_abs",
-    "isqrt",
-    "checked_isqrt",
-    "rem_euclid",
-    "checked_rem_euclid",
-    "wrapping_rem_euclid",
+const METHODS_RET_POSITIVE: &[Symbol] = &[
+    sym::checked_abs,
+    sym::saturating_abs,
+    sym::isqrt,
+    sym::checked_isqrt,
+    sym::rem_euclid,
+    sym::checked_rem_euclid,
+    sym::wrapping_rem_euclid,
 ];
 
 /// A list of methods that act like `pow()`. See `pow_call_result_sign()` for details.
 ///
 /// Methods that can overflow and return a negative value must not be included in this list,
 /// because casting their return values can still result in sign loss.
-const METHODS_POW: &[&str] = &["pow", "saturating_pow", "checked_pow"];
+const METHODS_POW: &[Symbol] = &[sym::pow, sym::saturating_pow, sym::checked_pow];
 
 /// A list of methods that act like `unwrap()`, and don't change the sign of the inner value.
-const METHODS_UNWRAP: &[&str] = &["unwrap", "unwrap_unchecked", "expect", "into_ok"];
+const METHODS_UNWRAP: &[Symbol] = &[sym::unwrap, sym::unwrap_unchecked, sym::expect, sym::into_ok];
 
 pub(super) fn check<'cx>(
     cx: &LateContext<'cx>,
@@ -129,7 +130,7 @@ fn expr_sign<'cx, 'tcx>(cx: &LateContext<'cx>, mut expr: &'tcx Expr<'tcx>, ty: i
 
     // Calling on methods that always return non-negative values.
     if let ExprKind::MethodCall(path, caller, args, ..) = expr.kind {
-        let mut method_name = path.ident.name.as_str();
+        let mut method_name = path.ident.name;
 
         // Peel unwrap(), expect(), etc.
         while let Some(&found_name) = METHODS_UNWRAP.iter().find(|&name| &method_name == name)
@@ -138,7 +139,7 @@ fn expr_sign<'cx, 'tcx>(cx: &LateContext<'cx>, mut expr: &'tcx Expr<'tcx>, ty: i
         {
             // The original type has changed, but we can't use `ty` here anyway, because it has been
             // moved.
-            method_name = inner_path.ident.name.as_str();
+            method_name = inner_path.ident.name;
             expr = recv;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs b/src/tools/clippy/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs
index 31cdd078f45..769cc120c95 100644
--- a/src/tools/clippy/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/confusing_method_to_numeric_cast.rs
@@ -1,11 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::sym;
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, GenericArg, Ty};
+use rustc_span::Symbol;
 use rustc_span::def_id::DefId;
-use rustc_span::{Symbol, sym};
 
 use super::CONFUSING_METHOD_TO_NUMERIC_CAST;
 
@@ -25,7 +26,6 @@ fn get_const_name_and_ty_name(
     method_def_id: DefId,
     generics: &[GenericArg<'_>],
 ) -> Option<(&'static str, &'static str)> {
-    let method_name = method_name.as_str();
     let diagnostic_name = cx.tcx.get_diagnostic_name(method_def_id);
 
     let ty_name = if diagnostic_name.is_some_and(|diag| diag == sym::cmp_ord_min || diag == sym::cmp_ord_max) {
@@ -39,14 +39,21 @@ fn get_const_name_and_ty_name(
         }
     } else if let Some(impl_id) = cx.tcx.impl_of_method(method_def_id)
         && let Some(ty_name) = get_primitive_ty_name(cx.tcx.type_of(impl_id).instantiate_identity())
-        && ["min", "max", "minimum", "maximum", "min_value", "max_value"].contains(&method_name)
+        && matches!(
+            method_name,
+            sym::min | sym::max | sym::minimum | sym::maximum | sym::min_value | sym::max_value
+        )
     {
         ty_name
     } else {
         return None;
     };
 
-    let const_name = if method_name.starts_with("max") { "MAX" } else { "MIN" };
+    let const_name = if matches!(method_name, sym::max | sym::maximum | sym::max_value) {
+        "MAX"
+    } else {
+        "MIN"
+    };
     Some((const_name, ty_name))
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs
index 2471c735551..c0c0a47f855 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs
@@ -1,12 +1,11 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::std_or_core;
 use clippy_utils::sugg::Sugg;
+use clippy_utils::{std_or_core, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, Mutability, QPath};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, Ty, TypeVisitableExt};
-use rustc_span::sym;
 
 use super::PTR_CAST_CONSTNESS;
 
@@ -78,9 +77,9 @@ pub(super) fn check_null_ptr_cast_method(cx: &LateContext<'_>, expr: &Expr<'_>)
         && let ExprKind::Call(func, []) = cast_expr.kind
         && let ExprKind::Path(QPath::Resolved(None, path)) = func.kind
         && let Some(defid) = path.res.opt_def_id()
-        && let method = match (cx.tcx.get_diagnostic_name(defid), method.ident.as_str()) {
-            (Some(sym::ptr_null), "cast_mut") => "null_mut",
-            (Some(sym::ptr_null_mut), "cast_const") => "null",
+        && let method = match (cx.tcx.get_diagnostic_name(defid), method.ident.name) {
+            (Some(sym::ptr_null), sym::cast_mut) => "null_mut",
+            (Some(sym::ptr_null_mut), sym::cast_const) => "null",
             _ => return,
         }
         && let Some(prefix) = std_or_core(cx)
diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
index 1d44c7e9c88..5c64216dd92 100644
--- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
@@ -3,14 +3,14 @@ use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::source::{IntoSpan, SpanRangeExt};
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::for_each_expr_without_closures;
-use clippy_utils::{LimitStack, get_async_fn_body, is_async_fn};
+use clippy_utils::{LimitStack, get_async_fn_body, is_async_fn, sym};
 use core::ops::ControlFlow;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Attribute, Body, Expr, ExprKind, FnDecl};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::impl_lint_pass;
+use rustc_span::Span;
 use rustc_span::def_id::LocalDefId;
-use rustc_span::{Span, sym};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -104,7 +104,7 @@ impl CognitiveComplexity {
                 FnKind::Closure => {
                     let header_span = body_span.with_hi(decl.output.span().lo());
                     #[expect(clippy::range_plus_one)]
-                    if let Some(range) = header_span.map_range(cx, |src, range| {
+                    if let Some(range) = header_span.map_range(cx, |_, src, range| {
                         let mut idxs = src.get(range.clone())?.match_indices('|');
                         Some(range.start + idxs.next()?.0..range.start + idxs.next()?.0 + 1)
                     }) {
@@ -157,9 +157,9 @@ impl<'tcx> LateLintPass<'tcx> for CognitiveComplexity {
     }
 
     fn check_attributes(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) {
-        self.limit.push_attrs(cx.sess(), attrs, "cognitive_complexity");
+        self.limit.push_attrs(cx.sess(), attrs, sym::cognitive_complexity);
     }
     fn check_attributes_post(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) {
-        self.limit.pop_attrs(cx.sess(), attrs, "cognitive_complexity");
+        self.limit.pop_attrs(cx.sess(), attrs, sym::cognitive_complexity);
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/comparison_chain.rs b/src/tools/clippy/clippy_lints/src/comparison_chain.rs
index 9c3009a86cd..238ebd4a444 100644
--- a/src/tools/clippy/clippy_lints/src/comparison_chain.rs
+++ b/src/tools/clippy/clippy_lints/src/comparison_chain.rs
@@ -75,11 +75,15 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain {
         }
 
         // Check that there exists at least one explicit else condition
-        let (conds, _) = if_sequence(expr);
+        let (conds, blocks) = if_sequence(expr);
         if conds.len() < 2 {
             return;
         }
 
+        if blocks.len() < 3 {
+            return;
+        }
+
         for cond in conds.windows(2) {
             if let (&ExprKind::Binary(ref kind1, lhs1, rhs1), &ExprKind::Binary(ref kind2, lhs2, rhs2)) =
                 (&cond[0].kind, &cond[1].kind)
@@ -125,6 +129,7 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain {
         let ExprKind::Binary(_, lhs, rhs) = conds[0].kind else {
             unreachable!();
         };
+
         let lhs = Sugg::hir(cx, lhs, "..").maybe_paren();
         let rhs = Sugg::hir(cx, rhs, "..").addr();
         span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs
index 42fbe6438d4..2467fc95fd0 100644
--- a/src/tools/clippy/clippy_lints/src/copies.rs
+++ b/src/tools/clippy/clippy_lints/src/copies.rs
@@ -1,5 +1,5 @@
 use clippy_config::Conf;
-use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then};
+use clippy_utils::diagnostics::{span_lint, span_lint_and_note, span_lint_and_then};
 use clippy_utils::source::{IntoSpan, SpanRangeExt, first_line_of_span, indent_of, reindent_multiline, snippet};
 use clippy_utils::ty::{InteriorMut, needs_ordered_drop};
 use clippy_utils::visitors::for_each_expr_without_closures;
@@ -258,7 +258,7 @@ fn lint_branches_sharing_code<'tcx>(
         let span = span.with_hi(last_block.span.hi());
         // Improve formatting if the inner block has indentation (i.e. normal Rust formatting)
         let span = span
-            .map_range(cx, |src, range| {
+            .map_range(cx, |_, src, range| {
                 (range.start > 4 && src.get(range.start - 4..range.start)? == "    ")
                     .then_some(range.start - 4..range.end)
             })
@@ -567,7 +567,7 @@ fn method_caller_is_mutable<'tcx>(
 
 /// Implementation of `IFS_SAME_COND`.
 fn lint_same_cond<'tcx>(cx: &LateContext<'tcx>, conds: &[&Expr<'_>], interior_mut: &mut InteriorMut<'tcx>) {
-    for (i, j) in search_same(
+    for group in search_same(
         conds,
         |e| hash_expr(cx, e),
         |lhs, rhs| {
@@ -584,14 +584,8 @@ fn lint_same_cond<'tcx>(cx: &LateContext<'tcx>, conds: &[&Expr<'_>], interior_mu
             }
         },
     ) {
-        span_lint_and_note(
-            cx,
-            IFS_SAME_COND,
-            j.span,
-            "this `if` has the same condition as a previous `if`",
-            Some(i.span),
-            "same as this",
-        );
+        let spans: Vec<_> = group.into_iter().map(|expr| expr.span).collect();
+        span_lint(cx, IFS_SAME_COND, spans, "these `if` branches have the same condition");
     }
 }
 
@@ -609,14 +603,13 @@ fn lint_same_fns_in_if_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>]) {
         SpanlessEq::new(cx).eq_expr(lhs, rhs)
     };
 
-    for (i, j) in search_same(conds, |e| hash_expr(cx, e), eq) {
-        span_lint_and_note(
+    for group in search_same(conds, |e| hash_expr(cx, e), eq) {
+        let spans: Vec<_> = group.into_iter().map(|expr| expr.span).collect();
+        span_lint(
             cx,
             SAME_FUNCTIONS_IN_IF_CONDITION,
-            j.span,
-            "this `if` has the same function call as a previous `if`",
-            Some(i.span),
-            "same as this",
+            spans,
+            "these `if` branches have the same function call",
         );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/dbg_macro.rs b/src/tools/clippy/clippy_lints/src/dbg_macro.rs
index 06376c57119..152516baf73 100644
--- a/src/tools/clippy/clippy_lints/src/dbg_macro.rs
+++ b/src/tools/clippy/clippy_lints/src/dbg_macro.rs
@@ -5,7 +5,7 @@ use clippy_utils::macros::{MacroCall, macro_backtrace};
 use clippy_utils::source::snippet_with_applicability;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, Node};
+use rustc_hir::{Closure, ClosureKind, CoroutineKind, Expr, ExprKind, LetStmt, LocalSource, Node, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::impl_lint_pass;
 use rustc_span::{Span, SyntaxContext, sym};
@@ -60,6 +60,8 @@ impl LateLintPass<'_> for DbgMacro {
         if cur_syntax_ctxt != self.prev_ctxt &&
             let Some(macro_call) = first_dbg_macro_in_expansion(cx, expr.span) &&
             !macro_call.span.in_external_macro(cx.sess().source_map()) &&
+            // avoids exprs generated by the desugaring of coroutines
+            !is_coroutine_desugar(expr) &&
             self.checked_dbg_call_site.insert(macro_call.span) &&
             // allows `dbg!` in test code if allow-dbg-in-test is set to true in clippy.toml
             !(self.allow_dbg_in_tests && is_in_test(cx.tcx, expr.hir_id))
@@ -73,50 +75,51 @@ impl LateLintPass<'_> for DbgMacro {
                 "the `dbg!` macro is intended as a debugging tool",
                 |diag| {
                     let mut applicability = Applicability::MachineApplicable;
-
-                    let (sugg_span, suggestion) = match expr.peel_drop_temps().kind {
-                        // dbg!()
-                        ExprKind::Block(..) => {
-                            // If the `dbg!` macro is a "free" statement and not contained within other expressions,
-                            // remove the whole statement.
-                            if let Node::Stmt(_) = cx.tcx.parent_hir_node(expr.hir_id)
-                                && let Some(semi_span) = cx.sess().source_map().mac_call_stmt_semi_span(macro_call.span)
-                            {
-                                (macro_call.span.to(semi_span), String::new())
-                            } else {
-                                (macro_call.span, String::from("()"))
-                            }
-                        },
-                        // dbg!(1)
-                        ExprKind::Match(val, ..) => (
-                            macro_call.span,
-                            snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability)
-                                .to_string(),
-                        ),
-                        // dbg!(2, 3)
-                        ExprKind::Tup(
-                            [
-                                Expr {
-                                    kind: ExprKind::Match(first, ..),
-                                    ..
-                                },
-                                ..,
-                                Expr {
-                                    kind: ExprKind::Match(last, ..),
-                                    ..
-                                },
-                            ],
-                        ) => {
-                            let snippet = snippet_with_applicability(
-                                cx,
-                                first.span.source_callsite().to(last.span.source_callsite()),
-                                "..",
-                                &mut applicability,
-                            );
-                            (macro_call.span, format!("({snippet})"))
-                        },
-                        _ => unreachable!(),
-                    };
+                    let (sugg_span, suggestion) =
+                        match is_async_move_desugar(expr).unwrap_or(expr).peel_drop_temps().kind {
+                            // dbg!()
+                            ExprKind::Block(..) => {
+                                // If the `dbg!` macro is a "free" statement and not contained within other expressions,
+                                // remove the whole statement.
+                                if let Node::Stmt(_) = cx.tcx.parent_hir_node(expr.hir_id)
+                                    && let Some(semi_span) =
+                                        cx.sess().source_map().mac_call_stmt_semi_span(macro_call.span)
+                                {
+                                    (macro_call.span.to(semi_span), String::new())
+                                } else {
+                                    (macro_call.span, String::from("()"))
+                                }
+                            },
+                            // dbg!(1)
+                            ExprKind::Match(val, ..) => (
+                                macro_call.span,
+                                snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability)
+                                    .to_string(),
+                            ),
+                            // dbg!(2, 3)
+                            ExprKind::Tup(
+                                [
+                                    Expr {
+                                        kind: ExprKind::Match(first, ..),
+                                        ..
+                                    },
+                                    ..,
+                                    Expr {
+                                        kind: ExprKind::Match(last, ..),
+                                        ..
+                                    },
+                                ],
+                            ) => {
+                                let snippet = snippet_with_applicability(
+                                    cx,
+                                    first.span.source_callsite().to(last.span.source_callsite()),
+                                    "..",
+                                    &mut applicability,
+                                );
+                                (macro_call.span, format!("({snippet})"))
+                            },
+                            _ => unreachable!(),
+                        };
 
                     diag.span_suggestion(
                         sugg_span,
@@ -134,6 +137,35 @@ impl LateLintPass<'_> for DbgMacro {
     }
 }
 
+fn is_coroutine_desugar(expr: &Expr<'_>) -> bool {
+    matches!(
+        expr.kind,
+        ExprKind::Closure(Closure {
+            kind: ClosureKind::Coroutine(CoroutineKind::Desugared(..)) | ClosureKind::CoroutineClosure(..),
+            ..
+        })
+    )
+}
+
+fn is_async_move_desugar<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
+    if let ExprKind::Block(block, _) = expr.kind
+        && let [
+            Stmt {
+                kind:
+                    StmtKind::Let(LetStmt {
+                        source: LocalSource::AsyncFn,
+                        ..
+                    }),
+                ..
+            },
+        ] = block.stmts
+    {
+        return block.expr;
+    }
+
+    None
+}
+
 fn first_dbg_macro_in_expansion(cx: &LateContext<'_>, span: Span) -> Option<MacroCall> {
     macro_backtrace(span).find(|mc| cx.tcx.is_diagnostic_item(sym::dbg_macro, mc.def_id))
 }
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index bb825c7655f..5fcb851dfeb 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -764,6 +764,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::unwrap_in_result::UNWRAP_IN_RESULT_INFO,
     crate::upper_case_acronyms::UPPER_CASE_ACRONYMS_INFO,
     crate::use_self::USE_SELF_INFO,
+    crate::useless_concat::USELESS_CONCAT_INFO,
     crate::useless_conversion::USELESS_CONVERSION_INFO,
     crate::vec::USELESS_VEC_INFO,
     crate::vec_init_then_push::VEC_INIT_THEN_PUSH_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
index 94651538669..5204f73ea0a 100644
--- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
@@ -14,36 +14,36 @@ macro_rules! declare_with_version {
 
 #[rustfmt::skip]
 declare_with_version! { DEPRECATED(DEPRECATED_VERSION) = [
-    #[clippy::version = "pre 1.29.0"]
-    ("clippy::should_assert_eq", "`assert!(a == b)` can now print the values the same way `assert_eq!(a, b) can"),
+    #[clippy::version = "1.30.0"]
+    ("clippy::assign_ops", "compound operators are harmless and linting on them is not in scope for clippy"),
     #[clippy::version = "pre 1.29.0"]
     ("clippy::extend_from_slice", "`Vec::extend_from_slice` is no longer faster than `Vec::extend` due to specialization"),
+    #[clippy::version = "1.86.0"]
+    ("clippy::match_on_vec_items", "`clippy::indexing_slicing` covers indexing and slicing on `Vec<_>`"),
+    #[clippy::version = "pre 1.29.0"]
+    ("clippy::misaligned_transmute", "split into `clippy::cast_ptr_alignment` and `clippy::transmute_ptr_to_ptr`"),
+    #[clippy::version = "1.86.0"]
+    ("clippy::option_map_or_err_ok", "`clippy::manual_ok_or` covers this case"),
+    #[clippy::version = "1.54.0"]
+    ("clippy::pub_enum_variant_names", "`clippy::enum_variant_names` now covers this case via the `avoid-breaking-exported-api` config"),
     #[clippy::version = "pre 1.29.0"]
     ("clippy::range_step_by_zero", "`Iterator::step_by(0)` now panics and is no longer an infinite iterator"),
+    #[clippy::version = "1.47.0"]
+    ("clippy::regex_macro", "the `regex!` macro was removed from the regex crate in 2018"),
+    #[clippy::version = "1.44.0"]
+    ("clippy::replace_consts", "`min_value` and `max_value` are now deprecated"),
     #[clippy::version = "pre 1.29.0"]
-    ("clippy::unstable_as_slice", "`Vec::as_slice` is now stable"),
+    ("clippy::should_assert_eq", "`assert!(a == b)` can now print the values the same way `assert_eq!(a, b) can"),
     #[clippy::version = "pre 1.29.0"]
-    ("clippy::unstable_as_mut_slice", "`Vec::as_mut_slice` is now stable"),
+    ("clippy::unsafe_vector_initialization", "the suggested alternative could be substantially slower"),
     #[clippy::version = "pre 1.29.0"]
-    ("clippy::misaligned_transmute", "split into `clippy::cast_ptr_alignment` and `clippy::transmute_ptr_to_ptr`"),
-    #[clippy::version = "1.30.0"]
-    ("clippy::assign_ops", "compound operators are harmless and linting on them is not in scope for clippy"),
+    ("clippy::unstable_as_mut_slice", "`Vec::as_mut_slice` is now stable"),
     #[clippy::version = "pre 1.29.0"]
-    ("clippy::unsafe_vector_initialization", "the suggested alternative could be substantially slower"),
+    ("clippy::unstable_as_slice", "`Vec::as_slice` is now stable"),
     #[clippy::version = "1.39.0"]
     ("clippy::unused_collect", "`Iterator::collect` is now marked as `#[must_use]`"),
-    #[clippy::version = "1.44.0"]
-    ("clippy::replace_consts", "`min_value` and `max_value` are now deprecated"),
-    #[clippy::version = "1.47.0"]
-    ("clippy::regex_macro", "the `regex!` macro was removed from the regex crate in 2018"),
-    #[clippy::version = "1.54.0"]
-    ("clippy::pub_enum_variant_names", "`clippy::enum_variant_names` now covers this case via the `avoid-breaking-exported-api` config"),
     #[clippy::version = "1.54.0"]
     ("clippy::wrong_pub_self_convention", "`clippy::wrong_self_convention` now covers this case via the `avoid-breaking-exported-api` config"),
-    #[clippy::version = "1.86.0"]
-    ("clippy::option_map_or_err_ok", "`clippy::manual_ok_or` covers this case"),
-    #[clippy::version = "1.86.0"]
-    ("clippy::match_on_vec_items", "`clippy::indexing_slicing` covers indexing and slicing on `Vec<_>`"),
 ]}
 
 #[rustfmt::skip]
@@ -61,6 +61,12 @@ declare_with_version! { RENAMED(RENAMED_VERSION) = [
     #[clippy::version = ""]
     ("clippy::box_vec", "clippy::box_collection"),
     #[clippy::version = ""]
+    ("clippy::cast_ref_to_mut", "invalid_reference_casting"),
+    #[clippy::version = ""]
+    ("clippy::clone_double_ref", "suspicious_double_ref_op"),
+    #[clippy::version = ""]
+    ("clippy::cmp_nan", "invalid_nan_comparisons"),
+    #[clippy::version = ""]
     ("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes"),
     #[clippy::version = ""]
     ("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"),
@@ -70,15 +76,35 @@ declare_with_version! { RENAMED(RENAMED_VERSION) = [
     ("clippy::disallowed_method", "clippy::disallowed_methods"),
     #[clippy::version = ""]
     ("clippy::disallowed_type", "clippy::disallowed_types"),
+    #[clippy::version = "1.86.0"]
+    ("clippy::double_neg", "double_negations"),
+    #[clippy::version = ""]
+    ("clippy::drop_bounds", "drop_bounds"),
+    #[clippy::version = ""]
+    ("clippy::drop_copy", "dropping_copy_types"),
+    #[clippy::version = ""]
+    ("clippy::drop_ref", "dropping_references"),
     #[clippy::version = ""]
     ("clippy::eval_order_dependence", "clippy::mixed_read_write_in_expression"),
-    #[clippy::version = "1.51.0"]
-    ("clippy::find_map", "clippy::manual_find_map"),
     #[clippy::version = "1.53.0"]
     ("clippy::filter_map", "clippy::manual_filter_map"),
+    #[clippy::version = "1.51.0"]
+    ("clippy::find_map", "clippy::manual_find_map"),
     #[clippy::version = ""]
     ("clippy::fn_address_comparisons", "unpredictable_function_pointer_comparisons"),
     #[clippy::version = ""]
+    ("clippy::fn_null_check", "useless_ptr_null_checks"),
+    #[clippy::version = ""]
+    ("clippy::for_loop_over_option", "for_loops_over_fallibles"),
+    #[clippy::version = ""]
+    ("clippy::for_loop_over_result", "for_loops_over_fallibles"),
+    #[clippy::version = ""]
+    ("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"),
+    #[clippy::version = ""]
+    ("clippy::forget_copy", "forgetting_copy_types"),
+    #[clippy::version = ""]
+    ("clippy::forget_ref", "forgetting_references"),
+    #[clippy::version = ""]
     ("clippy::identity_conversion", "clippy::useless_conversion"),
     #[clippy::version = "pre 1.29.0"]
     ("clippy::if_let_redundant_pattern_matching", "clippy::redundant_pattern_matching"),
@@ -91,7 +117,25 @@ declare_with_version! { RENAMED(RENAMED_VERSION) = [
     #[clippy::version = ""]
     ("clippy::integer_arithmetic", "clippy::arithmetic_side_effects"),
     #[clippy::version = ""]
+    ("clippy::into_iter_on_array", "array_into_iter"),
+    #[clippy::version = ""]
+    ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"),
+    #[clippy::version = "CURRENT_RUSTC_VERSION"]
+    ("clippy::invalid_null_ptr_usage", "invalid_null_arguments"),
+    #[clippy::version = ""]
+    ("clippy::invalid_ref", "invalid_value"),
+    #[clippy::version = ""]
+    ("clippy::invalid_utf8_in_unchecked", "invalid_from_utf8_unchecked"),
+    #[clippy::version = ""]
+    ("clippy::let_underscore_drop", "let_underscore_drop"),
+    #[clippy::version = ""]
     ("clippy::logic_bug", "clippy::overly_complex_bool_expr"),
+    #[clippy::version = "1.80.0"]
+    ("clippy::maybe_misused_cfg", "unexpected_cfgs"),
+    #[clippy::version = ""]
+    ("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums"),
+    #[clippy::version = "1.80.0"]
+    ("clippy::mismatched_target_os", "unexpected_cfgs"),
     #[clippy::version = ""]
     ("clippy::new_without_default_derive", "clippy::new_without_default"),
     #[clippy::version = ""]
@@ -107,6 +151,10 @@ declare_with_version! { RENAMED(RENAMED_VERSION) = [
     #[clippy::version = ""]
     ("clippy::overflow_check_conditional", "clippy::panicking_overflow_checks"),
     #[clippy::version = ""]
+    ("clippy::panic_params", "non_fmt_panics"),
+    #[clippy::version = ""]
+    ("clippy::positional_named_format_parameters", "named_arguments_used_positionally"),
+    #[clippy::version = ""]
     ("clippy::ref_in_deref", "clippy::needless_borrow"),
     #[clippy::version = ""]
     ("clippy::result_expect_used", "clippy::expect_used"),
@@ -115,67 +163,25 @@ declare_with_version! { RENAMED(RENAMED_VERSION) = [
     #[clippy::version = ""]
     ("clippy::result_unwrap_used", "clippy::unwrap_used"),
     #[clippy::version = ""]
+    ("clippy::reverse_range_loop", "clippy::reversed_empty_ranges"),
+    #[clippy::version = ""]
     ("clippy::single_char_push_str", "clippy::single_char_add_str"),
     #[clippy::version = ""]
     ("clippy::stutter", "clippy::module_name_repetitions"),
     #[clippy::version = ""]
+    ("clippy::temporary_cstring_as_ptr", "dangling_pointers_from_temporaries"),
+    #[clippy::version = ""]
     ("clippy::thread_local_initializer_can_be_made_const", "clippy::missing_const_for_thread_local"),
     #[clippy::version = ""]
     ("clippy::to_string_in_display", "clippy::recursive_format_impl"),
-    #[clippy::version = ""]
-    ("clippy::unwrap_or_else_default", "clippy::unwrap_or_default"),
-    #[clippy::version = ""]
-    ("clippy::zero_width_space", "clippy::invisible_characters"),
-    #[clippy::version = ""]
-    ("clippy::cast_ref_to_mut", "invalid_reference_casting"),
-    #[clippy::version = ""]
-    ("clippy::clone_double_ref", "suspicious_double_ref_op"),
-    #[clippy::version = ""]
-    ("clippy::cmp_nan", "invalid_nan_comparisons"),
-    #[clippy::version = "CURRENT_RUSTC_VERSION"]
-    ("clippy::invalid_null_ptr_usage", "invalid_null_arguments"),
-    #[clippy::version = "1.86.0"]
-    ("clippy::double_neg", "double_negations"),
-    #[clippy::version = ""]
-    ("clippy::drop_bounds", "drop_bounds"),
-    #[clippy::version = ""]
-    ("clippy::drop_copy", "dropping_copy_types"),
-    #[clippy::version = ""]
-    ("clippy::drop_ref", "dropping_references"),
-    #[clippy::version = ""]
-    ("clippy::fn_null_check", "useless_ptr_null_checks"),
-    #[clippy::version = ""]
-    ("clippy::for_loop_over_option", "for_loops_over_fallibles"),
-    #[clippy::version = ""]
-    ("clippy::for_loop_over_result", "for_loops_over_fallibles"),
-    #[clippy::version = ""]
-    ("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"),
-    #[clippy::version = ""]
-    ("clippy::forget_copy", "forgetting_copy_types"),
-    #[clippy::version = ""]
-    ("clippy::forget_ref", "forgetting_references"),
-    #[clippy::version = ""]
-    ("clippy::into_iter_on_array", "array_into_iter"),
-    #[clippy::version = ""]
-    ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"),
-    #[clippy::version = ""]
-    ("clippy::invalid_ref", "invalid_value"),
-    #[clippy::version = ""]
-    ("clippy::invalid_utf8_in_unchecked", "invalid_from_utf8_unchecked"),
-    #[clippy::version = ""]
-    ("clippy::let_underscore_drop", "let_underscore_drop"),
-    #[clippy::version = "1.80.0"]
-    ("clippy::maybe_misused_cfg", "unexpected_cfgs"),
-    #[clippy::version = ""]
-    ("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums"),
-    #[clippy::version = "1.80.0"]
-    ("clippy::mismatched_target_os", "unexpected_cfgs"),
-    #[clippy::version = ""]
-    ("clippy::panic_params", "non_fmt_panics"),
-    #[clippy::version = ""]
-    ("clippy::positional_named_format_parameters", "named_arguments_used_positionally"),
-    #[clippy::version = ""]
-    ("clippy::temporary_cstring_as_ptr", "dangling_pointers_from_temporaries"),
+    #[clippy::version = "1.88.0"]
+    ("clippy::transmute_float_to_int", "unnecessary_transmutes"),
+    #[clippy::version = "1.88.0"]
+    ("clippy::transmute_int_to_char", "unnecessary_transmutes"),
+    #[clippy::version = "1.88.0"]
+    ("clippy::transmute_int_to_float", "unnecessary_transmutes"),
+    #[clippy::version = "1.88.0"]
+    ("clippy::transmute_num_to_bytes", "unnecessary_transmutes"),
     #[clippy::version = ""]
     ("clippy::undropped_manually_drops", "undropped_manually_drops"),
     #[clippy::version = ""]
@@ -183,15 +189,9 @@ declare_with_version! { RENAMED(RENAMED_VERSION) = [
     #[clippy::version = ""]
     ("clippy::unused_label", "unused_labels"),
     #[clippy::version = ""]
+    ("clippy::unwrap_or_else_default", "clippy::unwrap_or_default"),
+    #[clippy::version = ""]
     ("clippy::vtable_address_comparisons", "ambiguous_wide_pointer_comparisons"),
     #[clippy::version = ""]
-    ("clippy::reverse_range_loop", "clippy::reversed_empty_ranges"),
-    #[clippy::version = "1.88.0"]
-    ("clippy::transmute_int_to_float", "unnecessary_transmutes"),
-    #[clippy::version = "1.88.0"]
-    ("clippy::transmute_int_to_char", "unnecessary_transmutes"),
-    #[clippy::version = "1.88.0"]
-    ("clippy::transmute_float_to_int", "unnecessary_transmutes"),
-    #[clippy::version = "1.88.0"]
-    ("clippy::transmute_num_to_bytes", "unnecessary_transmutes"),
+    ("clippy::zero_width_space", "clippy::invisible_characters"),
 ]}
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 5edb5c23570..cde9528cd87 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -22,6 +22,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypeckResults};
 use rustc_session::impl_lint_pass;
 use rustc_span::symbol::sym;
 use rustc_span::{Span, Symbol};
+use std::borrow::Cow;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -252,13 +253,14 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
         }
 
         let typeck = cx.typeck_results();
-        let Some((kind, sub_expr)) = try_parse_ref_op(cx.tcx, typeck, expr) else {
+        let Some((kind, sub_expr, skip_expr)) = try_parse_ref_op(cx.tcx, typeck, expr) else {
             // The whole chain of reference operations has been seen
             if let Some((state, data)) = self.state.take() {
                 report(cx, expr, state, data, typeck);
             }
             return;
         };
+        self.skip_expr = skip_expr;
 
         match (self.state.take(), kind) {
             (None, kind) => {
@@ -303,7 +305,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                     RefOp::Method { mutbl, is_ufcs }
                         if !is_lint_allowed(cx, EXPLICIT_DEREF_METHODS, expr.hir_id)
                             // Allow explicit deref in method chains. e.g. `foo.deref().bar()`
-                            && (is_ufcs || !in_postfix_position(cx, expr)) =>
+                            && (is_ufcs || !is_in_method_chain(cx, expr)) =>
                     {
                         let ty_changed_count = usize::from(!deref_method_same_type(expr_ty, typeck.expr_ty(sub_expr)));
                         self.state = Some((
@@ -671,42 +673,38 @@ fn try_parse_ref_op<'tcx>(
     tcx: TyCtxt<'tcx>,
     typeck: &'tcx TypeckResults<'_>,
     expr: &'tcx Expr<'_>,
-) -> Option<(RefOp, &'tcx Expr<'tcx>)> {
-    let (is_ufcs, def_id, arg) = match expr.kind {
-        ExprKind::MethodCall(_, arg, [], _) => (false, typeck.type_dependent_def_id(expr.hir_id)?, arg),
+) -> Option<(RefOp, &'tcx Expr<'tcx>, Option<HirId>)> {
+    let (call_path_id, def_id, arg) = match expr.kind {
+        ExprKind::MethodCall(_, arg, [], _) => (None, typeck.type_dependent_def_id(expr.hir_id)?, arg),
         ExprKind::Call(
-            Expr {
-                kind: ExprKind::Path(path),
+            &Expr {
+                kind: ExprKind::Path(QPath::Resolved(None, path)),
                 hir_id,
                 ..
             },
             [arg],
-        ) => (true, typeck.qpath_res(path, *hir_id).opt_def_id()?, arg),
+        ) => (Some(hir_id), path.res.opt_def_id()?, arg),
         ExprKind::Unary(UnOp::Deref, sub_expr) if !typeck.expr_ty(sub_expr).is_raw_ptr() => {
-            return Some((RefOp::Deref, sub_expr));
+            return Some((RefOp::Deref, sub_expr, None));
+        },
+        ExprKind::AddrOf(BorrowKind::Ref, mutability, sub_expr) => {
+            return Some((RefOp::AddrOf(mutability), sub_expr, None));
         },
-        ExprKind::AddrOf(BorrowKind::Ref, mutability, sub_expr) => return Some((RefOp::AddrOf(mutability), sub_expr)),
         _ => return None,
     };
-    if tcx.is_diagnostic_item(sym::deref_method, def_id) {
-        Some((
-            RefOp::Method {
-                mutbl: Mutability::Not,
-                is_ufcs,
-            },
-            arg,
-        ))
-    } else if tcx.trait_of_item(def_id)? == tcx.lang_items().deref_mut_trait()? {
-        Some((
-            RefOp::Method {
-                mutbl: Mutability::Mut,
-                is_ufcs,
-            },
-            arg,
-        ))
-    } else {
-        None
-    }
+    let mutbl = match tcx.get_diagnostic_name(def_id) {
+        Some(sym::deref_method) => Mutability::Not,
+        Some(sym::deref_mut_method) => Mutability::Mut,
+        _ => return None,
+    };
+    Some((
+        RefOp::Method {
+            mutbl,
+            is_ufcs: call_path_id.is_some(),
+        },
+        arg,
+        call_path_id,
+    ))
 }
 
 // Checks if the adjustments contains a deref of `ManuallyDrop<_>`
@@ -730,7 +728,13 @@ fn deref_method_same_type<'tcx>(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool {
     }
 }
 
-fn in_postfix_position<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> bool {
+fn is_in_method_chain<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> bool {
+    if let ExprKind::MethodCall(_, recv, _, _) = e.kind
+        && matches!(recv.kind, ExprKind::MethodCall(..))
+    {
+        return true;
+    }
+
     if let Some(parent) = get_parent_expr(cx, e)
         && parent.span.eq_ctxt(e.span)
     {
@@ -944,7 +948,7 @@ fn report<'tcx>(
             mutbl,
         } => {
             let mut app = Applicability::MachineApplicable;
-            let (expr_str, _expr_is_macro_call) =
+            let (expr_str, expr_is_macro_call) =
                 snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app);
             let ty = typeck.expr_ty(expr);
             let (_, ref_count) = peel_middle_ty_refs(ty);
@@ -968,20 +972,11 @@ fn report<'tcx>(
                 "&"
             };
 
-            // expr_str (the suggestion) is never shown if is_final_ufcs is true, since it's
-            // `expr.kind == ExprKind::Call`. Therefore, this is, afaik, always unnecessary.
-            /*
-            expr_str = if !expr_is_macro_call && is_final_ufcs && expr.precedence() < ExprPrecedence::Prefix {
+            let expr_str = if !expr_is_macro_call && is_ufcs && expr.precedence() < ExprPrecedence::Prefix {
                 Cow::Owned(format!("({expr_str})"))
             } else {
                 expr_str
             };
-            */
-
-            // Fix #10850, do not lint if it's `Foo::deref` instead of `foo.deref()`.
-            if is_ufcs {
-                return;
-            }
 
             span_lint_and_sugg(
                 cx,
@@ -997,6 +992,15 @@ fn report<'tcx>(
             );
         },
         State::DerefedBorrow(state) => {
+            // Do not suggest removing a non-mandatory `&` in `&*rawptr` in an `unsafe` context,
+            // as this may make rustc trigger its `dangerous_implicit_autorefs` lint.
+            if let ExprKind::AddrOf(BorrowKind::Ref, _, subexpr) = data.first_expr.kind
+                && let ExprKind::Unary(UnOp::Deref, subsubexpr) = subexpr.kind
+                && cx.typeck_results().expr_ty_adjusted(subsubexpr).is_raw_ptr()
+            {
+                return;
+            }
+
             let mut app = Applicability::MachineApplicable;
             let (snip, snip_is_macro) =
                 snippet_with_context(cx, expr.span, data.first_expr.span.ctxt(), "..", &mut app);
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 3443b36eb4f..062f7cef3a7 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -345,7 +345,7 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &h
     if ty_adt.repr().packed()
         && ty_subs
             .iter()
-            .any(|arg| matches!(arg.unpack(), GenericArgKind::Type(_) | GenericArgKind::Const(_)))
+            .any(|arg| matches!(arg.kind(), GenericArgKind::Type(_) | GenericArgKind::Const(_)))
     {
         return;
     }
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_types.rs b/src/tools/clippy/clippy_lints/src/disallowed_types.rs
index d0b2f0c8407..821bb25d2ce 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_types.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_types.rs
@@ -106,8 +106,8 @@ impl_lint_pass!(DisallowedTypes => [DISALLOWED_TYPES]);
 impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
         if let ItemKind::Use(path, UseKind::Single(_)) = &item.kind {
-            for res in &path.res {
-                self.check_res_emit(cx, res, item.span);
+            if let Some(res) = path.res.type_ns {
+                self.check_res_emit(cx, &res, item.span);
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs b/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs
index 8aeb835fe39..cb9d68224db 100644
--- a/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs
@@ -2,11 +2,10 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use itertools::Itertools;
 use rustc_errors::Applicability;
 use rustc_lint::LateContext;
-use rustc_span::{BytePos, Span};
-use std::cmp::Ordering;
+use rustc_span::BytePos;
 use std::ops::Range;
 
-use super::{DOC_LAZY_CONTINUATION, DOC_OVERINDENTED_LIST_ITEMS};
+use super::{DOC_LAZY_CONTINUATION, DOC_OVERINDENTED_LIST_ITEMS, Fragments};
 
 fn map_container_to_text(c: &super::Container) -> &'static str {
     match c {
@@ -19,29 +18,27 @@ fn map_container_to_text(c: &super::Container) -> &'static str {
 pub(super) fn check(
     cx: &LateContext<'_>,
     doc: &str,
-    range: Range<usize>,
-    mut span: Span,
+    cooked_range: Range<usize>,
+    fragments: &Fragments<'_>,
     containers: &[super::Container],
 ) {
-    if doc[range.clone()].contains('\t') {
-        // We don't do tab stops correctly.
-        return;
-    }
-
-    // Blockquote
-    let ccount = doc[range.clone()].chars().filter(|c| *c == '>').count();
+    // Get blockquotes
+    let ccount = doc[cooked_range.clone()].chars().filter(|c| *c == '>').count();
     let blockquote_level = containers
         .iter()
         .filter(|c| matches!(c, super::Container::Blockquote))
         .count();
-    if ccount < blockquote_level {
+
+    if ccount < blockquote_level
+        && let Some(mut span) = fragments.span(cx, cooked_range.clone())
+    {
         span_lint_and_then(
             cx,
             DOC_LAZY_CONTINUATION,
             span,
             "doc quote line without `>` marker",
             |diag| {
-                let mut doc_start_range = &doc[range];
+                let mut doc_start_range = &doc[cooked_range];
                 let mut suggested = String::new();
                 for c in containers {
                     let text = map_container_to_text(c);
@@ -78,7 +75,7 @@ pub(super) fn check(
     }
 
     // List
-    let leading_spaces = doc[range].chars().filter(|c| *c == ' ').count();
+    let leading_spaces = doc[cooked_range.clone()].chars().filter(|c| *c == ' ').count();
     let list_indentation = containers
         .iter()
         .map(|c| {
@@ -89,36 +86,41 @@ pub(super) fn check(
             }
         })
         .sum();
-    match leading_spaces.cmp(&list_indentation) {
-        Ordering::Less => span_lint_and_then(
-            cx,
-            DOC_LAZY_CONTINUATION,
-            span,
-            "doc list item without indentation",
-            |diag| {
-                // simpler suggestion style for indentation
-                let indent = list_indentation - leading_spaces;
-                diag.span_suggestion_verbose(
-                    span.shrink_to_hi(),
-                    "indent this line",
-                    std::iter::repeat_n(" ", indent).join(""),
-                    Applicability::MaybeIncorrect,
-                );
-                diag.help("if this is supposed to be its own paragraph, add a blank line");
-            },
-        ),
-        Ordering::Greater => {
-            let sugg = std::iter::repeat_n(" ", list_indentation).join("");
-            span_lint_and_sugg(
+
+    if leading_spaces != list_indentation
+        && let Some(span) = fragments.span(cx, cooked_range.clone())
+    {
+        if leading_spaces < list_indentation {
+            span_lint_and_then(
                 cx,
-                DOC_OVERINDENTED_LIST_ITEMS,
+                DOC_LAZY_CONTINUATION,
                 span,
-                "doc list item overindented",
-                format!("try using `{sugg}` ({list_indentation} spaces)"),
-                sugg,
-                Applicability::MaybeIncorrect,
+                "doc list item without indentation",
+                |diag| {
+                    // simpler suggestion style for indentation
+                    let indent = list_indentation - leading_spaces;
+                    diag.span_suggestion_verbose(
+                        span.shrink_to_hi(),
+                        "indent this line",
+                        std::iter::repeat_n(" ", indent).join(""),
+                        Applicability::MaybeIncorrect,
+                    );
+                    diag.help("if this is supposed to be its own paragraph, add a blank line");
+                },
             );
-        },
-        Ordering::Equal => {},
+
+            return;
+        }
+
+        let sugg = std::iter::repeat_n(" ", list_indentation).join("");
+        span_lint_and_sugg(
+            cx,
+            DOC_OVERINDENTED_LIST_ITEMS,
+            span,
+            "doc list item overindented",
+            format!("try using `{sugg}` ({list_indentation} spaces)"),
+            sugg,
+            Applicability::MaybeIncorrect,
+        );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/doc/markdown.rs b/src/tools/clippy/clippy_lints/src/doc/markdown.rs
index 7a1c7c675d2..69c3b9150c3 100644
--- a/src/tools/clippy/clippy_lints/src/doc/markdown.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/markdown.rs
@@ -6,13 +6,15 @@ use rustc_lint::LateContext;
 use rustc_span::{BytePos, Pos, Span};
 use url::Url;
 
-use crate::doc::DOC_MARKDOWN;
+use crate::doc::{DOC_MARKDOWN, Fragments};
+use std::ops::Range;
 
 pub fn check(
     cx: &LateContext<'_>,
     valid_idents: &FxHashSet<String>,
     text: &str,
-    span: Span,
+    fragments: &Fragments<'_>,
+    fragment_range: Range<usize>,
     code_level: isize,
     blockquote_level: isize,
 ) {
@@ -64,20 +66,31 @@ pub fn check(
             close_parens += 1;
         }
 
+        // We'll use this offset to calculate the span to lint.
+        let fragment_offset = word.as_ptr() as usize - text.as_ptr() as usize;
+
         // Adjust for the current word
-        let offset = word.as_ptr() as usize - text.as_ptr() as usize;
-        let span = Span::new(
-            span.lo() + BytePos::from_usize(offset),
-            span.lo() + BytePos::from_usize(offset + word.len()),
-            span.ctxt(),
-            span.parent(),
+        check_word(
+            cx,
+            word,
+            fragments,
+            &fragment_range,
+            fragment_offset,
+            code_level,
+            blockquote_level,
         );
-
-        check_word(cx, word, span, code_level, blockquote_level);
     }
 }
 
-fn check_word(cx: &LateContext<'_>, word: &str, span: Span, code_level: isize, blockquote_level: isize) {
+fn check_word(
+    cx: &LateContext<'_>,
+    word: &str,
+    fragments: &Fragments<'_>,
+    range: &Range<usize>,
+    fragment_offset: usize,
+    code_level: isize,
+    blockquote_level: isize,
+) {
     /// Checks if a string is upper-camel-case, i.e., starts with an uppercase and
     /// contains at least two uppercase letters (`Clippy` is ok) and one lower-case
     /// letter (`NASA` is ok).
@@ -117,6 +130,16 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span, code_level: isize, b
         // try to get around the fact that `foo::bar` parses as a valid URL
         && !url.cannot_be_a_base()
     {
+        let Some(fragment_span) = fragments.span(cx, range.clone()) else {
+            return;
+        };
+        let span = Span::new(
+            fragment_span.lo() + BytePos::from_usize(fragment_offset),
+            fragment_span.lo() + BytePos::from_usize(fragment_offset + word.len()),
+            fragment_span.ctxt(),
+            fragment_span.parent(),
+        );
+
         span_lint_and_sugg(
             cx,
             DOC_MARKDOWN,
@@ -137,6 +160,17 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span, code_level: isize, b
     }
 
     if has_underscore(word) || word.contains("::") || is_camel_case(word) || word.ends_with("()") {
+        let Some(fragment_span) = fragments.span(cx, range.clone()) else {
+            return;
+        };
+
+        let span = Span::new(
+            fragment_span.lo() + BytePos::from_usize(fragment_offset),
+            fragment_span.lo() + BytePos::from_usize(fragment_offset + word.len()),
+            fragment_span.ctxt(),
+            fragment_span.parent(),
+        );
+
         span_lint_and_then(
             cx,
             DOC_MARKDOWN,
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 039937e0207..9ee32fced8c 100644
--- a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
@@ -113,7 +113,8 @@ fn find_panic(cx: &LateContext<'_>, body_id: BodyId) -> Option<Span> {
         }
 
         // check for `unwrap` and `expect` for both `Option` and `Result`
-        if let Some(arglists) = method_chain_args(expr, &["unwrap"]).or_else(|| method_chain_args(expr, &["expect"]))
+        if let Some(arglists) =
+            method_chain_args(expr, &[sym::unwrap]).or_else(|| method_chain_args(expr, &[sym::expect]))
             && let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs()
             && matches!(
                 get_type_diagnostic_name(cx, receiver_ty),
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index 87da380e954..c46dd09d60c 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -3,7 +3,6 @@
 use clippy_config::Conf;
 use clippy_utils::attrs::is_doc_hidden;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_then};
-use clippy_utils::source::snippet_opt;
 use clippy_utils::{is_entrypoint_fn, is_trait_impl_item};
 use pulldown_cmark::Event::{
     Code, DisplayMath, End, FootnoteReference, HardBreak, Html, InlineHtml, InlineMath, Rule, SoftBreak, Start,
@@ -730,7 +729,10 @@ struct Fragments<'a> {
 }
 
 impl Fragments<'_> {
-    fn span(self, cx: &LateContext<'_>, range: Range<usize>) -> Option<Span> {
+    /// get the span for the markdown range. Note that this function is not cheap, use it with
+    /// caution.
+    #[must_use]
+    fn span(&self, cx: &LateContext<'_>, range: Range<usize>) -> Option<Span> {
         source_span_for_markdown_range(cx.tcx, self.doc, &range, self.fragments)
     }
 }
@@ -1068,9 +1070,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                     );
                 } else {
                     for (text, range, assoc_code_level) in text_to_check {
-                        if let Some(span) = fragments.span(cx, range) {
-                            markdown::check(cx, valid_idents, &text, span, assoc_code_level, blockquote_level);
-                        }
+                        markdown::check(cx, valid_idents, &text, &fragments, range, assoc_code_level, blockquote_level);
                     }
                 }
                 text_to_check = Vec::new();
@@ -1081,26 +1081,27 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
             | TaskListMarker(_) | Code(_) | Rule | InlineMath(..) | DisplayMath(..) => (),
             SoftBreak | HardBreak => {
                 if !containers.is_empty()
-                    && let Some((next_event, next_range)) = events.peek()
-                    && let Some(next_span) = fragments.span(cx, next_range.clone())
-                    && let Some(span) = fragments.span(cx, range.clone())
                     && !in_footnote_definition
+                    // Tabs aren't handled correctly vvvv
+                    && !doc[range.clone()].contains('\t')
+                    && let Some((next_event, next_range)) = events.peek()
                     && !matches!(next_event, End(_))
                 {
                     lazy_continuation::check(
                         cx,
                         doc,
                         range.end..next_range.start,
-                        Span::new(span.hi(), next_span.lo(), span.ctxt(), span.parent()),
+                        &fragments,
                         &containers[..],
                     );
                 }
 
-                if let Some(span) = fragments.span(cx, range.clone())
+
+                if event == HardBreak
+                    && !doc[range.clone()].trim().starts_with('\\')
+                    && let Some(span) = fragments.span(cx, range.clone())
                     && !span.from_expansion()
-                    && let Some(snippet) = snippet_opt(cx, span)
-                    && !snippet.trim().starts_with('\\')
-                    && event == HardBreak {
+                    {
                     collected_breaks.push(span);
                 }
             },
diff --git a/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs b/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs
index a38d6df89f2..4414aebbf9a 100644
--- a/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs
@@ -92,7 +92,8 @@ impl_lint_pass!(EmptyWithBrackets => [EMPTY_STRUCTS_WITH_BRACKETS, EMPTY_ENUM_VA
 
 impl LateLintPass<'_> for EmptyWithBrackets {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
-        if let ItemKind::Struct(ident, var_data, _) = &item.kind
+        if let ItemKind::Struct(ident, _, var_data) = &item.kind
+            && !item.span.from_expansion()
             && has_brackets(var_data)
             && let span_after_ident = item.span.with_lo(ident.span.hi())
             && has_no_fields(cx, var_data, span_after_ident)
diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs
index ec81294624e..098571a5351 100644
--- a/src/tools/clippy/clippy_lints/src/enum_clike.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs
@@ -38,7 +38,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
         if cx.tcx.data_layout.pointer_size.bits() != 64 {
             return;
         }
-        if let ItemKind::Enum(_, def, _) = &item.kind {
+        if let ItemKind::Enum(_, _, def) = &item.kind {
             for var in def.variants {
                 if let Some(anon_const) = &var.disr_expr {
                     let def_id = cx.tcx.hir_body_owner_def_id(anon_const.body);
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 645f9306849..6ed7c87915b 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -306,7 +306,7 @@ fn has_late_bound_to_non_late_bound_regions(from_sig: FnSig<'_>, to_sig: FnSig<'
             return true;
         }
         for (from_arg, to_arg) in to_subs.iter().zip(from_subs) {
-            match (from_arg.unpack(), to_arg.unpack()) {
+            match (from_arg.kind(), to_arg.kind()) {
                 (GenericArgKind::Lifetime(from_region), GenericArgKind::Lifetime(to_region)) => {
                     if check_region(from_region, to_region) {
                         return true;
@@ -354,5 +354,5 @@ fn has_late_bound_to_non_late_bound_regions(from_sig: FnSig<'_>, to_sig: FnSig<'
 
 fn ty_has_static(ty: Ty<'_>) -> bool {
     ty.walk()
-        .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(re) if re.is_static()))
+        .any(|arg| matches!(arg.kind(), GenericArgKind::Lifetime(re) if re.is_static()))
 }
diff --git a/src/tools/clippy/clippy_lints/src/excessive_bools.rs b/src/tools/clippy/clippy_lints/src/excessive_bools.rs
index 38d115b878c..686dc5c3c4f 100644
--- a/src/tools/clippy/clippy_lints/src/excessive_bools.rs
+++ b/src/tools/clippy/clippy_lints/src/excessive_bools.rs
@@ -127,7 +127,7 @@ fn check_fn_decl(cx: &LateContext<'_>, decl: &FnDecl<'_>, sp: Span, max: u64) {
 
 impl<'tcx> LateLintPass<'tcx> for ExcessiveBools {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
-        if let ItemKind::Struct(_, variant_data, _) = &item.kind
+        if let ItemKind::Struct(_, _, variant_data) = &item.kind
             && variant_data.fields().len() as u64 > self.max_struct_bools
             && has_n_bools(
                 variant_data.fields().iter().map(|field| field.ty),
diff --git a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
index 5a74e97c97c..1fb0e4d24d0 100644
--- a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
+++ b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
@@ -76,7 +76,7 @@ impl LateLintPass<'_> for ExhaustiveItems {
                 "exported enums should not be exhaustive",
                 [].as_slice(),
             ),
-            ItemKind::Struct(_, v, ..) => (
+            ItemKind::Struct(_, _, v) => (
                 EXHAUSTIVE_STRUCTS,
                 "exported structs should not be exhaustive",
                 v.fields(),
diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs
index a5a4e05b3a6..085ee4448a4 100644
--- a/src/tools/clippy/clippy_lints/src/explicit_write.rs
+++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs
@@ -1,13 +1,13 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::macros::{FormatArgsStorage, format_args_inputs_span};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{is_expn_of, path_def_id};
+use clippy_utils::{is_expn_of, path_def_id, sym};
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{BindingMode, Block, BlockCheckMode, Expr, ExprKind, Node, PatKind, QPath, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
-use rustc_span::{ExpnId, sym};
+use rustc_span::ExpnId;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -72,9 +72,9 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
             };
 
             // ordering is important here, since `writeln!` uses `write!` internally
-            let calling_macro = if is_expn_of(write_call.span, "writeln").is_some() {
+            let calling_macro = if is_expn_of(write_call.span, sym::writeln).is_some() {
                 Some("writeln")
-            } else if is_expn_of(write_call.span, "write").is_some() {
+            } else if is_expn_of(write_call.span, sym::write).is_some() {
                 Some("write")
             } else {
                 None
diff --git a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
index 6a217b6182c..c0b0fd88d9e 100644
--- a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
+++ b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
@@ -273,7 +273,7 @@ impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters {
         // Only lint on inherent methods, not trait methods.
         if let ImplItemKind::Fn(.., body_id) = item.kind
             && !item.generics.params.is_empty()
-            && trait_ref_of_method(cx, item.owner_id.def_id).is_none()
+            && trait_ref_of_method(cx, item.owner_id).is_none()
             && !is_empty_body(cx, body_id)
             && (!self.avoid_breaking_exported_api || !cx.effective_visibilities.is_exported(item.owner_id.def_id))
             && !item.span.in_external_macro(cx.sess().source_map())
diff --git a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
index c868b782f43..68d0cd19c8a 100644
--- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
+++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
@@ -82,7 +82,7 @@ fn lint_impl_body(cx: &LateContext<'_>, impl_span: Span, impl_items: &[hir::Impl
             }
 
             // check for `unwrap`
-            if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
+            if let Some(arglists) = method_chain_args(expr, &[sym::unwrap]) {
                 let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs();
                 if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option)
                     || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result)
diff --git a/src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs b/src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs
index aae8291905d..dfb0b4f103c 100644
--- a/src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs
+++ b/src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs
@@ -51,7 +51,7 @@ declare_lint_pass!(FieldScopedVisibilityModifiers => [FIELD_SCOPED_VISIBILITY_MO
 
 impl EarlyLintPass for FieldScopedVisibilityModifiers {
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
-        let ItemKind::Struct(_, ref st, _) = item.kind else {
+        let ItemKind::Struct(_, _, ref st) = item.kind else {
             return;
         };
         for field in st.fields() {
diff --git a/src/tools/clippy/clippy_lints/src/float_literal.rs b/src/tools/clippy/clippy_lints/src/float_literal.rs
index 012ad8e1a22..c51267567d0 100644
--- a/src/tools/clippy/clippy_lints/src/float_literal.rs
+++ b/src/tools/clippy/clippy_lints/src/float_literal.rs
@@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
                         },
                     );
                 }
-            } else if digits > max as usize && float_str.len() < sym_str.len() {
+            } else if digits > max as usize && count_digits(&float_str) < count_digits(sym_str) {
                 span_lint_and_then(
                     cx,
                     EXCESSIVE_PRECISION,
diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
index e653a57196d..3c7e83b0697 100644
--- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
@@ -294,8 +294,8 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args:
         && let Some(parent) = get_parent_expr(cx, expr)
     {
         if let Some(grandparent) = get_parent_expr(cx, parent)
-            && let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = grandparent.kind
-            && method_name.as_str() == "sqrt"
+            && let ExprKind::MethodCall(PathSegment { ident: method, .. }, receiver, ..) = grandparent.kind
+            && method.name == sym::sqrt
             && detect_hypot(cx, receiver).is_some()
         {
             return;
@@ -375,24 +375,10 @@ fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option<String> {
         }
 
         // check if expression of the form x.powi(2) + y.powi(2)
-        if let ExprKind::MethodCall(
-            PathSegment {
-                ident: lmethod_name, ..
-            },
-            largs_0,
-            [largs_1, ..],
-            _,
-        ) = &add_lhs.kind
-            && let ExprKind::MethodCall(
-                PathSegment {
-                    ident: rmethod_name, ..
-                },
-                rargs_0,
-                [rargs_1, ..],
-                _,
-            ) = &add_rhs.kind
-            && lmethod_name.as_str() == "powi"
-            && rmethod_name.as_str() == "powi"
+        if let ExprKind::MethodCall(PathSegment { ident: lmethod, .. }, largs_0, [largs_1, ..], _) = &add_lhs.kind
+            && let ExprKind::MethodCall(PathSegment { ident: rmethod, .. }, rargs_0, [rargs_1, ..], _) = &add_rhs.kind
+            && lmethod.name == sym::powi
+            && rmethod.name == sym::powi
             && let ecx = ConstEvalCtxt::new(cx)
             && let Some(lvalue) = ecx.eval(largs_1)
             && let Some(rvalue) = ecx.eval(rargs_1)
@@ -482,8 +468,8 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) {
     ) = &expr.kind
     {
         if let Some(parent) = get_parent_expr(cx, expr)
-            && let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = parent.kind
-            && method_name.as_str() == "sqrt"
+            && let ExprKind::MethodCall(PathSegment { ident: method, .. }, receiver, ..) = parent.kind
+            && method.name == sym::sqrt
             && detect_hypot(cx, receiver).is_some()
         {
             return;
@@ -623,27 +609,13 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) {
 }
 
 fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool {
-    if let ExprKind::MethodCall(
-        PathSegment {
-            ident: method_name_a, ..
-        },
-        _,
-        args_a,
-        _,
-    ) = expr_a.kind
-        && let ExprKind::MethodCall(
-            PathSegment {
-                ident: method_name_b, ..
-            },
-            _,
-            args_b,
-            _,
-        ) = expr_b.kind
+    if let ExprKind::MethodCall(PathSegment { ident: method_a, .. }, _, args_a, _) = expr_a.kind
+        && let ExprKind::MethodCall(PathSegment { ident: method_b, .. }, _, args_b, _) = expr_b.kind
     {
-        return method_name_a.as_str() == method_name_b.as_str()
+        return method_a.name == method_b.name
             && args_a.len() == args_b.len()
-            && (["ln", "log2", "log10"].contains(&method_name_a.as_str())
-                || method_name_a.as_str() == "log" && args_a.len() == 1 && eq_expr_value(cx, &args_a[0], &args_b[0]));
+            && (matches!(method_a.name, sym::ln | sym::log2 | sym::log10)
+                || method_a.name == sym::log && args_a.len() == 1 && eq_expr_value(cx, &args_a[0], &args_b[0]));
     }
 
     false
diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
index c3e0d5e8b69..70655838b6a 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -55,7 +55,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
         let attr = cx.tcx.get_attr(item.owner_id, sym::must_use);
         if let Some(attr) = attr {
             check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig);
-        } else if is_public && !is_proc_macro(attrs) && trait_ref_of_method(cx, item.owner_id.def_id).is_none() {
+        } else if is_public && !is_proc_macro(attrs) && trait_ref_of_method(cx, item.owner_id).is_none() {
             check_must_use_candidate(
                 cx,
                 sig.decl,
diff --git a/src/tools/clippy/clippy_lints/src/functions/ref_option.rs b/src/tools/clippy/clippy_lints/src/functions/ref_option.rs
index aba0fbcb9fe..106202d00d4 100644
--- a/src/tools/clippy/clippy_lints/src/functions/ref_option.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/ref_option.rs
@@ -17,7 +17,7 @@ fn check_ty<'a>(cx: &LateContext<'a>, param: &rustc_hir::Ty<'a>, param_ty: Ty<'a
         && is_type_diagnostic_item(cx, *opt_ty, sym::Option)
         && let ty::Adt(_, opt_gen_args) = opt_ty.kind()
         && let [gen_arg] = opt_gen_args.as_slice()
-        && let GenericArgKind::Type(gen_ty) = gen_arg.unpack()
+        && let GenericArgKind::Type(gen_ty) = gen_arg.kind()
         && !gen_ty.is_ref()
         // Need to gen the original spans, so first parsing mid, and hir parsing afterward
         && let hir::TyKind::Ref(lifetime, hir::MutTy { ty, .. }) = param.kind
diff --git a/src/tools/clippy/clippy_lints/src/functions/result.rs b/src/tools/clippy/clippy_lints/src/functions/result.rs
index 07a92a4ed70..bb98ae82611 100644
--- a/src/tools/clippy/clippy_lints/src/functions/result.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/result.rs
@@ -55,7 +55,7 @@ pub(super) fn check_impl_item<'tcx>(
     // Don't lint if method is a trait's implementation, we can't do anything about those
     if let hir::ImplItemKind::Fn(ref sig, _) = item.kind
         && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.owner_id.def_id, item.span)
-        && trait_ref_of_method(cx, item.owner_id.def_id).is_none()
+        && trait_ref_of_method(cx, item.owner_id).is_none()
     {
         if cx.effective_visibilities.is_exported(item.owner_id.def_id) {
             let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
@@ -103,7 +103,7 @@ fn check_result_large_err<'tcx>(cx: &LateContext<'tcx>, err_ty: Ty<'tcx>, hir_ty
             .did()
             .as_local()
         && let hir::Node::Item(item) = cx.tcx.hir_node_by_def_id(local_def_id)
-        && let hir::ItemKind::Enum(_, ref def, _) = item.kind
+        && let hir::ItemKind::Enum(_, _, ref def) = item.kind
     {
         let variants_size = AdtVariantInfo::new(cx, *adt, subst);
         if let Some((first_variant, variants)) = variants_size.split_first()
diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
index 4c17834c3ad..cab7a9fb709 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
@@ -119,7 +119,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
                     }
 
                     let generics_suggestion_span = impl_.generics.span.substitute_dummy({
-                        let range = (item.span.lo()..target.span().lo()).map_range(cx, |src, range| {
+                        let range = (item.span.lo()..target.span().lo()).map_range(cx, |_, src, range| {
                             Some(src.get(range.clone())?.find("impl")? + 4..range.end)
                         });
                         if let Some(range) = range {
@@ -165,11 +165,12 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
                             continue;
                         }
                         let generics_suggestion_span = generics.span.substitute_dummy({
-                            let range = (item.span.lo()..body.params[0].pat.span.lo()).map_range(cx, |src, range| {
-                                let (pre, post) = src.get(range.clone())?.split_once("fn")?;
-                                let pos = post.find('(')? + pre.len() + 2;
-                                Some(pos..pos)
-                            });
+                            let range =
+                                (item.span.lo()..body.params[0].pat.span.lo()).map_range(cx, |_, src, range| {
+                                    let (pre, post) = src.get(range.clone())?.split_once("fn")?;
+                                    let pos = post.find('(')? + pre.len() + 2;
+                                    Some(pos..pos)
+                                });
                             if let Some(range) = range {
                                 range.with_ctxt(item.span.ctxt())
                             } else {
diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
index 989997d69f7..3d131a7825a 100644
--- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
@@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher::IfLet;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::ty::is_copy;
-use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local};
+use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local, sym};
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
@@ -12,7 +12,6 @@ use rustc_hir::HirId;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
-use rustc_middle::ty;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 use rustc_span::symbol::Ident;
@@ -72,7 +71,7 @@ impl_lint_pass!(IndexRefutableSlice => [INDEX_REFUTABLE_SLICE]);
 impl<'tcx> LateLintPass<'tcx> for IndexRefutableSlice {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         if let Some(IfLet { let_pat, if_then, .. }) = IfLet::hir(cx, expr)
-            && (!expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some())
+            && (!expr.span.from_expansion() || is_expn_of(expr.span, sym::if_chain).is_some())
             && !is_lint_allowed(cx, INDEX_REFUTABLE_SLICE, expr.hir_id)
             && let found_slices = find_slice_values(cx, let_pat)
             && !found_slices.is_empty()
@@ -109,11 +108,11 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap<Hir
             }
 
             let bound_ty = cx.typeck_results().node_type(pat.hir_id);
-            if let ty::Slice(inner_ty) | ty::Array(inner_ty, _) = bound_ty.peel_refs().kind() {
+            if let Some(inner_ty) = bound_ty.peel_refs().builtin_index() {
                 // The values need to use the `ref` keyword if they can't be copied.
                 // This will need to be adjusted if the lint want to support mutable access in the future
                 let src_is_ref = bound_ty.is_ref() && by_ref == hir::ByRef::No;
-                let needs_ref = !(src_is_ref || is_copy(cx, *inner_ty));
+                let needs_ref = !(src_is_ref || is_copy(cx, inner_ty));
 
                 let slice_info = slices
                     .entry(value_hir_id)
diff --git a/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs b/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs
index 3a28553b55e..7a751514b64 100644
--- a/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs
+++ b/src/tools/clippy/clippy_lints/src/ineffective_open_options.rs
@@ -1,13 +1,13 @@
 use crate::methods::method_call;
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::peel_blocks;
+use clippy_utils::{peel_blocks, sym};
 use rustc_ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
-use rustc_span::{BytePos, Span, sym};
+use rustc_span::{BytePos, Span};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -57,7 +57,7 @@ fn index_if_arg_is_boolean(args: &[Expr<'_>], call_span: Span) -> Option<Span> {
 
 impl<'tcx> LateLintPass<'tcx> for IneffectiveOpenOptions {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        let Some(("open", mut receiver, [_arg], _, _)) = method_call(expr) else {
+        let Some((sym::open, mut receiver, [_arg], _, _)) = method_call(expr) else {
             return;
         };
         let receiver_ty = cx.typeck_results().expr_ty(receiver);
@@ -70,9 +70,9 @@ impl<'tcx> LateLintPass<'tcx> for IneffectiveOpenOptions {
         let mut write = None;
 
         while let Some((name, recv, args, _, span)) = method_call(receiver) {
-            if name == "append" {
+            if name == sym::append {
                 append = index_if_arg_is_boolean(args, span);
-            } else if name == "write" {
+            } else if name == sym::write {
                 write = index_if_arg_is_boolean(args, span);
             }
             receiver = recv;
diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
index c4e10837bf1..bf3eafe09b3 100644
--- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
@@ -4,6 +4,7 @@ use clippy_utils::{higher, sym};
 use rustc_hir::{BorrowKind, Closure, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
+use rustc_span::Symbol;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -119,33 +120,33 @@ use self::Heuristic::{All, Always, Any, First};
 /// returns an infinite or possibly infinite iterator. The finiteness
 /// is an upper bound, e.g., some methods can return a possibly
 /// infinite iterator at worst, e.g., `take_while`.
-const HEURISTICS: [(&str, usize, Heuristic, Finiteness); 19] = [
-    ("zip", 1, All, Infinite),
-    ("chain", 1, Any, Infinite),
-    ("cycle", 0, Always, Infinite),
-    ("map", 1, First, Infinite),
-    ("by_ref", 0, First, Infinite),
-    ("cloned", 0, First, Infinite),
-    ("rev", 0, First, Infinite),
-    ("inspect", 0, First, Infinite),
-    ("enumerate", 0, First, Infinite),
-    ("peekable", 1, First, Infinite),
-    ("fuse", 0, First, Infinite),
-    ("skip", 1, First, Infinite),
-    ("skip_while", 0, First, Infinite),
-    ("filter", 1, First, Infinite),
-    ("filter_map", 1, First, Infinite),
-    ("flat_map", 1, First, Infinite),
-    ("unzip", 0, First, Infinite),
-    ("take_while", 1, First, MaybeInfinite),
-    ("scan", 2, First, MaybeInfinite),
+const HEURISTICS: [(Symbol, usize, Heuristic, Finiteness); 19] = [
+    (sym::zip, 1, All, Infinite),
+    (sym::chain, 1, Any, Infinite),
+    (sym::cycle, 0, Always, Infinite),
+    (sym::map, 1, First, Infinite),
+    (sym::by_ref, 0, First, Infinite),
+    (sym::cloned, 0, First, Infinite),
+    (sym::rev, 0, First, Infinite),
+    (sym::inspect, 0, First, Infinite),
+    (sym::enumerate, 0, First, Infinite),
+    (sym::peekable, 1, First, Infinite),
+    (sym::fuse, 0, First, Infinite),
+    (sym::skip, 1, First, Infinite),
+    (sym::skip_while, 0, First, Infinite),
+    (sym::filter, 1, First, Infinite),
+    (sym::filter_map, 1, First, Infinite),
+    (sym::flat_map, 1, First, Infinite),
+    (sym::unzip, 0, First, Infinite),
+    (sym::take_while, 1, First, MaybeInfinite),
+    (sym::scan, 2, First, MaybeInfinite),
 ];
 
 fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
     match expr.kind {
         ExprKind::MethodCall(method, receiver, args, _) => {
             for &(name, len, heuristic, cap) in &HEURISTICS {
-                if method.ident.name.as_str() == name && args.len() == len {
+                if method.ident.name == name && args.len() == len {
                     return (match heuristic {
                         Always => Infinite,
                         First => is_infinite(cx, receiver),
@@ -183,36 +184,36 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
 
 /// the names and argument lengths of methods that *may* exhaust their
 /// iterators
-const POSSIBLY_COMPLETING_METHODS: [(&str, usize); 6] = [
-    ("find", 1),
-    ("rfind", 1),
-    ("position", 1),
-    ("rposition", 1),
-    ("any", 1),
-    ("all", 1),
+const POSSIBLY_COMPLETING_METHODS: [(Symbol, usize); 6] = [
+    (sym::find, 1),
+    (sym::rfind, 1),
+    (sym::position, 1),
+    (sym::rposition, 1),
+    (sym::any, 1),
+    (sym::all, 1),
 ];
 
 /// the names and argument lengths of methods that *always* exhaust
 /// their iterators
-const COMPLETING_METHODS: [(&str, usize); 12] = [
-    ("count", 0),
-    ("fold", 2),
-    ("for_each", 1),
-    ("partition", 1),
-    ("max", 0),
-    ("max_by", 1),
-    ("max_by_key", 1),
-    ("min", 0),
-    ("min_by", 1),
-    ("min_by_key", 1),
-    ("sum", 0),
-    ("product", 0),
+const COMPLETING_METHODS: [(Symbol, usize); 12] = [
+    (sym::count, 0),
+    (sym::fold, 2),
+    (sym::for_each, 1),
+    (sym::partition, 1),
+    (sym::max, 0),
+    (sym::max_by, 1),
+    (sym::max_by_key, 1),
+    (sym::min, 0),
+    (sym::min_by, 1),
+    (sym::min_by_key, 1),
+    (sym::sum, 0),
+    (sym::product, 0),
 ];
 
 fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
     match expr.kind {
         ExprKind::MethodCall(method, receiver, args, _) => {
-            let method_str = method.ident.name.as_str();
+            let method_str = method.ident.name;
             for &(name, len) in &COMPLETING_METHODS {
                 if method_str == name && args.len() == len {
                     return is_infinite(cx, receiver);
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 1d582fb0223..7f2e25367a6 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
@@ -106,7 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
             // Check if return type is String
             && is_type_lang_item(cx, return_ty(cx, impl_item.owner_id), LangItem::String)
             // Filters instances of to_string which are required by a trait
-            && trait_ref_of_method(cx, impl_item.owner_id.def_id).is_none()
+            && trait_ref_of_method(cx, impl_item.owner_id).is_none()
         {
             show_lint(cx, impl_item);
         }
diff --git a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
index 3d4dcd02070..9c91cf68085 100644
--- a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
+++ b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
@@ -535,10 +535,10 @@ impl LateLintPass<'_> for ItemNameRepetitions {
 
         if span_is_local(item.span) {
             match item.kind {
-                ItemKind::Enum(_, def, _) => {
+                ItemKind::Enum(_, _, def) => {
                     self.check_variants(cx, item, &def);
                 },
-                ItemKind::Struct(_, VariantData::Struct { fields, .. }, _) => {
+                ItemKind::Struct(_, _, VariantData::Struct { fields, .. }) => {
                     self.check_fields(cx, item, fields);
                 },
                 _ => (),
diff --git a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
index 394005e9912..cee8ca1261e 100644
--- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
+++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
@@ -48,7 +48,7 @@ impl_lint_pass!(LargeConstArrays => [LARGE_CONST_ARRAYS]);
 
 impl<'tcx> LateLintPass<'tcx> for LargeConstArrays {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if let ItemKind::Const(ident, _, generics, _) = &item.kind
+        if let ItemKind::Const(ident, generics, _, _) = &item.kind
             // Since static items may not have generics, skip generic const items.
             // FIXME(generic_const_items): I don't think checking `generics.hwcp` suffices as it
             // doesn't account for empty where-clauses that only consist of keyword `where` IINM.
diff --git a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
index d08efa0ec9c..e85d779b488 100644
--- a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
+++ b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
@@ -73,7 +73,7 @@ impl_lint_pass!(LargeEnumVariant => [LARGE_ENUM_VARIANT]);
 
 impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &Item<'tcx>) {
-        if let ItemKind::Enum(ident, ref def, _) = item.kind
+        if let ItemKind::Enum(ident, _, ref def) = item.kind
             && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
             && let ty::Adt(adt, subst) = ty.kind()
             && adt.variants().len() > 1
diff --git a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs
index 01b49403cac..b3c63f022d3 100644
--- a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs
+++ b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs
@@ -51,7 +51,9 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
         // so lint on the `use` statement directly.
         if let ItemKind::Use(path, kind @ (UseKind::Single(_) | UseKind::Glob)) = item.kind
             && !item.span.in_external_macro(cx.sess().source_map())
-            && let Some(def_id) = path.res[0].opt_def_id()
+            // use `present_items` because it could be in either type_ns or value_ns
+            && let Some(res) = path.res.present_items().next()
+            && let Some(def_id) = res.opt_def_id()
             && self.msrv.meets(cx, msrvs::NUMERIC_ASSOCIATED_CONSTANTS)
         {
             let module = if is_integer_module(cx, def_id) {
diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs
index 916191b2a7b..b72e14246db 100644
--- a/src/tools/clippy/clippy_lints/src/let_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs
@@ -137,7 +137,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
             && !local.span.in_external_macro(cx.tcx.sess.source_map())
         {
             let init_ty = cx.typeck_results().expr_ty(init);
-            let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() {
+            let contains_sync_guard = init_ty.walk().any(|inner| match inner.kind() {
                 GenericArgKind::Type(inner_ty) => inner_ty
                     .ty_adt_def()
                     .is_some_and(|adt| paths::PARKING_LOT_GUARDS.iter().any(|path| path.matches(cx, adt.did()))),
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index ff028713bf0..92eb3d7a7c5 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -393,6 +393,7 @@ mod unwrap;
 mod unwrap_in_result;
 mod upper_case_acronyms;
 mod use_self;
+mod useless_concat;
 mod useless_conversion;
 mod vec;
 mod vec_init_then_push;
@@ -866,7 +867,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(move |_| Box::new(unnecessary_box_returns::UnnecessaryBoxReturns::new(conf)));
     store.register_late_pass(move |_| Box::new(lines_filter_map_ok::LinesFilterMapOk::new(conf)));
     store.register_late_pass(|_| Box::new(tests_outside_test_module::TestsOutsideTestModule));
-    store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation));
+    store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation::new(conf)));
     store.register_early_pass(move || Box::new(excessive_nesting::ExcessiveNesting::new(conf)));
     store.register_late_pass(|_| Box::new(items_after_test_module::ItemsAfterTestModule));
     store.register_early_pass(|| Box::new(ref_patterns::RefPatterns));
@@ -937,6 +938,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(|_| Box::new(unnecessary_literal_bound::UnnecessaryLiteralBound));
     store.register_early_pass(|| Box::new(empty_line_after::EmptyLineAfter::new()));
     store.register_late_pass(move |_| Box::new(arbitrary_source_item_ordering::ArbitrarySourceItemOrdering::new(conf)));
+    store.register_late_pass(|_| Box::new(useless_concat::UselessConcat));
     store.register_late_pass(|_| Box::new(unneeded_struct_pattern::UnneededStructPattern));
     store.register_late_pass(|_| Box::<unnecessary_semicolon::UnnecessarySemicolon>::default());
     store.register_late_pass(move |_| Box::new(non_std_lazy_statics::NonStdLazyStatic::new(conf)));
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 9a64226b1ed..8fe0c9d60f9 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -159,7 +159,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
         if let ImplItemKind::Fn(ref sig, id) = item.kind {
-            let report_extra_lifetimes = trait_ref_of_method(cx, item.owner_id.def_id).is_none();
+            let report_extra_lifetimes = trait_ref_of_method(cx, item.owner_id).is_none();
             check_fn_inner(
                 cx,
                 sig,
diff --git a/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs b/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs
index d8af44233d3..14ccb6fce22 100644
--- a/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs
+++ b/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs
@@ -2,12 +2,12 @@ use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_diag_item_method, is_trait_method, path_to_local_id};
+use clippy_utils::{is_diag_item_method, is_trait_method, path_to_local_id, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{Body, Closure, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
-use rustc_span::sym;
+use rustc_span::Symbol;
 
 pub struct LinesFilterMapOk {
     msrv: Msrv,
@@ -74,17 +74,17 @@ impl LateLintPass<'_> for LinesFilterMapOk {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         if let ExprKind::MethodCall(fm_method, fm_receiver, fm_args, fm_span) = expr.kind
             && is_trait_method(cx, expr, sym::Iterator)
-            && let fm_method_str = fm_method.ident.as_str()
-            && matches!(fm_method_str, "filter_map" | "flat_map" | "flatten")
+            && let fm_method_name = fm_method.ident.name
+            && matches!(fm_method_name, sym::filter_map | sym::flat_map | sym::flatten)
             && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), sym::IoLines)
-            && should_lint(cx, fm_args, fm_method_str)
+            && should_lint(cx, fm_args, fm_method_name)
             && self.msrv.meets(cx, msrvs::MAP_WHILE)
         {
             span_lint_and_then(
                 cx,
                 LINES_FILTER_MAP_OK,
                 fm_span,
-                format!("`{fm_method_str}()` will run forever if the iterator repeatedly produces an `Err`",),
+                format!("`{fm_method_name}()` will run forever if the iterator repeatedly produces an `Err`",),
                 |diag| {
                     diag.span_note(
                         fm_receiver.span,
@@ -101,9 +101,9 @@ impl LateLintPass<'_> for LinesFilterMapOk {
     }
 }
 
-fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_str: &str) -> bool {
+fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_name: Symbol) -> bool {
     match args {
-        [] => method_str == "flatten",
+        [] => method_name == sym::flatten,
         [fm_arg] => {
             match &fm_arg.kind {
                 // Detect `Result::ok`
@@ -120,7 +120,7 @@ fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_str: &str) -> boo
                         && path_to_local_id(receiver, param.pat.hir_id)
                         && let Some(method_did) = cx.typeck_results().type_dependent_def_id(value.hir_id)
                     {
-                        is_diag_item_method(cx, method_did, sym::Result) && method.ident.as_str() == "ok"
+                        is_diag_item_method(cx, method_did, sym::Result) && method.ident.name == sym::ok
                     } else {
                         false
                     }
diff --git a/src/tools/clippy/clippy_lints/src/loops/char_indices_as_byte_indices.rs b/src/tools/clippy/clippy_lints/src/loops/char_indices_as_byte_indices.rs
index 8916454ada1..a702e60f1c2 100644
--- a/src/tools/clippy/clippy_lints/src/loops/char_indices_as_byte_indices.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/char_indices_as_byte_indices.rs
@@ -3,12 +3,12 @@ use std::ops::ControlFlow;
 use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::ty::is_type_lang_item;
 use clippy_utils::visitors::for_each_expr;
-use clippy_utils::{eq_expr_value, higher, path_to_local_id};
+use clippy_utils::{eq_expr_value, higher, path_to_local_id, sym};
 use rustc_errors::{Applicability, MultiSpan};
 use rustc_hir::{Expr, ExprKind, LangItem, Node, Pat, PatKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::Ty;
-use rustc_span::{Span, sym};
+use rustc_span::{Span, Symbol};
 
 use super::CHAR_INDICES_AS_BYTE_INDICES;
 
@@ -16,22 +16,22 @@ use super::CHAR_INDICES_AS_BYTE_INDICES;
 // Note: `String` also has methods that work with byte indices,
 // but they all take `&mut self` and aren't worth considering since the user couldn't have called
 // them while the chars iterator is live anyway.
-const BYTE_INDEX_METHODS: &[&str] = &[
-    "is_char_boundary",
-    "floor_char_boundary",
-    "ceil_char_boundary",
-    "get",
-    "index",
-    "index_mut",
-    "get_mut",
-    "get_unchecked",
-    "get_unchecked_mut",
-    "slice_unchecked",
-    "slice_mut_unchecked",
-    "split_at",
-    "split_at_mut",
-    "split_at_checked",
-    "split_at_mut_checked",
+const BYTE_INDEX_METHODS: &[Symbol] = &[
+    sym::ceil_char_boundary,
+    sym::floor_char_boundary,
+    sym::get,
+    sym::get_mut,
+    sym::get_unchecked,
+    sym::get_unchecked_mut,
+    sym::index,
+    sym::index_mut,
+    sym::is_char_boundary,
+    sym::slice_mut_unchecked,
+    sym::slice_unchecked,
+    sym::split_at,
+    sym::split_at_checked,
+    sym::split_at_mut,
+    sym::split_at_mut_checked,
 ];
 
 const CONTINUE: ControlFlow<!, ()> = ControlFlow::Continue(());
@@ -88,7 +88,7 @@ fn check_index_usage<'tcx>(
             // (contrary to the `ExprKind::Index` case which needs to handle both with `is_string_like` because `String` implements
             // `Index` directly and no deref to `str` would happen in that case).
             if cx.typeck_results().expr_ty_adjusted(recv).peel_refs().is_str()
-                && BYTE_INDEX_METHODS.contains(&segment.ident.name.as_str())
+                && BYTE_INDEX_METHODS.contains(&segment.ident.name)
                 && eq_expr_value(cx, chars_recv, recv) =>
         {
             "passing a character position to a method that expects a byte index"
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_into_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_into_iter_loop.rs
index d5ddc33e928..4aa1c2e211d 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_into_iter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_into_iter_loop.rs
@@ -1,7 +1,7 @@
 use super::EXPLICIT_INTO_ITER_LOOP;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::is_trait_method;
-use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::source::snippet_with_context;
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
@@ -76,7 +76,7 @@ pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, call_expr: &Expr<
     };
 
     let mut applicability = Applicability::MachineApplicable;
-    let object = snippet_with_applicability(cx, self_arg.span, "_", &mut applicability);
+    let object = snippet_with_context(cx, self_arg.span, call_expr.span.ctxt(), "_", &mut applicability).0;
     span_lint_and_sugg(
         cx,
         EXPLICIT_INTO_ITER_LOOP,
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
index d0b26c91ffa..010652e1cb9 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
@@ -1,7 +1,7 @@
 use super::EXPLICIT_ITER_LOOP;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::source::snippet_with_context;
 use clippy_utils::sym;
 use clippy_utils::ty::{
     implements_trait, implements_trait_with_env, is_copy, is_type_lang_item, make_normalized_projection,
@@ -36,7 +36,7 @@ pub(super) fn check(
     }
 
     let mut applicability = Applicability::MachineApplicable;
-    let object = snippet_with_applicability(cx, self_arg.span, "_", &mut applicability);
+    let object = snippet_with_context(cx, self_arg.span, call_expr.span.ctxt(), "_", &mut applicability).0;
     span_lint_and_sugg(
         cx,
         EXPLICIT_ITER_LOOP,
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs
index 35737f3eafe..f99989ec6ba 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs
@@ -83,6 +83,13 @@ pub(super) fn check<'tcx>(
                 )[..],
             );
         }
+
+        // If the return type requires adjustments, we need to add a `.map` after the iterator
+        let inner_ret_adjust = cx.typeck_results().expr_adjustments(inner_ret);
+        if !inner_ret_adjust.is_empty() {
+            snippet.push_str(".map(|v| v as _)");
+        }
+
         // Extends to `last_stmt` to include semicolon in case of `return None;`
         let lint_span = span.to(last_stmt.span).to(last_ret.span);
         span_lint_and_then(
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
index 9b6f97b9a2e..81f14b7b2b0 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
@@ -3,7 +3,7 @@ use super::utils::make_iterator_snippet;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::visitors::is_local_used;
-use clippy_utils::{higher, path_to_local_id, peel_blocks_with_stmt};
+use clippy_utils::{higher, is_refutable, path_to_local_id, peel_blocks_with_stmt};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Expr, Pat, PatKind};
@@ -28,7 +28,7 @@ pub(super) fn check<'tcx>(
         && let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind
         && path_to_local_id(let_expr, pat_hir_id)
         // Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result`
-        && let PatKind::TupleStruct(ref qpath, _, _) = let_pat.kind
+        && let PatKind::TupleStruct(ref qpath, [inner_pat], _) = let_pat.kind
         && let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(qpath, let_pat.hir_id)
         && let Some(variant_id) = cx.tcx.opt_parent(ctor_id)
         && let some_ctor = cx.tcx.lang_items().option_some_variant() == Some(variant_id)
@@ -37,6 +37,7 @@ pub(super) fn check<'tcx>(
         // Ensure expr in `if let` is not used afterwards
         && !is_local_used(cx, if_then, pat_hir_id)
         && msrv.meets(cx, msrvs::ITER_FLATTEN)
+        && !is_refutable(cx, inner_pat)
     {
         let if_let_type = if some_ctor { "Some" } else { "Ok" };
         // Prepare the error message
diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs
index 56d2bef2305..01c36b8cb12 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs
@@ -25,8 +25,8 @@ mod while_let_loop;
 mod while_let_on_iterator;
 
 use clippy_config::Conf;
-use clippy_utils::higher;
 use clippy_utils::msrvs::Msrv;
+use clippy_utils::{higher, sym};
 use rustc_ast::Label;
 use rustc_hir::{Expr, ExprKind, LoopSource, Pat};
 use rustc_lint::{LateContext, LateLintPass};
@@ -909,15 +909,17 @@ impl Loops {
     }
 
     fn check_for_loop_arg(&self, cx: &LateContext<'_>, _: &Pat<'_>, arg: &Expr<'_>) {
-        if let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind {
-            match method.ident.as_str() {
-                "iter" | "iter_mut" => {
+        if !arg.span.from_expansion()
+            && let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind
+        {
+            match method.ident.name {
+                sym::iter | sym::iter_mut => {
                     explicit_iter_loop::check(cx, self_arg, arg, self.msrv, self.enforce_iter_loop_reborrow);
                 },
-                "into_iter" => {
+                sym::into_iter => {
                     explicit_into_iter_loop::check(cx, self_arg, arg);
                 },
-                "next" => {
+                sym::next => {
                     iter_next_loop::check(cx, arg);
                 },
                 _ => {},
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs
index bd04827a1f0..845edb9cae1 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs
@@ -1,68 +1,65 @@
 use super::WHILE_LET_LOOP;
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::higher;
-use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::source::{snippet, snippet_indent, snippet_opt};
 use clippy_utils::ty::needs_ordered_drop;
 use clippy_utils::visitors::any_temporaries_need_ordered_drop;
+use clippy_utils::{higher, peel_blocks};
+use rustc_ast::BindingMode;
 use rustc_errors::Applicability;
-use rustc_hir::{Block, Expr, ExprKind, LetStmt, MatchSource, Pat, StmtKind};
+use rustc_hir::{Block, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind, Path, QPath, StmtKind, Ty};
 use rustc_lint::LateContext;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) {
-    let (init, has_trailing_exprs) = match (loop_block.stmts, loop_block.expr) {
-        ([stmt, stmts @ ..], expr) => {
-            if let StmtKind::Let(&LetStmt {
+    let (init, let_info) = match (loop_block.stmts, loop_block.expr) {
+        ([stmt, ..], _) => match stmt.kind {
+            StmtKind::Let(LetStmt {
                 init: Some(e),
                 els: None,
+                pat,
+                ty,
                 ..
-            })
-            | StmtKind::Semi(e)
-            | StmtKind::Expr(e) = stmt.kind
-            {
-                (e, !stmts.is_empty() || expr.is_some())
-            } else {
-                return;
-            }
+            }) => (*e, Some((*pat, *ty))),
+            StmtKind::Semi(e) | StmtKind::Expr(e) => (e, None),
+            _ => return,
         },
-        ([], Some(e)) => (e, false),
+        ([], Some(e)) => (e, None),
         _ => return,
     };
+    let has_trailing_exprs = loop_block.stmts.len() + usize::from(loop_block.expr.is_some()) > 1;
 
     if let Some(if_let) = higher::IfLet::hir(cx, init)
         && let Some(else_expr) = if_let.if_else
         && is_simple_break_expr(else_expr)
     {
-        could_be_while_let(cx, expr, if_let.let_pat, if_let.let_expr, has_trailing_exprs);
+        could_be_while_let(
+            cx,
+            expr,
+            if_let.let_pat,
+            if_let.let_expr,
+            has_trailing_exprs,
+            let_info,
+            if_let.if_then,
+        );
     } else if let ExprKind::Match(scrutinee, [arm1, arm2], MatchSource::Normal) = init.kind
         && arm1.guard.is_none()
         && arm2.guard.is_none()
         && is_simple_break_expr(arm2.body)
     {
-        could_be_while_let(cx, expr, arm1.pat, scrutinee, has_trailing_exprs);
+        could_be_while_let(cx, expr, arm1.pat, scrutinee, has_trailing_exprs, let_info, arm1.body);
     }
 }
 
-/// Returns `true` if expr contains a single break expression without a label or eub-expression.
+/// Returns `true` if expr contains a single break expression without a label or sub-expression,
+/// possibly embedded in blocks.
 fn is_simple_break_expr(e: &Expr<'_>) -> bool {
-    matches!(peel_blocks(e).kind, ExprKind::Break(dest, None) if dest.label.is_none())
-}
-
-/// Removes any blocks containing only a single expression.
-fn peel_blocks<'tcx>(e: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
     if let ExprKind::Block(b, _) = e.kind {
         match (b.stmts, b.expr) {
-            ([s], None) => {
-                if let StmtKind::Expr(e) | StmtKind::Semi(e) = s.kind {
-                    peel_blocks(e)
-                } else {
-                    e
-                }
-            },
-            ([], Some(e)) => peel_blocks(e),
-            _ => e,
+            ([s], None) => matches!(s.kind, StmtKind::Expr(e) | StmtKind::Semi(e) if is_simple_break_expr(e)),
+            ([], Some(e)) => is_simple_break_expr(e),
+            _ => false,
         }
     } else {
-        e
+        matches!(e.kind, ExprKind::Break(dest, None) if dest.label.is_none())
     }
 }
 
@@ -72,6 +69,8 @@ fn could_be_while_let<'tcx>(
     let_pat: &'tcx Pat<'_>,
     let_expr: &'tcx Expr<'_>,
     has_trailing_exprs: bool,
+    let_info: Option<(&Pat<'_>, Option<&Ty<'_>>)>,
+    inner_expr: &Expr<'_>,
 ) {
     if has_trailing_exprs
         && (needs_ordered_drop(cx, cx.typeck_results().expr_ty(let_expr))
@@ -86,7 +85,24 @@ fn could_be_while_let<'tcx>(
     // 1) it was ugly with big bodies;
     // 2) it was not indented properly;
     // 3) it wasn’t very smart (see #675).
-    let mut applicability = Applicability::HasPlaceholders;
+    let inner_content = if let Some((pat, ty)) = let_info
+        // Prevent trivial reassignments such as `let x = x;` or `let _ = …;`, but
+        // keep them if the type has been explicitly specified.
+        && (!is_trivial_assignment(pat, peel_blocks(inner_expr)) || ty.is_some())
+        && let Some(pat_str) = snippet_opt(cx, pat.span)
+        && let Some(init_str) = snippet_opt(cx, peel_blocks(inner_expr).span)
+    {
+        let ty_str = ty
+            .map(|ty| format!(": {}", snippet(cx, ty.span, "_")))
+            .unwrap_or_default();
+        format!(
+            "\n{indent}    let {pat_str}{ty_str} = {init_str};\n{indent}    ..\n{indent}",
+            indent = snippet_indent(cx, expr.span).unwrap_or_default(),
+        )
+    } else {
+        " .. ".into()
+    };
+
     span_lint_and_sugg(
         cx,
         WHILE_LET_LOOP,
@@ -94,10 +110,21 @@ fn could_be_while_let<'tcx>(
         "this loop could be written as a `while let` loop",
         "try",
         format!(
-            "while let {} = {} {{ .. }}",
-            snippet_with_applicability(cx, let_pat.span, "..", &mut applicability),
-            snippet_with_applicability(cx, let_expr.span, "..", &mut applicability),
+            "while let {} = {} {{{inner_content}}}",
+            snippet(cx, let_pat.span, ".."),
+            snippet(cx, let_expr.span, ".."),
         ),
-        applicability,
+        Applicability::HasPlaceholders,
     );
 }
+
+fn is_trivial_assignment(pat: &Pat<'_>, init: &Expr<'_>) -> bool {
+    match (pat.kind, init.kind) {
+        (PatKind::Wild, _) => true,
+        (
+            PatKind::Binding(BindingMode::NONE, _, pat_ident, None),
+            ExprKind::Path(QPath::Resolved(None, Path { segments: [init], .. })),
+        ) => pat_ident.name == init.ident.name,
+        _ => false,
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs
index 98ad1f6a160..c1a26c5a9c7 100644
--- a/src/tools/clippy/clippy_lints/src/macro_use.rs
+++ b/src/tools/clippy/clippy_lints/src/macro_use.rs
@@ -100,10 +100,7 @@ impl LateLintPass<'_> for MacroUseImports {
             && let hir_id = item.hir_id()
             && let attrs = cx.tcx.hir_attrs(hir_id)
             && let Some(mac_attr) = attrs.iter().find(|attr| attr.has_name(sym::macro_use))
-            && let Some(id) = path.res.iter().find_map(|res| match res {
-                Res::Def(DefKind::Mod, id) => Some(id),
-                _ => None,
-            })
+            && let Some(Res::Def(DefKind::Mod, id)) = path.res.type_ns
             && !id.is_local()
         {
             for kid in cx.tcx.module_children(id) {
diff --git a/src/tools/clippy/clippy_lints/src/manual_is_power_of_two.rs b/src/tools/clippy/clippy_lints/src/manual_is_power_of_two.rs
index b4cd988329d..4439a28763a 100644
--- a/src/tools/clippy/clippy_lints/src/manual_is_power_of_two.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_is_power_of_two.rs
@@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::ty_from_hir_ty;
-use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal};
+use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
@@ -103,7 +103,7 @@ fn count_ones_receiver<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Optio
     } else {
         return None;
     };
-    (method.ident.as_str() == "count_ones" && matches!(ty.kind(), ty::Uint(_))).then_some(receiver)
+    (method.ident.name == sym::count_ones && matches!(ty.kind(), ty::Uint(_))).then_some(receiver)
 }
 
 /// Return `greater` if `smaller == greater - 1`
diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
index 067b92cd46e..3562b1ff5cc 100644
--- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
@@ -87,7 +87,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive {
         }
 
         match item.kind {
-            ItemKind::Enum(_, def, _) if def.variants.len() > 1 => {
+            ItemKind::Enum(_, _, def) if def.variants.len() > 1 => {
                 let iter = def.variants.iter().filter_map(|v| {
                     (matches!(v.data, VariantData::Unit(_, _)) && is_doc_hidden(cx.tcx.hir_attrs(v.hir_id)))
                         .then_some((v.def_id, v.span))
@@ -98,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive {
                     self.potential_enums.push((item.owner_id.def_id, id, item.span, span));
                 }
             },
-            ItemKind::Struct(_, variant_data, _) => {
+            ItemKind::Struct(_, _, variant_data) => {
                 let fields = variant_data.fields();
                 let private_fields = fields
                     .iter()
diff --git a/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs b/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
index 2dad0fa4925..0c09a47c965 100644
--- a/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
@@ -1,11 +1,13 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::{expr_or_init, is_in_const_context, std_or_core};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
-use rustc_session::declare_lint_pass;
+use rustc_session::impl_lint_pass;
 use rustc_span::symbol::sym;
 
 declare_clippy_lint! {
@@ -36,20 +38,33 @@ declare_clippy_lint! {
     complexity,
     "manual slice size calculation"
 }
-declare_lint_pass!(ManualSliceSizeCalculation => [MANUAL_SLICE_SIZE_CALCULATION]);
+impl_lint_pass!(ManualSliceSizeCalculation => [MANUAL_SLICE_SIZE_CALCULATION]);
+
+pub struct ManualSliceSizeCalculation {
+    msrv: Msrv,
+}
+
+impl ManualSliceSizeCalculation {
+    pub fn new(conf: &Conf) -> Self {
+        Self { msrv: conf.msrv }
+    }
+}
 
 impl<'tcx> LateLintPass<'tcx> for ManualSliceSizeCalculation {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if let ExprKind::Binary(ref op, left, right) = expr.kind
             && BinOpKind::Mul == op.node
             && !expr.span.from_expansion()
-            // Does not apply inside const because size_of_val is not cost in stable.
-            && !is_in_const_context(cx)
             && let Some((receiver, refs_count)) = simplify(cx, left, right)
+            && (!is_in_const_context(cx) || self.msrv.meets(cx, msrvs::CONST_SIZE_OF_VAL))
         {
             let ctxt = expr.span.ctxt();
             let mut app = Applicability::MachineApplicable;
-            let deref = "*".repeat(refs_count - 1);
+            let deref = if refs_count > 0 {
+                "*".repeat(refs_count - 1)
+            } else {
+                "&".into()
+            };
             let val_name = snippet_with_context(cx, receiver.span, ctxt, "slice", &mut app).0;
             let Some(sugg) = std_or_core(cx) else { return };
 
diff --git a/src/tools/clippy/clippy_lints/src/manual_string_new.rs b/src/tools/clippy/clippy_lints/src/manual_string_new.rs
index 7ca3b712066..73ee1c3c78a 100644
--- a/src/tools/clippy/clippy_lints/src/manual_string_new.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_string_new.rs
@@ -5,7 +5,7 @@ use rustc_hir::{Expr, ExprKind, PathSegment, QPath, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
-use rustc_span::{Span, sym, symbol};
+use rustc_span::{Span, sym};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -67,7 +67,7 @@ impl LateLintPass<'_> for ManualStringNew {
 fn is_expr_kind_empty_str(expr_kind: &ExprKind<'_>) -> bool {
     if let ExprKind::Lit(lit) = expr_kind
         && let LitKind::Str(value, _) = lit.node
-        && value == symbol::kw::Empty
+        && value == sym::empty
     {
         return true;
     }
diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
index b607f8117eb..af6a1b07a49 100644
--- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
@@ -255,7 +255,7 @@ impl LateLintPass<'_> for MapUnit {
     fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &hir::Stmt<'_>) {
         if let hir::StmtKind::Semi(expr) = stmt.kind
             && !stmt.span.from_expansion()
-            && let Some(arglists) = method_chain_args(expr, &["map"])
+            && let Some(arglists) = method_chain_args(expr, &[sym::map])
         {
             lint_map_unit_fn(cx, stmt, expr, arglists[0]);
         }
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
index 3ac2c9fc2b3..8c3f52542d9 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
@@ -109,7 +109,7 @@ fn handle(
             && implements_trait(cx, expr_type, default_trait_id, &[])
             // We check if the initial condition implements Default.
             && let Some(condition_ty) = cx.typeck_results().expr_ty(condition).walk().nth(1)
-            && let GenericArgKind::Type(condition_ty) = condition_ty.unpack()
+            && let GenericArgKind::Type(condition_ty) = condition_ty.kind()
             && implements_trait(cx, condition_ty, default_trait_id, &[])
             && is_default_equivalent(cx, peel_blocks(body_none))
         {
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
index a21597ffb93..dbb29ee776b 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
@@ -1,8 +1,9 @@
-use clippy_utils::diagnostics::span_lint_hir_and_then;
-use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{SpanlessEq, SpanlessHash, is_lint_allowed, path_to_local, search_same};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::SpanRangeExt;
+use clippy_utils::{SpanlessEq, SpanlessHash, fulfill_or_allowed, is_lint_allowed, path_to_local, search_same};
 use core::cmp::Ordering;
 use core::{iter, slice};
+use itertools::Itertools;
 use rustc_arena::DroplessArena;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
@@ -110,57 +111,68 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
             && check_same_body()
     };
 
-    let mut appl = Applicability::MaybeIncorrect;
     let indexed_arms: Vec<(usize, &Arm<'_>)> = arms.iter().enumerate().collect();
-    for (&(i, arm1), &(j, arm2)) in search_same(&indexed_arms, hash, eq) {
-        if matches!(arm2.pat.kind, PatKind::Wild) {
-            if !cx.tcx.features().non_exhaustive_omitted_patterns_lint()
-                || is_lint_allowed(cx, NON_EXHAUSTIVE_OMITTED_PATTERNS, arm2.hir_id)
-            {
-                let arm_span = adjusted_arm_span(cx, arm1.span);
-                span_lint_hir_and_then(
-                    cx,
-                    MATCH_SAME_ARMS,
-                    arm1.hir_id,
-                    arm_span,
-                    "this match arm has an identical body to the `_` wildcard arm",
-                    |diag| {
-                        diag.span_suggestion(arm_span, "try removing the arm", "", appl)
-                            .help("or try changing either arm body")
-                            .span_note(arm2.span, "`_` wildcard arm here");
-                    },
-                );
-            }
-        } else {
-            let back_block = backwards_blocking_idxs[j];
-            let (keep_arm, move_arm) = if back_block < i || (back_block == 0 && forwards_blocking_idxs[i] <= j) {
-                (arm1, arm2)
-            } else {
-                (arm2, arm1)
-            };
-
-            span_lint_hir_and_then(
-                cx,
-                MATCH_SAME_ARMS,
-                keep_arm.hir_id,
-                keep_arm.span,
-                "this match arm has an identical body to another arm",
-                |diag| {
-                    let move_pat_snip = snippet_with_applicability(cx, move_arm.pat.span, "<pat2>", &mut appl);
-                    let keep_pat_snip = snippet_with_applicability(cx, keep_arm.pat.span, "<pat1>", &mut appl);
+    for mut group in search_same(&indexed_arms, hash, eq) {
+        // Filter out (and fulfill) `#[allow]`ed and `#[expect]`ed arms
+        group.retain(|(_, arm)| !fulfill_or_allowed(cx, MATCH_SAME_ARMS, [arm.hir_id]));
 
-                    diag.multipart_suggestion(
-                        "or try merging the arm patterns and removing the obsolete arm",
-                        vec![
-                            (keep_arm.pat.span, format!("{keep_pat_snip} | {move_pat_snip}")),
-                            (adjusted_arm_span(cx, move_arm.span), String::new()),
-                        ],
-                        appl,
-                    )
-                    .help("try changing either arm body");
-                },
-            );
+        if group.len() < 2 {
+            continue;
         }
+
+        span_lint_and_then(
+            cx,
+            MATCH_SAME_ARMS,
+            group.iter().map(|(_, arm)| arm.span).collect_vec(),
+            "these match arms have identical bodies",
+            |diag| {
+                diag.help("if this is unintentional make the arms return different values");
+
+                if let [prev @ .., (_, last)] = group.as_slice()
+                    && is_wildcard_arm(last.pat)
+                    && is_lint_allowed(cx, NON_EXHAUSTIVE_OMITTED_PATTERNS, last.hir_id)
+                {
+                    diag.span_label(last.span, "the wildcard arm");
+
+                    let s = if prev.len() > 1 { "s" } else { "" };
+                    diag.multipart_suggestion_verbose(
+                        format!("otherwise remove the non-wildcard arm{s}"),
+                        prev.iter()
+                            .map(|(_, arm)| (adjusted_arm_span(cx, arm.span), String::new()))
+                            .collect(),
+                        Applicability::MaybeIncorrect,
+                    );
+                } else if let &[&(first_idx, _), .., &(last_idx, _)] = group.as_slice() {
+                    let back_block = backwards_blocking_idxs[last_idx];
+                    let split = if back_block < first_idx
+                        || (back_block == 0 && forwards_blocking_idxs[first_idx] <= last_idx)
+                    {
+                        group.split_first()
+                    } else {
+                        group.split_last()
+                    };
+
+                    if let Some(((_, dest), src)) = split
+                        && let Some(pat_snippets) = group
+                            .iter()
+                            .map(|(_, arm)| arm.pat.span.get_source_text(cx))
+                            .collect::<Option<Vec<_>>>()
+                    {
+                        let mut suggs = src
+                            .iter()
+                            .map(|(_, arm)| (adjusted_arm_span(cx, arm.span), String::new()))
+                            .collect_vec();
+
+                        suggs.push((dest.pat.span, pat_snippets.iter().join(" | ")));
+                        diag.multipart_suggestion_verbose(
+                            "otherwise merge the patterns into a single arm",
+                            suggs,
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                }
+            },
+        );
     }
 }
 
@@ -450,3 +462,11 @@ fn bindings_eq(pat: &Pat<'_>, mut ids: HirIdSet) -> bool {
     pat.each_binding_or_first(&mut |_, id, _, _| result &= ids.swap_remove(&id));
     result && ids.is_empty()
 }
+
+fn is_wildcard_arm(pat: &Pat<'_>) -> bool {
+    match pat.kind {
+        PatKind::Wild => true,
+        PatKind::Or([.., last]) => matches!(last.kind, PatKind::Wild),
+        _ => false,
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index c6ebd6144c7..c128fc40b73 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -28,7 +28,7 @@ use clippy_config::Conf;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::walk_span_to_context;
 use clippy_utils::{
-    higher, is_direct_expn_of, is_in_const_context, is_span_match, span_contains_cfg, span_extract_comments,
+    higher, is_direct_expn_of, is_in_const_context, is_span_match, span_contains_cfg, span_extract_comments, sym,
 };
 use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -1053,13 +1053,13 @@ impl_lint_pass!(Matches => [
 impl<'tcx> LateLintPass<'tcx> for Matches {
     #[expect(clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if is_direct_expn_of(expr.span, "matches").is_none() && expr.span.in_external_macro(cx.sess().source_map()) {
+        if is_direct_expn_of(expr.span, sym::matches).is_none() && expr.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
         let from_expansion = expr.span.from_expansion();
 
         if let ExprKind::Match(ex, arms, source) = expr.kind {
-            if is_direct_expn_of(expr.span, "matches").is_some()
+            if is_direct_expn_of(expr.span, sym::matches).is_some()
                 && let [arm, _] = arms
             {
                 redundant_pattern_match::check_match(cx, expr, ex, arms);
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 6c5d7cab203..b04db03f8d2 100644
--- a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
@@ -74,7 +74,7 @@ fn check_all_arms(cx: &LateContext<'_>, match_expr: &Expr<'_>, arms: &[Arm<'_>])
         }
 
         if let PatKind::Wild = arm.pat.kind {
-            if !eq_expr_value(cx, match_expr, strip_return(arm_expr)) {
+            if !eq_expr_value(cx, match_expr, arm_expr) {
                 return false;
             }
         } else if !pat_same_as_expr(arm.pat, arm_expr) {
@@ -103,27 +103,18 @@ fn check_if_let_inner(cx: &LateContext<'_>, if_let: &higher::IfLet<'_>) -> bool
             if matches!(else_expr.kind, ExprKind::Block(..)) {
                 return false;
             }
-            let ret = strip_return(else_expr);
             let let_expr_ty = cx.typeck_results().expr_ty(if_let.let_expr);
             if is_type_diagnostic_item(cx, let_expr_ty, sym::Option) {
-                return is_res_lang_ctor(cx, path_res(cx, ret), OptionNone) || eq_expr_value(cx, if_let.let_expr, ret);
+                return is_res_lang_ctor(cx, path_res(cx, else_expr), OptionNone)
+                    || eq_expr_value(cx, if_let.let_expr, else_expr);
             }
-            return eq_expr_value(cx, if_let.let_expr, ret);
+            return eq_expr_value(cx, if_let.let_expr, else_expr);
         }
     }
 
     false
 }
 
-/// Strip `return` keyword if the expression type is `ExprKind::Ret`.
-fn strip_return<'hir>(expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> {
-    if let ExprKind::Ret(Some(ret)) = expr.kind {
-        ret
-    } else {
-        expr
-    }
-}
-
 /// Manually check for coercion casting by checking if the type of the match operand or let expr
 /// differs with the assigned local variable or the function return type.
 fn expr_ty_matches_p_ty(cx: &LateContext<'_>, expr: &Expr<'_>, p_expr: &Expr<'_>) -> bool {
@@ -161,7 +152,6 @@ fn expr_ty_matches_p_ty(cx: &LateContext<'_>, expr: &Expr<'_>, p_expr: &Expr<'_>
 }
 
 fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
-    let expr = strip_return(expr);
     match (&pat.kind, &expr.kind) {
         // Example: `Some(val) => Some(val)`
         (PatKind::TupleStruct(QPath::Resolved(_, path), tuple_params, _), ExprKind::Call(call_expr, call_params)) => {
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
index 9bbef8da0a4..7c6d45e4240 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
@@ -3,14 +3,14 @@ use clippy_utils::macros::matching_root_macro_call;
 use clippy_utils::msrvs::Msrv;
 use clippy_utils::source::snippet;
 use clippy_utils::visitors::{for_each_expr_without_closures, is_local_used};
-use clippy_utils::{is_in_const_context, path_to_local};
+use clippy_utils::{is_in_const_context, path_to_local, sym};
 use rustc_ast::{BorrowKind, LitKind};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Arm, BinOpKind, Expr, ExprKind, MatchSource, Node, PatKind, UnOp};
 use rustc_lint::LateContext;
 use rustc_span::symbol::Ident;
-use rustc_span::{Span, sym};
+use rustc_span::{Span, Symbol};
 use std::borrow::Cow;
 use std::ops::ControlFlow;
 
@@ -95,7 +95,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv:
         } else if let ExprKind::MethodCall(path, recv, args, ..) = guard.kind
             && let Some(binding) = get_pat_binding(cx, recv, outer_arm)
         {
-            check_method_calls(cx, outer_arm, path.ident.name.as_str(), recv, args, guard, &binding);
+            check_method_calls(cx, outer_arm, path.ident.name, recv, args, guard, &binding);
         }
     }
 }
@@ -103,7 +103,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv:
 fn check_method_calls<'tcx>(
     cx: &LateContext<'tcx>,
     arm: &Arm<'tcx>,
-    method: &str,
+    method: Symbol,
     recv: &Expr<'_>,
     args: &[Expr<'_>],
     if_expr: &Expr<'_>,
@@ -112,7 +112,7 @@ fn check_method_calls<'tcx>(
     let ty = cx.typeck_results().expr_ty(recv).peel_refs();
     let slice_like = ty.is_slice() || ty.is_array();
 
-    let sugg = if method == "is_empty" {
+    let sugg = if method == sym::is_empty {
         // `s if s.is_empty()` becomes ""
         // `arr if arr.is_empty()` becomes []
 
@@ -137,9 +137,9 @@ fn check_method_calls<'tcx>(
 
         if needles.is_empty() {
             sugg.insert_str(1, "..");
-        } else if method == "starts_with" {
+        } else if method == sym::starts_with {
             sugg.insert_str(sugg.len() - 1, ", ..");
-        } else if method == "ends_with" {
+        } else if method == sym::ends_with {
             sugg.insert_str(1, ".., ");
         } else {
             return;
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 db20be40f27..c936c96f971 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
@@ -108,7 +108,7 @@ fn find_match_true<'tcx>(
 fn try_get_generic_ty(ty: Ty<'_>, index: usize) -> Option<Ty<'_>> {
     if let ty::Adt(_, subs) = ty.kind()
         && let Some(sub) = subs.get(index)
-        && let GenericArgKind::Type(sub_ty) = sub.unpack()
+        && let GenericArgKind::Type(sub_ty) = sub.kind()
     {
         Some(sub_ty)
     } else {
@@ -273,7 +273,7 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
         let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
 
         if let Some((good_method, maybe_guard)) = found_good_method(cx, arms, node_pair) {
-            let span = is_expn_of(expr.span, "matches").unwrap_or(expr.span.to(op.span));
+            let span = is_expn_of(expr.span, sym::matches).unwrap_or(expr.span.to(op.span));
             let result_expr = match &op.kind {
                 ExprKind::AddrOf(_, _, borrowed) => borrowed,
                 _ => op,
diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
index d7dc7604088..88b4d9b7d54 100644
--- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
@@ -4,7 +4,7 @@ use crate::FxHashSet;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::{first_line_of_span, indent_of, snippet};
 use clippy_utils::ty::{for_each_top_level_late_bound_region, is_copy};
-use clippy_utils::{get_attr, is_lint_allowed};
+use clippy_utils::{get_attr, is_lint_allowed, sym};
 use itertools::Itertools;
 use rustc_ast::Mutability;
 use rustc_data_structures::fx::FxIndexSet;
@@ -186,7 +186,7 @@ impl<'a, 'tcx> SigDropChecker<'a, 'tcx> {
             && get_attr(
                 self.cx.sess(),
                 self.cx.tcx.get_attrs_unchecked(adt.did()),
-                "has_significant_drop",
+                sym::has_significant_drop,
             )
             .count()
                 > 0
@@ -208,12 +208,12 @@ impl<'a, 'tcx> SigDropChecker<'a, 'tcx> {
                     // (to avoid false positive on `Ref<'a, MutexGuard<Foo>>`)
                     || (args
                         .iter()
-                        .all(|arg| !matches!(arg.unpack(), GenericArgKind::Lifetime(_)))
+                        .all(|arg| !matches!(arg.kind(), GenericArgKind::Lifetime(_)))
                         // some generic parameter has significant drop
                         // (to avoid false negative on `Box<MutexGuard<Foo>>`)
                         && args
                             .iter()
-                            .filter_map(|arg| match arg.unpack() {
+                            .filter_map(|arg| match arg.kind() {
                                 GenericArgKind::Type(ty) => Some(ty),
                                 _ => None,
                             })
diff --git a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
index de22514c37c..02fc09170e5 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::sym;
 use clippy_utils::ty::is_type_lang_item;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, LangItem};
@@ -25,7 +26,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E
 
     if let Some(parent) = clippy_utils::get_parent_expr(cx, expr)
         && let Some((name, _, _, _, _)) = method_call(parent)
-        && name == "unwrap"
+        && name == sym::unwrap
     {
         span_lint_and_sugg(
             cx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs b/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
index 4ae0aeea2d1..de27a45ba4d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
@@ -5,12 +5,13 @@ use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, Lint};
 use rustc_middle::ty;
+use rustc_span::Symbol;
 
 /// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints.
 pub(super) fn check(
     cx: &LateContext<'_>,
     info: &crate::methods::BinaryExprInfo<'_>,
-    chain_methods: &[&str],
+    chain_methods: &[Symbol],
     lint: &'static Lint,
     suggest: &str,
 ) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
index 9c45ec2e56c..1c72a973cfa 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
@@ -5,12 +5,13 @@ use rustc_ast::ast;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, Lint};
+use rustc_span::Symbol;
 
 /// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints with `unwrap()`.
 pub(super) fn check(
     cx: &LateContext<'_>,
     info: &crate::methods::BinaryExprInfo<'_>,
-    chain_methods: &[&str],
+    chain_methods: &[Symbol],
     lint: &'static Lint,
     suggest: &str,
 ) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp.rs b/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp.rs
index 2efff4c3c54..8729e91d191 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp.rs
@@ -1,13 +1,14 @@
 use crate::methods::chars_cmp;
+use clippy_utils::sym;
 use rustc_lint::LateContext;
 
 use super::CHARS_LAST_CMP;
 
 /// Checks for the `CHARS_LAST_CMP` lint.
 pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
-    if chars_cmp::check(cx, info, &["chars", "last"], CHARS_LAST_CMP, "ends_with") {
+    if chars_cmp::check(cx, info, &[sym::chars, sym::last], CHARS_LAST_CMP, "ends_with") {
         true
     } else {
-        chars_cmp::check(cx, info, &["chars", "next_back"], CHARS_LAST_CMP, "ends_with")
+        chars_cmp::check(cx, info, &[sym::chars, sym::next_back], CHARS_LAST_CMP, "ends_with")
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs
index 5b8713f7d79..027d0a3947b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_last_cmp_with_unwrap.rs
@@ -1,13 +1,26 @@
 use crate::methods::chars_cmp_with_unwrap;
+use clippy_utils::sym;
 use rustc_lint::LateContext;
 
 use super::CHARS_LAST_CMP;
 
 /// Checks for the `CHARS_LAST_CMP` lint with `unwrap()`.
 pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
-    if chars_cmp_with_unwrap::check(cx, info, &["chars", "last", "unwrap"], CHARS_LAST_CMP, "ends_with") {
+    if chars_cmp_with_unwrap::check(
+        cx,
+        info,
+        &[sym::chars, sym::last, sym::unwrap],
+        CHARS_LAST_CMP,
+        "ends_with",
+    ) {
         true
     } else {
-        chars_cmp_with_unwrap::check(cx, info, &["chars", "next_back", "unwrap"], CHARS_LAST_CMP, "ends_with")
+        chars_cmp_with_unwrap::check(
+            cx,
+            info,
+            &[sym::chars, sym::next_back, sym::unwrap],
+            CHARS_LAST_CMP,
+            "ends_with",
+        )
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp.rs b/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp.rs
index b631fecab97..2438843bf3a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp.rs
@@ -1,8 +1,9 @@
+use clippy_utils::sym;
 use rustc_lint::LateContext;
 
 use super::CHARS_NEXT_CMP;
 
 /// Checks for the `CHARS_NEXT_CMP` lint.
 pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
-    crate::methods::chars_cmp::check(cx, info, &["chars", "next"], CHARS_NEXT_CMP, "starts_with")
+    crate::methods::chars_cmp::check(cx, info, &[sym::chars, sym::next], CHARS_NEXT_CMP, "starts_with")
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs
index caf21d3ff3b..9b3609f19d7 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_next_cmp_with_unwrap.rs
@@ -1,8 +1,15 @@
+use clippy_utils::sym;
 use rustc_lint::LateContext;
 
 use super::CHARS_NEXT_CMP;
 
 /// Checks for the `CHARS_NEXT_CMP` lint with `unwrap()`.
 pub(super) fn check(cx: &LateContext<'_>, info: &crate::methods::BinaryExprInfo<'_>) -> bool {
-    crate::methods::chars_cmp_with_unwrap::check(cx, info, &["chars", "next", "unwrap"], CHARS_NEXT_CMP, "starts_with")
+    crate::methods::chars_cmp_with_unwrap::check(
+        cx,
+        info,
+        &[sym::chars, sym::next, sym::unwrap],
+        CHARS_NEXT_CMP,
+        "starts_with",
+    )
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs b/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs
index f7bf8764bde..6d0b944df55 100644
--- a/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
 use clippy_utils::visitors::for_each_expr_without_closures;
-use clippy_utils::{eq_expr_value, get_parent_expr};
+use clippy_utils::{eq_expr_value, get_parent_expr, sym};
 use core::ops::ControlFlow;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
@@ -22,7 +22,7 @@ pub(super) fn check<'tcx>(
         // If the parent node's `to` argument is the same as the `to` argument
         // of the last replace call in the current chain, don't lint as it was already linted
         if let Some(parent) = get_parent_expr(cx, expr)
-            && let Some(("replace", _, [current_from, current_to], _, _)) = method_call(parent)
+            && let Some((sym::replace, _, [current_from, current_to], _, _)) = method_call(parent)
             && eq_expr_value(cx, to, current_to)
             && from_kind == cx.typeck_results().expr_ty(current_from).peel_refs().kind()
         {
@@ -47,7 +47,7 @@ fn collect_replace_calls<'tcx>(
     let mut from_args = VecDeque::new();
 
     let _: Option<()> = for_each_expr_without_closures(expr, |e| {
-        if let Some(("replace", _, [from, to], _, _)) = method_call(e) {
+        if let Some((sym::replace, _, [from, to], _, _)) = method_call(e) {
             if eq_expr_value(cx, to_arg, to) && cx.typeck_results().expr_ty(from).peel_refs().is_char() {
                 methods.push_front(e);
                 from_args.push_front(from);
diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
index f5688e370a4..82e5a6d5a41 100644
--- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
@@ -6,8 +6,8 @@ use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 use rustc_middle::ty;
-use rustc_span::Span;
 use rustc_span::symbol::sym;
+use rustc_span::{Span, Symbol};
 use std::borrow::Cow;
 
 use super::EXPECT_FUN_CALL;
@@ -19,7 +19,7 @@ pub(super) fn check<'tcx>(
     format_args_storage: &FormatArgsStorage,
     expr: &hir::Expr<'_>,
     method_span: Span,
-    name: &str,
+    name: Symbol,
     receiver: &'tcx hir::Expr<'tcx>,
     args: &'tcx [hir::Expr<'tcx>],
 ) {
@@ -114,7 +114,7 @@ pub(super) fn check<'tcx>(
         }
     }
 
-    if args.len() != 1 || name != "expect" || !is_call(&args[0].kind) {
+    if args.len() != 1 || name != sym::expect || !is_call(&args[0].kind) {
         return;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs b/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs
index 460ec7b3640..db60061904f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs
@@ -1,10 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::sym;
 use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, LangItem};
 use rustc_lint::LateContext;
-use rustc_span::symbol::sym;
 
 use super::EXTEND_WITH_DRAIN;
 
@@ -13,7 +13,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg:
     if is_type_diagnostic_item(cx, ty, sym::Vec)
         //check source object
         && let ExprKind::MethodCall(src_method, drain_vec, [drain_arg], _) = &arg.kind
-        && src_method.ident.as_str() == "drain"
+        && src_method.ident.name == sym::drain
         && let src_ty = cx.typeck_results().expr_ty(drain_vec)
         //check if actual src type is mutable for code suggestion
         && let immutable = src_ty.is_mutable_ptr()
diff --git a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
index 519091406cc..9724463f0c0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs
@@ -1,15 +1,15 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::implements_trait;
-use clippy_utils::{is_diag_item_method, is_diag_trait_item, peel_middle_ty_refs};
+use clippy_utils::{is_diag_item_method, is_diag_trait_item, peel_middle_ty_refs, sym};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
-use rustc_span::sym;
+use rustc_span::Symbol;
 
 use super::IMPLICIT_CLONE;
 
-pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
+pub fn check(cx: &LateContext<'_>, method_name: Symbol, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
     if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
         && is_clone_like(cx, method_name, method_def_id)
         && let return_type = cx.typeck_results().expr_ty(expr)
@@ -43,12 +43,12 @@ pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv
 /// Note that `to_string` is not flagged by `implicit_clone`. So other lints that call
 /// `is_clone_like` and that do flag `to_string` must handle it separately. See, e.g.,
 /// `is_to_owned_like` in `unnecessary_to_owned.rs`.
-pub fn is_clone_like(cx: &LateContext<'_>, method_name: &str, method_def_id: hir::def_id::DefId) -> bool {
+pub fn is_clone_like(cx: &LateContext<'_>, method_name: Symbol, method_def_id: hir::def_id::DefId) -> bool {
     match method_name {
-        "to_os_string" => is_diag_item_method(cx, method_def_id, sym::OsStr),
-        "to_owned" => is_diag_trait_item(cx, method_def_id, sym::ToOwned),
-        "to_path_buf" => is_diag_item_method(cx, method_def_id, sym::Path),
-        "to_vec" => cx
+        sym::to_os_string => is_diag_item_method(cx, method_def_id, sym::OsStr),
+        sym::to_owned => is_diag_trait_item(cx, method_def_id, sym::ToOwned),
+        sym::to_path_buf => is_diag_item_method(cx, method_def_id, sym::Path),
+        sym::to_vec => cx
             .tcx
             .impl_of_method(method_def_id)
             .filter(|&impl_did| {
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs b/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs
index 17cc07b91c5..b4ab313fe98 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs
@@ -5,11 +5,16 @@ use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 use rustc_middle::ty;
-use rustc_span::sym;
+use rustc_span::{Symbol, sym};
 
 use super::ITER_CLONED_COLLECT;
 
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, method_name: &str, expr: &hir::Expr<'_>, recv: &'tcx hir::Expr<'_>) {
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    method_name: Symbol,
+    expr: &hir::Expr<'_>,
+    recv: &'tcx hir::Expr<'_>,
+) {
     let expr_ty = cx.typeck_results().expr_ty(expr);
     if is_type_diagnostic_item(cx, expr_ty, sym::Vec)
         && let Some(slice) = derefs_to_slice(cx, recv, cx.typeck_results().expr_ty(recv))
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_count.rs b/src/tools/clippy/clippy_lints/src/methods/iter_count.rs
index 209cf2fcc0a..6b64cc8b50a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_count.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_count.rs
@@ -5,11 +5,11 @@ use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
-use rustc_span::sym;
+use rustc_span::{Symbol, sym};
 
 use super::ITER_COUNT;
 
-pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx Expr<'tcx>, iter_method: &str) {
+pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx Expr<'tcx>, iter_method: Symbol) {
     let ty = cx.typeck_results().expr_ty(recv);
     let caller_type = if derefs_to_slice(cx, recv, ty).is_some() {
         "slice"
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
index 3ac9299ba91..c88462129af 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
@@ -1,12 +1,12 @@
 use super::ITER_KV_MAP;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::pat_is_wild;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{pat_is_wild, sym};
 use rustc_hir::{Body, Expr, ExprKind, PatKind};
 use rustc_lint::LateContext;
-use rustc_span::sym;
+use rustc_span::Symbol;
 
 /// lint use of:
 ///
@@ -16,13 +16,13 @@ use rustc_span::sym;
 /// on `HashMaps` and `BTreeMaps` in std
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
-    map_type: &'tcx str,     // iter / into_iter
+    map_type: Symbol,        // iter / into_iter
     expr: &'tcx Expr<'tcx>,  // .iter().map(|(_, v_| v))
     recv: &'tcx Expr<'tcx>,  // hashmap
     m_arg: &'tcx Expr<'tcx>, // |(_, v)| v
     msrv: Msrv,
 ) {
-    if map_type == "into_iter" && !msrv.meets(cx, msrvs::INTO_KEYS) {
+    if map_type == sym::into_iter && !msrv.meets(cx, msrvs::INTO_KEYS) {
         return;
     }
     if !expr.span.from_expansion()
@@ -42,7 +42,7 @@ pub(super) fn check<'tcx>(
     {
         let mut applicability = rustc_errors::Applicability::MachineApplicable;
         let recv_snippet = snippet_with_applicability(cx, recv.span, "map", &mut applicability);
-        let into_prefix = if map_type == "into_iter" { "into_" } else { "" };
+        let into_prefix = if map_type == sym::into_iter { "into_" } else { "" };
 
         if let ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body_expr.kind
             && let [local_ident] = path.segments
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs b/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs
index 82bda5d9512..1fdbd81bf24 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_nth.rs
@@ -1,10 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::sym;
 use clippy_utils::ty::get_type_diagnostic_name;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
-use rustc_span::Span;
-use rustc_span::symbol::sym;
+use rustc_span::{Span, Symbol};
 
 use super::ITER_NTH;
 
@@ -12,7 +12,7 @@ pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &hir::Expr<'_>,
     iter_recv: &'tcx hir::Expr<'tcx>,
-    iter_method: &str,
+    iter_method: Symbol,
     iter_span: Span,
     nth_span: Span,
 ) -> bool {
@@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(
         expr.span,
         format!("called `.{iter_method}().nth()` on a {caller_type}"),
         |diag| {
-            let get_method = if iter_method == "iter_mut" { "get_mut" } else { "get" };
+            let get_method = if iter_method == sym::iter_mut { "get_mut" } else { "get" };
             diag.span_suggestion_verbose(
                 iter_span.to(nth_span),
                 format!("`{get_method}` is equivalent but more concise"),
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs
index 9d562f5e51d..c0366765234 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs
@@ -2,7 +2,7 @@ use std::iter::once;
 
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
-use clippy_utils::{get_expr_use_or_unification_node, is_res_lang_ctor, path_res, std_or_core};
+use clippy_utils::{get_expr_use_or_unification_node, is_res_lang_ctor, path_res, std_or_core, sym};
 
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
@@ -10,6 +10,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::hir_id::HirId;
 use rustc_hir::{Expr, ExprKind, Node};
 use rustc_lint::LateContext;
+use rustc_span::Symbol;
 
 use super::{ITER_ON_EMPTY_COLLECTIONS, ITER_ON_SINGLE_ITEMS};
 
@@ -51,7 +52,7 @@ fn is_arg_ty_unified_in_fn<'tcx>(
         .any(|(i, ty)| i != arg_id_in_args && ty.skip_binder().walk().any(|arg| arg.as_type() == Some(arg_ty_in_args)))
 }
 
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: &str, recv: &'tcx Expr<'tcx>) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol, recv: &'tcx Expr<'tcx>) {
     let item = match recv.kind {
         ExprKind::Array([]) => None,
         ExprKind::Array([e]) => Some(e),
@@ -60,9 +61,9 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method
         _ => return,
     };
     let iter_type = match method_name {
-        "iter" => IterType::Iter,
-        "iter_mut" => IterType::IterMut,
-        "into_iter" => IterType::IntoIter,
+        sym::iter => IterType::Iter,
+        sym::iter_mut => IterType::IterMut,
+        sym::into_iter => IterType::IntoIter,
         _ => return,
     };
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
index 7bb625222ec..f5fe4316eb0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
@@ -8,7 +8,7 @@ use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, Pl
 use rustc_lint::LateContext;
 use rustc_middle::mir::{FakeReadCause, Mutability};
 use rustc_middle::ty::{self, BorrowKind};
-use rustc_span::sym;
+use rustc_span::{Symbol, sym};
 
 use super::ITER_OVEREAGER_CLONED;
 use crate::redundant_clone::REDUNDANT_CLONE;
@@ -26,7 +26,7 @@ pub(super) enum Op<'a> {
     // later `.cloned()`
     // and add `&` to the parameter of closure parameter
     // e.g. `find` `filter`
-    FixClosure(&'a str, &'a Expr<'a>),
+    FixClosure(Symbol, &'a Expr<'a>),
 
     // later `.cloned()`
     // e.g. `skip` `take`
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_c_str_literals.rs b/src/tools/clippy/clippy_lints/src/methods/manual_c_str_literals.rs
index 3fa83cd39d1..a8445b68dd6 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_c_str_literals.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_c_str_literals.rs
@@ -168,7 +168,7 @@ fn rewrite_as_cstr(cx: &LateContext<'_>, span: Span) -> Option<String> {
 
 fn get_cast_target<'tcx>(e: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
     match &e.kind {
-        ExprKind::MethodCall(method, receiver, [], _) if method.ident.as_str() == "cast" => Some(receiver),
+        ExprKind::MethodCall(method, receiver, [], _) if method.ident.name == sym::cast => Some(receiver),
         ExprKind::Cast(expr, _) => Some(expr),
         _ => None,
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs
index 173ebcb7020..21f2ce8b7c9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs
@@ -3,18 +3,18 @@ use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::{IntoSpan, SpanRangeExt};
 use clippy_utils::ty::get_field_by_name;
 use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures};
-use clippy_utils::{ExprUseNode, expr_use_ctxt, is_diag_item_method, is_diag_trait_item, path_to_local_id};
+use clippy_utils::{ExprUseNode, expr_use_ctxt, is_diag_item_method, is_diag_trait_item, path_to_local_id, sym};
 use core::ops::ControlFlow;
 use rustc_errors::Applicability;
 use rustc_hir::{BindingMode, BorrowKind, ByRef, ClosureKind, Expr, ExprKind, Mutability, Node, PatKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
-use rustc_span::{DUMMY_SP, Span, Symbol, sym};
+use rustc_span::{DUMMY_SP, Span, Symbol};
 
 use super::MANUAL_INSPECT;
 
 #[expect(clippy::too_many_lines)]
-pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: &str, name_span: Span, msrv: Msrv) {
+pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: Symbol, name_span: Span, msrv: Msrv) {
     if let ExprKind::Closure(c) = arg.kind
         && matches!(c.kind, ClosureKind::Closure)
         && let typeck = cx.typeck_results()
@@ -101,7 +101,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
                 UseKind::Return(s) => edits.push((s.with_leading_whitespace(cx).with_ctxt(s.ctxt()), String::new())),
                 UseKind::Borrowed(s) => {
                     #[expect(clippy::range_plus_one)]
-                    let range = s.map_range(cx, |src, range| {
+                    let range = s.map_range(cx, |_, src, range| {
                         let src = src.get(range.clone())?;
                         let trimmed = src.trim_start_matches([' ', '\t', '\n', '\r', '(']);
                         trimmed.starts_with('&').then(|| {
@@ -168,8 +168,8 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
                 edits.extend(addr_of_edits);
             }
             let edit = match name {
-                "map" => "inspect",
-                "map_err" => "inspect_err",
+                sym::map => "inspect",
+                sym::map_err => "inspect_err",
                 _ => return,
             };
             edits.push((name_span, edit.to_string()));
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_is_variant_and.rs b/src/tools/clippy/clippy_lints/src/methods/manual_is_variant_and.rs
index 40aad03960c..4a61c223d2c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_is_variant_and.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_is_variant_and.rs
@@ -1,18 +1,22 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::get_parent_expr;
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::source::snippet;
+use clippy_utils::source::{snippet, snippet_opt};
 use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_errors::Applicability;
+use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
+use rustc_hir::{BinOpKind, Expr, ExprKind, QPath};
 use rustc_lint::LateContext;
-use rustc_span::{Span, sym};
+use rustc_middle::ty;
+use rustc_span::{BytePos, Span, sym};
 
 use super::MANUAL_IS_VARIANT_AND;
 
-pub(super) fn check<'tcx>(
+pub(super) fn check(
     cx: &LateContext<'_>,
-    expr: &'tcx rustc_hir::Expr<'_>,
-    map_recv: &'tcx rustc_hir::Expr<'_>,
-    map_arg: &'tcx rustc_hir::Expr<'_>,
+    expr: &Expr<'_>,
+    map_recv: &Expr<'_>,
+    map_arg: &Expr<'_>,
     map_span: Span,
     msrv: Msrv,
 ) {
@@ -57,3 +61,57 @@ pub(super) fn check<'tcx>(
         Applicability::MachineApplicable,
     );
 }
+
+fn emit_lint(cx: &LateContext<'_>, op: BinOpKind, parent: &Expr<'_>, method_span: Span, is_option: bool) {
+    if let Some(before_map_snippet) = snippet_opt(cx, parent.span.with_hi(method_span.lo()))
+        && let Some(after_map_snippet) = snippet_opt(cx, method_span.with_lo(method_span.lo() + BytePos(3)))
+    {
+        span_lint_and_sugg(
+            cx,
+            MANUAL_IS_VARIANT_AND,
+            parent.span,
+            format!(
+                "called `.map() {}= {}()`",
+                if op == BinOpKind::Eq { '=' } else { '!' },
+                if is_option { "Some" } else { "Ok" },
+            ),
+            "use",
+            if is_option && op == BinOpKind::Ne {
+                format!("{before_map_snippet}is_none_or{after_map_snippet}",)
+            } else {
+                format!(
+                    "{}{before_map_snippet}{}{after_map_snippet}",
+                    if op == BinOpKind::Eq { "" } else { "!" },
+                    if is_option { "is_some_and" } else { "is_ok_and" },
+                )
+            },
+            Applicability::MachineApplicable,
+        );
+    }
+}
+
+pub(super) fn check_map(cx: &LateContext<'_>, expr: &Expr<'_>) {
+    if let Some(parent_expr) = get_parent_expr(cx, expr)
+        && let ExprKind::Binary(op, left, right) = parent_expr.kind
+        && matches!(op.node, BinOpKind::Eq | BinOpKind::Ne)
+        && op.span.eq_ctxt(expr.span)
+    {
+        // Check `left` and `right` expression in any order, and for `Option` and `Result`
+        for (expr1, expr2) in [(left, right), (right, left)] {
+            for item in [sym::Option, sym::Result] {
+                if let ExprKind::Call(call, ..) = expr1.kind
+                    && let ExprKind::Path(QPath::Resolved(_, path)) = call.kind
+                    && let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), _) = path.res
+                    && let ty = cx.typeck_results().expr_ty(expr1)
+                    && let ty::Adt(adt, args) = ty.kind()
+                    && cx.tcx.is_diagnostic_item(item, adt.did())
+                    && args.type_at(0).is_bool()
+                    && let ExprKind::MethodCall(_, recv, _, span) = expr2.kind
+                    && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), item)
+                {
+                    return emit_lint(cx, op.node, parent_expr, span, item == sym::Option);
+                }
+            }
+        }
+    }
+}
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 05360144657..98def66ca14 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
@@ -5,7 +5,7 @@ use rustc_ast::BindingMode;
 use rustc_errors::Applicability;
 use rustc_hir::{self as hir, Node, PatKind};
 use rustc_lint::LateContext;
-use rustc_span::{Span, sym};
+use rustc_span::{Span, Symbol, sym};
 
 use super::MAP_IDENTITY;
 
@@ -14,7 +14,7 @@ pub(super) fn check(
     expr: &hir::Expr<'_>,
     caller: &hir::Expr<'_>,
     map_arg: &hir::Expr<'_>,
-    name: &str,
+    name: Symbol,
     _map_span: Span,
 ) {
     let caller_ty = cx.typeck_results().expr_ty(caller);
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index e0e6a1a59b6..bc159206985 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -150,7 +150,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::macros::FormatArgsStorage;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item};
-use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, peel_blocks, return_ty};
+use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, peel_blocks, return_ty, sym};
 pub use path_ends_with_ext::DEFAULT_ALLOWED_DOTFILES;
 use rustc_abi::ExternAbi;
 use rustc_data_structures::fx::FxHashSet;
@@ -159,7 +159,7 @@ use rustc_hir::{Expr, ExprKind, Node, Stmt, StmtKind, TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty::{self, TraitRef, Ty};
 use rustc_session::impl_lint_pass;
-use rustc_span::{Span, sym};
+use rustc_span::{Span, Symbol, kw};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -4439,7 +4439,7 @@ declare_clippy_lint! {
     /// Checks for usage of `iter().any()` on slices when it can be replaced with `contains()` and suggests doing so.
     ///
     /// ### Why is this bad?
-    /// `contains()` is more concise and idiomatic, sometimes more fast.
+    /// `contains()` is more concise and idiomatic, while also being faster in some cases.
     ///
     /// ### Example
     /// ```no_run
@@ -4711,17 +4711,15 @@ impl_lint_pass!(Methods => [
 /// Extracts a method call name, args, and `Span` of the method name.
 /// This ensures that neither the receiver nor any of the arguments
 /// come from expansion.
-pub fn method_call<'tcx>(
-    recv: &'tcx Expr<'tcx>,
-) -> Option<(&'tcx str, &'tcx Expr<'tcx>, &'tcx [Expr<'tcx>], Span, Span)> {
+pub fn method_call<'tcx>(recv: &'tcx Expr<'tcx>) -> Option<(Symbol, &'tcx Expr<'tcx>, &'tcx [Expr<'tcx>], Span, Span)> {
     if let ExprKind::MethodCall(path, receiver, args, call_span) = recv.kind
         && !args.iter().any(|e| e.span.from_expansion())
         && !receiver.span.from_expansion()
     {
-        let name = path.ident.name.as_str();
-        return Some((name, receiver, args, path.ident.span, call_span));
+        Some((path.ident.name, receiver, args, path.ident.span, call_span))
+    } else {
+        None
     }
-    None
 }
 
 impl<'tcx> LateLintPass<'tcx> for Methods {
@@ -4743,13 +4741,13 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             },
             ExprKind::MethodCall(method_call, receiver, args, _) => {
                 let method_span = method_call.ident.span;
-                or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args);
+                or_fun_call::check(cx, expr, method_span, method_call.ident.name, receiver, args);
                 expect_fun_call::check(
                     cx,
                     &self.format_args,
                     expr,
                     method_span,
-                    method_call.ident.as_str(),
+                    method_call.ident.name,
                     receiver,
                     args,
                 );
@@ -4778,7 +4776,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
         if impl_item.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
-        let name = impl_item.ident.name.as_str();
+        let name = impl_item.ident.name;
         let parent = cx.tcx.hir_get_parent_item(impl_item.hir_id()).def_id;
         let item = cx.tcx.hir_expect_item(parent);
         let self_ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
@@ -4851,7 +4849,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
                 return;
             }
 
-            if name == "new" && ret_ty != self_ty {
+            if name == sym::new && ret_ty != self_ty {
                 span_lint(
                     cx,
                     NEW_RET_NO_SELF,
@@ -4881,7 +4879,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()).self_ty();
             wrong_self_convention::check(
                 cx,
-                item.ident.name.as_str(),
+                item.ident.name,
                 self_ty,
                 first_arg_ty,
                 first_arg_hir_ty.span,
@@ -4912,14 +4910,17 @@ impl Methods {
         // Handle method calls whose receiver and arguments may not come from expansion
         if let Some((name, recv, args, span, call_span)) = method_call(expr) {
             match (name, args) {
-                ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => {
+                (
+                    sym::add | sym::offset | sym::sub | sym::wrapping_offset | sym::wrapping_add | sym::wrapping_sub,
+                    [_arg],
+                ) => {
                     zst_offset::check(cx, expr, recv);
                 },
-                ("all", [arg]) => {
+                (sym::all, [arg]) => {
                     unused_enumerate_index::check(cx, expr, recv, arg);
                     needless_character_iteration::check(cx, expr, recv, arg, true);
                     match method_call(recv) {
-                        Some(("cloned", recv2, [], _, _)) => {
+                        Some((sym::cloned, recv2, [], _, _)) => {
                             iter_overeager_cloned::check(
                                 cx,
                                 expr,
@@ -4929,13 +4930,13 @@ impl Methods {
                                 false,
                             );
                         },
-                        Some(("map", _, [map_arg], _, map_call_span)) => {
+                        Some((sym::map, _, [map_arg], _, map_call_span)) => {
                             map_all_any_identity::check(cx, expr, recv, map_call_span, map_arg, call_span, arg, "all");
                         },
                         _ => {},
                     }
                 },
-                ("and_then", [arg]) => {
+                (sym::and_then, [arg]) => {
                     let biom_option_linted = bind_instead_of_map::check_and_then_some(cx, expr, recv, arg);
                     let biom_result_linted = bind_instead_of_map::check_and_then_ok(cx, expr, recv, arg);
                     if !biom_option_linted && !biom_result_linted {
@@ -4945,11 +4946,11 @@ impl Methods {
                         }
                     }
                 },
-                ("any", [arg]) => {
+                (sym::any, [arg]) => {
                     unused_enumerate_index::check(cx, expr, recv, arg);
                     needless_character_iteration::check(cx, expr, recv, arg, false);
                     match method_call(recv) {
-                        Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(
+                        Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check(
                             cx,
                             expr,
                             recv,
@@ -4957,80 +4958,79 @@ impl Methods {
                             iter_overeager_cloned::Op::NeedlessMove(arg),
                             false,
                         ),
-                        Some(("chars", recv, _, _, _))
+                        Some((sym::chars, recv, _, _, _))
                             if let ExprKind::Closure(arg) = arg.kind
                                 && let body = cx.tcx.hir_body(arg.body)
                                 && let [param] = body.params =>
                         {
                             string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), self.msrv);
                         },
-                        Some(("map", _, [map_arg], _, map_call_span)) => {
+                        Some((sym::map, _, [map_arg], _, map_call_span)) => {
                             map_all_any_identity::check(cx, expr, recv, map_call_span, map_arg, call_span, arg, "any");
                         },
-                        Some(("iter", iter_recv, ..)) => {
+                        Some((sym::iter, iter_recv, ..)) => {
                             manual_contains::check(cx, expr, iter_recv, arg);
                         },
                         _ => {},
                     }
                 },
-                ("arg", [arg]) => {
+                (sym::arg, [arg]) => {
                     suspicious_command_arg_space::check(cx, recv, arg, span);
                 },
-                ("as_deref" | "as_deref_mut", []) => {
+                (sym::as_deref | sym::as_deref_mut, []) => {
                     needless_option_as_deref::check(cx, expr, recv, name);
                 },
-                ("as_bytes", []) => {
-                    if let Some(("as_str", recv, [], as_str_span, _)) = method_call(recv) {
+                (sym::as_bytes, []) => {
+                    if let Some((sym::as_str, recv, [], as_str_span, _)) = method_call(recv) {
                         redundant_as_str::check(cx, expr, recv, as_str_span, span);
                     }
                     sliced_string_as_bytes::check(cx, expr, recv);
                 },
-                ("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv),
-                ("as_ptr", []) => manual_c_str_literals::check_as_ptr(cx, expr, recv, self.msrv),
-                ("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
-                ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
-                ("bytes", []) => unbuffered_bytes::check(cx, expr, recv),
-                ("cloned", []) => {
+                (sym::as_mut | sym::as_ref, []) => useless_asref::check(cx, expr, name, recv),
+                (sym::as_ptr, []) => manual_c_str_literals::check_as_ptr(cx, expr, recv, self.msrv),
+                (sym::assume_init, []) => uninit_assumed_init::check(cx, expr, recv),
+                (sym::bytes, []) => unbuffered_bytes::check(cx, expr, recv),
+                (sym::cloned, []) => {
                     cloned_instead_of_copied::check(cx, expr, recv, span, self.msrv);
                     option_as_ref_cloned::check(cx, recv, span);
                 },
-                ("collect", []) if is_trait_method(cx, expr, sym::Iterator) => {
+                (sym::collect, []) if is_trait_method(cx, expr, sym::Iterator) => {
                     needless_collect::check(cx, span, expr, recv, call_span);
                     match method_call(recv) {
-                        Some((name @ ("cloned" | "copied"), recv2, [], _, _)) => {
+                        Some((name @ (sym::cloned | sym::copied), recv2, [], _, _)) => {
                             iter_cloned_collect::check(cx, name, expr, recv2);
                         },
-                        Some(("map", m_recv, [m_arg], m_ident_span, _)) => {
+                        Some((sym::map, m_recv, [m_arg], m_ident_span, _)) => {
                             map_collect_result_unit::check(cx, expr, m_recv, m_arg);
                             format_collect::check(cx, expr, m_arg, m_ident_span);
                         },
-                        Some(("take", take_self_arg, [take_arg], _, _)) => {
+                        Some((sym::take, take_self_arg, [take_arg], _, _)) => {
                             if self.msrv.meets(cx, msrvs::STR_REPEAT) {
                                 manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
                             }
                         },
-                        Some(("drain", recv, args, ..)) => {
+                        Some((sym::drain, recv, args, ..)) => {
                             drain_collect::check(cx, args, expr, recv);
                         },
                         _ => {},
                     }
                 },
-                ("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) {
-                    Some(("cloned", recv2, [], _, _)) => {
+                (sym::count, []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) {
+                    Some((sym::cloned, recv2, [], _, _)) => {
                         iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::RmCloned, false);
                     },
-                    Some((name2 @ ("into_iter" | "iter" | "iter_mut"), recv2, [], _, _)) => {
+                    Some((name2 @ (sym::into_iter | sym::iter | sym::iter_mut), recv2, [], _, _)) => {
                         iter_count::check(cx, expr, recv2, name2);
                     },
-                    Some(("map", _, [arg], _, _)) => suspicious_map::check(cx, expr, recv, arg),
-                    Some(("filter", recv2, [arg], _, _)) => bytecount::check(cx, expr, recv2, arg),
-                    Some(("bytes", recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
+                    Some((sym::map, _, [arg], _, _)) => suspicious_map::check(cx, expr, recv, arg),
+                    Some((sym::filter, recv2, [arg], _, _)) => bytecount::check(cx, expr, recv2, arg),
+                    Some((sym::bytes, recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
                     _ => {},
                 },
-                ("min" | "max", [arg]) => {
+                (sym::min | sym::max, [arg]) => {
                     unnecessary_min_or_max::check(cx, expr, name, recv, arg);
                 },
-                ("drain", ..) => {
+                (sym::drain, ..) => {
                     if let Node::Stmt(Stmt { hir_id: _, kind, .. }) = cx.tcx.parent_hir_node(expr.hir_id)
                         && matches!(kind, StmtKind::Semi(_))
                         && args.len() <= 1
@@ -5040,31 +5040,31 @@ impl Methods {
                         iter_with_drain::check(cx, expr, recv, span, arg);
                     }
                 },
-                ("ends_with", [arg]) => {
+                (sym::ends_with, [arg]) => {
                     if let ExprKind::MethodCall(.., span) = expr.kind {
                         case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg, self.msrv);
                     }
                     path_ends_with_ext::check(cx, recv, arg, expr, self.msrv, &self.allowed_dotfiles);
                 },
-                ("expect", [_]) => {
+                (sym::expect, [_]) => {
                     match method_call(recv) {
-                        Some(("ok", recv, [], _, _)) => ok_expect::check(cx, expr, recv),
-                        Some(("err", recv, [], err_span, _)) => {
+                        Some((sym::ok, recv, [], _, _)) => ok_expect::check(cx, expr, recv),
+                        Some((sym::err, recv, [], err_span, _)) => {
                             err_expect::check(cx, expr, recv, span, err_span, self.msrv);
                         },
                         _ => {},
                     }
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
                 },
-                ("expect_err", [_]) | ("unwrap_err" | "unwrap_unchecked" | "unwrap_err_unchecked", []) => {
+                (sym::expect_err, [_]) | (sym::unwrap_err | sym::unwrap_unchecked | sym::unwrap_err_unchecked, []) => {
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
                 },
-                ("extend", [arg]) => {
+                (sym::extend, [arg]) => {
                     string_extend_chars::check(cx, expr, recv, arg);
                     extend_with_drain::check(cx, expr, recv, arg);
                 },
-                ("filter", [arg]) => {
-                    if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
+                (sym::filter, [arg]) => {
+                    if let Some((sym::cloned, recv2, [], _span2, _)) = method_call(recv) {
                         // if `arg` has side-effect, the semantic will change
                         iter_overeager_cloned::check(
                             cx,
@@ -5080,8 +5080,8 @@ impl Methods {
                         iter_filter::check(cx, expr, arg, span);
                     }
                 },
-                ("find", [arg]) => {
-                    if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
+                (sym::find, [arg]) => {
+                    if let Some((sym::cloned, recv2, [], _span2, _)) = method_call(recv) {
                         // if `arg` has side-effect, the semantic will change
                         iter_overeager_cloned::check(
                             cx,
@@ -5093,26 +5093,26 @@ impl Methods {
                         );
                     }
                 },
-                ("filter_map", [arg]) => {
+                (sym::filter_map, [arg]) => {
                     unused_enumerate_index::check(cx, expr, recv, arg);
                     unnecessary_filter_map::check(cx, expr, arg, name);
                     filter_map_bool_then::check(cx, expr, arg, call_span);
                     filter_map_identity::check(cx, expr, arg, span);
                 },
-                ("find_map", [arg]) => {
+                (sym::find_map, [arg]) => {
                     unused_enumerate_index::check(cx, expr, recv, arg);
                     unnecessary_filter_map::check(cx, expr, arg, name);
                 },
-                ("flat_map", [arg]) => {
+                (sym::flat_map, [arg]) => {
                     unused_enumerate_index::check(cx, expr, recv, arg);
                     flat_map_identity::check(cx, expr, arg, span);
                     flat_map_option::check(cx, expr, arg, span);
                 },
-                ("flatten", []) => match method_call(recv) {
-                    Some(("map", recv, [map_arg], map_span, _)) => {
+                (sym::flatten, []) => match method_call(recv) {
+                    Some((sym::map, recv, [map_arg], map_span, _)) => {
                         map_flatten::check(cx, expr, recv, map_arg, map_span);
                     },
-                    Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(
+                    Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check(
                         cx,
                         expr,
                         recv,
@@ -5122,15 +5122,15 @@ impl Methods {
                     ),
                     _ => {},
                 },
-                ("fold", [init, acc]) => {
+                (sym::fold, [init, acc]) => {
                     manual_try_fold::check(cx, expr, init, acc, call_span, self.msrv);
                     unnecessary_fold::check(cx, expr, init, acc, span);
                 },
-                ("for_each", [arg]) => {
+                (sym::for_each, [arg]) => {
                     unused_enumerate_index::check(cx, expr, recv, arg);
                     match method_call(recv) {
-                        Some(("inspect", _, [_], span2, _)) => inspect_for_each::check(cx, expr, span2),
-                        Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(
+                        Some((sym::inspect, _, [_], span2, _)) => inspect_for_each::check(cx, expr, span2),
+                        Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check(
                             cx,
                             expr,
                             recv,
@@ -5141,44 +5141,44 @@ impl Methods {
                         _ => {},
                     }
                 },
-                ("get", [arg]) => {
+                (sym::get, [arg]) => {
                     get_first::check(cx, expr, recv, arg);
                     get_last_with_len::check(cx, expr, recv, arg);
                 },
-                ("get_or_insert_with", [arg]) => {
+                (sym::get_or_insert_with, [arg]) => {
                     unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert");
                 },
-                ("hash", [arg]) => {
+                (sym::hash, [arg]) => {
                     unit_hash::check(cx, expr, recv, arg);
                 },
-                ("is_empty", []) => {
+                (sym::is_empty, []) => {
                     match method_call(recv) {
-                        Some((prev_method @ ("as_bytes" | "bytes"), prev_recv, [], _, _)) => {
-                            needless_as_bytes::check(cx, prev_method, "is_empty", prev_recv, expr.span);
+                        Some((prev_method @ (sym::as_bytes | sym::bytes), prev_recv, [], _, _)) => {
+                            needless_as_bytes::check(cx, prev_method, name, prev_recv, expr.span);
                         },
-                        Some(("as_str", recv, [], as_str_span, _)) => {
+                        Some((sym::as_str, recv, [], as_str_span, _)) => {
                             redundant_as_str::check(cx, expr, recv, as_str_span, span);
                         },
                         _ => {},
                     }
                     is_empty::check(cx, expr, recv);
                 },
-                ("is_file", []) => filetype_is_file::check(cx, expr, recv),
-                ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv),
-                ("is_none", []) => check_is_some_is_none(cx, expr, recv, call_span, false),
-                ("is_some", []) => check_is_some_is_none(cx, expr, recv, call_span, true),
-                ("iter" | "iter_mut" | "into_iter", []) => {
+                (sym::is_file, []) => filetype_is_file::check(cx, expr, recv),
+                (sym::is_digit, [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv),
+                (sym::is_none, []) => check_is_some_is_none(cx, expr, recv, call_span, false),
+                (sym::is_some, []) => check_is_some_is_none(cx, expr, recv, call_span, true),
+                (sym::iter | sym::iter_mut | sym::into_iter, []) => {
                     iter_on_single_or_empty_collections::check(cx, expr, name, recv);
                 },
-                ("join", [join_arg]) => {
-                    if let Some(("collect", _, _, span, _)) = method_call(recv) {
+                (sym::join, [join_arg]) => {
+                    if let Some((sym::collect, _, _, span, _)) = method_call(recv) {
                         unnecessary_join::check(cx, expr, recv, join_arg, span);
                     } else {
                         join_absolute_paths::check(cx, recv, join_arg, expr.span);
                     }
                 },
-                ("last", []) => {
-                    if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
+                (sym::last, []) => {
+                    if let Some((sym::cloned, recv2, [], _span2, _)) = method_call(recv) {
                         iter_overeager_cloned::check(
                             cx,
                             expr,
@@ -5190,24 +5190,25 @@ impl Methods {
                     }
                     double_ended_iterator_last::check(cx, expr, recv, call_span);
                 },
-                ("len", []) => {
-                    if let Some((prev_method @ ("as_bytes" | "bytes"), prev_recv, [], _, _)) = method_call(recv) {
-                        needless_as_bytes::check(cx, prev_method, "len", prev_recv, expr.span);
+                (sym::len, []) => {
+                    if let Some((prev_method @ (sym::as_bytes | sym::bytes), prev_recv, [], _, _)) = method_call(recv) {
+                        needless_as_bytes::check(cx, prev_method, sym::len, prev_recv, expr.span);
                     }
                 },
-                ("lock", []) => {
+                (sym::lock, []) => {
                     mut_mutex_lock::check(cx, expr, recv, span);
                 },
-                (name @ ("map" | "map_err"), [m_arg]) => {
-                    if name == "map" {
+                (name @ (sym::map | sym::map_err), [m_arg]) => {
+                    if name == sym::map {
                         unused_enumerate_index::check(cx, expr, recv, m_arg);
                         map_clone::check(cx, expr, recv, m_arg, self.msrv);
                         map_with_unused_argument_over_ranges::check(cx, expr, recv, m_arg, self.msrv, span);
+                        manual_is_variant_and::check_map(cx, expr);
                         match method_call(recv) {
-                            Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) => {
+                            Some((map_name @ (sym::iter | sym::into_iter), recv2, _, _, _)) => {
                                 iter_kv_map::check(cx, map_name, expr, recv2, m_arg, self.msrv);
                             },
-                            Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(
+                            Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check(
                                 cx,
                                 expr,
                                 recv,
@@ -5222,12 +5223,12 @@ impl Methods {
                     }
                     if let Some((name, recv2, args, span2, _)) = method_call(recv) {
                         match (name, args) {
-                            ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv),
-                            ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv),
-                            ("filter", [f_arg]) => {
+                            (sym::as_mut, []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv),
+                            (sym::as_ref, []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv),
+                            (sym::filter, [f_arg]) => {
                                 filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false);
                             },
-                            ("find", [f_arg]) => {
+                            (sym::find, [f_arg]) => {
                                 filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, true);
                             },
                             _ => {},
@@ -5237,22 +5238,22 @@ impl Methods {
                     manual_inspect::check(cx, expr, m_arg, name, span, self.msrv);
                     crate::useless_conversion::check_function_application(cx, expr, recv, m_arg);
                 },
-                ("map_break" | "map_continue", [m_arg]) => {
+                (sym::map_break | sym::map_continue, [m_arg]) => {
                     crate::useless_conversion::check_function_application(cx, expr, recv, m_arg);
                 },
-                ("map_or", [def, map]) => {
+                (sym::map_or, [def, map]) => {
                     option_map_or_none::check(cx, expr, recv, def, map);
                     manual_ok_or::check(cx, expr, recv, def, map);
                     unnecessary_map_or::check(cx, expr, recv, def, map, span, self.msrv);
                 },
-                ("map_or_else", [def, map]) => {
+                (sym::map_or_else, [def, map]) => {
                     result_map_or_else_none::check(cx, expr, recv, def, map);
                     unnecessary_result_map_or_else::check(cx, expr, recv, def, map);
                 },
-                ("next", []) => {
+                (sym::next, []) => {
                     if let Some((name2, recv2, args2, _, _)) = method_call(recv) {
                         match (name2, args2) {
-                            ("cloned", []) => iter_overeager_cloned::check(
+                            (sym::cloned, []) => iter_overeager_cloned::check(
                                 cx,
                                 expr,
                                 recv,
@@ -5260,19 +5261,19 @@ impl Methods {
                                 iter_overeager_cloned::Op::LaterCloned,
                                 false,
                             ),
-                            ("filter", [arg]) => filter_next::check(cx, expr, recv2, arg),
-                            ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, self.msrv),
-                            ("iter", []) => iter_next_slice::check(cx, expr, recv2),
-                            ("skip", [arg]) => iter_skip_next::check(cx, expr, recv2, arg),
-                            ("skip_while", [_]) => skip_while_next::check(cx, expr),
-                            ("rev", []) => manual_next_back::check(cx, expr, recv, recv2),
+                            (sym::filter, [arg]) => filter_next::check(cx, expr, recv2, arg),
+                            (sym::filter_map, [arg]) => filter_map_next::check(cx, expr, recv2, arg, self.msrv),
+                            (sym::iter, []) => iter_next_slice::check(cx, expr, recv2),
+                            (sym::skip, [arg]) => iter_skip_next::check(cx, expr, recv2, arg),
+                            (sym::skip_while, [_]) => skip_while_next::check(cx, expr),
+                            (sym::rev, []) => manual_next_back::check(cx, expr, recv, recv2),
                             _ => {},
                         }
                     }
                 },
-                ("nth", [n_arg]) => match method_call(recv) {
-                    Some(("bytes", recv2, [], _, _)) => bytes_nth::check(cx, expr, recv2, n_arg),
-                    Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(
+                (sym::nth, [n_arg]) => match method_call(recv) {
+                    Some((sym::bytes, recv2, [], _, _)) => bytes_nth::check(cx, expr, recv2, n_arg),
+                    Some((sym::cloned, recv2, [], _, _)) => iter_overeager_cloned::check(
                         cx,
                         expr,
                         recv,
@@ -5280,54 +5281,54 @@ impl Methods {
                         iter_overeager_cloned::Op::LaterCloned,
                         false,
                     ),
-                    Some((iter_method @ ("iter" | "iter_mut"), iter_recv, [], iter_span, _)) => {
+                    Some((iter_method @ (sym::iter | sym::iter_mut), iter_recv, [], iter_span, _)) => {
                         if !iter_nth::check(cx, expr, iter_recv, iter_method, iter_span, span) {
                             iter_nth_zero::check(cx, expr, recv, n_arg);
                         }
                     },
                     _ => iter_nth_zero::check(cx, expr, recv, n_arg),
                 },
-                ("ok_or_else", [arg]) => {
+                (sym::ok_or_else, [arg]) => {
                     unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or");
                 },
-                ("open", [_]) => {
+                (sym::open, [_]) => {
                     open_options::check(cx, expr, recv);
                 },
-                ("or_else", [arg]) => {
+                (sym::or_else, [arg]) => {
                     if !bind_instead_of_map::check_or_else_err(cx, expr, recv, arg) {
                         unnecessary_lazy_eval::check(cx, expr, recv, arg, "or");
                     }
                 },
-                ("push", [arg]) => {
+                (sym::push, [arg]) => {
                     path_buf_push_overwrite::check(cx, expr, arg);
                 },
-                ("read_to_end", [_]) => {
+                (sym::read_to_end, [_]) => {
                     verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_END_MSG);
                 },
-                ("read_to_string", [_]) => {
+                (sym::read_to_string, [_]) => {
                     verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_STRING_MSG);
                 },
-                ("read_line", [arg]) => {
+                (sym::read_line, [arg]) => {
                     read_line_without_trim::check(cx, expr, recv, arg);
                 },
-                ("repeat", [arg]) => {
+                (sym::repeat, [arg]) => {
                     repeat_once::check(cx, expr, recv, arg);
                 },
-                (name @ ("replace" | "replacen"), [arg1, arg2] | [arg1, arg2, _]) => {
+                (name @ (sym::replace | sym::replacen), [arg1, arg2] | [arg1, arg2, _]) => {
                     no_effect_replace::check(cx, expr, arg1, arg2);
 
                     // Check for repeated `str::replace` calls to perform `collapsible_str_replace` lint
                     if self.msrv.meets(cx, msrvs::PATTERN_TRAIT_CHAR_ARRAY)
-                        && name == "replace"
-                        && let Some(("replace", ..)) = method_call(recv)
+                        && name == sym::replace
+                        && let Some((sym::replace, ..)) = method_call(recv)
                     {
                         collapsible_str_replace::check(cx, expr, arg1, arg2);
                     }
                 },
-                ("resize", [count_arg, default_arg]) => {
+                (sym::resize, [count_arg, default_arg]) => {
                     vec_resize_to_zero::check(cx, expr, count_arg, default_arg, span);
                 },
-                ("seek", [arg]) => {
+                (sym::seek, [arg]) => {
                     if self.msrv.meets(cx, msrvs::SEEK_FROM_CURRENT) {
                         seek_from_current::check(cx, expr, recv, arg);
                     }
@@ -5335,11 +5336,11 @@ impl Methods {
                         seek_to_start_instead_of_rewind::check(cx, expr, recv, arg, span);
                     }
                 },
-                ("skip", [arg]) => {
+                (sym::skip, [arg]) => {
                     iter_skip_zero::check(cx, expr, arg);
                     iter_out_of_bounds::check_skip(cx, expr, recv, arg);
 
-                    if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
+                    if let Some((sym::cloned, recv2, [], _span2, _)) = method_call(recv) {
                         iter_overeager_cloned::check(
                             cx,
                             expr,
@@ -5350,34 +5351,34 @@ impl Methods {
                         );
                     }
                 },
-                ("sort", []) => {
+                (sym::sort, []) => {
                     stable_sort_primitive::check(cx, expr, recv);
                 },
-                ("sort_by", [arg]) => {
+                (sym::sort_by, [arg]) => {
                     unnecessary_sort_by::check(cx, expr, recv, arg, false);
                 },
-                ("sort_unstable_by", [arg]) => {
+                (sym::sort_unstable_by, [arg]) => {
                     unnecessary_sort_by::check(cx, expr, recv, arg, true);
                 },
-                ("split", [arg]) => {
+                (sym::split, [arg]) => {
                     str_split::check(cx, expr, recv, arg);
                 },
-                ("splitn" | "rsplitn", [count_arg, pat_arg]) => {
+                (sym::splitn | sym::rsplitn, [count_arg, pat_arg]) => {
                     if let Some(Constant::Int(count)) = ConstEvalCtxt::new(cx).eval(count_arg) {
                         suspicious_splitn::check(cx, name, expr, recv, count);
                         str_splitn::check(cx, name, expr, recv, pat_arg, count, self.msrv);
                     }
                 },
-                ("splitn_mut" | "rsplitn_mut", [count_arg, _]) => {
+                (sym::splitn_mut | sym::rsplitn_mut, [count_arg, _]) => {
                     if let Some(Constant::Int(count)) = ConstEvalCtxt::new(cx).eval(count_arg) {
                         suspicious_splitn::check(cx, name, expr, recv, count);
                     }
                 },
-                ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
-                ("take", [arg]) => {
+                (sym::step_by, [arg]) => iterator_step_by_zero::check(cx, expr, arg),
+                (sym::take, [arg]) => {
                     iter_out_of_bounds::check_take(cx, expr, recv, arg);
                     manual_repeat_n::check(cx, expr, recv, arg, self.msrv);
-                    if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
+                    if let Some((sym::cloned, recv2, [], _span2, _)) = method_call(recv) {
                         iter_overeager_cloned::check(
                             cx,
                             expr,
@@ -5388,74 +5389,89 @@ impl Methods {
                         );
                     }
                 },
-                ("take", []) => needless_option_take::check(cx, expr, recv),
-                ("then", [arg]) => {
+                (sym::take, []) => needless_option_take::check(cx, expr, recv),
+                (sym::then, [arg]) => {
                     if !self.msrv.meets(cx, msrvs::BOOL_THEN_SOME) {
                         return;
                     }
                     unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some");
                 },
-                ("try_into", []) if is_trait_method(cx, expr, sym::TryInto) => {
+                (sym::try_into, []) if is_trait_method(cx, expr, sym::TryInto) => {
                     unnecessary_fallible_conversions::check_method(cx, expr);
                 },
-                ("to_owned", []) => {
+                (sym::to_owned, []) => {
                     if !suspicious_to_owned::check(cx, expr, recv) {
                         implicit_clone::check(cx, name, expr, recv);
                     }
                 },
-                ("to_os_string" | "to_path_buf" | "to_vec", []) => {
+                (sym::to_os_string | sym::to_path_buf | sym::to_vec, []) => {
                     implicit_clone::check(cx, name, expr, recv);
                 },
-                ("type_id", []) => {
+                (sym::type_id, []) => {
                     type_id_on_box::check(cx, recv, expr.span);
                 },
-                ("unwrap", []) => {
+                (sym::unwrap, []) => {
                     match method_call(recv) {
-                        Some(("get", recv, [get_arg], _, _)) => {
+                        Some((sym::get, recv, [get_arg], _, _)) => {
                             get_unwrap::check(cx, expr, recv, get_arg, false);
                         },
-                        Some(("get_mut", recv, [get_arg], _, _)) => {
+                        Some((sym::get_mut, recv, [get_arg], _, _)) => {
                             get_unwrap::check(cx, expr, recv, get_arg, true);
                         },
-                        Some(("or", recv, [or_arg], or_span, _)) => {
+                        Some((sym::or, recv, [or_arg], or_span, _)) => {
                             or_then_unwrap::check(cx, expr, recv, or_arg, or_span);
                         },
                         _ => {},
                     }
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
                 },
-                ("unwrap_or", [u_arg]) => {
+                (sym::unwrap_or, [u_arg]) => {
                     match method_call(recv) {
-                        Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), lhs, [rhs], _, _)) => {
-                            manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
+                        Some((arith @ (sym::checked_add | sym::checked_sub | sym::checked_mul), lhs, [rhs], _, _)) => {
+                            manual_saturating_arithmetic::check(
+                                cx,
+                                expr,
+                                lhs,
+                                rhs,
+                                u_arg,
+                                &arith.as_str()[const { "checked_".len() }..],
+                            );
                         },
-                        Some(("map", m_recv, [m_arg], span, _)) => {
+                        Some((sym::map, m_recv, [m_arg], span, _)) => {
                             option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span, self.msrv);
                         },
-                        Some((then_method @ ("then" | "then_some"), t_recv, [t_arg], _, _)) => {
-                            obfuscated_if_else::check(cx, expr, t_recv, t_arg, Some(u_arg), then_method, "unwrap_or");
+                        Some((then_method @ (sym::then | sym::then_some), t_recv, [t_arg], _, _)) => {
+                            obfuscated_if_else::check(cx, expr, t_recv, t_arg, Some(u_arg), then_method, name);
                         },
                         _ => {},
                     }
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
                 },
-                ("unwrap_or_default", []) => {
+                (sym::unwrap_or_default, []) => {
                     match method_call(recv) {
-                        Some(("map", m_recv, [arg], span, _)) => {
+                        Some((sym::map, m_recv, [arg], span, _)) => {
                             manual_is_variant_and::check(cx, expr, m_recv, arg, span, self.msrv);
                         },
-                        Some((then_method @ ("then" | "then_some"), t_recv, [t_arg], _, _)) => {
-                            obfuscated_if_else::check(cx, expr, t_recv, t_arg, None, then_method, "unwrap_or_default");
+                        Some((then_method @ (sym::then | sym::then_some), t_recv, [t_arg], _, _)) => {
+                            obfuscated_if_else::check(
+                                cx,
+                                expr,
+                                t_recv,
+                                t_arg,
+                                None,
+                                then_method,
+                                sym::unwrap_or_default,
+                            );
                         },
                         _ => {},
                     }
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
                 },
-                ("unwrap_or_else", [u_arg]) => {
+                (sym::unwrap_or_else, [u_arg]) => {
                     match method_call(recv) {
-                        Some(("map", recv, [map_arg], _, _))
+                        Some((sym::map, recv, [map_arg], _, _))
                             if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, self.msrv) => {},
-                        Some((then_method @ ("then" | "then_some"), t_recv, [t_arg], _, _)) => {
+                        Some((then_method @ (sym::then | sym::then_some), t_recv, [t_arg], _, _)) => {
                             obfuscated_if_else::check(
                                 cx,
                                 expr,
@@ -5463,7 +5479,7 @@ impl Methods {
                                 t_arg,
                                 Some(u_arg),
                                 then_method,
-                                "unwrap_or_else",
+                                sym::unwrap_or_else,
                             );
                         },
                         _ => {
@@ -5472,13 +5488,13 @@ impl Methods {
                     }
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
                 },
-                ("wake", []) => {
+                (sym::wake, []) => {
                     waker_clone_wake::check(cx, expr, recv);
                 },
-                ("write", []) => {
+                (sym::write, []) => {
                     readonly_write_lock::check(cx, expr, recv);
                 },
-                ("zip", [arg]) => {
+                (sym::zip, [arg]) => {
                     if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind
                         && name.ident.name == sym::iter
                     {
@@ -5490,8 +5506,8 @@ impl Methods {
         }
         // Handle method calls whose receiver and arguments may come from expansion
         if let ExprKind::MethodCall(path, recv, args, _call_span) = expr.kind {
-            match (path.ident.name.as_str(), args) {
-                ("expect", [_]) if !matches!(method_call(recv), Some(("ok" | "err", _, [], _, _))) => {
+            match (path.ident.name, args) {
+                (sym::expect, [_]) if !matches!(method_call(recv), Some((sym::ok | sym::err, _, [], _, _))) => {
                     unwrap_expect_used::check(
                         cx,
                         expr,
@@ -5502,7 +5518,7 @@ impl Methods {
                         unwrap_expect_used::Variant::Expect,
                     );
                 },
-                ("expect_err", [_]) => {
+                (sym::expect_err, [_]) => {
                     unwrap_expect_used::check(
                         cx,
                         expr,
@@ -5513,7 +5529,7 @@ impl Methods {
                         unwrap_expect_used::Variant::Expect,
                     );
                 },
-                ("unwrap", []) => {
+                (sym::unwrap, []) => {
                     unwrap_expect_used::check(
                         cx,
                         expr,
@@ -5524,7 +5540,7 @@ impl Methods {
                         unwrap_expect_used::Variant::Unwrap,
                     );
                 },
-                ("unwrap_err", []) => {
+                (sym::unwrap_err, []) => {
                     unwrap_expect_used::check(
                         cx,
                         expr,
@@ -5543,13 +5559,13 @@ impl Methods {
 
 fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, call_span: Span, is_some: bool) {
     match method_call(recv) {
-        Some((name @ ("find" | "position" | "rposition"), f_recv, [arg], span, _)) => {
+        Some((name @ (sym::find | sym::position | sym::rposition), f_recv, [arg], span, _)) => {
             search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span);
         },
-        Some(("get", f_recv, [arg], _, _)) => {
+        Some((sym::get, f_recv, [arg], _, _)) => {
             unnecessary_get_then_check::check(cx, call_span, recv, f_recv, arg, is_some);
         },
-        Some(("first", f_recv, [], _, _)) => {
+        Some((sym::first, f_recv, [], _, _)) => {
             unnecessary_first_then_check::check(cx, call_span, recv, f_recv, is_some);
         },
         _ => {},
@@ -5593,7 +5609,7 @@ const FN_HEADER: hir::FnHeader = hir::FnHeader {
 
 struct ShouldImplTraitCase {
     trait_name: &'static str,
-    method_name: &'static str,
+    method_name: Symbol,
     param_count: usize,
     fn_header: hir::FnHeader,
     // implicit self kind expected (none, self, &self, ...)
@@ -5606,7 +5622,7 @@ struct ShouldImplTraitCase {
 impl ShouldImplTraitCase {
     const fn new(
         trait_name: &'static str,
-        method_name: &'static str,
+        method_name: Symbol,
         param_count: usize,
         fn_header: hir::FnHeader,
         self_kind: SelfKind,
@@ -5639,36 +5655,36 @@ impl ShouldImplTraitCase {
 
 #[rustfmt::skip]
 const TRAIT_METHODS: [ShouldImplTraitCase; 30] = [
-    ShouldImplTraitCase::new("std::ops::Add", "add",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::convert::AsMut", "as_mut",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
-    ShouldImplTraitCase::new("std::convert::AsRef", "as_ref",  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
-    ShouldImplTraitCase::new("std::ops::BitAnd", "bitand",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::BitOr", "bitor",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::BitXor", "bitxor",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::borrow::Borrow", "borrow",  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
-    ShouldImplTraitCase::new("std::borrow::BorrowMut", "borrow_mut",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
-    ShouldImplTraitCase::new("std::clone::Clone", "clone",  1,  FN_HEADER,  SelfKind::Ref,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::cmp::Ord", "cmp",  2,  FN_HEADER,  SelfKind::Ref,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::default::Default", "default",  0,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::Deref", "deref",  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
-    ShouldImplTraitCase::new("std::ops::DerefMut", "deref_mut",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
-    ShouldImplTraitCase::new("std::ops::Div", "div",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::Drop", "drop",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Unit, true),
-    ShouldImplTraitCase::new("std::cmp::PartialEq", "eq",  2,  FN_HEADER,  SelfKind::Ref,  OutType::Bool, true),
-    ShouldImplTraitCase::new("std::iter::FromIterator", "from_iter",  1,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::str::FromStr", "from_str",  1,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::hash::Hash", "hash",  2,  FN_HEADER,  SelfKind::Ref,  OutType::Unit, true),
-    ShouldImplTraitCase::new("std::ops::Index", "index",  2,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
-    ShouldImplTraitCase::new("std::ops::IndexMut", "index_mut",  2,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
-    ShouldImplTraitCase::new("std::iter::IntoIterator", "into_iter",  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::Mul", "mul",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::Neg", "neg",  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::iter::Iterator", "next",  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Any, false),
-    ShouldImplTraitCase::new("std::ops::Not", "not",  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::Rem", "rem",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::Shl", "shl",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::Shr", "shr",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
-    ShouldImplTraitCase::new("std::ops::Sub", "sub",  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::Add", sym::add,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::convert::AsMut", sym::as_mut,  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
+    ShouldImplTraitCase::new("std::convert::AsRef", sym::as_ref,  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
+    ShouldImplTraitCase::new("std::ops::BitAnd", sym::bitand,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::BitOr", sym::bitor,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::BitXor", sym::bitxor,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::borrow::Borrow", sym::borrow,  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
+    ShouldImplTraitCase::new("std::borrow::BorrowMut", sym::borrow_mut,  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
+    ShouldImplTraitCase::new("std::clone::Clone", sym::clone,  1,  FN_HEADER,  SelfKind::Ref,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::cmp::Ord", sym::cmp,  2,  FN_HEADER,  SelfKind::Ref,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::default::Default", kw::Default,  0,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::Deref", sym::deref,  1,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
+    ShouldImplTraitCase::new("std::ops::DerefMut", sym::deref_mut,  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
+    ShouldImplTraitCase::new("std::ops::Div", sym::div,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::Drop", sym::drop,  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Unit, true),
+    ShouldImplTraitCase::new("std::cmp::PartialEq", sym::eq,  2,  FN_HEADER,  SelfKind::Ref,  OutType::Bool, true),
+    ShouldImplTraitCase::new("std::iter::FromIterator", sym::from_iter,  1,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::str::FromStr", sym::from_str,  1,  FN_HEADER,  SelfKind::No,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::hash::Hash", sym::hash,  2,  FN_HEADER,  SelfKind::Ref,  OutType::Unit, true),
+    ShouldImplTraitCase::new("std::ops::Index", sym::index,  2,  FN_HEADER,  SelfKind::Ref,  OutType::Ref, true),
+    ShouldImplTraitCase::new("std::ops::IndexMut", sym::index_mut,  2,  FN_HEADER,  SelfKind::RefMut,  OutType::Ref, true),
+    ShouldImplTraitCase::new("std::iter::IntoIterator", sym::into_iter,  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::Mul", sym::mul,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::Neg", sym::neg,  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::iter::Iterator", sym::next,  1,  FN_HEADER,  SelfKind::RefMut,  OutType::Any, false),
+    ShouldImplTraitCase::new("std::ops::Not", sym::not,  1,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::Rem", sym::rem,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::Shl", sym::shl,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::Shr", sym::shr,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
+    ShouldImplTraitCase::new("std::ops::Sub", sym::sub,  2,  FN_HEADER,  SelfKind::Value,  OutType::Any, true),
 ];
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_as_bytes.rs b/src/tools/clippy/clippy_lints/src/methods/needless_as_bytes.rs
index 7c9f7bae990..635d06330e0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_as_bytes.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_as_bytes.rs
@@ -4,11 +4,11 @@ use clippy_utils::ty::is_type_lang_item;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, LangItem};
 use rustc_lint::LateContext;
-use rustc_span::Span;
+use rustc_span::{Span, Symbol};
 
 use super::NEEDLESS_AS_BYTES;
 
-pub fn check(cx: &LateContext<'_>, prev_method: &str, method: &str, prev_recv: &Expr<'_>, span: Span) {
+pub fn check(cx: &LateContext<'_>, prev_method: Symbol, method: Symbol, prev_recv: &Expr<'_>, span: Span) {
     let ty1 = cx.typeck_results().expr_ty_adjusted(prev_recv).peel_refs();
     if is_type_lang_item(cx, ty1, LangItem::String) || ty1.is_str() {
         let mut app = Applicability::MachineApplicable;
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 4c1ed6a1d83..2b75d6a8248 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -508,7 +508,7 @@ fn get_captured_ids(cx: &LateContext<'_>, ty: Ty<'_>) -> HirIdSet {
         match ty.kind() {
             ty::Adt(_, generics) => {
                 for generic in *generics {
-                    if let GenericArgKind::Type(ty) = generic.unpack() {
+                    if let GenericArgKind::Type(ty) = generic.kind() {
                         get_captured_ids_recursive(cx, ty, set);
                     }
                 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs b/src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs
index 538aa9097a4..d77d044340d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_option_as_deref.rs
@@ -1,22 +1,22 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::path_res;
 use clippy_utils::source::SpanRangeExt;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::usage::local_used_after_expr;
+use clippy_utils::{path_res, sym};
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_hir::def::Res;
 use rustc_lint::LateContext;
-use rustc_span::sym;
+use rustc_span::Symbol;
 
 use super::NEEDLESS_OPTION_AS_DEREF;
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, name: &str) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, name: Symbol) {
     let typeck = cx.typeck_results();
     let outer_ty = typeck.expr_ty(expr);
 
     if is_type_diagnostic_item(cx, outer_ty, sym::Option) && outer_ty == typeck.expr_ty(recv) {
-        if name == "as_deref_mut" && recv.is_syntactic_place_expr() {
+        if name == sym::as_deref_mut && recv.is_syntactic_place_expr() {
             let Res::Local(binding_id) = path_res(cx, recv) else {
                 return;
             };
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_option_take.rs b/src/tools/clippy/clippy_lints/src/methods/needless_option_take.rs
index cd1b97f3c51..1544a12e6ba 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_option_take.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_option_take.rs
@@ -3,7 +3,7 @@ use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, QPath};
 use rustc_lint::LateContext;
-use rustc_span::sym;
+use rustc_span::{Symbol, sym};
 
 use super::NEEDLESS_OPTION_TAKE;
 
@@ -42,20 +42,20 @@ fn is_expr_option(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 /// When this function is called, we are reasonably certain that the `ExprKind` is either
 /// `Call` or `MethodCall` because we already checked that the expression is not
 /// `is_syntactic_place_expr()`.
-fn source_of_temporary_value<'a>(expr: &'a Expr<'_>) -> Option<&'a str> {
+fn source_of_temporary_value(expr: &Expr<'_>) -> Option<Symbol> {
     match expr.peel_borrows().kind {
         ExprKind::Call(function, _) => {
             if let ExprKind::Path(QPath::Resolved(_, func_path)) = function.kind
                 && !func_path.segments.is_empty()
             {
-                return Some(func_path.segments[0].ident.name.as_str());
+                return Some(func_path.segments[0].ident.name);
             }
             if let ExprKind::Path(QPath::TypeRelative(_, func_path_segment)) = function.kind {
-                return Some(func_path_segment.ident.name.as_str());
+                return Some(func_path_segment.ident.name);
             }
             None
         },
-        ExprKind::MethodCall(path_segment, ..) => Some(path_segment.ident.name.as_str()),
+        ExprKind::MethodCall(path_segment, ..) => Some(path_segment.ident.name),
         _ => None,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs b/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs
index 1cc56de4876..604b48656ae 100644
--- a/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs
@@ -1,13 +1,14 @@
 use super::OBFUSCATED_IF_ELSE;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::eager_or_lazy::switch_to_eager_eval;
-use clippy_utils::get_parent_expr;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sugg::Sugg;
+use clippy_utils::{get_parent_expr, sym};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::ExprKind;
 use rustc_lint::LateContext;
+use rustc_span::Symbol;
 
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
@@ -15,8 +16,8 @@ pub(super) fn check<'tcx>(
     then_recv: &'tcx hir::Expr<'_>,
     then_arg: &'tcx hir::Expr<'_>,
     unwrap_arg: Option<&'tcx hir::Expr<'_>>,
-    then_method_name: &str,
-    unwrap_method_name: &str,
+    then_method_name: Symbol,
+    unwrap_method_name: Symbol,
 ) {
     let recv_ty = cx.typeck_results().expr_ty(then_recv);
 
@@ -31,25 +32,25 @@ pub(super) fn check<'tcx>(
         };
 
         let if_then = match then_method_name {
-            "then" if let ExprKind::Closure(closure) = then_arg.kind => {
+            sym::then if let ExprKind::Closure(closure) = then_arg.kind => {
                 let body = cx.tcx.hir_body(closure.body);
                 snippet_with_applicability(cx, body.value.span, "..", &mut applicability)
             },
-            "then_some" => snippet_with_applicability(cx, then_arg.span, "..", &mut applicability),
+            sym::then_some => snippet_with_applicability(cx, then_arg.span, "..", &mut applicability),
             _ => return,
         };
 
         // FIXME: Add `unwrap_or_else` and `unwrap_or_default` symbol
         let els = match unwrap_method_name {
-            "unwrap_or" => snippet_with_applicability(cx, unwrap_arg.unwrap().span, "..", &mut applicability),
-            "unwrap_or_else" if let ExprKind::Closure(closure) = unwrap_arg.unwrap().kind => {
+            sym::unwrap_or => snippet_with_applicability(cx, unwrap_arg.unwrap().span, "..", &mut applicability),
+            sym::unwrap_or_else if let ExprKind::Closure(closure) = unwrap_arg.unwrap().kind => {
                 let body = cx.tcx.hir_body(closure.body);
                 snippet_with_applicability(cx, body.value.span, "..", &mut applicability)
             },
-            "unwrap_or_else" if let ExprKind::Path(_) = unwrap_arg.unwrap().kind => {
+            sym::unwrap_or_else if let ExprKind::Path(_) = unwrap_arg.unwrap().kind => {
                 snippet_with_applicability(cx, unwrap_arg.unwrap().span, "_", &mut applicability) + "()"
             },
-            "unwrap_or_default" => "Default::default()".into(),
+            sym::unwrap_or_default => "Default::default()".into(),
             _ => return,
         };
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs
index 9b22494888f..3c38deca6cd 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs
@@ -1,14 +1,16 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::sym;
 use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
-use rustc_span::{Span, sym};
+use rustc_span::Span;
 
 use super::{OPTION_AS_REF_CLONED, method_call};
 
 pub(super) fn check(cx: &LateContext<'_>, cloned_recv: &Expr<'_>, cloned_ident_span: Span) {
-    if let Some((method @ ("as_ref" | "as_mut"), as_ref_recv, [], as_ref_ident_span, _)) = method_call(cloned_recv)
+    if let Some((method @ (sym::as_ref | sym::as_mut), as_ref_recv, [], as_ref_ident_span, _)) =
+        method_call(cloned_recv)
         && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(as_ref_recv).peel_refs(), sym::Option)
     {
         span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
index b78b082e460..7bdd999bbba 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
@@ -11,8 +11,7 @@ use clippy_utils::{
 use rustc_errors::Applicability;
 use rustc_lint::LateContext;
 use rustc_middle::ty;
-use rustc_span::Span;
-use rustc_span::symbol::{self, Symbol};
+use rustc_span::{Span, Symbol};
 use {rustc_ast as ast, rustc_hir as hir};
 
 use super::{OR_FUN_CALL, UNWRAP_OR_DEFAULT};
@@ -23,7 +22,7 @@ pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &hir::Expr<'_>,
     method_span: Span,
-    name: &str,
+    name: Symbol,
     receiver: &'tcx hir::Expr<'_>,
     args: &'tcx [hir::Expr<'_>],
 ) {
@@ -33,7 +32,7 @@ pub(super) fn check<'tcx>(
     /// `or_insert_with(T::new)` or `or_insert_with(T::default)`.
     fn check_unwrap_or_default(
         cx: &LateContext<'_>,
-        name: &str,
+        name: Symbol,
         receiver: &hir::Expr<'_>,
         fun: &hir::Expr<'_>,
         call_expr: Option<&hir::Expr<'_>>,
@@ -66,8 +65,8 @@ pub(super) fn check<'tcx>(
         };
 
         let sugg = match (name, call_expr.is_some()) {
-            ("unwrap_or", true) | ("unwrap_or_else", false) => sym::unwrap_or_default,
-            ("or_insert", true) | ("or_insert_with", false) => sym::or_default,
+            (sym::unwrap_or, true) | (sym::unwrap_or_else, false) => sym::unwrap_or_default,
+            (sym::or_insert, true) | (sym::or_insert_with, false) => sym::or_default,
             _ => return false,
         };
 
@@ -126,7 +125,7 @@ pub(super) fn check<'tcx>(
     #[expect(clippy::too_many_arguments)]
     fn check_or_fn_call<'tcx>(
         cx: &LateContext<'tcx>,
-        name: &str,
+        name: Symbol,
         method_span: Span,
         self_expr: &hir::Expr<'_>,
         arg: &'tcx hir::Expr<'_>,
@@ -137,11 +136,16 @@ pub(super) fn check<'tcx>(
         fun_span: Option<Span>,
     ) -> bool {
         // (path, fn_has_argument, methods, suffix)
-        const KNOW_TYPES: [(Symbol, bool, &[&str], &str); 4] = [
-            (sym::BTreeEntry, false, &["or_insert"], "with"),
-            (sym::HashMapEntry, false, &["or_insert"], "with"),
-            (sym::Option, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"),
-            (sym::Result, true, &["or", "unwrap_or"], "else"),
+        const KNOW_TYPES: [(Symbol, bool, &[Symbol], &str); 4] = [
+            (sym::BTreeEntry, false, &[sym::or_insert], "with"),
+            (sym::HashMapEntry, false, &[sym::or_insert], "with"),
+            (
+                sym::Option,
+                false,
+                &[sym::map_or, sym::ok_or, sym::or, sym::unwrap_or],
+                "else",
+            ),
+            (sym::Result, true, &[sym::or, sym::unwrap_or], "else"),
         ];
 
         if KNOW_TYPES.iter().any(|k| k.2.contains(&name))
@@ -260,7 +264,7 @@ fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>)
             && ident.name == sym::to_string
             && let hir::Expr { kind, .. } = self_arg
             && let hir::ExprKind::Lit(lit) = kind
-            && let ast::LitKind::Str(symbol::kw::Empty, _) = lit.node
+            && let ast::LitKind::Str(rustc_span::sym::empty, _) = lit.node
         {
             return true;
         }
diff --git a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
index 97c8ce2bcdd..855babb797a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
@@ -2,14 +2,13 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
 use clippy_utils::source::{snippet, snippet_with_applicability};
 use clippy_utils::sugg::deref_closure_args;
 use clippy_utils::ty::is_type_lang_item;
-use clippy_utils::{is_receiver_of_method_call, is_trait_method, strip_pat_refs};
+use clippy_utils::{is_receiver_of_method_call, is_trait_method, strip_pat_refs, sym};
 use hir::ExprKind;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::PatKind;
 use rustc_lint::LateContext;
-use rustc_span::Span;
-use rustc_span::symbol::sym;
+use rustc_span::{Span, Symbol};
 
 use super::SEARCH_IS_SOME;
 
@@ -19,7 +18,7 @@ use super::SEARCH_IS_SOME;
 pub(super) fn check<'tcx>(
     cx: &LateContext<'_>,
     expr: &'tcx hir::Expr<'_>,
-    search_method: &str,
+    search_method: Symbol,
     is_some: bool,
     search_recv: &hir::Expr<'_>,
     search_arg: &'tcx hir::Expr<'_>,
@@ -35,7 +34,7 @@ pub(super) fn check<'tcx>(
             // suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()`
             // suggest `any(|..| *..)` instead of `any(|..| **..)` for `find(|..| **..).is_some()`
             let mut applicability = Applicability::MachineApplicable;
-            let any_search_snippet = if search_method == "find"
+            let any_search_snippet = if search_method == sym::find
                 && let ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind
                 && let closure_body = cx.tcx.hir_body(body)
                 && let Some(closure_arg) = closure_body.params.first()
@@ -107,7 +106,7 @@ pub(super) fn check<'tcx>(
         }
     }
     // lint if `find()` is called by `String` or `&str`
-    else if search_method == "find" {
+    else if search_method == sym::find {
         let is_string_or_str_slice = |e| {
             let self_ty = cx.typeck_results().expr_ty(e).peel_refs();
             if is_type_lang_item(cx, self_ty, hir::LangItem::String) {
diff --git a/src/tools/clippy/clippy_lints/src/methods/str_split.rs b/src/tools/clippy/clippy_lints/src/methods/str_split.rs
index fb4ac7b3613..479064a0671 100644
--- a/src/tools/clippy/clippy_lints/src/methods/str_split.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_split.rs
@@ -15,7 +15,7 @@ pub(super) fn check<'a>(cx: &LateContext<'a>, expr: &'_ Expr<'_>, split_recv: &'
     // or `"\r\n"`). There are a lot of ways to specify a pattern, and this lint only checks the most
     // basic ones: a `'\n'`, `"\n"`, and `"\r\n"`.
     if let ExprKind::MethodCall(trim_method_name, trim_recv, [], _) = split_recv.kind
-        && trim_method_name.ident.as_str() == "trim"
+        && trim_method_name.ident.name == sym::trim
         && cx.typeck_results().expr_ty_adjusted(trim_recv).peel_refs().is_str()
         && !is_const_evaluatable(cx, trim_recv)
         && let ExprKind::Lit(split_lit) = split_arg.kind
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 c8efb600f57..6935ae1f391 100644
--- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
@@ -4,7 +4,7 @@ use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::usage::local_used_after_expr;
 use clippy_utils::visitors::{Descend, for_each_expr};
-use clippy_utils::{is_diag_item_method, path_to_local_id, paths};
+use clippy_utils::{is_diag_item_method, path_to_local_id, paths, sym};
 use core::ops::ControlFlow;
 use rustc_errors::Applicability;
 use rustc_hir::{
@@ -12,13 +12,13 @@ use rustc_hir::{
 };
 use rustc_lint::LateContext;
 use rustc_middle::ty;
-use rustc_span::{Span, Symbol, SyntaxContext, sym};
+use rustc_span::{Span, Symbol, SyntaxContext};
 
 use super::{MANUAL_SPLIT_ONCE, NEEDLESS_SPLITN};
 
 pub(super) fn check(
     cx: &LateContext<'_>,
-    method_name: &str,
+    method_name: Symbol,
     expr: &Expr<'_>,
     self_arg: &Expr<'_>,
     pat_arg: &Expr<'_>,
@@ -45,9 +45,9 @@ pub(super) fn check(
     }
 }
 
-fn lint_needless(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_arg: &Expr<'_>, pat_arg: &Expr<'_>) {
+fn lint_needless(cx: &LateContext<'_>, method_name: Symbol, expr: &Expr<'_>, self_arg: &Expr<'_>, pat_arg: &Expr<'_>) {
     let mut app = Applicability::MachineApplicable;
-    let r = if method_name == "splitn" { "" } else { "r" };
+    let r = if method_name == sym::splitn { "" } else { "r" };
 
     span_lint_and_sugg(
         cx,
@@ -66,14 +66,14 @@ fn lint_needless(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_
 
 fn check_manual_split_once(
     cx: &LateContext<'_>,
-    method_name: &str,
+    method_name: Symbol,
     expr: &Expr<'_>,
     self_arg: &Expr<'_>,
     pat_arg: &Expr<'_>,
     usage: &IterUsage,
 ) {
     let ctxt = expr.span.ctxt();
-    let (msg, reverse) = if method_name == "splitn" {
+    let (msg, reverse) = if method_name == sym::splitn {
         ("manual implementation of `split_once`", false)
     } else {
         ("manual implementation of `rsplit_once`", true)
@@ -121,7 +121,7 @@ fn check_manual_split_once(
 /// ```
 fn check_manual_split_once_indirect(
     cx: &LateContext<'_>,
-    method_name: &str,
+    method_name: Symbol,
     expr: &Expr<'_>,
     self_arg: &Expr<'_>,
     pat_arg: &Expr<'_>,
@@ -143,7 +143,7 @@ fn check_manual_split_once_indirect(
         && first.name != second.name
         && !local_used_after_expr(cx, iter_binding_id, second.init_expr)
     {
-        let (r, lhs, rhs) = if method_name == "splitn" {
+        let (r, lhs, rhs) = if method_name == sym::splitn {
             ("", first.name, second.name)
         } else {
             ("r", second.name, first.name)
diff --git a/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs b/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs
index c7885f689d7..f11a41f90f1 100644
--- a/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::method_chain_args;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::is_type_lang_item;
+use clippy_utils::{method_chain_args, sym};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -13,7 +13,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
     if !is_type_lang_item(cx, obj_ty, hir::LangItem::String) {
         return;
     }
-    if let Some(arglists) = method_chain_args(arg, &["chars"]) {
+    if let Some(arglists) = method_chain_args(arg, &[sym::chars]) {
         let target = &arglists[0].0;
         let self_ty = cx.typeck_results().expr_ty(target).peel_refs();
         let ref_str = if self_ty.is_str() {
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
index ff5c1d1a401..f8b6d4349fb 100644
--- a/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
@@ -2,11 +2,12 @@ use clippy_utils::diagnostics::span_lint_and_note;
 use rustc_ast::LitKind;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::LateContext;
+use rustc_span::Symbol;
 use rustc_span::source_map::Spanned;
 
 use super::SUSPICIOUS_SPLITN;
 
-pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, self_arg: &Expr<'_>, count: u128) {
+pub(super) fn check(cx: &LateContext<'_>, method_name: Symbol, expr: &Expr<'_>, self_arg: &Expr<'_>, count: u128) {
     if count <= 1
         && let Some(call_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
         && let Some(impl_id) = cx.tcx.impl_of_method(call_id)
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
index 79ed352193f..d260e0ef6e1 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
@@ -9,10 +9,16 @@ use rustc_hir as hir;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
+use rustc_span::Symbol;
 
 use super::{UNNECESSARY_FILTER_MAP, UNNECESSARY_FIND_MAP};
 
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, arg: &'tcx hir::Expr<'tcx>, name: &str) {
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx hir::Expr<'tcx>,
+    arg: &'tcx hir::Expr<'tcx>,
+    name: Symbol,
+) {
     if !is_trait_method(cx, expr, sym::Iterator) {
         return;
     }
@@ -38,7 +44,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a
         let in_ty = cx.typeck_results().node_type(body.params[0].hir_id);
         let sugg = if !found_filtering {
             // Check if the closure is .filter_map(|x| Some(x))
-            if name == "filter_map"
+            if name == sym::filter_map
                 && let hir::ExprKind::Call(expr, args) = body.value.kind
                 && is_res_lang_ctor(cx, path_res(cx, expr), OptionSome)
                 && let hir::ExprKind::Path(_) = args[0].kind
@@ -51,7 +57,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a
                 );
                 return;
             }
-            if name == "filter_map" {
+            if name == sym::filter_map {
                 "map(..)"
             } else {
                 "map(..).next()"
@@ -61,7 +67,11 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a
                 ty::Adt(adt, subst)
                     if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && in_ty == subst.type_at(0) =>
                 {
-                    if name == "filter_map" { "filter(..)" } else { "find(..)" }
+                    if name == sym::filter_map {
+                        "filter(..)"
+                    } else {
+                        "find(..)"
+                    }
                 },
                 _ => return,
             }
@@ -70,7 +80,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a
         };
         span_lint(
             cx,
-            if name == "filter_map" {
+            if name == sym::filter_map {
                 UNNECESSARY_FILTER_MAP
             } else {
                 UNNECESSARY_FIND_MAP
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
index fa3a29e3667..cc4448192d3 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
@@ -1,10 +1,11 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::{MaybePath, is_res_lang_ctor, last_path_segment, path_res};
+use clippy_utils::{MaybePath, is_res_lang_ctor, last_path_segment, path_res, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{self as hir, AmbigArg};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
 use rustc_middle::ty::print::with_forced_trimmed_paths;
+use rustc_span::Symbol;
 
 use super::UNNECESSARY_LITERAL_UNWRAP;
 
@@ -25,7 +26,7 @@ pub(super) fn check(
     cx: &LateContext<'_>,
     expr: &hir::Expr<'_>,
     recv: &hir::Expr<'_>,
-    method: &str,
+    method: Symbol,
     args: &[hir::Expr<'_>],
 ) {
     let init = clippy_utils::expr_or_init(cx, recv);
@@ -42,17 +43,17 @@ pub(super) fn check(
         let res = cx.qpath_res(qpath, call.hir_id());
 
         if is_res_lang_ctor(cx, res, hir::LangItem::OptionSome) {
-            ("Some", call_args, get_ty_from_args(args, 0))
+            (sym::Some, call_args, get_ty_from_args(args, 0))
         } else if is_res_lang_ctor(cx, res, hir::LangItem::ResultOk) {
-            ("Ok", call_args, get_ty_from_args(args, 0))
+            (sym::Ok, call_args, get_ty_from_args(args, 0))
         } else if is_res_lang_ctor(cx, res, hir::LangItem::ResultErr) {
-            ("Err", call_args, get_ty_from_args(args, 1))
+            (sym::Err, call_args, get_ty_from_args(args, 1))
         } else {
             return;
         }
     } else if is_res_lang_ctor(cx, path_res(cx, init), hir::LangItem::OptionNone) {
         let call_args: &[hir::Expr<'_>] = &[];
-        ("None", call_args, None)
+        (sym::None, call_args, None)
     } else {
         return;
     };
@@ -62,12 +63,12 @@ pub(super) fn check(
 
     span_lint_and_then(cx, UNNECESSARY_LITERAL_UNWRAP, expr.span, help_message, |diag| {
         let suggestions = match (constructor, method, ty) {
-            ("None", "unwrap", _) => Some(vec![(expr.span, "panic!()".to_string())]),
-            ("None", "expect", _) => Some(vec![
+            (sym::None, sym::unwrap, _) => Some(vec![(expr.span, "panic!()".to_string())]),
+            (sym::None, sym::expect, _) => Some(vec![
                 (expr.span.with_hi(args[0].span.lo()), "panic!(".to_string()),
                 (expr.span.with_lo(args[0].span.hi()), ")".to_string()),
             ]),
-            ("Some" | "Ok", "unwrap_unchecked", _) | ("Err", "unwrap_err_unchecked", _) => {
+            (sym::Some | sym::Ok, sym::unwrap_unchecked, _) | (sym::Err, sym::unwrap_err_unchecked, _) => {
                 let mut suggs = vec![
                     (recv.span.with_hi(call_args[0].span.lo()), String::new()),
                     (expr.span.with_lo(call_args[0].span.hi()), String::new()),
@@ -83,7 +84,7 @@ pub(super) fn check(
                 }
                 Some(suggs)
             },
-            ("None", "unwrap_or_default", _) => {
+            (sym::None, sym::unwrap_or_default, _) => {
                 let ty = cx.typeck_results().expr_ty(expr);
                 let default_ty_string = if let ty::Adt(def, ..) = ty.kind() {
                     with_forced_trimmed_paths!(format!("{}", cx.tcx.def_path_str(def.did())))
@@ -92,11 +93,11 @@ pub(super) fn check(
                 };
                 Some(vec![(expr.span, format!("{default_ty_string}::default()"))])
             },
-            ("None", "unwrap_or", _) => Some(vec![
+            (sym::None, sym::unwrap_or, _) => Some(vec![
                 (expr.span.with_hi(args[0].span.lo()), String::new()),
                 (expr.span.with_lo(args[0].span.hi()), String::new()),
             ]),
-            ("None", "unwrap_or_else", _) => match args[0].kind {
+            (sym::None, sym::unwrap_or_else, _) => match args[0].kind {
                 hir::ExprKind::Closure(hir::Closure { body, .. }) => Some(vec![
                     (expr.span.with_hi(cx.tcx.hir_body(*body).value.span.lo()), String::new()),
                     (expr.span.with_lo(args[0].span.hi()), String::new()),
@@ -105,14 +106,14 @@ pub(super) fn check(
             },
             _ if call_args.is_empty() => None,
             (_, _, Some(_)) => None,
-            ("Ok", "unwrap_err", None) | ("Err", "unwrap", None) => Some(vec![
+            (sym::Ok, sym::unwrap_err, None) | (sym::Err, sym::unwrap, None) => Some(vec![
                 (
                     recv.span.with_hi(call_args[0].span.lo()),
                     "panic!(\"{:?}\", ".to_string(),
                 ),
                 (expr.span.with_lo(call_args[0].span.hi()), ")".to_string()),
             ]),
-            ("Ok", "expect_err", None) | ("Err", "expect", None) => Some(vec![
+            (sym::Ok, sym::expect_err, None) | (sym::Err, sym::expect, None) => Some(vec![
                 (
                     recv.span.with_hi(call_args[0].span.lo()),
                     "panic!(\"{1}: {:?}\", ".to_string(),
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs
index 7d01bdc2269..413881d5ec9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_min_or_max.rs
@@ -5,16 +5,17 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant, ConstantSource, FullInt};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
 
+use clippy_utils::sym;
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
 use rustc_middle::ty;
-use rustc_span::{Span, sym};
+use rustc_span::{Span, Symbol};
 
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'_>,
-    name: &str,
+    name: Symbol,
     recv: &'tcx Expr<'_>,
     arg: &'tcx Expr<'_>,
 ) {
@@ -47,10 +48,10 @@ pub(super) fn check<'tcx>(
     }
 }
 
-fn lint(cx: &LateContext<'_>, expr: &Expr<'_>, name: &str, lhs: Span, rhs: Span, order: Ordering) {
+fn lint(cx: &LateContext<'_>, expr: &Expr<'_>, name: Symbol, lhs: Span, rhs: Span, order: Ordering) {
     let cmp_str = if order.is_ge() { "smaller" } else { "greater" };
 
-    let suggested_value = if (name == "min" && order.is_ge()) || (name == "max" && order.is_le()) {
+    let suggested_value = if (name == sym::min && order.is_ge()) || (name == sym::max && order.is_le()) {
         snippet(cx, rhs, "..")
     } else {
         snippet(cx, lhs, "..")
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
index fb4984914eb..dbff08bc51c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
@@ -188,7 +188,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Exp
 
 fn expr_borrows(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     let ty = cx.typeck_results().expr_ty(expr);
-    matches!(ty.kind(), ty::Ref(..)) || ty.walk().any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_)))
+    matches!(ty.kind(), ty::Ref(..)) || ty.walk().any(|arg| matches!(arg.kind(), GenericArgKind::Lifetime(_)))
 }
 
 pub(super) fn check<'tcx>(
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 87bb8d46a1d..fdccf1fb33d 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
@@ -44,7 +44,7 @@ pub fn check<'tcx>(
                 return;
             }
             // At this point, we know the call is of a `to_owned`-like function. The functions
-            // `check_addr_of_expr` and `check_call_arg` determine whether the call is unnecessary
+            // `check_addr_of_expr` and `check_into_iter_call_arg` determine whether the call is unnecessary
             // based on its context, that is, whether it is a referent in an `AddrOf` expression, an
             // argument in a `into_iter` call, or an argument in the call of some other function.
             if check_addr_of_expr(cx, expr, method_name, method_def_id, receiver) {
@@ -608,7 +608,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
 }
 
 fn has_lifetime(ty: Ty<'_>) -> bool {
-    ty.walk().any(|t| matches!(t.unpack(), GenericArgKind::Lifetime(_)))
+    ty.walk().any(|t| matches!(t.kind(), GenericArgKind::Lifetime(_)))
 }
 
 /// Returns true if the named method is `Iterator::cloned` or `Iterator::copied`.
@@ -619,7 +619,7 @@ fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_def_id:
 /// Returns true if the named method can be used to convert the receiver to its "owned"
 /// representation.
 fn is_to_owned_like<'a>(cx: &LateContext<'a>, call_expr: &Expr<'a>, method_name: Symbol, method_def_id: DefId) -> bool {
-    is_clone_like(cx, method_name.as_str(), method_def_id)
+    is_clone_like(cx, method_name, method_def_id)
         || is_cow_into_owned(cx, method_name, method_def_id)
         || is_to_string_on_string_like(cx, call_expr, method_name, method_def_id)
 }
@@ -643,7 +643,7 @@ fn is_to_string_on_string_like<'a>(
 
     if let Some(args) = cx.typeck_results().node_args_opt(call_expr.hir_id)
         && let [generic_arg] = args.as_slice()
-        && let GenericArgKind::Type(ty) = generic_arg.unpack()
+        && let GenericArgKind::Type(ty) = generic_arg.kind()
         && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref)
         && let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef)
         && (cx.get_associated_type(ty, deref_trait_id, sym::Target) == Some(cx.tcx.types.str_)
@@ -655,11 +655,18 @@ fn is_to_string_on_string_like<'a>(
     }
 }
 
-fn is_a_std_map_type(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
-    is_type_diagnostic_item(cx, ty, sym::HashSet)
-        || is_type_diagnostic_item(cx, ty, sym::HashMap)
-        || is_type_diagnostic_item(cx, ty, sym::BTreeMap)
-        || is_type_diagnostic_item(cx, ty, sym::BTreeSet)
+fn std_map_key<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
+    match ty.kind() {
+        ty::Adt(adt, args)
+            if matches!(
+                cx.tcx.get_diagnostic_name(adt.did()),
+                Some(sym::BTreeMap | sym::BTreeSet | sym::HashMap | sym::HashSet)
+            ) =>
+        {
+            Some(args.type_at(0))
+        },
+        _ => None,
+    }
 }
 
 fn is_str_and_string(cx: &LateContext<'_>, arg_ty: Ty<'_>, original_arg_ty: Ty<'_>) -> bool {
@@ -679,11 +686,11 @@ fn check_if_applicable_to_argument<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'tcx
     if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, expr) = arg.kind
         && let ExprKind::MethodCall(method_path, caller, &[], _) = expr.kind
         && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
-        && let method_name = method_path.ident.name.as_str()
+        && let method_name = method_path.ident.name
         && match method_name {
-            "to_owned" => cx.tcx.is_diagnostic_item(sym::to_owned_method, method_def_id),
-            "to_string" => cx.tcx.is_diagnostic_item(sym::to_string_method, method_def_id),
-            "to_vec" => cx
+            sym::to_owned => cx.tcx.is_diagnostic_item(sym::to_owned_method, method_def_id),
+            sym::to_string => cx.tcx.is_diagnostic_item(sym::to_string_method, method_def_id),
+            sym::to_vec => cx
                 .tcx
                 .impl_of_method(method_def_id)
                 .filter(|&impl_did| cx.tcx.type_of(impl_did).instantiate_identity().is_slice())
@@ -721,6 +728,7 @@ fn check_if_applicable_to_argument<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'tcx
 // 1. This is a method with only one argument that doesn't come from a trait.
 // 2. That it has `Borrow` in its generic predicates.
 // 3. `Self` is a std "map type" (ie `HashSet`, `HashMap`, `BTreeSet`, `BTreeMap`).
+// 4. The key to the "map type" is not a reference.
 fn check_borrow_predicate<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
     if let ExprKind::MethodCall(_, caller, &[arg], _) = expr.kind
         && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
@@ -738,7 +746,9 @@ fn check_borrow_predicate<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
         })
         && let caller_ty = cx.typeck_results().expr_ty(caller)
         // For now we limit it to "map types".
-        && is_a_std_map_type(cx, caller_ty)
+        && let Some(key_ty) = std_map_key(cx, caller_ty)
+        // We need to check that the key type is not a reference.
+        && !key_ty.is_ref()
     {
         check_if_applicable_to_argument(cx, &arg);
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
index 17e2620d9dd..d30c12e0c48 100644
--- a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
@@ -7,7 +7,7 @@ use rustc_hir::{self as hir, LangItem};
 use rustc_lint::LateContext;
 use rustc_middle::ty::adjustment::Adjust;
 use rustc_middle::ty::{Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
-use rustc_span::{Span, sym};
+use rustc_span::{Span, Symbol, sym};
 
 use core::ops::ControlFlow;
 
@@ -39,7 +39,7 @@ fn get_enum_ty(enum_ty: Ty<'_>) -> Option<Ty<'_>> {
 }
 
 /// Checks for the `USELESS_ASREF` lint.
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, recvr: &hir::Expr<'_>) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: Symbol, recvr: &hir::Expr<'_>) {
     // when we get here, we've already checked that the call name is "as_ref" or "as_mut"
     // check if the call is to the actual `AsRef` or `AsMut` trait
     let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) else {
@@ -79,9 +79,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str,
                 applicability,
             );
         }
-    } else if let Some(impl_id) = cx.tcx.opt_parent(def_id)
+    } else if let Some(impl_id) = cx.tcx.impl_of_method(def_id)
         && let Some(adt) = cx.tcx.type_of(impl_id).instantiate_identity().ty_adt_def()
-        && (cx.tcx.lang_items().option_type() == Some(adt.did()) || cx.tcx.is_diagnostic_item(sym::Result, adt.did()))
+        && matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::Option | sym::Result))
     {
         let rcv_ty = cx.typeck_results().expr_ty(recvr).peel_refs();
         let res_ty = cx.typeck_results().expr_ty(expr).peel_refs();
@@ -161,7 +161,7 @@ fn is_calling_clone(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
     }
 }
 
-fn lint_as_ref_clone(cx: &LateContext<'_>, span: Span, recvr: &hir::Expr<'_>, call_name: &str) {
+fn lint_as_ref_clone(cx: &LateContext<'_>, span: Span, recvr: &hir::Expr<'_>, call_name: Symbol) {
     let mut applicability = Applicability::MachineApplicable;
     span_lint_and_sugg(
         cx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
index 7384e534ed7..ad9b3c36454 100644
--- a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
@@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::ty::is_copy;
 use rustc_lint::LateContext;
 use rustc_middle::ty::Ty;
-use rustc_span::Span;
+use rustc_span::{Span, Symbol};
 use std::fmt;
 
 use super::WRONG_SELF_CONVENTION;
@@ -83,17 +83,18 @@ impl fmt::Display for Convention {
 #[allow(clippy::too_many_arguments)]
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
-    item_name: &str,
+    item_name: Symbol,
     self_ty: Ty<'tcx>,
     first_arg_ty: Ty<'tcx>,
     first_arg_span: Span,
     implements_trait: bool,
     is_trait_item: bool,
 ) {
+    let item_name_str = item_name.as_str();
     if let Some((conventions, self_kinds)) = &CONVENTIONS.iter().find(|(convs, _)| {
         convs
             .iter()
-            .all(|conv| conv.check(cx, self_ty, item_name, implements_trait, is_trait_item))
+            .all(|conv| conv.check(cx, self_ty, item_name_str, implements_trait, is_trait_item))
     }) {
         // don't lint if it implements a trait but not willing to check `Copy` types conventions (see #7032)
         if implements_trait
diff --git a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
index 00ea9bba0d1..99f01c8001a 100644
--- a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
+++ b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
@@ -131,8 +131,9 @@ impl Visitor<'_> for IdentVisitor<'_, '_> {
             // If however the identifier is different, this means it is an alias (`use foo::bar as baz`). In
             // this case, we need to emit the warning for `baz`.
             if let Some(imported_item_path) = usenode
-                && let Some(Res::Def(_, imported_item_defid)) = imported_item_path.res.first()
-                && cx.tcx.item_name(*imported_item_defid).as_str() == str
+                // use `present_items` because it could be in any of type_ns, value_ns, macro_ns
+                && let Some(Res::Def(_, imported_item_defid)) = imported_item_path.res.value_ns
+                && cx.tcx.item_name(imported_item_defid).as_str() == str
             {
                 return;
             }
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 f3e24044fb6..a6be7581c9a 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
@@ -7,7 +7,7 @@ use rustc_abi::ExternAbi;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::CRATE_DEF_ID;
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{self as hir, Body, Constness, FnDecl, GenericParamKind};
+use rustc_hir::{self as hir, Body, Constness, FnDecl, GenericParamKind, OwnerId};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::impl_lint_pass;
@@ -125,7 +125,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
                 }
             },
             FnKind::Method(_, sig, ..) => {
-                if already_const(sig.header) || trait_ref_of_method(cx, def_id).is_some() {
+                if already_const(sig.header) || trait_ref_of_method(cx, OwnerId { def_id }).is_some() {
                     return;
                 }
             },
diff --git a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
index a1e621cc9f6..eeea6dfd5f4 100644
--- a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
@@ -72,7 +72,8 @@ impl_lint_pass!(ImportRename => [MISSING_ENFORCED_IMPORT_RENAMES]);
 impl LateLintPass<'_> for ImportRename {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
         if let ItemKind::Use(path, UseKind::Single(_)) = &item.kind {
-            for &res in &path.res {
+            // use `present_items` because it could be in any of type_ns, value_ns, macro_ns
+            for res in path.res.present_items() {
                 if let Res::Def(_, id) = res
                     && let Some(name) = self.renames.get(&id)
                     // Remove semicolon since it is not present for nested imports
diff --git a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
index be7dd74fd62..d4d33029dbd 100644
--- a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
@@ -225,7 +225,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingFieldsInDebug {
             && let typeck_results = cx.tcx.typeck_body(*body_id)
             && should_lint(cx, typeck_results, block)
             // we intentionally only lint structs, see lint description
-            && let ItemKind::Struct(_, data, _) = &self_item.kind
+            && let ItemKind::Struct(_, _, data) = &self_item.kind
         {
             check_struct(cx, typeck_results, block, self_ty, item, data);
         }
diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs
index a45031ce22b..98a9a98d281 100644
--- a/src/tools/clippy/clippy_lints/src/mut_key.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_key.rs
@@ -83,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType<'tcx> {
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'tcx>) {
         if let hir::ImplItemKind::Fn(ref sig, ..) = item.kind
-            && trait_ref_of_method(cx, item.owner_id.def_id).is_none()
+            && trait_ref_of_method(cx, item.owner_id).is_none()
         {
             self.check_sig(cx, item.owner_id.def_id, sig.decl);
         }
diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs
index 2fd1049f42e..2f1ab3d2652 100644
--- a/src/tools/clippy/clippy_lints/src/mut_reference.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs
@@ -79,25 +79,19 @@ fn check_arguments<'tcx>(
     name: &str,
     fn_kind: &str,
 ) {
-    match type_definition.kind() {
-        ty::FnDef(..) | ty::FnPtr(..) => {
-            let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs();
-            for (argument, parameter) in iter::zip(arguments, parameters) {
-                match parameter.kind() {
-                    ty::Ref(_, _, Mutability::Not) | ty::RawPtr(_, Mutability::Not) => {
-                        if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) = argument.kind {
-                            span_lint(
-                                cx,
-                                UNNECESSARY_MUT_PASSED,
-                                argument.span,
-                                format!("the {fn_kind} `{name}` doesn't need a mutable reference"),
-                            );
-                        }
-                    },
-                    _ => (),
-                }
+    if let ty::FnDef(..) | ty::FnPtr(..) = type_definition.kind() {
+        let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs();
+        for (argument, parameter) in iter::zip(arguments, parameters) {
+            if let ty::Ref(_, _, Mutability::Not) | ty::RawPtr(_, Mutability::Not) = parameter.kind()
+                && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) = argument.kind
+            {
+                span_lint(
+                    cx,
+                    UNNECESSARY_MUT_PASSED,
+                    argument.span,
+                    format!("the {fn_kind} `{name}` doesn't need a mutable reference"),
+                );
             }
-        },
-        _ => (),
+        }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs
index f768e11a4a2..3ed4b1c2ea9 100644
--- a/src/tools/clippy/clippy_lints/src/needless_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs
@@ -3,7 +3,7 @@ use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{
     SpanlessEq, get_parent_expr, higher, is_block_like, is_else_clause, is_expn_of, is_parent_stmt,
-    is_receiver_of_method_call, peel_blocks, peel_blocks_with_stmt, span_extract_comment,
+    is_receiver_of_method_call, peel_blocks, peel_blocks_with_stmt, span_extract_comment, sym,
 };
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
@@ -320,7 +320,7 @@ fn check_comparison<'a, 'tcx>(
             cx.typeck_results().expr_ty(left_side),
             cx.typeck_results().expr_ty(right_side),
         );
-        if is_expn_of(left_side.span, "cfg").is_some() || is_expn_of(right_side.span, "cfg").is_some() {
+        if is_expn_of(left_side.span, sym::cfg).is_some() || is_expn_of(right_side.span, sym::cfg).is_some() {
             return;
         }
         if l_ty.is_bool() && r_ty.is_bool() {
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 e579dd5947d..2efb55b9880 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
@@ -269,7 +269,7 @@ fn needless_borrow_count<'tcx>(
                     .tcx
                     .is_diagnostic_item(sym::IntoIterator, trait_predicate.trait_ref.def_id)
                 && let ty::Param(param_ty) = trait_predicate.self_ty().kind()
-                && let GenericArgKind::Type(ty) = args_with_referent_ty[param_ty.index as usize].unpack()
+                && let GenericArgKind::Type(ty) = args_with_referent_ty[param_ty.index as usize].kind()
                 && ty.is_array()
                 && !msrv.meets(cx, msrvs::ARRAY_INTO_ITERATOR)
             {
diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
index 7dd96f1f037..6a7c8436bad 100644
--- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
@@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
             && let body = cx.tcx.hir_body(body)
             // Skip the lint if the body is not safe, so as not to suggest `for … in … unsafe {}`
             // and suggesting `for … in … { unsafe { } }` is a little ugly.
-            && let ExprKind::Block(Block { rules: BlockCheckMode::DefaultBlock, .. }, ..) = body.value.kind
+            && !matches!(body.value.kind, ExprKind::Block(Block { rules: BlockCheckMode::UnsafeBlock(_), .. }, ..))
         {
             let mut ret_collector = RetCollector::default();
             ret_collector.visit_expr(body.value);
@@ -99,11 +99,21 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
                 )
             };
 
+            let body_param_sugg = snippet_with_applicability(cx, body.params[0].pat.span, "..", &mut applicability);
+            let for_each_rev_sugg = snippet_with_applicability(cx, for_each_recv.span, "..", &mut applicability);
+            let body_value_sugg = snippet_with_applicability(cx, body.value.span, "..", &mut applicability);
+
             let sugg = format!(
                 "for {} in {} {}",
-                snippet_with_applicability(cx, body.params[0].pat.span, "..", &mut applicability),
-                snippet_with_applicability(cx, for_each_recv.span, "..", &mut applicability),
-                snippet_with_applicability(cx, body.value.span, "..", &mut applicability),
+                body_param_sugg,
+                for_each_rev_sugg,
+                match body.value.kind {
+                    ExprKind::Block(block, _) if is_let_desugar(block) => {
+                        format!("{{ {body_value_sugg} }}")
+                    },
+                    ExprKind::Block(_, _) => body_value_sugg.to_string(),
+                    _ => format!("{{ {body_value_sugg}; }}"),
+                }
             );
 
             span_lint_and_then(cx, NEEDLESS_FOR_EACH, stmt.span, "needless use of `for_each`", |diag| {
@@ -116,6 +126,20 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
     }
 }
 
+/// Check if the block is a desugared `_ = expr` statement.
+fn is_let_desugar(block: &Block<'_>) -> bool {
+    matches!(
+        block,
+        Block {
+            stmts: [Stmt {
+                kind: StmtKind::Let(_),
+                ..
+            },],
+            ..
+        }
+    )
+}
+
 /// This type plays two roles.
 /// 1. Collect spans of `return` in the closure body.
 /// 2. Detect use of `return` in `Loop` in the closure body.
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 275d710c76a..95623467b81 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -212,7 +212,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                     }
 
                     if is_type_diagnostic_item(cx, ty, sym::Vec)
-                        && let Some(clone_spans) = get_spans(cx, Some(body.id()), idx, &[("clone", ".to_owned()")])
+                        && let Some(clone_spans) = get_spans(cx, Some(body.id()), idx, &[(sym::clone, ".to_owned()")])
                         && let TyKind::Path(QPath::Resolved(_, path)) = input.kind
                         && let Some(elem_ty) = path
                             .segments
@@ -253,8 +253,12 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                     }
 
                     if is_type_lang_item(cx, ty, LangItem::String)
-                        && let Some(clone_spans) =
-                            get_spans(cx, Some(body.id()), idx, &[("clone", ".to_string()"), ("as_str", "")])
+                        && let Some(clone_spans) = get_spans(
+                            cx,
+                            Some(body.id()),
+                            idx,
+                            &[(sym::clone, ".to_string()"), (sym::as_str, "")],
+                        )
                     {
                         diag.span_suggestion(
                             input.span,
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index 7ab7976d569..02c48166131 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -221,10 +221,16 @@ fn is_operator_overridden(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     }
 }
 
+/// Checks if dropping `expr` might have a visible side effect.
+fn expr_ty_has_significant_drop(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    let ty = cx.typeck_results().expr_ty(expr);
+    ty.has_significant_drop(cx.tcx, cx.typing_env())
+}
+
 fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     match expr.kind {
         ExprKind::Lit(..) | ExprKind::Closure { .. } => true,
-        ExprKind::Path(..) => !has_drop(cx, cx.typeck_results().expr_ty(expr)),
+        ExprKind::Path(..) => !expr_ty_has_significant_drop(cx, expr),
         ExprKind::Index(a, b, _) | ExprKind::Binary(_, a, b) => has_no_effect(cx, a) && has_no_effect(cx, b),
         ExprKind::Array(v) | ExprKind::Tup(v) => v.iter().all(|val| has_no_effect(cx, val)),
         ExprKind::Repeat(inner, _)
@@ -233,8 +239,8 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
         | ExprKind::Unary(_, inner)
         | ExprKind::Field(inner, _)
         | ExprKind::AddrOf(_, _, inner) => has_no_effect(cx, inner),
-        ExprKind::Struct(_, fields, ref base) => {
-            !has_drop(cx, cx.typeck_results().expr_ty(expr))
+        ExprKind::Struct(_, fields, base) => {
+            !expr_ty_has_significant_drop(cx, expr)
                 && fields.iter().all(|field| has_no_effect(cx, field.expr))
                 && match &base {
                     StructTailExpr::None | StructTailExpr::DefaultFields(_) => true,
@@ -252,7 +258,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
                     Res::Def(DefKind::Struct | DefKind::Variant | DefKind::Ctor(..), ..)
                 );
                 if def_matched || is_range_literal(expr) {
-                    !has_drop(cx, cx.typeck_results().expr_ty(expr)) && args.iter().all(|arg| has_no_effect(cx, arg))
+                    !expr_ty_has_significant_drop(cx, expr) && args.iter().all(|arg| has_no_effect(cx, arg))
                 } else {
                     false
                 }
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 6d3e77b6b6e..a27c6aa75e3 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -1,56 +1,78 @@
-use std::ptr;
+// Implementation for lints detecting interior mutability in constants.
+//
+// For `declare_interior_mutable_const` there are three strategies used to
+// determine if a value has interior mutability:
+// * A type-based check. This is the least accurate, but can always run.
+// * A const-eval based check. This is the most accurate, but this requires that the value is
+//   defined and does not work with generics.
+// * A HIR-tree based check. This is less accurate than const-eval, but it can be applied to generic
+//   values.
+//
+// For `borrow_interior_mutable_const` the same three strategies are applied
+// when checking a constant's value, but field and array index projections at
+// the borrow site are taken into account as well. As an example: `FOO.bar` may
+// have interior mutability, but `FOO.baz` may not. When borrowing `FOO.baz` no
+// warning will be issued.
+//
+// No matter the lint or strategy, a warning should only be issued if a value
+// definitely contains interior mutability.
 
 use clippy_config::Conf;
-use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
+use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::is_in_const_context;
 use clippy_utils::macros::macro_backtrace;
-use clippy_utils::ty::{InteriorMut, implements_trait};
-use rustc_abi::VariantIdx;
+use clippy_utils::paths::{PathNS, lookup_path_str};
+use clippy_utils::ty::{get_field_idx_by_name, implements_trait};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, DefIdSet};
 use rustc_hir::{
-    BodyId, Expr, ExprKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp,
+    Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, Node, StructTailExpr, TraitItem, TraitItemKind, UnOp,
+};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::mir::{ConstValue, UnevaluatedConst};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment};
+use rustc_middle::ty::{
+    self, AliasTyKind, EarlyBinder, GenericArgs, GenericArgsRef, Instance, Ty, TyCtxt, TypeFolder, TypeSuperFoldable,
+    TypeckResults, TypingEnv,
 };
-use rustc_lint::{LateContext, LateLintPass, Lint};
-use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId, ReportedErrorInfo};
-use rustc_middle::ty::adjustment::Adjust;
-use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::impl_lint_pass;
-use rustc_span::{DUMMY_SP, Span, sym};
+use rustc_span::{DUMMY_SP, sym};
+use std::collections::hash_map::Entry;
 
-// FIXME: this is a correctness problem but there's no suitable
-// warn-by-default category.
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for declaration of `const` items which is interior
-    /// mutable (e.g., contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.).
+    /// Checks for the declaration of named constant which contain interior mutability.
     ///
     /// ### Why is this bad?
-    /// Consts are copied everywhere they are referenced, i.e.,
-    /// every time you refer to the const a fresh instance of the `Cell` or `Mutex`
-    /// or `AtomicXxxx` will be created, which defeats the whole purpose of using
-    /// these types in the first place.
+    /// Named constants are copied at every use site which means any change to their value
+    /// will be lost after the newly created value is dropped. e.g.
     ///
-    /// The `const` should better be replaced by a `static` item if a global
-    /// variable is wanted, or replaced by a `const fn` if a constructor is wanted.
+    /// ```rust
+    /// use core::sync::atomic::{AtomicUsize, Ordering};
+    /// const ATOMIC: AtomicUsize = AtomicUsize::new(0);
+    /// fn add_one() -> usize {
+    ///     // This will always return `0` since `ATOMIC` is copied before it's used.
+    ///     ATOMIC.fetch_add(1, Ordering::AcqRel)
+    /// }
+    /// ```
     ///
-    /// ### Known problems
-    /// A "non-constant" const item is a legacy way to supply an
-    /// initialized value to downstream `static` items (e.g., the
-    /// `std::sync::ONCE_INIT` constant). In this case the use of `const` is legit,
-    /// and this lint should be suppressed.
+    /// If shared modification of the value is desired, a `static` item is needed instead.
+    /// If that is not desired, a `const fn` constructor should be used to make it obvious
+    /// at the use site that a new value is created.
     ///
-    /// Even though the lint avoids triggering on a constant whose type has enums that have variants
-    /// with interior mutability, and its value uses non interior mutable variants (see
-    /// [#3962](https://github.com/rust-lang/rust-clippy/issues/3962) and
-    /// [#3825](https://github.com/rust-lang/rust-clippy/issues/3825) for examples);
-    /// it complains about associated constants without default values only based on its types;
-    /// which might not be preferable.
-    /// There're other enums plus associated constants cases that the lint cannot handle.
+    /// ### Known problems
+    /// Prior to `const fn` stabilization this was the only way to provide a value which
+    /// could initialize a `static` item (e.g. the `std::sync::ONCE_INIT` constant). In
+    /// this case the use of `const` is required and this lint should be suppressed.
     ///
-    /// Types that have underlying or potential interior mutability trigger the lint whether
-    /// the interior mutable field is used or not. See issue
-    /// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812)
+    /// There also exists types which contain private fields with interior mutability, but
+    /// no way to both create a value as a constant and modify any mutable field using the
+    /// type's public interface (e.g. `bytes::Bytes`). As there is no reasonable way to
+    /// scan a crate's interface to see if this is the case, all such types will be linted.
+    /// If this happens use the `ignore-interior-mutability` configuration option to allow
+    /// the type.
     ///
     /// ### Example
     /// ```no_run
@@ -74,20 +96,44 @@ declare_clippy_lint! {
     "declaring `const` with interior mutability"
 }
 
-// FIXME: this is a correctness problem but there's no suitable
-// warn-by-default category.
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks if `const` items which is interior mutable (e.g.,
-    /// contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.) has been borrowed directly.
+    /// Checks for a borrow of a named constant with interior mutability.
     ///
     /// ### Why is this bad?
-    /// Consts are copied everywhere they are referenced, i.e.,
-    /// every time you refer to the const a fresh instance of the `Cell` or `Mutex`
-    /// or `AtomicXxxx` will be created, which defeats the whole purpose of using
-    /// these types in the first place.
+    /// Named constants are copied at every use site which means any change to their value
+    /// will be lost after the newly created value is dropped. e.g.
+    ///
+    /// ```rust
+    /// use core::sync::atomic::{AtomicUsize, Ordering};
+    /// const ATOMIC: AtomicUsize = AtomicUsize::new(0);
+    /// fn add_one() -> usize {
+    ///     // This will always return `0` since `ATOMIC` is copied before it's borrowed
+    ///     // for use by `fetch_add`.
+    ///     ATOMIC.fetch_add(1, Ordering::AcqRel)
+    /// }
+    /// ```
     ///
-    /// The `const` value should be stored inside a `static` item.
+    /// ### Known problems
+    /// This lint does not, and cannot in general, determine if the borrow of the constant
+    /// is used in a way which causes a mutation. e.g.
+    ///
+    /// ```rust
+    /// use core::cell::Cell;
+    /// const CELL: Cell<usize> = Cell::new(0);
+    /// fn get_cell() -> Cell<usize> {
+    ///     // This is fine. It borrows a copy of `CELL`, but never mutates it through the
+    ///     // borrow.
+    ///     CELL.clone()
+    /// }
+    /// ```
+    ///
+    /// There also exists types which contain private fields with interior mutability, but
+    /// no way to both create a value as a constant and modify any mutable field using the
+    /// type's public interface (e.g. `bytes::Bytes`). As there is no reasonable way to
+    /// scan a crate's interface to see if this is the case, all such types will be linted.
+    /// If this happens use the `ignore-interior-mutability` configuration option to allow
+    /// the type.
     ///
     /// ### Example
     /// ```no_run
@@ -113,60 +159,101 @@ declare_clippy_lint! {
     "referencing `const` with interior mutability"
 }
 
-#[derive(Copy, Clone)]
-enum Source<'tcx> {
-    Item { item: Span, ty: Ty<'tcx> },
-    Assoc { item: Span },
-    Expr { expr: Span },
+#[derive(Clone, Copy)]
+enum IsFreeze {
+    /// The type and all possible values are `Freeze`
+    Yes,
+    /// The type itself is non-`Freeze`, but not all values are.
+    Maybe,
+    /// The type and all possible values are non-`Freeze`
+    No,
 }
+impl IsFreeze {
+    /// Merges the variants of a sum type (i.e. an enum).
+    fn from_variants(iter: impl Iterator<Item = Self>) -> Self {
+        iter.fold(Self::Yes, |x, y| match (x, y) {
+            (Self::Maybe, _) | (_, Self::Maybe) | (Self::No, Self::Yes) | (Self::Yes, Self::No) => Self::Maybe,
+            (Self::No, Self::No) => Self::No,
+            (Self::Yes, Self::Yes) => Self::Yes,
+        })
+    }
 
-impl Source<'_> {
-    #[must_use]
-    fn lint(&self) -> (&'static Lint, &'static str, Span) {
-        match self {
-            Self::Item { item, .. } | Self::Assoc { item, .. } => (
-                DECLARE_INTERIOR_MUTABLE_CONST,
-                "a `const` item should not be interior mutable",
-                *item,
-            ),
-            Self::Expr { expr } => (
-                BORROW_INTERIOR_MUTABLE_CONST,
-                "a `const` item with interior mutability should not be borrowed",
-                *expr,
-            ),
-        }
+    /// Merges the fields of a product type (e.g. a struct or tuple).
+    fn from_fields(mut iter: impl Iterator<Item = Self>) -> Self {
+        iter.try_fold(Self::Yes, |x, y| match (x, y) {
+            (Self::No, _) | (_, Self::No) => None,
+            (Self::Maybe, _) | (_, Self::Maybe) => Some(Self::Maybe),
+            (Self::Yes, Self::Yes) => Some(Self::Yes),
+        })
+        .unwrap_or(Self::No)
+    }
+
+    /// Checks if this is definitely `Freeze`.
+    fn is_freeze(self) -> bool {
+        matches!(self, Self::Yes)
+    }
+
+    /// Checks if this is definitely not `Freeze`.
+    fn is_not_freeze(self) -> bool {
+        matches!(self, Self::No)
     }
 }
 
-fn lint<'tcx>(cx: &LateContext<'tcx>, source: Source<'tcx>) {
-    let (lint, msg, span) = source.lint();
-    span_lint_and_then(cx, lint, span, msg, |diag| {
-        if span.from_expansion() {
-            return; // Don't give suggestions into macros.
-        }
-        match source {
-            Source::Item { ty, .. } => {
-                let Some(sync_trait) = cx.tcx.lang_items().sync_trait() else {
-                    return;
-                };
-                if implements_trait(cx, ty, sync_trait, &[]) {
-                    diag.help("consider making this a static item");
-                } else {
-                    diag.help(
-                        "consider making this `Sync` so that it can go in a static item or using a `thread_local`",
-                    );
-                }
-            },
-            Source::Assoc { .. } => (),
-            Source::Expr { .. } => {
-                diag.help("assign this const to a local or static variable, and use the variable here");
+/// What operation caused a borrow to occur.
+#[derive(Clone, Copy)]
+enum BorrowCause {
+    Borrow,
+    Deref,
+    Index,
+    AutoDeref,
+    AutoBorrow,
+    AutoDerefField,
+}
+impl BorrowCause {
+    fn note(self) -> Option<&'static str> {
+        match self {
+            Self::Borrow => None,
+            Self::Deref => Some("this deref expression is a call to `Deref::deref`"),
+            Self::Index => Some("this index expression is a call to `Index::index`"),
+            Self::AutoDeref => Some("there is a compiler inserted call to `Deref::deref` here"),
+            Self::AutoBorrow => Some("there is a compiler inserted borrow here"),
+            Self::AutoDerefField => {
+                Some("there is a compiler inserted call to `Deref::deref` when accessing this field")
             },
         }
-    });
+    }
+}
+
+/// The source of a borrow. Both what caused it and where.
+struct BorrowSource<'tcx> {
+    expr: &'tcx Expr<'tcx>,
+    cause: BorrowCause,
+}
+impl<'tcx> BorrowSource<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>, expr: &'tcx Expr<'tcx>, cause: BorrowCause) -> Self {
+        // Custom deref and index impls will always have an auto-borrow inserted since we
+        // never work with reference types.
+        let (expr, cause) = if matches!(cause, BorrowCause::AutoBorrow)
+            && let Node::Expr(parent) = tcx.parent_hir_node(expr.hir_id)
+        {
+            match parent.kind {
+                ExprKind::Unary(UnOp::Deref, _) => (parent, BorrowCause::Deref),
+                ExprKind::Index(..) => (parent, BorrowCause::Index),
+                ExprKind::Field(..) => (parent, BorrowCause::AutoDerefField),
+                _ => (expr, cause),
+            }
+        } else {
+            (expr, cause)
+        };
+        Self { expr, cause }
+    }
 }
 
 pub struct NonCopyConst<'tcx> {
-    interior_mut: InteriorMut<'tcx>,
+    ignore_tys: DefIdSet,
+    // Cache checked types. We can recurse through a type multiple times so this
+    // can be hit quite frequently.
+    freeze_tys: FxHashMap<Ty<'tcx>, IsFreeze>,
 }
 
 impl_lint_pass!(NonCopyConst<'_> => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST]);
@@ -174,332 +261,629 @@ impl_lint_pass!(NonCopyConst<'_> => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTE
 impl<'tcx> NonCopyConst<'tcx> {
     pub fn new(tcx: TyCtxt<'tcx>, conf: &'static Conf) -> Self {
         Self {
-            interior_mut: InteriorMut::without_pointers(tcx, &conf.ignore_interior_mutability),
+            ignore_tys: conf
+                .ignore_interior_mutability
+                .iter()
+                .flat_map(|ignored_ty| lookup_path_str(tcx, PathNS::Type, ignored_ty))
+                .collect(),
+            freeze_tys: FxHashMap::default(),
         }
     }
 
-    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 branch
-        let Some(branched_val) = val.try_to_branch() 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.
-            ty::Adt(ty_def, ..) if ty_def.is_unsafe_cell() => true,
-            // As of 2022-09-08 miri doesn't track which union field is active so there's no safe way to check the
-            // contained value.
-            ty::Adt(def, ..) if def.is_union() => false,
-            ty::Array(ty, _) => branched_val
-                .iter()
-                .any(|field| Self::is_value_unfrozen_raw_inner(cx, *field, ty)),
-            ty::Adt(def, args) if def.is_enum() => {
-                let Some((&variant_valtree, fields)) = branched_val.split_first() else {
-                    return false;
-                };
-                let variant_index = variant_valtree.unwrap_leaf();
-                let variant_index = VariantIdx::from_u32(variant_index.to_u32());
-                fields
-                    .iter()
-                    .copied()
-                    .zip(
-                        def.variants()[variant_index]
+    /// Checks if a value of the given type is `Freeze`, or may be depending on the value.
+    fn is_ty_freeze(&mut self, tcx: TyCtxt<'tcx>, typing_env: TypingEnv<'tcx>, ty: Ty<'tcx>) -> IsFreeze {
+        let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
+        match self.freeze_tys.entry(ty) {
+            Entry::Occupied(e) => *e.get(),
+            Entry::Vacant(e) => {
+                let e = e.insert(IsFreeze::Yes);
+                if ty.is_freeze(tcx, typing_env) {
+                    return IsFreeze::Yes;
+                }
+                let is_freeze = match *ty.kind() {
+                    ty::Adt(adt, _) if adt.is_unsafe_cell() => {
+                        *e = IsFreeze::No;
+                        return IsFreeze::No;
+                    },
+                    ty::Adt(adt, _) if self.ignore_tys.contains(&adt.did()) => return IsFreeze::Yes,
+                    ty::Adt(adt, args) if adt.is_enum() => IsFreeze::from_variants(adt.variants().iter().map(|v| {
+                        IsFreeze::from_fields(
+                            v.fields
+                                .iter()
+                                .map(|f| self.is_ty_freeze(tcx, typing_env, f.ty(tcx, args))),
+                        )
+                    })),
+                    // Workaround for `ManuallyDrop`-like unions.
+                    ty::Adt(adt, args)
+                        if adt.is_union()
+                            && adt.non_enum_variant().fields.iter().any(|f| {
+                                tcx.layout_of(typing_env.as_query_input(f.ty(tcx, args)))
+                                    .is_ok_and(|l| l.layout.size().bytes() == 0)
+                            }) =>
+                    {
+                        return IsFreeze::Yes;
+                    },
+                    // Rust doesn't have the concept of an active union field so we have
+                    // to treat all fields as active.
+                    ty::Adt(adt, args) => IsFreeze::from_fields(
+                        adt.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::Adt(def, args) => branched_val
-                .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) => branched_val
-                .iter()
-                .zip(tys)
-                .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, *field, ty)),
-            ty::Alias(ty::Projection, _) => match cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty) {
-                Ok(normalized_ty) if ty != normalized_ty => Self::is_value_unfrozen_raw_inner(cx, val, normalized_ty),
-                _ => false,
+                            .map(|f| self.is_ty_freeze(tcx, typing_env, f.ty(tcx, args))),
+                    ),
+                    ty::Array(ty, _) | ty::Pat(ty, _) => self.is_ty_freeze(tcx, typing_env, ty),
+                    ty::Tuple(tys) => {
+                        IsFreeze::from_fields(tys.iter().map(|ty| self.is_ty_freeze(tcx, typing_env, ty)))
+                    },
+                    // Treat type parameters as though they were `Freeze`.
+                    ty::Param(_) | ty::Alias(..) => return IsFreeze::Yes,
+                    // TODO: check other types.
+                    _ => {
+                        *e = IsFreeze::No;
+                        return IsFreeze::No;
+                    },
+                };
+                if !is_freeze.is_freeze() {
+                    self.freeze_tys.insert(ty, is_freeze);
+                }
+                is_freeze
             },
-            _ => false,
         }
     }
 
-    fn is_value_unfrozen_raw(
-        cx: &LateContext<'tcx>,
-        result: Result<Result<ty::ValTree<'tcx>, Ty<'tcx>>, ErrorHandled>,
+    /// Checks if the given constant value is `Freeze`. Returns `Err` if the constant
+    /// cannot be read, but the result depends on the value.
+    fn is_value_freeze(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        typing_env: TypingEnv<'tcx>,
         ty: Ty<'tcx>,
-    ) -> bool {
-        result.map_or_else(
-            |err| {
-                // Consider `TooGeneric` cases as being unfrozen.
-                // This causes a false positive where an assoc const whose type is unfrozen
-                // have a value that is a frozen variant with a generic param (an example is
-                // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::GENERIC_VARIANT`).
-                // However, it prevents a number of false negatives that is, I think, important:
-                // 1. assoc consts in trait defs referring to consts of themselves (an example is
-                //    `declare_interior_mutable_const::traits::ConcreteTypes::ANOTHER_ATOMIC`).
-                // 2. a path expr referring to assoc consts whose type is doesn't have any frozen variants in trait
-                //    defs (i.e. without substitute for `Self`). (e.g. borrowing
-                //    `borrow_interior_mutable_const::trait::ConcreteTypes::ATOMIC`)
-                // 3. similar to the false positive above; but the value is an unfrozen variant, or the type has no
-                //    enums. (An example is
-                //    `declare_interior_mutable_const::enums::BothOfCellAndGeneric::UNFROZEN_VARIANT` and
-                //    `declare_interior_mutable_const::enums::BothOfCellAndGeneric::NO_ENUM`).
-                // One might be able to prevent these FNs correctly, and replace this with `false`;
-                // e.g. implementing `has_frozen_variant` described above, and not running this function
-                // when the type doesn't have any frozen variants would be the 'correct' way for the 2nd
-                // case (that actually removes another suboptimal behavior (I won't say 'false positive') where,
-                // similar to 2., but with a frozen variant) (e.g. borrowing
-                // `borrow_interior_mutable_const::enums::AssocConsts::TO_BE_FROZEN_VARIANT`).
-                // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none).
-                matches!(err, ErrorHandled::TooGeneric(..))
+        val: ConstValue<'tcx>,
+    ) -> Result<bool, ()> {
+        let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
+        match self.is_ty_freeze(tcx, typing_env, ty) {
+            IsFreeze::Yes => Ok(true),
+            IsFreeze::Maybe if matches!(ty.kind(), ty::Adt(..) | ty::Array(..) | ty::Tuple(..)) => {
+                for &(val, ty) in tcx
+                    .try_destructure_mir_constant_for_user_output(val, ty)
+                    .ok_or(())?
+                    .fields
+                {
+                    if !self.is_value_freeze(tcx, typing_env, ty, val)? {
+                        return Ok(false);
+                    }
+                }
+                Ok(true)
             },
-            |val| val.map_or(true, |val| Self::is_value_unfrozen_raw_inner(cx, val, ty)),
-        )
-    }
-
-    fn is_value_unfrozen_poly(cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool {
-        let def_id = body_id.hir_id.owner.to_def_id();
-        let args = ty::GenericArgs::identity_for_item(cx.tcx, def_id);
-        let instance = ty::Instance::new_raw(def_id, args);
-        let cid = GlobalId {
-            instance,
-            promoted: None,
-        };
-        let typing_env = ty::TypingEnv::post_analysis(cx.tcx, def_id);
-        let result = cx.tcx.const_eval_global_id_for_typeck(typing_env, cid, DUMMY_SP);
-        Self::is_value_unfrozen_raw(cx, result, ty)
-    }
-
-    fn is_value_unfrozen_expr(cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool {
-        let args = cx.typeck_results().node_args(hir_id);
-
-        let result = Self::const_eval_resolve(
-            cx.tcx,
-            cx.typing_env(),
-            ty::UnevaluatedConst::new(def_id, args),
-            DUMMY_SP,
-        );
-        Self::is_value_unfrozen_raw(cx, result, ty)
+            IsFreeze::Maybe | IsFreeze::No => Ok(false),
+        }
     }
 
-    pub fn const_eval_resolve(
+    /// Checks if the given expression creates a value which is `Freeze`.
+    ///
+    /// This will return `true` if the type is maybe `Freeze`, but it cannot be
+    /// determined for certain from the value.
+    ///
+    /// `typing_env` and `gen_args` are from the constant's use site.
+    /// `typeck` and `e` are from the constant's definition site.
+    fn is_init_expr_freeze(
+        &mut self,
         tcx: TyCtxt<'tcx>,
-        typing_env: ty::TypingEnv<'tcx>,
-        ct: ty::UnevaluatedConst<'tcx>,
-        span: Span,
-    ) -> EvalToValTreeResult<'tcx> {
-        match ty::Instance::try_resolve(tcx, typing_env, ct.def, ct.args) {
-            Ok(Some(instance)) => {
-                let cid = GlobalId {
-                    instance,
-                    promoted: None,
-                };
-                tcx.const_eval_global_id_for_typeck(typing_env, cid, span)
+        typing_env: TypingEnv<'tcx>,
+        typeck: &'tcx TypeckResults<'tcx>,
+        gen_args: GenericArgsRef<'tcx>,
+        e: &'tcx Expr<'tcx>,
+    ) -> bool {
+        // Make sure to instantiate all types coming from `typeck` with `gen_args`.
+        let ty = EarlyBinder::bind(typeck.expr_ty(e)).instantiate(tcx, gen_args);
+        let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
+        match self.is_ty_freeze(tcx, typing_env, ty) {
+            IsFreeze::Yes => true,
+            IsFreeze::No => false,
+            IsFreeze::Maybe => match e.kind {
+                ExprKind::Block(b, _)
+                    if !b.targeted_by_break
+                        && b.stmts.is_empty()
+                        && let Some(e) = b.expr =>
+                {
+                    self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, e)
+                },
+                ExprKind::Path(ref p) => {
+                    let res = typeck.qpath_res(p, e.hir_id);
+                    let gen_args = EarlyBinder::bind(typeck.node_args(e.hir_id)).instantiate(tcx, gen_args);
+                    match res {
+                        Res::Def(DefKind::Const | DefKind::AssocConst, did)
+                            if let Ok(val) =
+                                tcx.const_eval_resolve(typing_env, UnevaluatedConst::new(did, gen_args), DUMMY_SP)
+                                && let Ok(is_freeze) = self.is_value_freeze(tcx, typing_env, ty, val) =>
+                        {
+                            is_freeze
+                        },
+                        Res::Def(DefKind::Const | DefKind::AssocConst, did)
+                            if let Some((typeck, init)) = get_const_hir_value(tcx, typing_env, did, gen_args) =>
+                        {
+                            self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, init)
+                        },
+                        // Either this is a unit constructor, or some unknown value.
+                        // In either case we consider the value to be `Freeze`.
+                        _ => true,
+                    }
+                },
+                ExprKind::Call(callee, args)
+                    if let ExprKind::Path(p) = &callee.kind
+                        && let res = typeck.qpath_res(p, callee.hir_id)
+                        && matches!(res, Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(_)) =>
+                {
+                    args.iter()
+                        .all(|e| self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, e))
+                },
+                ExprKind::Struct(_, fields, StructTailExpr::None) => fields
+                    .iter()
+                    .all(|f| self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, f.expr)),
+                ExprKind::Tup(exprs) | ExprKind::Array(exprs) => exprs
+                    .iter()
+                    .all(|e| self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, e)),
+                ExprKind::Repeat(e, _) => self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, e),
+                _ => true,
             },
-            Ok(None) => Err(ErrorHandled::TooGeneric(span)),
-            Err(err) => Err(ErrorHandled::Reported(
-                ReportedErrorInfo::non_const_eval_error(err),
-                span,
-            )),
         }
     }
-}
 
-impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> {
-    fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) {
-        if let ItemKind::Const(.., body_id) = it.kind {
-            let ty = cx.tcx.type_of(it.owner_id).instantiate_identity();
-            if !ignored_macro(cx, it)
-                && self.interior_mut.is_interior_mut_ty(cx, ty)
-                && Self::is_value_unfrozen_poly(cx, body_id, ty)
-            {
-                lint(cx, Source::Item { item: it.span, ty });
+    /// Checks if the given expression (or a local projection of it) is both borrowed and
+    /// definitely a non-`Freeze` type.
+    fn is_non_freeze_expr_borrowed(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        typing_env: TypingEnv<'tcx>,
+        typeck: &'tcx TypeckResults<'tcx>,
+        mut src_expr: &'tcx Expr<'tcx>,
+    ) -> Option<BorrowSource<'tcx>> {
+        let mut parents = tcx.hir_parent_iter(src_expr.hir_id);
+        loop {
+            let ty = typeck.expr_ty(src_expr);
+            // Normalized as we need to check if this is an array later.
+            let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
+            let is_freeze = self.is_ty_freeze(tcx, typing_env, ty);
+            if is_freeze.is_freeze() {
+                return None;
             }
-        }
-    }
-
-    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx TraitItem<'_>) {
-        if let TraitItemKind::Const(_, body_id_opt) = &trait_item.kind {
-            let ty = cx.tcx.type_of(trait_item.owner_id).instantiate_identity();
-
-            // Normalize assoc types because ones originated from generic params
-            // bounded other traits could have their bound.
-            let normalized = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
-            if self.interior_mut.is_interior_mut_ty(cx, normalized)
-                // When there's no default value, lint it only according to its type;
-                // in other words, lint consts whose value *could* be unfrozen, not definitely is.
-                // This feels inconsistent with how the lint treats generic types,
-                // which avoids linting types which potentially become unfrozen.
-                // One could check whether an unfrozen type have a *frozen variant*
-                // (like `body_id_opt.map_or_else(|| !has_frozen_variant(...), ...)`),
-                // and do the same as the case of generic types at impl items.
-                // Note that it isn't sufficient to check if it has an enum
-                // since all of that enum's variants can be unfrozen:
-                // i.e. having an enum doesn't necessary mean a type has a frozen variant.
-                // And, implementing it isn't a trivial task; it'll probably end up
-                // re-implementing the trait predicate evaluation specific to `Freeze`.
-                && body_id_opt.is_none_or(|body_id| Self::is_value_unfrozen_poly(cx, body_id, normalized))
-            {
-                lint(cx, Source::Assoc { item: trait_item.span });
+            if let [adjust, ..] = typeck.expr_adjustments(src_expr) {
+                return does_adjust_borrow(adjust)
+                    .filter(|_| is_freeze.is_not_freeze())
+                    .map(|cause| BorrowSource::new(tcx, src_expr, cause));
+            }
+            let Some((_, Node::Expr(use_expr))) = parents.next() else {
+                return None;
+            };
+            match use_expr.kind {
+                ExprKind::Field(..) => {},
+                ExprKind::Index(..) if ty.is_array() => {},
+                ExprKind::AddrOf(..) if is_freeze.is_not_freeze() => {
+                    return Some(BorrowSource::new(tcx, use_expr, BorrowCause::Borrow));
+                },
+                // All other expressions use the value.
+                _ => return None,
             }
+            src_expr = use_expr;
         }
     }
 
-    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
-        if let ImplItemKind::Const(_, body_id) = &impl_item.kind {
-            let item_def_id = cx.tcx.hir_get_parent_item(impl_item.hir_id()).def_id;
-            let item = cx.tcx.hir_expect_item(item_def_id);
-
-            match &item.kind {
-                ItemKind::Impl(Impl {
-                    of_trait: Some(of_trait_ref),
-                    ..
-                }) => {
-                    if let Some(of_trait_def_id) = of_trait_ref.trait_def_id()
-                        // Lint a trait impl item only when the definition is a generic type,
-                        // assuming an assoc const is not meant to be an interior mutable type.
-                        && let Some(of_assoc_item) = cx
-                            .tcx
-                            .associated_item(impl_item.owner_id)
-                            .trait_item_def_id
-                        && cx
-                            .tcx
-                            .layout_of(ty::TypingEnv::post_analysis(cx.tcx, of_trait_def_id).as_query_input(
-                                // Normalize assoc types because ones originated from generic params
-                                // bounded other traits could have their bound at the trait defs;
-                                // and, in that case, the definition is *not* generic.
-                                cx.tcx.normalize_erasing_regions(
-                                    ty::TypingEnv::post_analysis(cx.tcx, of_trait_def_id),
-                                    cx.tcx.type_of(of_assoc_item).instantiate_identity(),
-                                ),
-                            ))
-                            .is_err()
-                            // If there were a function like `has_frozen_variant` described above,
-                            // we should use here as a frozen variant is a potential to be frozen
-                            // similar to unknown layouts.
-                            // e.g. `layout_of(...).is_err() || has_frozen_variant(...);`
-                        && let ty = cx.tcx.type_of(impl_item.owner_id).instantiate_identity()
-                        && let normalized = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty)
-                        && self.interior_mut.is_interior_mut_ty(cx, normalized)
-                        && Self::is_value_unfrozen_poly(cx, *body_id, normalized)
-                    {
-                        lint(cx, Source::Assoc { item: impl_item.span });
+    /// Checks if the given value (or a local projection of it) is both borrowed and
+    /// definitely non-`Freeze`. Returns `Err` if the constant cannot be read, but the
+    /// result depends on the value.
+    fn is_non_freeze_val_borrowed(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        typing_env: TypingEnv<'tcx>,
+        typeck: &'tcx TypeckResults<'tcx>,
+        mut src_expr: &'tcx Expr<'tcx>,
+        mut val: ConstValue<'tcx>,
+    ) -> Result<Option<BorrowSource<'tcx>>, ()> {
+        let mut parents = tcx.hir_parent_iter(src_expr.hir_id);
+        let mut ty = typeck.expr_ty(src_expr);
+        loop {
+            // Normalized as we need to check if this is an array later.
+            ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
+            if let [adjust, ..] = typeck.expr_adjustments(src_expr) {
+                let res = if let Some(cause) = does_adjust_borrow(adjust)
+                    && !self.is_value_freeze(tcx, typing_env, ty, val)?
+                {
+                    Some(BorrowSource::new(tcx, src_expr, cause))
+                } else {
+                    None
+                };
+                return Ok(res);
+            }
+            // Check only the type here as the result gets cached for each type.
+            if self.is_ty_freeze(tcx, typing_env, ty).is_freeze() {
+                return Ok(None);
+            }
+            let Some((_, Node::Expr(use_expr))) = parents.next() else {
+                return Ok(None);
+            };
+            let next_val = match use_expr.kind {
+                ExprKind::Field(_, name) => {
+                    if let Some(idx) = get_field_idx_by_name(ty, name.name) {
+                        tcx.try_destructure_mir_constant_for_user_output(val, ty)
+                            .ok_or(())?
+                            .fields
+                            .get(idx)
+                    } else {
+                        return Ok(None);
                     }
                 },
-                ItemKind::Impl(Impl { of_trait: None, .. }) => {
-                    let ty = cx.tcx.type_of(impl_item.owner_id).instantiate_identity();
-                    // Normalize assoc types originated from generic params.
-                    let normalized = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
-
-                    if self.interior_mut.is_interior_mut_ty(cx, normalized)
-                        && Self::is_value_unfrozen_poly(cx, *body_id, normalized)
-                    {
-                        lint(cx, Source::Assoc { item: impl_item.span });
+                ExprKind::Index(_, idx, _) if ty.is_array() => {
+                    let val = tcx.try_destructure_mir_constant_for_user_output(val, ty).ok_or(())?;
+                    if let Some(Constant::Int(idx)) = ConstEvalCtxt::with_env(tcx, typing_env, typeck).eval(idx) {
+                        val.fields.get(idx as usize)
+                    } else {
+                        // It's some value in the array so check all of them.
+                        for &(val, _) in val.fields {
+                            if let Some(src) =
+                                self.is_non_freeze_val_borrowed(tcx, typing_env, typeck, use_expr, val)?
+                            {
+                                return Ok(Some(src));
+                            }
+                        }
+                        return Ok(None);
                     }
                 },
-                _ => (),
+                ExprKind::AddrOf(..) if !self.is_value_freeze(tcx, typing_env, ty, val)? => {
+                    return Ok(Some(BorrowSource::new(tcx, use_expr, BorrowCause::Borrow)));
+                },
+                // All other expressions use the value.
+                _ => return Ok(None),
+            };
+            src_expr = use_expr;
+            if let Some(&(next_val, next_ty)) = next_val {
+                ty = next_ty;
+                val = next_val;
+            } else {
+                return Ok(None);
             }
         }
     }
 
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if let ExprKind::Path(qpath) = &expr.kind {
-            // Only lint if we use the const item inside a function.
-            if is_in_const_context(cx) {
-                return;
+    /// Checks if the given value (or a local projection of it) is both borrowed and
+    /// definitely non-`Freeze`.
+    ///
+    /// `typing_env` and `init_args` are from the constant's use site.
+    /// `init_typeck` and `init_expr` are from the constant's definition site.
+    #[expect(clippy::too_many_arguments, clippy::too_many_lines)]
+    fn is_non_freeze_init_borrowed(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        typing_env: TypingEnv<'tcx>,
+        typeck: &'tcx TypeckResults<'tcx>,
+        mut src_expr: &'tcx Expr<'tcx>,
+        mut init_typeck: &'tcx TypeckResults<'tcx>,
+        mut init_args: GenericArgsRef<'tcx>,
+        mut init_expr: &'tcx Expr<'tcx>,
+    ) -> Option<BorrowSource<'tcx>> {
+        // Make sure to instantiate all types coming from `init_typeck` with `init_args`.
+        let mut parents = tcx.hir_parent_iter(src_expr.hir_id);
+        loop {
+            // First handle any adjustments since they are cheap to check.
+            if let [adjust, ..] = typeck.expr_adjustments(src_expr) {
+                return does_adjust_borrow(adjust)
+                    .filter(|_| !self.is_init_expr_freeze(tcx, typing_env, init_typeck, init_args, init_expr))
+                    .map(|cause| BorrowSource::new(tcx, src_expr, cause));
             }
 
-            // Make sure it is a const item.
-            let Res::Def(DefKind::Const | DefKind::AssocConst, item_def_id) = cx.qpath_res(qpath, expr.hir_id) else {
-                return;
-            };
-
-            // Climb up to resolve any field access and explicit referencing.
-            let mut cur_expr = expr;
-            let mut dereferenced_expr = expr;
-            let mut needs_check_adjustment = true;
+            // Then read through constants and blocks on the init expression before
+            // applying the next use expression.
             loop {
-                let parent_id = cx.tcx.parent_hir_id(cur_expr.hir_id);
-                if parent_id == cur_expr.hir_id {
-                    break;
+                match init_expr.kind {
+                    ExprKind::Block(b, _)
+                        if !b.targeted_by_break
+                            && b.stmts.is_empty()
+                            && let Some(next_init) = b.expr =>
+                    {
+                        init_expr = next_init;
+                    },
+                    ExprKind::Path(ref init_path) => {
+                        let next_init_args =
+                            EarlyBinder::bind(init_typeck.node_args(init_expr.hir_id)).instantiate(tcx, init_args);
+                        match init_typeck.qpath_res(init_path, init_expr.hir_id) {
+                            Res::Def(DefKind::Ctor(..), _) => return None,
+                            Res::Def(DefKind::Const | DefKind::AssocConst, did)
+                                if let Ok(val) = tcx.const_eval_resolve(
+                                    typing_env,
+                                    UnevaluatedConst::new(did, next_init_args),
+                                    DUMMY_SP,
+                                ) && let Ok(res) =
+                                    self.is_non_freeze_val_borrowed(tcx, typing_env, init_typeck, src_expr, val) =>
+                            {
+                                return res;
+                            },
+                            Res::Def(DefKind::Const | DefKind::AssocConst, did)
+                                if let Some((next_typeck, value)) =
+                                    get_const_hir_value(tcx, typing_env, did, next_init_args) =>
+                            {
+                                init_typeck = next_typeck;
+                                init_args = next_init_args;
+                                init_expr = value;
+                            },
+                            // There's no more that we can read from the init expression. Switch to a
+                            // type based check.
+                            _ => {
+                                return self.is_non_freeze_expr_borrowed(tcx, typing_env, typeck, src_expr);
+                            },
+                        }
+                    },
+                    _ => break,
                 }
-                if let Node::Expr(parent_expr) = cx.tcx.hir_node(parent_id) {
-                    match &parent_expr.kind {
-                        ExprKind::AddrOf(..) => {
-                            // `&e` => `e` must be referenced.
-                            needs_check_adjustment = false;
-                        },
-                        ExprKind::Field(..) => {
-                            needs_check_adjustment = true;
+            }
 
-                            // Check whether implicit dereferences happened;
-                            // if so, no need to go further up
-                            // because of the same reason as the `ExprKind::Unary` case.
-                            if cx
-                                .typeck_results()
-                                .expr_adjustments(dereferenced_expr)
-                                .iter()
-                                .any(|adj| matches!(adj.kind, Adjust::Deref(_)))
-                            {
-                                break;
-                            }
+            // Then a type check. Note we only check the type here as the result
+            // gets cached.
+            let ty = EarlyBinder::bind(typeck.expr_ty(src_expr)).instantiate(tcx, init_args);
+            // Normalized as we need to check if this is an array later.
+            let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
+            if self.is_ty_freeze(tcx, typing_env, ty).is_freeze() {
+                return None;
+            }
 
-                            dereferenced_expr = parent_expr;
-                        },
-                        ExprKind::Index(e, _, _) if ptr::eq(&raw const **e, cur_expr) => {
-                            // `e[i]` => desugared to `*Index::index(&e, i)`,
-                            // meaning `e` must be referenced.
-                            // no need to go further up since a method call is involved now.
-                            needs_check_adjustment = false;
-                            break;
-                        },
-                        ExprKind::Unary(UnOp::Deref, _) => {
-                            // `*e` => desugared to `*Deref::deref(&e)`,
-                            // meaning `e` must be referenced.
-                            // no need to go further up since a method call is involved now.
-                            needs_check_adjustment = false;
-                            break;
+            // Finally reduce the init expression using the next use expression.
+            let Some((_, Node::Expr(use_expr))) = parents.next() else {
+                return None;
+            };
+            init_expr = match &use_expr.kind {
+                ExprKind::Field(_, name) => match init_expr.kind {
+                    ExprKind::Struct(_, fields, _)
+                        if let Some(field) = fields.iter().find(|f| f.ident.name == name.name) =>
+                    {
+                        field.expr
+                    },
+                    ExprKind::Tup(fields)
+                        if let Ok(idx) = name.as_str().parse::<usize>()
+                            && let Some(field) = fields.get(idx) =>
+                    {
+                        field
+                    },
+                    ExprKind::Call(callee, args)
+                        if let ExprKind::Path(callee_path) = &callee.kind
+                            && matches!(
+                                init_typeck.qpath_res(callee_path, callee.hir_id),
+                                Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(_)
+                            )
+                            && let Ok(idx) = name.as_str().parse::<usize>()
+                            && let Some(arg) = args.get(idx) =>
+                    {
+                        arg
+                    },
+                    // Revert to a type based check as we don't know the field's value.
+                    _ => return self.is_non_freeze_expr_borrowed(tcx, typing_env, typeck, use_expr),
+                },
+                ExprKind::Index(_, idx, _) if ty.is_array() => match init_expr.kind {
+                    ExprKind::Array(fields) => {
+                        if let Some(Constant::Int(idx)) = ConstEvalCtxt::with_env(tcx, typing_env, typeck).eval(idx) {
+                            // If the index is out of bounds it means the code
+                            // unconditionally panics. In that case there is no borrow.
+                            fields.get(idx as usize)?
+                        } else {
+                            // Unknown index, just run the check for all values.
+                            return fields.iter().find_map(|f| {
+                                self.is_non_freeze_init_borrowed(
+                                    tcx,
+                                    typing_env,
+                                    typeck,
+                                    use_expr,
+                                    init_typeck,
+                                    init_args,
+                                    f,
+                                )
+                            });
+                        }
+                    },
+                    // Just assume the index expression doesn't panic here.
+                    ExprKind::Repeat(field, _) => field,
+                    _ => return self.is_non_freeze_expr_borrowed(tcx, typing_env, typeck, use_expr),
+                },
+                ExprKind::AddrOf(..)
+                    if !self.is_init_expr_freeze(tcx, typing_env, init_typeck, init_args, init_expr) =>
+                {
+                    return Some(BorrowSource::new(tcx, use_expr, BorrowCause::Borrow));
+                },
+                // All other expressions use the value.
+                _ => return None,
+            };
+            src_expr = use_expr;
+        }
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
+        if let ItemKind::Const(ident, .., body_id) = item.kind
+            && !ident.is_special()
+            && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
+            && match self.is_ty_freeze(cx.tcx, cx.typing_env(), ty) {
+                IsFreeze::No => true,
+                IsFreeze::Yes => false,
+                IsFreeze::Maybe => match cx.tcx.const_eval_poly(item.owner_id.to_def_id()) {
+                    Ok(val) if let Ok(is_freeze) = self.is_value_freeze(cx.tcx, cx.typing_env(), ty, val) => !is_freeze,
+                    _ => !self.is_init_expr_freeze(
+                        cx.tcx,
+                        cx.typing_env(),
+                        cx.tcx.typeck(item.owner_id),
+                        GenericArgs::identity_for_item(cx.tcx, item.owner_id),
+                        cx.tcx.hir_body(body_id).value,
+                    ),
+                },
+            }
+            && !item.span.in_external_macro(cx.sess().source_map())
+            // Only needed when compiling `std`
+            && !is_thread_local(cx, item)
+        {
+            span_lint_and_then(
+                cx,
+                DECLARE_INTERIOR_MUTABLE_CONST,
+                ident.span,
+                "named constant with interior mutability",
+                |diag| {
+                    let Some(sync_trait) = cx.tcx.lang_items().sync_trait() else {
+                        return;
+                    };
+                    if implements_trait(cx, ty, sync_trait, &[]) {
+                        diag.help("did you mean to make this a `static` item");
+                    } else {
+                        diag.help("did you mean to make this a `thread_local!` item");
+                    }
+                },
+            );
+        }
+    }
+
+    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
+        if let TraitItemKind::Const(_, body_id_opt) = item.kind
+            && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
+            && match self.is_ty_freeze(cx.tcx, cx.typing_env(), ty) {
+                IsFreeze::No => true,
+                IsFreeze::Maybe if let Some(body_id) = body_id_opt => {
+                    match cx.tcx.const_eval_poly(item.owner_id.to_def_id()) {
+                        Ok(val) if let Ok(is_freeze) = self.is_value_freeze(cx.tcx, cx.typing_env(), ty, val) => {
+                            !is_freeze
                         },
-                        _ => break,
+                        _ => !self.is_init_expr_freeze(
+                            cx.tcx,
+                            cx.typing_env(),
+                            cx.tcx.typeck(item.owner_id),
+                            GenericArgs::identity_for_item(cx.tcx, item.owner_id),
+                            cx.tcx.hir_body(body_id).value,
+                        ),
                     }
-                    cur_expr = parent_expr;
-                } else {
-                    break;
-                }
+                },
+                IsFreeze::Yes | IsFreeze::Maybe => false,
             }
+            && !item.span.in_external_macro(cx.sess().source_map())
+        {
+            span_lint(
+                cx,
+                DECLARE_INTERIOR_MUTABLE_CONST,
+                item.ident.span,
+                "named constant with interior mutability",
+            );
+        }
+    }
 
-            let ty = if needs_check_adjustment {
-                let adjustments = cx.typeck_results().expr_adjustments(dereferenced_expr);
-                if let Some(i) = adjustments
-                    .iter()
-                    .position(|adj| matches!(adj.kind, Adjust::Borrow(_) | Adjust::Deref(_)))
-                {
-                    if i == 0 {
-                        cx.typeck_results().expr_ty(dereferenced_expr)
+    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
+        if let ImplItemKind::Const(_, body_id) = item.kind
+            && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
+            && match self.is_ty_freeze(cx.tcx, cx.typing_env(), ty) {
+                IsFreeze::Yes => false,
+                IsFreeze::No => {
+                    // If this is a trait impl, check if the trait definition is the source
+                    // of the cell.
+                    if let Node::Item(parent_item) = cx.tcx.parent_hir_node(item.hir_id())
+                        && let ItemKind::Impl(impl_block) = parent_item.kind
+                        && let Some(of_trait) = impl_block.of_trait
+                        && let Some(trait_id) = of_trait.trait_def_id()
+                    {
+                        // Replace all instances of `<Self as Trait>::AssocType` with the
+                        // unit type and check again. If the result is the same then the
+                        // trait definition is the cause.
+                        let ty = (ReplaceAssocFolder {
+                            tcx: cx.tcx,
+                            trait_id,
+                            self_ty: cx.tcx.type_of(parent_item.owner_id).instantiate_identity(),
+                        })
+                        .fold_ty(cx.tcx.type_of(item.owner_id).instantiate_identity());
+                        // `ty` may not be normalizable, but that should be fine.
+                        !self.is_ty_freeze(cx.tcx, cx.typing_env(), ty).is_not_freeze()
                     } else {
-                        adjustments[i - 1].target
+                        true
                     }
+                },
+                // Even if this is from a trait, there are values which don't have
+                // interior mutability.
+                IsFreeze::Maybe => match cx.tcx.const_eval_poly(item.owner_id.to_def_id()) {
+                    Ok(val) if let Ok(is_freeze) = self.is_value_freeze(cx.tcx, cx.typing_env(), ty, val) => !is_freeze,
+                    _ => !self.is_init_expr_freeze(
+                        cx.tcx,
+                        cx.typing_env(),
+                        cx.tcx.typeck(item.owner_id),
+                        GenericArgs::identity_for_item(cx.tcx, item.owner_id),
+                        cx.tcx.hir_body(body_id).value,
+                    ),
+                },
+            }
+            && !item.span.in_external_macro(cx.sess().source_map())
+        {
+            span_lint(
+                cx,
+                DECLARE_INTERIOR_MUTABLE_CONST,
+                item.ident.span,
+                "named constant with interior mutability",
+            );
+        }
+    }
+
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
+        if let ExprKind::Path(qpath) = &e.kind
+            && let typeck = cx.typeck_results()
+            && let Res::Def(DefKind::Const | DefKind::AssocConst, did) = typeck.qpath_res(qpath, e.hir_id)
+            // As of `1.80` constant contexts can't borrow any type with interior mutability
+            && !is_in_const_context(cx)
+            && !self.is_ty_freeze(cx.tcx, cx.typing_env(), typeck.expr_ty(e)).is_freeze()
+            && let Some(borrow_src) = {
+                // The extra block helps formatting a lot.
+                if let Ok(val) = cx.tcx.const_eval_resolve(
+                    cx.typing_env(),
+                    UnevaluatedConst::new(did, typeck.node_args(e.hir_id)),
+                    DUMMY_SP,
+                ) && let Ok(src) = self.is_non_freeze_val_borrowed(cx.tcx, cx.typing_env(), typeck, e, val)
+                {
+                    src
+                } else if let init_args = typeck.node_args(e.hir_id)
+                    && let Some((init_typeck, init)) = get_const_hir_value(cx.tcx, cx.typing_env(), did, init_args)
+                {
+                    self.is_non_freeze_init_borrowed(cx.tcx, cx.typing_env(), typeck, e, init_typeck, init_args, init)
                 } else {
-                    // No borrow adjustments means the entire const is moved.
-                    return;
+                    self.is_non_freeze_expr_borrowed(cx.tcx, cx.typing_env(), typeck, e)
                 }
-            } else {
-                cx.typeck_results().expr_ty(dereferenced_expr)
-            };
-
-            if self.interior_mut.is_interior_mut_ty(cx, ty)
-                && Self::is_value_unfrozen_expr(cx, expr.hir_id, item_def_id, ty)
-            {
-                lint(cx, Source::Expr { expr: expr.span });
             }
+            && !borrow_src.expr.span.in_external_macro(cx.sess().source_map())
+        {
+            span_lint_and_then(
+                cx,
+                BORROW_INTERIOR_MUTABLE_CONST,
+                borrow_src.expr.span,
+                "borrow of a named constant with interior mutability",
+                |diag| {
+                    if let Some(note) = borrow_src.cause.note() {
+                        diag.note(note);
+                    }
+                    diag.help("this lint can be silenced by assigning the value to a local variable before borrowing");
+                },
+            );
+        }
+    }
+}
+
+struct ReplaceAssocFolder<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    trait_id: DefId,
+    self_ty: Ty<'tcx>,
+}
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceAssocFolder<'tcx> {
+    fn cx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        if let ty::Alias(AliasTyKind::Projection, ty) = ty.kind()
+            && ty.trait_def_id(self.tcx) == self.trait_id
+            && ty.self_ty() == self.self_ty
+        {
+            self.tcx.types.unit
+        } else {
+            ty.super_fold_with(self)
         }
     }
 }
 
-fn ignored_macro(cx: &LateContext<'_>, it: &Item<'_>) -> bool {
+fn is_thread_local(cx: &LateContext<'_>, it: &Item<'_>) -> bool {
     macro_backtrace(it.span).any(|macro_call| {
         matches!(
             cx.tcx.get_diagnostic_name(macro_call.def_id),
@@ -507,3 +891,42 @@ fn ignored_macro(cx: &LateContext<'_>, it: &Item<'_>) -> bool {
         )
     })
 }
+
+/// Checks if the adjustment causes a borrow of the original value. Returns
+/// `None` if the value is consumed instead of borrowed.
+fn does_adjust_borrow(adjust: &Adjustment<'_>) -> Option<BorrowCause> {
+    match adjust.kind {
+        Adjust::Borrow(_) => Some(BorrowCause::AutoBorrow),
+        // Custom deref calls `<T as Deref>::deref(&x)` resulting in a borrow.
+        Adjust::Deref(Some(_)) => Some(BorrowCause::AutoDeref),
+        // All other adjustments read the value.
+        _ => None,
+    }
+}
+
+/// Attempts to get the value of a constant as a HIR expression. Also gets the
+/// `TypeckResults` associated with the constant's body.
+fn get_const_hir_value<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    typing_env: TypingEnv<'tcx>,
+    did: DefId,
+    args: GenericArgsRef<'tcx>,
+) -> Option<(&'tcx TypeckResults<'tcx>, &'tcx Expr<'tcx>)> {
+    let did = did.as_local()?;
+    let (did, body_id) = match tcx.hir_node(tcx.local_def_id_to_hir_id(did)) {
+        Node::Item(item) if let ItemKind::Const(.., body_id) = item.kind => (did, body_id),
+        Node::ImplItem(item) if let ImplItemKind::Const(.., body_id) = item.kind => (did, body_id),
+        Node::TraitItem(_)
+            if let Ok(Some(inst)) = Instance::try_resolve(tcx, typing_env, did.into(), args)
+                && let Some(did) = inst.def_id().as_local() =>
+        {
+            match tcx.hir_node(tcx.local_def_id_to_hir_id(did)) {
+                Node::ImplItem(item) if let ImplItemKind::Const(.., body_id) = item.kind => (did, body_id),
+                Node::TraitItem(item) if let TraitItemKind::Const(.., Some(body_id)) = item.kind => (did, body_id),
+                _ => return None,
+            }
+        },
+        _ => return None,
+    };
+    Some((tcx.typeck(did), tcx.hir_body(body_id).value))
+}
diff --git a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
index 9542fed3875..8ff78ec7c58 100644
--- a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
+++ b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
@@ -172,7 +172,7 @@ impl NonSendField<'_> {
 /// Example: `MyStruct<P, Box<Q, R>>` => `vec![P, Q, R]`
 fn collect_generic_params(ty: Ty<'_>) -> Vec<Ty<'_>> {
     ty.walk()
-        .filter_map(|inner| match inner.unpack() {
+        .filter_map(|inner| match inner.kind() {
             GenericArgKind::Type(inner_ty) => Some(inner_ty),
             _ => None,
         })
@@ -208,7 +208,7 @@ fn ty_allowed_with_raw_pointer_heuristic<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'t
         ty::Adt(_, args) => {
             if contains_pointer_like(cx, ty) {
                 // descends only if ADT contains any raw pointers
-                args.iter().all(|generic_arg| match generic_arg.unpack() {
+                args.iter().all(|generic_arg| match generic_arg.kind() {
                     GenericArgKind::Type(ty) => ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait),
                     // Lifetimes and const generics are not solid part of ADT and ignored
                     GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => true,
@@ -226,7 +226,7 @@ fn ty_allowed_with_raw_pointer_heuristic<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'t
 /// Checks if the type contains any pointer-like types in args (including nested ones)
 fn contains_pointer_like<'tcx>(cx: &LateContext<'tcx>, target_ty: Ty<'tcx>) -> bool {
     for ty_node in target_ty.walk() {
-        if let GenericArgKind::Type(inner_ty) = ty_node.unpack() {
+        if let GenericArgKind::Type(inner_ty) = ty_node.kind() {
             match inner_ty.kind() {
                 ty::RawPtr(_, _) => {
                     return true;
diff --git a/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs b/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs
index f66b9519317..abee3c44c5a 100644
--- a/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs
+++ b/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs
@@ -187,7 +187,7 @@ struct LazyInfo {
 impl LazyInfo {
     fn from_item(cx: &LateContext<'_>, item: &Item<'_>) -> Option<Self> {
         // Check if item is a `once_cell:sync::Lazy` static.
-        if let ItemKind::Static(_, ty, _, body_id) = item.kind
+        if let ItemKind::Static(_, _, ty, body_id) = item.kind
             && let Some(path_def_id) = path_def_id(cx, ty)
             && let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind
             && paths::ONCE_CELL_SYNC_LAZY.matches(cx, path_def_id)
diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
index 6de203e068b..ba8f6354d97 100644
--- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
@@ -385,7 +385,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
 fn has_matching_args(kind: FnKind, args: GenericArgsRef<'_>) -> bool {
     match kind {
         FnKind::Fn => true,
-        FnKind::TraitFn => args.iter().enumerate().all(|(idx, subst)| match subst.unpack() {
+        FnKind::TraitFn => args.iter().enumerate().all(|(idx, subst)| match subst.kind() {
             GenericArgKind::Lifetime(_) => true,
             GenericArgKind::Type(ty) => matches!(*ty.kind(), ty::Param(ty) if ty.index as usize == idx),
             GenericArgKind::Const(c) => matches!(c.kind(), ConstKind::Param(c) if c.index as usize == idx),
diff --git a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
index 03b907ebdf4..9c6141d8222 100644
--- a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
@@ -1,8 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::msrvs::Msrv;
+use clippy_utils::qualify_min_const_fn::is_stable_const_fn;
 use clippy_utils::source::SpanRangeExt;
 use clippy_utils::ty::implements_trait;
 use clippy_utils::visitors::for_each_expr_without_closures;
-use clippy_utils::{binop_traits, eq_expr_value, trait_ref_of_method};
+use clippy_utils::{binop_traits, eq_expr_value, is_in_const_context, trait_ref_of_method};
 use core::ops::ControlFlow;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
@@ -19,6 +21,7 @@ pub(super) fn check<'tcx>(
     expr: &'tcx hir::Expr<'_>,
     assignee: &'tcx hir::Expr<'_>,
     e: &'tcx hir::Expr<'_>,
+    msrv: Msrv,
 ) {
     if let hir::ExprKind::Binary(op, l, r) = &e.kind {
         let lint = |assignee: &hir::Expr<'_>, rhs: &hir::Expr<'_>| {
@@ -26,7 +29,7 @@ pub(super) fn check<'tcx>(
             let rty = cx.typeck_results().expr_ty(rhs);
             if let Some((_, lang_item)) = binop_traits(op.node)
                 && let Some(trait_id) = cx.tcx.lang_items().get(lang_item)
-                && let parent_fn = cx.tcx.hir_get_parent_item(e.hir_id).def_id
+                && let parent_fn = cx.tcx.hir_get_parent_item(e.hir_id)
                 && trait_ref_of_method(cx, parent_fn).is_none_or(|t| t.path.res.def_id() != trait_id)
                 && implements_trait(cx, ty, trait_id, &[rty.into()])
             {
@@ -40,6 +43,15 @@ pub(super) fn check<'tcx>(
                         return;
                     }
                 }
+
+                // Skip if the trait is not stable in const contexts
+                if is_in_const_context(cx)
+                    && let Some(binop_id) = cx.tcx.associated_item_def_ids(trait_id).first()
+                    && !is_stable_const_fn(cx, *binop_id, msrv)
+                {
+                    return;
+                }
+
                 span_lint_and_then(
                     cx,
                     ASSIGN_OP_PATTERN,
diff --git a/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs
index e3029f8438e..6c9be7c5e90 100644
--- a/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs
@@ -1,11 +1,11 @@
 use clippy_utils::consts::{ConstEvalCtxt, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::sym;
 use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::LateContext;
-use rustc_span::sym;
 
 use super::DURATION_SUBSEC;
 
@@ -21,9 +21,9 @@ pub(crate) fn check<'tcx>(
         && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_arg).peel_refs(), sym::Duration)
         && let Some(Constant::Int(divisor)) = ConstEvalCtxt::new(cx).eval(right)
     {
-        let suggested_fn = match (method_path.ident.as_str(), divisor) {
-            ("subsec_micros", 1_000) | ("subsec_nanos", 1_000_000) => "subsec_millis",
-            ("subsec_nanos", 1_000) => "subsec_micros",
+        let suggested_fn = match (method_path.ident.name, divisor) {
+            (sym::subsec_micros, 1_000) | (sym::subsec_nanos, 1_000_000) => "subsec_millis",
+            (sym::subsec_nanos, 1_000) => "subsec_micros",
             _ => return,
         };
         let mut applicability = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs
index d32c062cf56..2f4e8e99588 100644
--- a/src/tools/clippy/clippy_lints/src/operators/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs
@@ -919,7 +919,7 @@ impl<'tcx> LateLintPass<'tcx> for Operators {
                 modulo_arithmetic::check(cx, e, bin_op, lhs, rhs, false);
             },
             ExprKind::Assign(lhs, rhs, _) => {
-                assign_op_pattern::check(cx, e, lhs, rhs);
+                assign_op_pattern::check(cx, e, lhs, rhs, self.msrv);
                 self_assignment::check(cx, e, lhs, rhs);
             },
             ExprKind::Unary(op, arg) => {
diff --git a/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs
index 691d7b904ef..b79461663d7 100644
--- a/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs
@@ -34,14 +34,10 @@ pub(super) fn check<'tcx>(
 }
 
 fn used_in_comparison_with_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    let Node::Expr(parent_expr) = cx.tcx.parent_hir_node(expr.hir_id) else {
-        return false;
-    };
-    let ExprKind::Binary(op, lhs, rhs) = parent_expr.kind else {
-        return false;
-    };
-
-    if op.node == BinOpKind::Eq || op.node == BinOpKind::Ne {
+    if let Node::Expr(parent_expr) = cx.tcx.parent_hir_node(expr.hir_id)
+        && let ExprKind::Binary(op, lhs, rhs) = parent_expr.kind
+        && let BinOpKind::Eq | BinOpKind::Ne = op.node
+    {
         let ecx = ConstEvalCtxt::new(cx);
         matches!(ecx.eval(lhs), Some(Constant::Int(0))) || matches!(ecx.eval(rhs), Some(Constant::Int(0)))
     } else {
@@ -56,35 +52,28 @@ struct OperandInfo {
 }
 
 fn analyze_operand(operand: &Expr<'_>, cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<OperandInfo> {
-    match ConstEvalCtxt::new(cx).eval(operand) {
-        Some(Constant::Int(v)) => match *cx.typeck_results().expr_ty(expr).kind() {
+    match ConstEvalCtxt::new(cx).eval(operand)? {
+        Constant::Int(v) => match *cx.typeck_results().expr_ty(expr).kind() {
             ty::Int(ity) => {
                 let value = sext(cx.tcx, v, ity);
-                return Some(OperandInfo {
+                Some(OperandInfo {
                     string_representation: Some(value.to_string()),
                     is_negative: value < 0,
                     is_integral: true,
-                });
-            },
-            ty::Uint(_) => {
-                return Some(OperandInfo {
-                    string_representation: None,
-                    is_negative: false,
-                    is_integral: true,
-                });
+                })
             },
-            _ => {},
+            ty::Uint(_) => Some(OperandInfo {
+                string_representation: None,
+                is_negative: false,
+                is_integral: true,
+            }),
+            _ => None,
         },
         // FIXME(f16_f128): add when casting is available on all platforms
-        Some(Constant::F32(f)) => {
-            return Some(floating_point_operand_info(&f));
-        },
-        Some(Constant::F64(f)) => {
-            return Some(floating_point_operand_info(&f));
-        },
-        _ => {},
+        Constant::F32(f) => Some(floating_point_operand_info(&f)),
+        Constant::F64(f) => Some(floating_point_operand_info(&f)),
+        _ => None,
     }
-    None
 }
 
 fn floating_point_operand_info<T: Display + PartialOrd + From<f32>>(f: &T) -> OperandInfo {
diff --git a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
index d16f5f8e112..64ad92b1ebb 100644
--- a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
@@ -37,7 +37,7 @@ impl EarlyLintPass for OptionEnvUnwrap {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
         if let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &expr.kind
             && matches!(seg.ident.name, sym::expect | sym::unwrap)
-            && is_direct_expn_of(receiver.span, "option_env").is_some()
+            && is_direct_expn_of(receiver.span, sym::option_env).is_some()
         {
             span_lint_and_help(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
index 8962f36db1e..449d3da7639 100644
--- a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
+++ b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
@@ -152,7 +152,6 @@ impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented {
                 expr.span,
                 "`panic_any` should not be present in production code",
             );
-            return;
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs b/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs
index cda752d003f..65e93af9420 100644
--- a/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs
+++ b/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs
@@ -41,7 +41,7 @@ declare_lint_pass!(PartialPubFields => [PARTIAL_PUB_FIELDS]);
 
 impl EarlyLintPass for PartialPubFields {
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
-        let ItemKind::Struct(_, ref st, _) = item.kind else {
+        let ItemKind::Struct(_, _, ref st) = item.kind else {
             return;
         };
 
diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
index 5d30b66def2..dadf49b64e5 100644
--- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
@@ -1,5 +1,3 @@
-use std::{cmp, iter};
-
 use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
@@ -20,6 +18,7 @@ use rustc_middle::ty::{self, RegionKind, TyCtxt};
 use rustc_session::impl_lint_pass;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{Span, sym};
+use std::iter;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -33,10 +32,8 @@ declare_clippy_lint! {
     /// registers.
     ///
     /// ### Known problems
-    /// This lint is target register size dependent, it is
-    /// limited to 32-bit to try and reduce portability problems between 32 and
-    /// 64-bit, but if you are compiling for 8 or 16-bit targets then the limit
-    /// will be different.
+    /// This lint is target dependent, some cases will lint on 64-bit targets but
+    /// not 32-bit or lower targets.
     ///
     /// The configuration option `trivial_copy_size_limit` can be set to override
     /// this limit for a project.
@@ -112,16 +109,9 @@ pub struct PassByRefOrValue {
 
 impl PassByRefOrValue {
     pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self {
-        let ref_min_size = conf.trivial_copy_size_limit.unwrap_or_else(|| {
-            let bit_width = u64::from(tcx.sess.target.pointer_width);
-            // Cap the calculated bit width at 32-bits to reduce
-            // portability problems between 32 and 64-bit targets
-            let bit_width = cmp::min(bit_width, 32);
-            #[expect(clippy::integer_division)]
-            let byte_width = bit_width / 8;
-            // Use a limit of 2 times the register byte width
-            byte_width * 2
-        });
+        let ref_min_size = conf
+            .trivial_copy_size_limit
+            .unwrap_or_else(|| u64::from(tcx.sess.target.pointer_width / 8));
 
         Self {
             ref_min_size,
diff --git a/src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs b/src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs
index e4a9bf7a848..66c59cb70d3 100644
--- a/src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs
+++ b/src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs
@@ -58,7 +58,7 @@ impl PubUnderscoreFields {
 impl<'tcx> LateLintPass<'tcx> for PubUnderscoreFields {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         // This lint only pertains to structs.
-        let ItemKind::Struct(_, variant_data, _) = &item.kind else {
+        let ItemKind::Struct(_, _, variant_data) = &item.kind else {
             return;
         };
 
diff --git a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
index 7b381fac5f1..3828aff4164 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::HasSession;
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{Item, ItemKind};
+use rustc_hir::{Item, ItemKind, UseKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::impl_lint_pass;
@@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
         if cx.tcx.visibility(item.owner_id.def_id) == ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id())
             && !cx.effective_visibilities.is_exported(item.owner_id.def_id)
             && self.is_exported.last() == Some(&false)
-            && is_not_macro_export(item)
+            && !is_ignorable_export(item)
             && !item.span.in_external_macro(cx.sess().source_map())
         {
             let span = item
@@ -86,18 +86,17 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
     }
 }
 
-fn is_not_macro_export<'tcx>(item: &'tcx Item<'tcx>) -> bool {
-    if let ItemKind::Use(path, _) = item.kind {
-        if path
-            .res
-            .iter()
-            .all(|res| matches!(res, Res::Def(DefKind::Macro(MacroKind::Bang), _)))
-        {
-            return false;
+// We ignore macro exports. And `ListStem` uses, which aren't interesting.
+fn is_ignorable_export<'tcx>(item: &'tcx Item<'tcx>) -> bool {
+    if let ItemKind::Use(path, kind) = item.kind {
+        let ignore = matches!(path.res.macro_ns, Some(Res::Def(DefKind::Macro(MacroKind::Bang), _)))
+            || kind == UseKind::ListStem;
+        if ignore {
+            return true;
         }
     } else if let ItemKind::Macro(..) = item.kind {
-        return false;
+        return true;
     }
 
-    true
+    false
 }
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index 122d97fdf81..e0c93153a77 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -423,12 +423,21 @@ fn check_final_expr<'tcx>(
                 _ => return,
             }
 
-            emit_return_lint(cx, ret_span, semi_spans, &replacement, expr.hir_id);
+            emit_return_lint(
+                cx,
+                peeled_drop_expr.span,
+                ret_span,
+                semi_spans,
+                &replacement,
+                expr.hir_id,
+            );
         },
         ExprKind::If(_, then, else_clause_opt) => {
             check_block_return(cx, &then.kind, peeled_drop_expr.span, semi_spans.clone());
             if let Some(else_clause) = else_clause_opt {
-                check_block_return(cx, &else_clause.kind, peeled_drop_expr.span, semi_spans);
+                // The `RetReplacement` won't be used there as `else_clause` will be either a block or
+                // a `if` expression.
+                check_final_expr(cx, else_clause, semi_spans, RetReplacement::Empty, match_ty_opt);
             }
         },
         // a match expr, check all arms
@@ -448,6 +457,7 @@ fn check_final_expr<'tcx>(
 
 fn emit_return_lint(
     cx: &LateContext<'_>,
+    lint_span: Span,
     ret_span: Span,
     semi_spans: Vec<Span>,
     replacement: &RetReplacement<'_>,
@@ -457,7 +467,7 @@ fn emit_return_lint(
         cx,
         NEEDLESS_RETURN,
         at,
-        ret_span,
+        lint_span,
         "unneeded `return` statement",
         |diag| {
             let suggestions = std::iter::once((ret_span, replacement.to_string()))
@@ -479,7 +489,7 @@ fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>)
                 .skip_binder()
                 .output()
                 .walk()
-                .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(re) if !re.is_static()))
+                .any(|arg| matches!(arg.kind(), GenericArgKind::Lifetime(re) if !re.is_static()))
         {
             ControlFlow::Break(())
         } else {
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 ccb1209c6fc..521754f7bab 100644
--- a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
+++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::{indent_of, snippet};
-use clippy_utils::{expr_or_init, get_attr, path_to_local, peel_hir_expr_unary};
+use clippy_utils::{expr_or_init, get_attr, path_to_local, peel_hir_expr_unary, sym};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
@@ -10,7 +10,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty::{GenericArgKind, Ty};
 use rustc_session::impl_lint_pass;
 use rustc_span::symbol::Ident;
-use rustc_span::{DUMMY_SP, Span, sym};
+use rustc_span::{DUMMY_SP, Span};
 use std::borrow::Cow;
 use std::collections::hash_map::Entry;
 
@@ -169,7 +169,7 @@ impl<'cx, 'others, 'tcx> AttrChecker<'cx, 'others, 'tcx> {
             let mut iter = get_attr(
                 self.cx.sess(),
                 self.cx.tcx.get_attrs_unchecked(adt.did()),
-                "has_significant_drop",
+                sym::has_significant_drop,
             );
             if iter.next().is_some() {
                 return true;
@@ -184,7 +184,7 @@ impl<'cx, 'others, 'tcx> AttrChecker<'cx, 'others, 'tcx> {
                     }
                 }
                 for generic_arg in *b {
-                    if let GenericArgKind::Type(ty) = generic_arg.unpack()
+                    if let GenericArgKind::Type(ty) = generic_arg.kind()
                         && self.has_sig_drop_attr(ty, depth)
                     {
                         return true;
diff --git a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
index 835ec1e4ca1..3623039aece 100644
--- a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
+++ b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
@@ -1,9 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::sym;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, Ty};
 use rustc_session::declare_lint_pass;
-use rustc_span::sym;
+use rustc_span::Symbol;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -62,17 +63,17 @@ fn get_pointee_ty_and_count_expr<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'_>,
 ) -> Option<(Ty<'tcx>, &'tcx Expr<'tcx>)> {
-    const METHODS: [&str; 10] = [
-        "copy_to",
-        "copy_from",
-        "copy_to_nonoverlapping",
-        "copy_from_nonoverlapping",
-        "add",
-        "wrapping_add",
-        "sub",
-        "wrapping_sub",
-        "offset",
-        "wrapping_offset",
+    const METHODS: [Symbol; 10] = [
+        sym::copy_to,
+        sym::copy_from,
+        sym::copy_to_nonoverlapping,
+        sym::copy_from_nonoverlapping,
+        sym::add,
+        sym::wrapping_add,
+        sym::sub,
+        sym::wrapping_sub,
+        sym::offset,
+        sym::wrapping_offset,
     ];
 
     if let ExprKind::Call(func, [.., count]) = expr.kind
@@ -97,7 +98,7 @@ fn get_pointee_ty_and_count_expr<'tcx>(
     }
     if let ExprKind::MethodCall(method_path, ptr_self, [.., count], _) = expr.kind
         // Find calls to copy_{from,to}{,_nonoverlapping}
-        && let method_ident = method_path.ident.as_str()
+        && let method_ident = method_path.ident.name
         && METHODS.contains(&method_ident)
 
         // Get the pointee type
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 30a5fe4db27..f497d0700b8 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -266,7 +266,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> {
             let is_matching_resize = if let InitializedSize::Initialized(size_expr) = self.vec_alloc.size_expr {
                 // If we have a size expression, check that it is equal to what's passed to `resize`
                 SpanlessEq::new(self.cx).eq_expr(len_arg, size_expr)
-                    || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.as_str() == "capacity")
+                    || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.name == sym::capacity)
             } else {
                 self.vec_alloc.size_expr = InitializedSize::Initialized(len_arg);
                 true
@@ -288,7 +288,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> {
             if let InitializedSize::Initialized(size_expr) = self.vec_alloc.size_expr {
                 // Check that len expression is equals to `with_capacity` expression
                 return SpanlessEq::new(self.cx).eq_expr(len_arg, size_expr)
-                    || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.as_str() == "capacity");
+                    || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.name == sym::capacity);
             }
 
             self.vec_alloc.size_expr = InitializedSize::Initialized(len_arg);
diff --git a/src/tools/clippy/clippy_lints/src/string_patterns.rs b/src/tools/clippy/clippy_lints/src/string_patterns.rs
index 5c95dfe8347..f63e6b3087b 100644
--- a/src/tools/clippy/clippy_lints/src/string_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/string_patterns.rs
@@ -5,9 +5,9 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::eager_or_lazy::switch_to_eager_eval;
 use clippy_utils::macros::matching_root_macro_call;
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::path_to_local_id;
 use clippy_utils::source::{snippet, str_literal_to_char_literal};
 use clippy_utils::visitors::{Descend, for_each_expr};
+use clippy_utils::{path_to_local_id, sym};
 use itertools::Itertools;
 use rustc_ast::{BinOpKind, LitKind};
 use rustc_errors::Applicability;
@@ -15,7 +15,7 @@ use rustc_hir::{Expr, ExprKind, PatExprKind, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::impl_lint_pass;
-use rustc_span::{Span, sym};
+use rustc_span::{Span, Symbol};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -83,29 +83,29 @@ impl StringPatterns {
 
 impl_lint_pass!(StringPatterns => [MANUAL_PATTERN_CHAR_COMPARISON, SINGLE_CHAR_PATTERN]);
 
-const PATTERN_METHODS: [(&str, usize); 22] = [
-    ("contains", 0),
-    ("starts_with", 0),
-    ("ends_with", 0),
-    ("find", 0),
-    ("rfind", 0),
-    ("split", 0),
-    ("split_inclusive", 0),
-    ("rsplit", 0),
-    ("split_terminator", 0),
-    ("rsplit_terminator", 0),
-    ("splitn", 1),
-    ("rsplitn", 1),
-    ("split_once", 0),
-    ("rsplit_once", 0),
-    ("matches", 0),
-    ("rmatches", 0),
-    ("match_indices", 0),
-    ("rmatch_indices", 0),
-    ("trim_start_matches", 0),
-    ("trim_end_matches", 0),
-    ("replace", 0),
-    ("replacen", 0),
+const PATTERN_METHODS: [(Symbol, usize); 22] = [
+    (sym::contains, 0),
+    (sym::starts_with, 0),
+    (sym::ends_with, 0),
+    (sym::find, 0),
+    (sym::rfind, 0),
+    (sym::split, 0),
+    (sym::split_inclusive, 0),
+    (sym::rsplit, 0),
+    (sym::split_terminator, 0),
+    (sym::rsplit_terminator, 0),
+    (sym::splitn, 1),
+    (sym::rsplitn, 1),
+    (sym::split_once, 0),
+    (sym::rsplit_once, 0),
+    (sym::matches, 0),
+    (sym::rmatches, 0),
+    (sym::match_indices, 0),
+    (sym::rmatch_indices, 0),
+    (sym::trim_start_matches, 0),
+    (sym::trim_end_matches, 0),
+    (sym::replace, 0),
+    (sym::replacen, 0),
 ];
 
 fn check_single_char_pattern_lint(cx: &LateContext<'_>, arg: &Expr<'_>) {
@@ -228,7 +228,7 @@ impl<'tcx> LateLintPass<'tcx> for StringPatterns {
             && let ExprKind::MethodCall(method, receiver, args, _) = expr.kind
             && let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind()
             && ty.is_str()
-            && let method_name = method.ident.name.as_str()
+            && let method_name = method.ident.name
             && let Some(&(_, pos)) = PATTERN_METHODS
                 .iter()
                 .find(|(array_method_name, _)| *array_method_name == method_name)
diff --git a/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs b/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
index 1ada7094dc5..33856c750d7 100644
--- a/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
@@ -1,13 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::match_libc_symbol;
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
 use clippy_utils::visitors::is_expr_unsafe;
+use clippy_utils::{match_libc_symbol, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, LangItem, Node, UnsafeSource};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::symbol::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -44,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings {
             && let ExprKind::Call(func, [recv]) = expr.kind
             && let ExprKind::Path(path) = &func.kind
             && let Some(did) = cx.qpath_res(path, func.hir_id).opt_def_id()
-            && match_libc_symbol(cx, did, "strlen")
+            && match_libc_symbol(cx, did, sym::strlen)
             && let ExprKind::MethodCall(path, self_arg, [], _) = recv.kind
             && !recv.span.from_expansion()
             && path.ident.name == sym::as_ptr
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
index 83241f97a99..edb7600b7c0 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
@@ -80,7 +80,7 @@ fn check_expr_inner<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, bin
             && let hir::Node::ImplItem(impl_item) = cx.tcx.hir_node_by_def_id(parent_fn)
             && let hir::ImplItemKind::Fn(_, body_id) = impl_item.kind
             && let body = cx.tcx.hir_body(body_id)
-            && let parent_fn = cx.tcx.hir_get_parent_item(expr.hir_id).def_id
+            && let parent_fn = cx.tcx.hir_get_parent_item(expr.hir_id)
             && let Some(trait_ref) = trait_ref_of_method(cx, parent_fn)
             && let trait_id = trait_ref.path.res.def_id()
             && ![binop_trait_id, op_assign_trait_id].contains(&trait_id)
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 20bf3a0bff1..75a82770af0 100644
--- a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
+++ b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
@@ -57,7 +57,7 @@ impl<'tcx> LateLintPass<'tcx> for TrailingEmptyArray {
 }
 
 fn is_struct_with_trailing_zero_sized_array<'tcx>(cx: &LateContext<'tcx>, item: &Item<'tcx>) -> bool {
-    if let ItemKind::Struct(_, data, _) = &item.kind
+    if let ItemKind::Struct(_, _, data) = &item.kind
         && let Some(last_field) = data.fields().last()
         && let field_ty = cx.tcx.normalize_erasing_regions(
             cx.typing_env(),
diff --git a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
index 95ce19975c7..3c21d194b81 100644
--- a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
@@ -66,7 +66,7 @@ impl LateLintPass<'_> for TupleArrayConversions {
 }
 
 fn check_array<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: &'tcx [Expr<'tcx>]) {
-    let (ty::Array(ty, _) | ty::Slice(ty)) = cx.typeck_results().expr_ty(expr).kind() else {
+    let Some(ty) = cx.typeck_results().expr_ty(expr).builtin_index() else {
         unreachable!("`expr` must be an array or slice due to `ExprKind::Array`");
     };
 
@@ -85,7 +85,7 @@ fn check_array<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: &
             ExprKind::Path(_) => Some(elements.iter().collect()),
             _ => None,
         })
-        && all_bindings_are_for_conv(cx, &[*ty], expr, elements, &locals, ToType::Array)
+        && all_bindings_are_for_conv(cx, &[ty], expr, elements, &locals, ToType::Array)
         && !is_from_proc_macro(cx, expr)
     {
         span_lint_and_help(
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index c1c7cc51656..515be5adeed 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -447,7 +447,7 @@ impl<'tcx> LateLintPass<'tcx> for Types {
         let is_exported = cx.effective_visibilities.is_exported(item.owner_id.def_id);
 
         match item.kind {
-            ItemKind::Static(_, ty, _, _) | ItemKind::Const(_, ty, _, _) => self.check_ty(
+            ItemKind::Static(_, _, ty, _) | ItemKind::Const(_, _, ty, _) => self.check_ty(
                 cx,
                 ty,
                 CheckTyContext {
diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
index 67ceac92dbc..39f4130afcf 100644
--- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
@@ -5,7 +5,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_middle::ty::{ClauseKind, GenericPredicates, ProjectionPredicate, TraitPredicate};
 use rustc_session::declare_lint_pass;
-use rustc_span::{BytePos, Span, sym};
+use rustc_span::{BytePos, Span, Symbol, sym};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -36,21 +36,26 @@ declare_clippy_lint! {
 
 declare_lint_pass!(UnitReturnExpectingOrd => [UNIT_RETURN_EXPECTING_ORD]);
 
-fn get_trait_predicates_for_trait_id<'tcx>(
+// For each
+fn get_trait_predicates_for_trait_ids<'tcx>(
     cx: &LateContext<'tcx>,
     generics: GenericPredicates<'tcx>,
-    trait_id: Option<DefId>,
-) -> Vec<TraitPredicate<'tcx>> {
-    let mut preds = Vec::new();
+    trait_ids: &[Option<DefId>], // At least 2 ids
+) -> [Vec<TraitPredicate<'tcx>>; 3] {
+    debug_assert!(trait_ids.len() >= 2);
+    let mut preds = [Vec::new(), Vec::new(), Vec::new()];
     for (pred, _) in generics.predicates {
-        if let ClauseKind::Trait(poly_trait_pred) = pred.kind().skip_binder()
-            && let trait_pred = cx
+        if let ClauseKind::Trait(poly_trait_pred) = pred.kind().skip_binder() {
+            let trait_pred = cx
                 .tcx
-                .instantiate_bound_regions_with_erased(pred.kind().rebind(poly_trait_pred))
-            && let Some(trait_def_id) = trait_id
-            && trait_def_id == trait_pred.trait_ref.def_id
-        {
-            preds.push(trait_pred);
+                .instantiate_bound_regions_with_erased(pred.kind().rebind(poly_trait_pred));
+            for (i, tid) in trait_ids.iter().enumerate() {
+                if let Some(tid) = tid
+                    && *tid == trait_pred.trait_ref.def_id
+                {
+                    preds[i].push(trait_pred);
+                }
+            }
         }
     }
     preds
@@ -74,15 +79,24 @@ fn get_projection_pred<'tcx>(
     })
 }
 
-fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Vec<(usize, String)> {
+fn get_args_to_check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+    args_len: usize,
+    fn_mut_trait: DefId,
+    ord_trait: Option<DefId>,
+    partial_ord_trait: Option<DefId>,
+) -> Vec<(usize, Symbol)> {
     let mut args_to_check = Vec::new();
     if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
         let fn_sig = cx.tcx.fn_sig(def_id).instantiate_identity();
         let generics = cx.tcx.predicates_of(def_id);
-        let fn_mut_preds = get_trait_predicates_for_trait_id(cx, generics, cx.tcx.lang_items().fn_mut_trait());
-        let ord_preds = get_trait_predicates_for_trait_id(cx, generics, cx.tcx.get_diagnostic_item(sym::Ord));
-        let partial_ord_preds =
-            get_trait_predicates_for_trait_id(cx, generics, cx.tcx.lang_items().partial_ord_trait());
+        let [fn_mut_preds, ord_preds, partial_ord_preds] =
+            get_trait_predicates_for_trait_ids(cx, generics, &[Some(fn_mut_trait), ord_trait, partial_ord_trait]);
+        if fn_mut_preds.is_empty() {
+            return vec![];
+        }
+
         // Trying to call instantiate_bound_regions_with_erased on fn_sig.inputs() gives the following error
         // The trait `rustc::ty::TypeFoldable<'_>` is not implemented for
         // `&[rustc_middle::ty::Ty<'_>]`
@@ -102,12 +116,18 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve
                             .iter()
                             .any(|ord| Some(ord.self_ty()) == return_ty_pred.term.as_type())
                         {
-                            args_to_check.push((i, "Ord".to_string()));
+                            args_to_check.push((i, sym::Ord));
+                            if args_to_check.len() == args_len - 1 {
+                                break;
+                            }
                         } else if partial_ord_preds
                             .iter()
                             .any(|pord| pord.self_ty() == return_ty_pred.term.expect_type())
                         {
-                            args_to_check.push((i, "PartialOrd".to_string()));
+                            args_to_check.push((i, sym::PartialOrd));
+                            if args_to_check.len() == args_len - 1 {
+                                break;
+                            }
                         }
                     }
                 }
@@ -142,38 +162,50 @@ fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Spa
 
 impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if let ExprKind::MethodCall(_, receiver, args, _) = expr.kind {
-            let arg_indices = get_args_to_check(cx, expr);
+        if let ExprKind::MethodCall(_, receiver, args, _) = expr.kind
+            && args.iter().any(|arg| {
+                matches!(
+                    arg.peel_blocks().peel_borrows().peel_drop_temps().kind,
+                    ExprKind::Path(_) | ExprKind::Closure(_)
+                )
+            })
+            && let Some(fn_mut_trait) = cx.tcx.lang_items().fn_mut_trait()
+        {
+            let ord_trait = cx.tcx.get_diagnostic_item(sym::Ord);
+            let partial_ord_trait = cx.tcx.lang_items().partial_ord_trait();
+            if (ord_trait, partial_ord_trait) == (None, None) {
+                return;
+            }
+
             let args = std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>();
+            let arg_indices = get_args_to_check(cx, expr, args.len(), fn_mut_trait, ord_trait, partial_ord_trait);
             for (i, trait_name) in arg_indices {
-                if i < args.len() {
-                    match check_arg(cx, args[i]) {
-                        Some((span, None)) => {
-                            span_lint(
-                                cx,
-                                UNIT_RETURN_EXPECTING_ORD,
-                                span,
-                                format!(
-                                    "this closure returns \
+                match check_arg(cx, args[i]) {
+                    Some((span, None)) => {
+                        span_lint(
+                            cx,
+                            UNIT_RETURN_EXPECTING_ORD,
+                            span,
+                            format!(
+                                "this closure returns \
                                    the unit type which also implements {trait_name}"
-                                ),
-                            );
-                        },
-                        Some((span, Some(last_semi))) => {
-                            span_lint_and_help(
-                                cx,
-                                UNIT_RETURN_EXPECTING_ORD,
-                                span,
-                                format!(
-                                    "this closure returns \
+                            ),
+                        );
+                    },
+                    Some((span, Some(last_semi))) => {
+                        span_lint_and_help(
+                            cx,
+                            UNIT_RETURN_EXPECTING_ORD,
+                            span,
+                            format!(
+                                "this closure returns \
                                    the unit type which also implements {trait_name}"
-                                ),
-                                Some(last_semi),
-                                "probably caused by this trailing semicolon",
-                            );
-                        },
-                        None => {},
-                    }
+                            ),
+                            Some(last_semi),
+                            "probably caused by this trailing semicolon",
+                        );
+                    },
+                    None => {},
                 }
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
index bcd05cceca9..54a7efc090a 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
@@ -1,3 +1,5 @@
+use std::borrow::Cow;
+
 use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet;
@@ -78,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
         fn_kind: FnKind<'tcx>,
         fn_decl: &FnDecl<'tcx>,
         body: &Body<'tcx>,
-        span: Span,
+        _span: Span,
         def_id: LocalDefId,
     ) {
         // Abort if public function/method or closure.
@@ -147,19 +149,22 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
                     "remove the return type...".to_string(),
                     // FIXME: we should instead get the span including the `->` and suggest an
                     // empty string for this case.
-                    "()".to_string(),
-                    "...and then remove returned values",
+                    Cow::Borrowed("()"),
+                    Cow::Borrowed("...and then remove returned values"),
                 )
             } else {
+                let wrapper = if lang_item == OptionSome { "Some" } else { "Ok" };
                 (
                     format!("this function's return value is unnecessarily wrapped by `{return_type_label}`"),
                     format!("remove `{return_type_label}` from the return type..."),
-                    inner_type.to_string(),
-                    "...and then change returning expressions",
+                    Cow::Owned(inner_type.to_string()),
+                    Cow::Owned(format!(
+                        "...and then remove the surrounding `{wrapper}()` from returning expressions"
+                    )),
                 )
             };
 
-            span_lint_and_then(cx, UNNECESSARY_WRAPS, span, lint_msg, |diag| {
+            span_lint_and_then(cx, UNNECESSARY_WRAPS, cx.tcx.def_span(def_id), lint_msg, |diag| {
                 diag.span_suggestion(
                     fn_decl.output.span(),
                     return_type_sugg_msg,
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 9ad184450de..b839b6f5672 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -426,7 +426,7 @@ fn drain_matching(
         // Check if we should extract, but only if `idx >= start`.
         if idx > start && predicate(&alternatives[i].kind) {
             let pat = alternatives.remove(i);
-            tail_or.push(extract(pat.into_inner().kind));
+            tail_or.push(extract(pat.kind));
         } else {
             i += 1;
         }
diff --git a/src/tools/clippy/clippy_lints/src/unused_peekable.rs b/src/tools/clippy/clippy_lints/src/unused_peekable.rs
index 7487e273caa..1f5351e32aa 100644
--- a/src/tools/clippy/clippy_lints/src/unused_peekable.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_peekable.rs
@@ -1,13 +1,12 @@
 use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable};
-use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, peel_ref_operators};
+use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, peel_ref_operators, sym};
 use rustc_ast::Mutability;
 use rustc_hir::intravisit::{Visitor, walk_expr};
 use rustc_hir::{Block, Expr, ExprKind, HirId, LetStmt, Node, PatKind, PathSegment, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter::OnlyBodies;
 use rustc_session::declare_lint_pass;
-use rustc_span::sym;
 use std::ops::ControlFlow;
 
 declare_clippy_lint! {
@@ -150,10 +149,10 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> {
                                 remaining_args,
                                 _,
                             ) => {
-                                let method_name = method_name_ident.name.as_str();
+                                let method_name = method_name_ident.name;
 
                                 // `Peekable` methods
-                                if matches!(method_name, "peek" | "peek_mut" | "next_if" | "next_if_eq")
+                                if matches!(method_name, sym::peek | sym::peek_mut | sym::next_if | sym::next_if_eq)
                                     && arg_is_mut_peekable(self.cx, self_arg)
                                 {
                                     return ControlFlow::Break(());
@@ -167,7 +166,7 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> {
                                 }
 
                                 // foo.by_ref(), keep checking for `peek`
-                                if method_name == "by_ref" {
+                                if method_name == sym::by_ref {
                                     continue;
                                 }
 
diff --git a/src/tools/clippy/clippy_lints/src/unused_rounding.rs b/src/tools/clippy/clippy_lints/src/unused_rounding.rs
index 3e5afec541c..c21004b5362 100644
--- a/src/tools/clippy/clippy_lints/src/unused_rounding.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_rounding.rs
@@ -1,9 +1,11 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
+use clippy_utils::sym;
 use rustc_ast::ast::{Expr, ExprKind, MethodCall};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::declare_lint_pass;
+use rustc_span::Symbol;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -30,19 +32,20 @@ declare_clippy_lint! {
 }
 declare_lint_pass!(UnusedRounding => [UNUSED_ROUNDING]);
 
-fn is_useless_rounding<'a>(cx: &EarlyContext<'_>, expr: &'a Expr) -> Option<(&'a str, String)> {
+fn is_useless_rounding(cx: &EarlyContext<'_>, expr: &Expr) -> Option<(Symbol, String)> {
     if let ExprKind::MethodCall(box MethodCall {
         seg: name_ident,
         receiver,
         ..
     }) = &expr.kind
-        && let method_name = name_ident.ident.name.as_str()
-        && (method_name == "ceil" || method_name == "round" || method_name == "floor")
+        && let method_name = name_ident.ident.name
+        && matches!(method_name, sym::ceil | sym::floor | sym::round)
         && let ExprKind::Lit(token_lit) = &receiver.kind
         && token_lit.is_semantic_float()
         && let Ok(f) = token_lit.symbol.as_str().replace('_', "").parse::<f64>()
+        && f.fract() == 0.0
     {
-        (f.fract() == 0.0).then(|| (method_name, snippet(cx, receiver.span, "..").to_string()))
+        Some((method_name, snippet(cx, receiver.span, "..").into()))
     } else {
         None
     }
diff --git a/src/tools/clippy/clippy_lints/src/unused_trait_names.rs b/src/tools/clippy/clippy_lints/src/unused_trait_names.rs
index 14ac65cf4df..610cec7b8c8 100644
--- a/src/tools/clippy/clippy_lints/src/unused_trait_names.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_trait_names.rs
@@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedTraitNames {
             // Ignore imports that already use Underscore
             && ident.name != kw::Underscore
             // Only check traits
-            && let Some(Res::Def(DefKind::Trait, _)) = path.res.first()
+            && let Some(Res::Def(DefKind::Trait, _)) = path.res.type_ns
             && cx.tcx.maybe_unused_trait_imports(()).contains(&item.owner_id.def_id)
             // Only check this import if it is visible to its module only (no pub, pub(crate), ...)
             && let module = cx.tcx.parent_module_from_def_id(item.owner_id.def_id)
diff --git a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
index f870eb71e19..7bec212a23c 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
@@ -79,7 +79,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tc
         let mut result = Vec::new();
         let _: Option<!> = for_each_expr(cx, body.value, |e| {
             // check for `expect`
-            if let Some(arglists) = method_chain_args(e, &["expect"]) {
+            if let Some(arglists) = method_chain_args(e, &[sym::expect]) {
                 let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs();
                 if is_type_diagnostic_item(cx, receiver_ty, sym::Option)
                     || is_type_diagnostic_item(cx, receiver_ty, sym::Result)
@@ -89,7 +89,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tc
             }
 
             // check for `unwrap`
-            if let Some(arglists) = method_chain_args(e, &["unwrap"]) {
+            if let Some(arglists) = method_chain_args(e, &[sym::unwrap]) {
                 let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs();
                 if is_type_diagnostic_item(cx, receiver_ty, sym::Option)
                     || is_type_diagnostic_item(cx, receiver_ty, sym::Result)
diff --git a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
index 8922478e718..02281b9e922 100644
--- a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
+++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
@@ -134,7 +134,7 @@ impl LateLintPass<'_> for UpperCaseAcronyms {
             ItemKind::TyAlias(ident, ..) | ItemKind::Struct(ident, ..) | ItemKind::Trait(_, _, ident, ..) => {
                 check_ident(cx, &ident, it.hir_id(), self.upper_case_acronyms_aggressive);
             },
-            ItemKind::Enum(ident, ref enumdef, _) => {
+            ItemKind::Enum(ident, _, ref enumdef) => {
                 check_ident(cx, &ident, it.hir_id(), self.upper_case_acronyms_aggressive);
                 // check enum variants separately because again we only want to lint on private enums and
                 // the fn check_variant does not know about the vis of the enum of its variants
diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs
index 743f54ca993..aeda864b7eb 100644
--- a/src/tools/clippy/clippy_lints/src/use_self.rs
+++ b/src/tools/clippy/clippy_lints/src/use_self.rs
@@ -319,7 +319,7 @@ fn same_lifetimes<'tcx>(a: MiddleTy<'tcx>, b: MiddleTy<'tcx>) -> bool {
             args_a
                 .iter()
                 .zip(args_b.iter())
-                .all(|(arg_a, arg_b)| match (arg_a.unpack(), arg_b.unpack()) {
+                .all(|(arg_a, arg_b)| match (arg_a.kind(), arg_b.kind()) {
                     // TODO: Handle inferred lifetimes
                     (GenericArgKind::Lifetime(inner_a), GenericArgKind::Lifetime(inner_b)) => inner_a == inner_b,
                     (GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => same_lifetimes(type_a, type_b),
@@ -337,7 +337,7 @@ fn has_no_lifetime(ty: MiddleTy<'_>) -> bool {
         &Adt(_, args) => !args
             .iter()
             // TODO: Handle inferred lifetimes
-            .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(..))),
+            .any(|arg| matches!(arg.kind(), GenericArgKind::Lifetime(..))),
         _ => true,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/useless_concat.rs b/src/tools/clippy/clippy_lints/src/useless_concat.rs
new file mode 100644
index 00000000000..1ed1fbb3b9c
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/useless_concat.rs
@@ -0,0 +1,104 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::macros::macro_backtrace;
+use clippy_utils::paths::CONCAT;
+use clippy_utils::source::snippet_opt;
+use clippy_utils::tokenize_with_text;
+use rustc_ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lexer::TokenKind;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::declare_lint_pass;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks that the `concat!` macro has at least two arguments.
+    ///
+    /// ### Why is this bad?
+    /// If there are less than 2 arguments, then calling the macro is doing nothing.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// let x = concat!("a");
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// let x = "a";
+    /// ```
+    #[clippy::version = "1.89.0"]
+    pub USELESS_CONCAT,
+    complexity,
+    "checks that the `concat` macro has at least two arguments"
+}
+
+declare_lint_pass!(UselessConcat => [USELESS_CONCAT]);
+
+impl LateLintPass<'_> for UselessConcat {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+        // Check that the expression is generated by a macro.
+        if expr.span.from_expansion()
+            // Check that it's a string literal.
+            && let ExprKind::Lit(lit) = expr.kind
+            && let LitKind::Str(lit_s, _) = lit.node
+            // Get the direct parent of the expression.
+            && let Some(macro_call) = macro_backtrace(expr.span).next()
+            // Check if the `concat` macro from the `core` library.
+            && CONCAT.matches(cx, macro_call.def_id)
+            // We get the original code to parse it.
+            && let Some(original_code) = snippet_opt(cx, macro_call.span)
+            // This check allows us to ensure that the code snippet:
+            // 1. Doesn't come from proc-macro expansion.
+            // 2. Doesn't come from foreign macro expansion.
+            //
+            // It works as follows: if the snippet we get doesn't contain `concat!(`, then it
+            // means it's not code written in the current crate so we shouldn't lint.
+            && let mut parts = original_code.split('!')
+            && parts.next().is_some_and(|p| p.trim() == "concat")
+            && parts.next().is_some_and(|p| p.trim().starts_with('('))
+        {
+            let mut literal = None;
+            let mut nb_commas = 0;
+            let mut nb_idents = 0;
+            for (token_kind, token_s, _) in tokenize_with_text(&original_code) {
+                match token_kind {
+                    TokenKind::Eof => break,
+                    TokenKind::Literal { .. } => {
+                        if literal.is_some() {
+                            return;
+                        }
+                        literal = Some(token_s);
+                    },
+                    TokenKind::Ident => {
+                        if token_s == "true" || token_s == "false" {
+                            literal = Some(token_s);
+                        } else {
+                            nb_idents += 1;
+                        }
+                    },
+                    TokenKind::Comma => {
+                        nb_commas += 1;
+                        if nb_commas > 1 {
+                            return;
+                        }
+                    },
+                    // We're inside a macro definition and we are manipulating something we likely
+                    // shouldn't, so aborting.
+                    TokenKind::Dollar => return,
+                    _ => {},
+                }
+            }
+            // There should always be the ident of the `concat` macro.
+            if nb_idents == 1 {
+                span_lint_and_sugg(
+                    cx,
+                    USELESS_CONCAT,
+                    macro_call.span,
+                    "unneeded use of `concat!` macro",
+                    "replace with",
+                    format!("{lit_s:?}"),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index 3a9c997a579..380ddea4e1e 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -3,11 +3,11 @@ use clippy_utils::source::{snippet, snippet_with_context};
 use clippy_utils::sugg::{DiagExt as _, Sugg};
 use clippy_utils::ty::{get_type_diagnostic_name, is_copy, is_type_diagnostic_item, same_type_and_consts};
 use clippy_utils::{
-    get_parent_expr, is_inherent_method_call, is_trait_item, is_trait_method, is_ty_alias, path_to_local,
+    get_parent_expr, is_inherent_method_call, is_trait_item, is_trait_method, is_ty_alias, path_to_local, sym,
 };
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{BindingMode, Expr, ExprKind, HirId, MatchSource, Node, PatKind};
+use rustc_hir::{BindingMode, Expr, ExprKind, HirId, MatchSource, Mutability, Node, PatKind};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::Obligation;
 use rustc_lint::{LateContext, LateLintPass};
@@ -15,7 +15,7 @@ use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::adjustment::{Adjust, AutoBorrow, AutoBorrowMutability};
 use rustc_middle::ty::{self, EarlyBinder, GenericArg, GenericArgsRef, Ty, TypeVisitableExt};
 use rustc_session::impl_lint_pass;
-use rustc_span::{Span, sym};
+use rustc_span::Span;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 
 declare_clippy_lint! {
@@ -177,7 +177,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
             },
 
             ExprKind::MethodCall(name, recv, [], _) => {
-                if is_trait_method(cx, e, sym::Into) && name.ident.as_str() == "into" {
+                if is_trait_method(cx, e, sym::Into) && name.ident.name == sym::into {
                     let a = cx.typeck_results().expr_ty(e);
                     let b = cx.typeck_results().expr_ty(recv);
                     if same_type_and_consts(a, b) {
@@ -298,6 +298,33 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                     // implements Copy, in which case .into_iter() returns a copy of the receiver and
                     // cannot be safely omitted.
                     if same_type_and_consts(a, b) && !is_copy(cx, b) {
+                        // Below we check if the parent method call meets the following conditions:
+                        // 1. First parameter is `&mut self` (requires mutable reference)
+                        // 2. Second parameter implements the `FnMut` trait (e.g., Iterator::any)
+                        // For methods satisfying these conditions (like any), .into_iter() must be preserved.
+                        if let Some(parent) = get_parent_expr(cx, e)
+                            && let ExprKind::MethodCall(_, recv, _, _) = parent.kind
+                            && recv.hir_id == e.hir_id
+                            && let Some(def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id)
+                            && let sig = cx.tcx.fn_sig(def_id).skip_binder().skip_binder()
+                            && let inputs = sig.inputs()
+                            && inputs.len() >= 2
+                            && let Some(self_ty) = inputs.first()
+                            && let ty::Ref(_, _, Mutability::Mut) = self_ty.kind()
+                            && let Some(second_ty) = inputs.get(1)
+                            && let predicates = cx.tcx.param_env(def_id).caller_bounds()
+                            && predicates.iter().any(|pred| {
+                                if let ty::ClauseKind::Trait(trait_pred) = pred.kind().skip_binder() {
+                                    trait_pred.self_ty() == *second_ty
+                                        && cx.tcx.lang_items().fn_mut_trait() == Some(trait_pred.def_id())
+                                } else {
+                                    false
+                                }
+                            })
+                        {
+                            return;
+                        }
+
                         let sugg = snippet(cx, recv.span, "<expr>").into_owned();
                         span_lint_and_sugg(
                             cx,
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 812c4df4ddd..3a08531cf1c 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -1,4 +1,4 @@
-use clippy_utils::{MaybePath, get_attr, higher, path_def_id};
+use clippy_utils::{MaybePath, get_attr, higher, path_def_id, sym};
 use itertools::Itertools;
 use rustc_ast::LitIntType;
 use rustc_ast::ast::{LitFloatType, LitKind};
@@ -826,5 +826,5 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
 
 fn has_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool {
     let attrs = cx.tcx.hir_attrs(hir_id);
-    get_attr(cx.sess(), attrs, "author").count() > 0
+    get_attr(cx.sess(), attrs, sym::author).count() > 0
 }
diff --git a/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs b/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs
index 9910be9bc28..d6cf07fdaf3 100644
--- a/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs
@@ -1,4 +1,4 @@
-use clippy_utils::get_attr;
+use clippy_utils::{get_attr, sym};
 use hir::TraitItem;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -60,5 +60,5 @@ impl<'tcx> LateLintPass<'tcx> for DumpHir {
 
 fn has_attr(cx: &LateContext<'_>, hir_id: hir::HirId) -> bool {
     let attrs = cx.tcx.hir_attrs(hir_id);
-    get_attr(cx.sess(), attrs, "dump").count() > 0
+    get_attr(cx.sess(), attrs, sym::dump).count() > 0
 }
diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs
index 3346b15dae9..7b6a25123e8 100644
--- a/src/tools/clippy/clippy_lints/src/vec.rs
+++ b/src/tools/clippy/clippy_lints/src/vec.rs
@@ -8,14 +8,14 @@ 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, span_contains_comment};
+use clippy_utils::{get_parent_expr, higher, is_in_test, is_trait_method, span_contains_comment, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, LetStmt, Mutability, Node, Pat, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_session::impl_lint_pass;
-use rustc_span::{DesugaringKind, Span, sym};
+use rustc_span::{DesugaringKind, Span};
 
 pub struct UselessVec {
     too_large_for_stack: u64,
@@ -249,10 +249,8 @@ fn adjusts_to_slice(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 /// that also exists on slices. If this returns true, it means that
 /// this expression does not actually require a `Vec` and could just work with an array.
 pub fn is_allowed_vec_method(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
-    const ALLOWED_METHOD_NAMES: &[&str] = &["len", "as_ptr", "is_empty"];
-
     if let ExprKind::MethodCall(path, _, [], _) = e.kind {
-        ALLOWED_METHOD_NAMES.contains(&path.ident.name.as_str())
+        matches!(path.ident.name, sym::as_ptr | sym::is_empty | sym::len)
     } else {
         is_trait_method(cx, e, sym::IntoIterator)
     }
diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
index 45a5dbabeb4..467811c586b 100644
--- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
@@ -169,8 +169,8 @@ impl LateLintPass<'_> for WildcardImports {
                 format!("{import_source_snippet}::{imports_string}")
             };
 
-            // Glob imports always have a single resolution.
-            let (lint, message) = if let Res::Def(DefKind::Enum, _) = use_path.res[0] {
+            // Glob imports always have a single resolution. Enums are in the value namespace.
+            let (lint, message) = if let Some(Res::Def(DefKind::Enum, _)) = use_path.res.value_ns {
                 (ENUM_GLOB_USE, "usage of wildcard import for enum variants")
             } else {
                 (WILDCARD_IMPORTS, "usage of wildcard import")
diff --git a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
index 24b1381ba45..1550872bca2 100644
--- a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
@@ -51,9 +51,11 @@ impl LateLintPass<'_> for ZeroSizedMapValues {
             && (is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap))
             && let ty::Adt(_, args) = ty.kind()
             && let ty = args.type_at(1)
-            // Fixes https://github.com/rust-lang/rust-clippy/issues/7447 because of
-            // https://github.com/rust-lang/rust/blob/master/compiler/rustc_middle/src/ty/sty.rs#L968
-            && !ty.has_escaping_bound_vars()
+            // Ensure that no type information is missing, to avoid a delayed bug in the compiler if this is not the case.
+            // This might happen when computing a reference/pointer metadata on a type for which we
+            // cannot check if it is `Sized` or not, such as an incomplete associated type in a
+            // type alias. See an example in `issue14822()` of `tests/ui/zero_sized_hashmap_values.rs`.
+            && !ty.has_non_region_param()
             && let Ok(layout) = cx.layout_of(ty)
             && layout.is_zst()
         {
diff --git a/src/tools/clippy/clippy_lints_internal/src/almost_standard_lint_formulation.rs b/src/tools/clippy/clippy_lints_internal/src/almost_standard_lint_formulation.rs
index 4fd5ea459a5..311f76fee6b 100644
--- a/src/tools/clippy/clippy_lints_internal/src/almost_standard_lint_formulation.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/almost_standard_lint_formulation.rs
@@ -3,8 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help;
 use regex::Regex;
 use rustc_hir::{Attribute, Item, ItemKind, Mutability};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_lint_defs::declare_tool_lint;
-use rustc_session::impl_lint_pass;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 
 declare_tool_lint! {
     /// ### What it does
diff --git a/src/tools/clippy/clippy_lints_internal/src/collapsible_calls.rs b/src/tools/clippy/clippy_lints_internal/src/collapsible_calls.rs
index 407deb45db0..7c9e7286925 100644
--- a/src/tools/clippy/clippy_lints_internal/src/collapsible_calls.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/collapsible_calls.rs
@@ -4,8 +4,7 @@ use clippy_utils::{SpanlessEq, is_lint_allowed, peel_blocks_with_stmt};
 use rustc_errors::Applicability;
 use rustc_hir::{Closure, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_lint_defs::declare_tool_lint;
-use rustc_session::declare_lint_pass;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::Span;
 
 use std::borrow::{Borrow, Cow};
diff --git a/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs b/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs
index 655d8fb8d1b..0edeef3ab85 100644
--- a/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs
@@ -10,9 +10,8 @@ use rustc_hir::hir_id::CRATE_HIR_ID;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::{ExprKind, HirId, Item, MutTy, Mutability, Path, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_lint_defs::declare_tool_lint;
 use rustc_middle::hir::nested_filter;
-use rustc_session::impl_lint_pass;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::Symbol;
 use rustc_span::{Span, sym};
diff --git a/src/tools/clippy/clippy_lints_internal/src/msrv_attr_impl.rs b/src/tools/clippy/clippy_lints_internal/src/msrv_attr_impl.rs
index d48d8dc57b2..70b3c03d2bb 100644
--- a/src/tools/clippy/clippy_lints_internal/src/msrv_attr_impl.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/msrv_attr_impl.rs
@@ -4,9 +4,8 @@ use clippy_utils::source::snippet;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_lint_defs::declare_tool_lint;
 use rustc_middle::ty::{self, EarlyBinder, GenericArgKind};
-use rustc_session::declare_lint_pass;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 declare_tool_lint! {
     /// ### What it does
@@ -38,7 +37,7 @@ impl LateLintPass<'_> for MsrvAttrImpl {
                     .type_of(f.did)
                     .instantiate_identity()
                     .walk()
-                    .filter(|t| matches!(t.unpack(), GenericArgKind::Type(_)))
+                    .filter(|t| matches!(t.kind(), GenericArgKind::Type(_)))
                     .any(|t| internal_paths::MSRV_STACK.matches_ty(cx, t.expect_ty()))
             })
             && !items.iter().any(|item| item.ident.name.as_str() == "check_attributes")
diff --git a/src/tools/clippy/clippy_lints_internal/src/outer_expn_data_pass.rs b/src/tools/clippy/clippy_lints_internal/src/outer_expn_data_pass.rs
index 40951443a48..5cdc66ae905 100644
--- a/src/tools/clippy/clippy_lints_internal/src/outer_expn_data_pass.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/outer_expn_data_pass.rs
@@ -1,12 +1,11 @@
 use crate::internal_paths;
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::{is_lint_allowed, method_calls};
+use clippy_utils::{is_lint_allowed, method_calls, sym};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_lint_defs::declare_tool_lint;
 use rustc_session::declare_lint_pass;
-use rustc_span::symbol::Symbol;
 
 declare_tool_lint! {
     /// ### What it does
@@ -40,8 +39,7 @@ impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass {
         }
 
         let (method_names, arg_lists, spans) = method_calls(expr, 2);
-        let method_names: Vec<&str> = method_names.iter().map(Symbol::as_str).collect();
-        if let ["expn_data", "outer_expn"] = method_names.as_slice()
+        if let [sym::expn_data, sym::outer_expn] = method_names.as_slice()
             && let (self_arg, args) = arg_lists[1]
             && args.is_empty()
             && let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs()
diff --git a/src/tools/clippy/clippy_lints_internal/src/produce_ice.rs b/src/tools/clippy/clippy_lints_internal/src/produce_ice.rs
index 14e93dc6d5f..3a813b4b9a2 100644
--- a/src/tools/clippy/clippy_lints_internal/src/produce_ice.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/produce_ice.rs
@@ -1,8 +1,7 @@
 use rustc_ast::ast::NodeId;
 use rustc_ast::visit::FnKind;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_lint_defs::declare_tool_lint;
-use rustc_session::declare_lint_pass;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::Span;
 
 declare_tool_lint! {
diff --git a/src/tools/clippy/clippy_lints_internal/src/symbols.rs b/src/tools/clippy/clippy_lints_internal/src/symbols.rs
index 5aee545fb0f..7b5d58824c3 100644
--- a/src/tools/clippy/clippy_lints_internal/src/symbols.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/symbols.rs
@@ -6,10 +6,9 @@ use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Expr, ExprKind, Lit, Node, Pat, PatExprKind, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_lint_defs::declare_tool_lint;
 use rustc_middle::mir::ConstValue;
 use rustc_middle::ty;
-use rustc_session::impl_lint_pass;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::Symbol;
 use rustc_span::{Span, sym};
 
diff --git a/src/tools/clippy/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs b/src/tools/clippy/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs
index 8e281ecb2ee..9ca4ae31d45 100644
--- a/src/tools/clippy/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs
@@ -1,8 +1,8 @@
 use clippy_utils::diagnostics::span_lint;
+use clippy_utils::sym;
 use rustc_ast::ast::{Crate, ItemKind, ModKind};
 use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_lint_defs::declare_tool_lint;
-use rustc_session::declare_lint_pass;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 declare_tool_lint! {
     /// ### What it does
@@ -26,11 +26,11 @@ impl EarlyLintPass for UnsortedClippyUtilsPaths {
         if let Some(utils) = krate
             .items
             .iter()
-            .find(|item| item.kind.ident().is_some_and(|i| i.name.as_str() == "utils"))
+            .find(|item| item.kind.ident().is_some_and(|i| i.name == sym::utils))
             && let ItemKind::Mod(_, _, ModKind::Loaded(ref items, ..)) = utils.kind
             && let Some(paths) = items
                 .iter()
-                .find(|item| item.kind.ident().is_some_and(|i| i.name.as_str() == "paths"))
+                .find(|item| item.kind.ident().is_some_and(|i| i.name == sym::paths))
             && let ItemKind::Mod(_, _, ModKind::Loaded(ref items, ..)) = paths.kind
         {
             let mut last_name: Option<String> = None;
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index ac970e1c4b0..615c0995e8b 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -1,8 +1,6 @@
 [package]
 name = "clippy_utils"
-# begin autogenerated version
 version = "0.1.89"
-# end autogenerated version
 edition = "2024"
 description = "Helpful tools for writing lints, provided as they are used in Clippy"
 repository = "https://github.com/rust-lang/rust-clippy"
diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md
index d4080d06d3c..efbacbd72db 100644
--- a/src/tools/clippy/clippy_utils/README.md
+++ b/src/tools/clippy/clippy_utils/README.md
@@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain:
 
 <!-- begin autogenerated nightly -->
 ```
-nightly-2025-05-14
+nightly-2025-05-31
 ```
 <!-- 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 8996b694ed8..e65914b9b5e 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
@@ -436,11 +436,11 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
                 && over(lb, rb, eq_generic_bound)
                 && both(lt.as_ref(), rt.as_ref(), |l, r| eq_ty(l, r))
         },
-        (Enum(li, le, lg), Enum(ri, re, rg)) => {
-            eq_id(*li, *ri) && over(&le.variants, &re.variants, eq_variant) && eq_generics(lg, rg)
+        (Enum(li, lg, le), Enum(ri, rg, re)) => {
+            eq_id(*li, *ri) && eq_generics(lg, rg) && over(&le.variants, &re.variants, eq_variant)
         },
-        (Struct(li, lv, lg), Struct(ri, rv, rg)) | (Union(li, lv, lg), Union(ri, rv, rg)) => {
-            eq_id(*li, *ri) && eq_variant_data(lv, rv) && eq_generics(lg, rg)
+        (Struct(li, lg, lv), Struct(ri, rg, rv)) | (Union(li, lg, lv), Union(ri, rg, rv)) => {
+            eq_id(*li, *ri) && eq_generics(lg, rg) && eq_variant_data(lv, rv)
         },
         (
             Trait(box ast::Trait {
@@ -960,5 +960,7 @@ pub fn eq_attr_args(l: &AttrArgs, r: &AttrArgs) -> bool {
 }
 
 pub fn eq_delim_args(l: &DelimArgs, r: &DelimArgs) -> bool {
-    l.delim == r.delim && l.tokens.eq_unspanned(&r.tokens)
+    l.delim == r.delim
+        && l.tokens.len() == r.tokens.len()
+        && l.tokens.iter().zip(r.tokens.iter()).all(|(a, b)| a.eq_unspanned(b))
 }
diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs
index 09de5c05537..8a0ff5323c9 100644
--- a/src/tools/clippy/clippy_utils/src/attrs.rs
+++ b/src/tools/clippy/clippy_utils/src/attrs.rs
@@ -5,11 +5,11 @@ use rustc_lexer::TokenKind;
 use rustc_lint::LateContext;
 use rustc_middle::ty::{AdtDef, TyCtxt};
 use rustc_session::Session;
-use rustc_span::{Span, sym};
+use rustc_span::{Span, Symbol};
 use std::str::FromStr;
 
 use crate::source::SpanRangeExt;
-use crate::tokenize_with_text;
+use crate::{sym, tokenize_with_text};
 
 /// Deprecation status of attributes known by Clippy.
 pub enum DeprecationStatus {
@@ -21,17 +21,17 @@ pub enum DeprecationStatus {
 }
 
 #[rustfmt::skip]
-pub const BUILTIN_ATTRIBUTES: &[(&str, DeprecationStatus)] = &[
-    ("author",                DeprecationStatus::None),
-    ("version",               DeprecationStatus::None),
-    ("cognitive_complexity",  DeprecationStatus::None),
-    ("cyclomatic_complexity", DeprecationStatus::Replaced("cognitive_complexity")),
-    ("dump",                  DeprecationStatus::None),
-    ("msrv",                  DeprecationStatus::None),
+pub const BUILTIN_ATTRIBUTES: &[(Symbol, DeprecationStatus)] = &[
+    (sym::author,                DeprecationStatus::None),
+    (sym::version,               DeprecationStatus::None),
+    (sym::cognitive_complexity,  DeprecationStatus::None),
+    (sym::cyclomatic_complexity, DeprecationStatus::Replaced("cognitive_complexity")),
+    (sym::dump,                  DeprecationStatus::None),
+    (sym::msrv,                  DeprecationStatus::None),
     // The following attributes are for the 3rd party crate authors.
     // See book/src/attribs.md
-    ("has_significant_drop",  DeprecationStatus::None),
-    ("format_args",           DeprecationStatus::None),
+    (sym::has_significant_drop,  DeprecationStatus::None),
+    (sym::format_args,           DeprecationStatus::None),
 ];
 
 pub struct LimitStack {
@@ -52,11 +52,11 @@ impl LimitStack {
     pub fn limit(&self) -> u64 {
         *self.stack.last().expect("there should always be a value in the stack")
     }
-    pub fn push_attrs(&mut self, sess: &Session, attrs: &[impl AttributeExt], name: &'static str) {
+    pub fn push_attrs(&mut self, sess: &Session, attrs: &[impl AttributeExt], name: Symbol) {
         let stack = &mut self.stack;
         parse_attrs(sess, attrs, name, |val| stack.push(val));
     }
-    pub fn pop_attrs(&mut self, sess: &Session, attrs: &[impl AttributeExt], name: &'static str) {
+    pub fn pop_attrs(&mut self, sess: &Session, attrs: &[impl AttributeExt], name: Symbol) {
         let stack = &mut self.stack;
         parse_attrs(sess, attrs, name, |val| assert_eq!(stack.pop(), Some(val)));
     }
@@ -65,7 +65,7 @@ impl LimitStack {
 pub fn get_attr<'a, A: AttributeExt + 'a>(
     sess: &'a Session,
     attrs: &'a [A],
-    name: &'static str,
+    name: Symbol,
 ) -> impl Iterator<Item = &'a A> {
     attrs.iter().filter(move |attr| {
         let Some(attr_segments) = attr.ident_path() else {
@@ -75,8 +75,8 @@ pub fn get_attr<'a, A: AttributeExt + 'a>(
         if attr_segments.len() == 2 && attr_segments[0].name == sym::clippy {
             BUILTIN_ATTRIBUTES
                 .iter()
-                .find_map(|&(builtin_name, ref deprecation_status)| {
-                    if attr_segments[1].name.as_str() == builtin_name {
+                .find_map(|(builtin_name, deprecation_status)| {
+                    if attr_segments[1].name == *builtin_name {
                         Some(deprecation_status)
                     } else {
                         None
@@ -108,7 +108,7 @@ pub fn get_attr<'a, A: AttributeExt + 'a>(
                             },
                             DeprecationStatus::None => {
                                 diag.cancel();
-                                attr_segments[1].as_str() == name
+                                attr_segments[1].name == name
                             },
                         }
                     },
@@ -119,9 +119,9 @@ pub fn get_attr<'a, A: AttributeExt + 'a>(
     })
 }
 
-fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[impl AttributeExt], name: &'static str, mut f: F) {
+fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[impl AttributeExt], name: Symbol, mut f: F) {
     for attr in get_attr(sess, attrs, name) {
-        if let Some(ref value) = attr.value_str() {
+        if let Some(value) = attr.value_str() {
             if let Ok(value) = FromStr::from_str(value.as_str()) {
                 f(value);
             } else {
@@ -133,7 +133,7 @@ fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[impl AttributeExt], name:
     }
 }
 
-pub fn get_unique_attr<'a, A: AttributeExt>(sess: &'a Session, attrs: &'a [A], name: &'static str) -> Option<&'a A> {
+pub fn get_unique_attr<'a, A: AttributeExt>(sess: &'a Session, attrs: &'a [A], name: Symbol) -> Option<&'a A> {
     let mut unique_attr: Option<&A> = None;
     for attr in get_attr(sess, attrs, name) {
         if let Some(duplicate) = unique_attr {
diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
index 004c840c331..407e92d88fb 100644
--- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
+++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
@@ -249,7 +249,7 @@ fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) {
         ItemKind::ForeignMod { .. } => (Pat::Str("extern"), Pat::Str("}")),
         ItemKind::TyAlias(..) => (Pat::Str("type"), Pat::Str(";")),
         ItemKind::Enum(..) => (Pat::Str("enum"), Pat::Str("}")),
-        ItemKind::Struct(_, VariantData::Struct { .. }, _) => (Pat::Str("struct"), Pat::Str("}")),
+        ItemKind::Struct(_, _, VariantData::Struct { .. }) => (Pat::Str("struct"), Pat::Str("}")),
         ItemKind::Struct(..) => (Pat::Str("struct"), Pat::Str(";")),
         ItemKind::Union(..) => (Pat::Str("union"), Pat::Str("}")),
         ItemKind::Trait(_, Safety::Unsafe, ..)
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index b9928b8eed4..1ec5d11384f 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -235,9 +235,7 @@ impl Constant<'_> {
                 _ => None,
             },
             (Self::Vec(l), Self::Vec(r)) => {
-                let (ty::Array(cmp_type, _) | ty::Slice(cmp_type)) = *cmp_type.kind() else {
-                    return None;
-                };
+                let cmp_type = cmp_type.builtin_index()?;
                 iter::zip(l, r)
                     .map(|(li, ri)| Self::partial_cmp(tcx, cmp_type, li, ri))
                     .find(|r| r.is_none_or(|o| o != Ordering::Equal))
@@ -487,7 +485,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
             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() {
+                if is_direct_expn_of(e.span, sym::cfg).is_some() {
                     None
                 } else {
                     Some(lit_to_mir_constant(&lit.node, self.typeck.expr_ty_opt(e)))
@@ -565,7 +563,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
                 })
             },
             ExprKind::Lit(lit) => {
-                if is_direct_expn_of(e.span, "cfg").is_some() {
+                if is_direct_expn_of(e.span, sym::cfg).is_some() {
                     None
                 } else {
                     match &lit.node {
@@ -654,7 +652,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
                         span,
                         ..
                     }) = self.tcx.hir_node(body_id.hir_id)
-                    && is_direct_expn_of(*span, "cfg").is_some()
+                    && is_direct_expn_of(*span, sym::cfg).is_some()
                 {
                     return None;
                 }
diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
index 4543a20cc2c..9d38672efad 100644
--- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
+++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
@@ -10,6 +10,7 @@
 //!  - option-if-let-else
 
 use crate::consts::{ConstEvalCtxt, FullInt};
+use crate::sym;
 use crate::ty::{all_predicates_of, is_copy};
 use crate::visitors::is_const_evaluatable;
 use rustc_hir::def::{DefKind, Res};
@@ -19,7 +20,7 @@ use rustc_hir::{BinOpKind, Block, Expr, ExprKind, QPath, UnOp};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
 use rustc_middle::ty::adjustment::Adjust;
-use rustc_span::{Symbol, sym};
+use rustc_span::Symbol;
 use std::{cmp, ops};
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
@@ -49,14 +50,13 @@ impl ops::BitOrAssign for EagernessSuggestion {
 /// Determine the eagerness of the given function call.
 fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg: bool) -> EagernessSuggestion {
     use EagernessSuggestion::{Eager, Lazy, NoChange};
-    let name = name.as_str();
 
     let ty = match cx.tcx.impl_of_method(fn_id) {
         Some(id) => cx.tcx.type_of(id).instantiate_identity(),
         None => return Lazy,
     };
 
-    if (name.starts_with("as_") || name == "len" || name == "is_empty") && have_one_arg {
+    if (matches!(name, sym::is_empty | sym::len) || name.as_str().starts_with("as_")) && have_one_arg {
         if matches!(
             cx.tcx.crate_name(fn_id.krate),
             sym::std | sym::core | sym::alloc | sym::proc_macro
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index dbb99348290..6971b488013 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -299,7 +299,7 @@ impl<'a> VecArgs<'a> {
     pub fn hir(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option<VecArgs<'a>> {
         if let ExprKind::Call(fun, args) = expr.kind
             && let ExprKind::Path(ref qpath) = fun.kind
-            && is_expn_of(fun.span, "vec").is_some()
+            && is_expn_of(fun.span, sym::vec).is_some()
             && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id()
         {
             return if cx.tcx.is_diagnostic_item(sym::vec_from_elem, fun_def_id) && args.len() == 2 {
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 4fb608a6482..f6ef638e618 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -25,6 +25,7 @@
 
 // FIXME: switch to something more ergonomic here, once available.
 // (Currently there is no way to opt into sysroot crates without `extern crate`.)
+extern crate indexmap;
 extern crate rustc_abi;
 extern crate rustc_ast;
 extern crate rustc_attr_data_structures;
@@ -82,7 +83,6 @@ pub use self::hir_utils::{
 use core::mem;
 use core::ops::ControlFlow;
 use std::collections::hash_map::Entry;
-use std::hash::BuildHasherDefault;
 use std::iter::{once, repeat_n};
 use std::sync::{Mutex, MutexGuard, OnceLock};
 
@@ -92,7 +92,7 @@ use rustc_ast::ast::{self, LitKind, RangeLimits};
 use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::packed::Pu128;
-use rustc_data_structures::unhash::UnhashMap;
+use rustc_data_structures::unhash::UnindexMap;
 use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
@@ -524,12 +524,8 @@ pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>
 ///     }
 /// }
 /// ```
-pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, def_id: LocalDefId) -> Option<&'tcx TraitRef<'tcx>> {
-    // Get the implemented trait for the current function
-    let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
-    let parent_impl = cx.tcx.hir_get_parent_item(hir_id);
-    if parent_impl != hir::CRATE_OWNER_ID
-        && let Node::Item(item) = cx.tcx.hir_node_by_def_id(parent_impl.def_id)
+pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, owner: OwnerId) -> Option<&'tcx TraitRef<'tcx>> {
+    if let Node::Item(item) = cx.tcx.hir_node(cx.tcx.hir_owner_parent(owner))
         && let ItemKind::Impl(impl_) = &item.kind
     {
         return impl_.of_trait.as_ref();
@@ -1102,13 +1098,13 @@ pub fn method_calls<'tcx>(expr: &'tcx Expr<'tcx>, max_depth: usize) -> (Vec<Symb
 /// `method_chain_args(expr, &["bar", "baz"])` will return a `Vec`
 /// containing the `Expr`s for
 /// `.bar()` and `.baz()`
-pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec<(&'a Expr<'a>, &'a [Expr<'a>])>> {
+pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[Symbol]) -> Option<Vec<(&'a Expr<'a>, &'a [Expr<'a>])>> {
     let mut current = expr;
     let mut matched = Vec::with_capacity(methods.len());
     for method_name in methods.iter().rev() {
         // method chains are stored last -> first
         if let ExprKind::MethodCall(path, receiver, args, _) = current.kind {
-            if path.ident.name.as_str() == *method_name {
+            if path.ident.name == *method_name {
                 if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) {
                     return None;
                 }
@@ -1494,14 +1490,14 @@ pub fn is_adjusted(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 /// macro `name`.
 /// See also [`is_direct_expn_of`].
 #[must_use]
-pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> {
+pub fn is_expn_of(mut span: Span, name: Symbol) -> Option<Span> {
     loop {
         if span.from_expansion() {
             let data = span.ctxt().outer_expn_data();
             let new_span = data.call_site;
 
             if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind
-                && mac_name.as_str() == name
+                && mac_name == name
             {
                 return Some(new_span);
             }
@@ -1524,13 +1520,13 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> {
 /// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only
 /// from `bar!` by `is_direct_expn_of`.
 #[must_use]
-pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> {
+pub fn is_direct_expn_of(span: Span, name: Symbol) -> Option<Span> {
     if span.from_expansion() {
         let data = span.ctxt().outer_expn_data();
         let new_span = data.call_site;
 
         if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind
-            && mac_name.as_str() == name
+            && mac_name == name
         {
             return Some(new_span);
         }
@@ -1569,10 +1565,10 @@ pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_
 /// Returns `true` if a pattern is refutable.
 // TODO: should be implemented using rustc/mir_build/thir machinery
 pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
-    fn is_enum_variant(cx: &LateContext<'_>, qpath: &QPath<'_>, id: HirId) -> bool {
-        matches!(
+    fn is_qpath_refutable(cx: &LateContext<'_>, qpath: &QPath<'_>, id: HirId) -> bool {
+        !matches!(
             cx.qpath_res(qpath, id),
-            Res::Def(DefKind::Variant, ..) | Res::Def(DefKind::Ctor(def::CtorOf::Variant, _), _)
+            Res::Def(DefKind::Struct, ..) | Res::Def(DefKind::Ctor(def::CtorOf::Struct, _), _)
         )
     }
 
@@ -1589,16 +1585,18 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
             kind: PatExprKind::Path(qpath),
             hir_id,
             ..
-        }) => is_enum_variant(cx, qpath, *hir_id),
+        }) => is_qpath_refutable(cx, qpath, *hir_id),
         PatKind::Or(pats) => {
             // TODO: should be the honest check, that pats is exhaustive set
             are_refutable(cx, pats)
         },
         PatKind::Tuple(pats, _) => are_refutable(cx, pats),
         PatKind::Struct(ref qpath, fields, _) => {
-            is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, fields.iter().map(|field| field.pat))
+            is_qpath_refutable(cx, qpath, pat.hir_id) || are_refutable(cx, fields.iter().map(|field| field.pat))
+        },
+        PatKind::TupleStruct(ref qpath, pats, _) => {
+            is_qpath_refutable(cx, qpath, pat.hir_id) || are_refutable(cx, pats)
         },
-        PatKind::TupleStruct(ref qpath, pats, _) => is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, pats),
         PatKind::Slice(head, middle, tail) => {
             match &cx.typeck_results().node_type(pat.hir_id).kind() {
                 rustc_ty::Slice(..) => {
@@ -1794,11 +1792,11 @@ pub fn in_automatically_derived(tcx: TyCtxt<'_>, id: HirId) -> bool {
 }
 
 /// Checks if the given `DefId` matches the `libc` item.
-pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: &str) -> bool {
+pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: Symbol) -> bool {
     let path = cx.get_def_path(did);
     // libc is meant to be used as a flat list of names, but they're all actually defined in different
     // modules based on the target platform. Ignore everything but crate name and the item name.
-    path.first().is_some_and(|s| *s == sym::libc) && path.last().is_some_and(|s| s.as_str() == name)
+    path.first().is_some_and(|s| *s == sym::libc) && path.last().copied() == Some(name)
 }
 
 /// Returns the list of condition expressions and the list of blocks in a
@@ -2197,45 +2195,46 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<S
     None
 }
 
-/// Returns list of all pairs `(a, b)` where `eq(a, b) == true`
-/// and `a` is before `b` in `exprs` for all `a` and `b` in
-/// `exprs`
+/// Returns a list of groups where elements in each group are equal according to `eq`
+///
+/// - Within each group the elements are sorted by the order they appear in `exprs`
+/// - The groups themselves are sorted by their first element's appearence in `exprs`
 ///
 /// Given functions `eq` and `hash` such that `eq(a, b) == true`
 /// implies `hash(a) == hash(b)`
-pub fn search_same<T, Hash, Eq>(exprs: &[T], mut hash: Hash, mut eq: Eq) -> Vec<(&T, &T)>
+pub fn search_same<T, Hash, Eq>(exprs: &[T], mut hash: Hash, mut eq: Eq) -> Vec<Vec<&T>>
 where
     Hash: FnMut(&T) -> u64,
     Eq: FnMut(&T, &T) -> bool,
 {
     match exprs {
-        [a, b] if eq(a, b) => return vec![(a, b)],
+        [a, b] if eq(a, b) => return vec![vec![a, b]],
         _ if exprs.len() <= 2 => return vec![],
         _ => {},
     }
 
-    let mut match_expr_list: Vec<(&T, &T)> = Vec::new();
-
-    let mut map: UnhashMap<u64, Vec<&_>> =
-        UnhashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default());
+    let mut buckets: UnindexMap<u64, Vec<Vec<&T>>> = UnindexMap::default();
 
     for expr in exprs {
-        match map.entry(hash(expr)) {
-            Entry::Occupied(mut o) => {
-                for o in o.get() {
-                    if eq(o, expr) {
-                        match_expr_list.push((o, expr));
-                    }
+        match buckets.entry(hash(expr)) {
+            indexmap::map::Entry::Occupied(mut o) => {
+                let bucket = o.get_mut();
+                match bucket.iter_mut().find(|group| eq(expr, group[0])) {
+                    Some(group) => group.push(expr),
+                    None => bucket.push(vec![expr]),
                 }
-                o.get_mut().push(expr);
             },
-            Entry::Vacant(v) => {
-                v.insert(vec![expr]);
+            indexmap::map::Entry::Vacant(v) => {
+                v.insert(vec![vec![expr]]);
             },
         }
     }
 
-    match_expr_list
+    buckets
+        .into_values()
+        .flatten()
+        .filter(|group| group.len() > 1)
+        .collect()
 }
 
 /// Peels off all references on the pattern. Returns the underlying pattern and the number of
@@ -2365,7 +2364,7 @@ fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalModDefId, f: impl FnOnce(&
             for id in tcx.hir_module_free_items(module) {
                 if matches!(tcx.def_kind(id.owner_id), DefKind::Const)
                     && let item = tcx.hir_item(id)
-                    && let ItemKind::Const(ident, ty, _generics, _body) = item.kind
+                    && let ItemKind::Const(ident, _generics, ty, _body) = item.kind
                     && let TyKind::Path(QPath::Resolved(_, path)) = ty.kind
                         // We could also check for the type name `test::TestDescAndFn`
                         && let Res::Def(DefKind::Struct, _) = path.res
@@ -3319,7 +3318,7 @@ pub fn leaks_droppable_temporary_with_limited_lifetime<'tcx>(cx: &LateContext<'t
         if temporary_ty.has_significant_drop(cx.tcx, cx.typing_env())
             && temporary_ty
                 .walk()
-                .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(re) if !re.is_static()))
+                .any(|arg| matches!(arg.kind(), GenericArgKind::Lifetime(re) if !re.is_static()))
         {
             ControlFlow::Break(())
         } else {
diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs
index dfb30b9c218..ba126fcd05d 100644
--- a/src/tools/clippy/clippy_utils/src/macros.rs
+++ b/src/tools/clippy/clippy_utils/src/macros.rs
@@ -2,8 +2,8 @@
 
 use std::sync::{Arc, OnceLock};
 
-use crate::get_unique_attr;
 use crate::visitors::{Descend, for_each_expr_without_closures};
+use crate::{get_unique_attr, sym};
 
 use arrayvec::ArrayVec;
 use rustc_ast::{FormatArgs, FormatArgument, FormatPlaceholder};
@@ -12,7 +12,7 @@ use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath};
 use rustc_lint::{LateContext, LintContext};
 use rustc_span::def_id::DefId;
 use rustc_span::hygiene::{self, MacroKind, SyntaxContext};
-use rustc_span::{BytePos, ExpnData, ExpnId, ExpnKind, Span, SpanData, Symbol, sym};
+use rustc_span::{BytePos, ExpnData, ExpnId, ExpnKind, Span, SpanData, Symbol};
 use std::ops::ControlFlow;
 
 const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[
@@ -42,7 +42,7 @@ pub fn is_format_macro(cx: &LateContext<'_>, macro_def_id: DefId) -> bool {
     } else {
         // Allow users to tag any macro as being format!-like
         // TODO: consider deleting FORMAT_MACRO_DIAG_ITEMS and using just this method
-        get_unique_attr(cx.sess(), cx.tcx.get_attrs_unchecked(macro_def_id), "format_args").is_some()
+        get_unique_attr(cx.sess(), cx.tcx.get_attrs_unchecked(macro_def_id), sym::format_args).is_some()
     }
 }
 
@@ -248,10 +248,10 @@ impl<'a> PanicExpn<'a> {
         let ExprKind::Path(QPath::Resolved(_, path)) = &callee.kind else {
             return None;
         };
-        let name = path.segments.last().unwrap().ident.as_str();
+        let name = path.segments.last().unwrap().ident.name;
 
         // This has no argument
-        if name == "panic_cold_explicit" {
+        if name == sym::panic_cold_explicit {
             return Some(Self::Empty);
         }
 
@@ -259,18 +259,18 @@ impl<'a> PanicExpn<'a> {
             return None;
         };
         let result = match name {
-            "panic" if arg.span.eq_ctxt(expr.span) => Self::Empty,
-            "panic" | "panic_str" => Self::Str(arg),
-            "panic_display" | "panic_cold_display" => {
+            sym::panic if arg.span.eq_ctxt(expr.span) => Self::Empty,
+            sym::panic | sym::panic_str => Self::Str(arg),
+            sym::panic_display | sym::panic_cold_display => {
                 let ExprKind::AddrOf(_, _, e) = &arg.kind else {
                     return None;
                 };
                 Self::Display(e)
             },
-            "panic_fmt" => Self::Format(arg),
+            sym::panic_fmt => Self::Format(arg),
             // Since Rust 1.52, `assert_{eq,ne}` macros expand to use:
             // `core::panicking::assert_failed(.., left_val, right_val, None | Some(format_args!(..)));`
-            "assert_failed" => {
+            sym::assert_failed => {
                 // It should have 4 arguments in total (we already matched with the first argument,
                 // so we're just checking for 3)
                 if rest.len() != 3 {
diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs
index 599c6f3a4ff..a5e66ad463b 100644
--- a/src/tools/clippy/clippy_utils/src/msrvs.rs
+++ b/src/tools/clippy/clippy_utils/src/msrvs.rs
@@ -25,7 +25,7 @@ macro_rules! msrv_aliases {
 msrv_aliases! {
     1,88,0 { LET_CHAINS }
     1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT }
-    1,85,0 { UINT_FLOAT_MIDPOINT }
+    1,85,0 { UINT_FLOAT_MIDPOINT, CONST_SIZE_OF_VAL }
     1,84,0 { CONST_OPTION_AS_SLICE, MANUAL_DANGLING_PTR }
     1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY, CONST_MUT_REFS, CONST_UNWRAP }
     1,82,0 { IS_NONE_OR, REPEAT_N, RAW_REF_OP }
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index e5179e479cc..f37a609497e 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -129,6 +129,7 @@ path_macros! {
 // Paths in `core`/`alloc`/`std`. This should be avoided and cleaned up by adding diagnostic items.
 pub static ALIGN_OF: PathLookup = value_path!(core::mem::align_of);
 pub static CHAR_TO_DIGIT: PathLookup = value_path!(char::to_digit);
+pub static CONCAT: PathLookup = macro_path!(core::concat);
 pub static IO_ERROR_NEW: PathLookup = value_path!(std::io::Error::new);
 pub static IO_ERRORKIND_OTHER_CTOR: PathLookup = value_path!(std::io::ErrorKind::Other);
 pub static ITER_STEP: PathLookup = type_path!(core::iter::Step);
@@ -305,10 +306,13 @@ fn local_item_child_by_name(tcx: TyCtxt<'_>, local_id: LocalDefId, ns: PathNS, n
             let item = tcx.hir_item(item_id);
             if let ItemKind::Use(path, UseKind::Single(ident)) = item.kind {
                 if ident.name == name {
-                    path.res
-                        .iter()
-                        .find(|res| ns.matches(res.ns()))
-                        .and_then(Res::opt_def_id)
+                    let opt_def_id = |ns: Option<Res>| ns.and_then(|res| res.opt_def_id());
+                    match ns {
+                        PathNS::Type => opt_def_id(path.res.type_ns),
+                        PathNS::Value => opt_def_id(path.res.value_ns),
+                        PathNS::Macro => opt_def_id(path.res.macro_ns),
+                        PathNS::Arbitrary => unreachable!(),
+                    }
                 } else {
                     None
                 }
diff --git a/src/tools/clippy/clippy_utils/src/ptr.rs b/src/tools/clippy/clippy_utils/src/ptr.rs
index 360c6251a57..5847e916e34 100644
--- a/src/tools/clippy/clippy_utils/src/ptr.rs
+++ b/src/tools/clippy/clippy_utils/src/ptr.rs
@@ -1,17 +1,17 @@
 use crate::source::snippet;
 use crate::visitors::{Descend, for_each_expr_without_closures};
-use crate::{path_to_local_id, strip_pat_refs};
+use crate::{path_to_local_id, strip_pat_refs, sym};
 use core::ops::ControlFlow;
 use rustc_hir::{Body, BodyId, ExprKind, HirId, PatKind};
 use rustc_lint::LateContext;
-use rustc_span::Span;
+use rustc_span::{Span, Symbol};
 use std::borrow::Cow;
 
 pub fn get_spans(
     cx: &LateContext<'_>,
     opt_body_id: Option<BodyId>,
     idx: usize,
-    replacements: &[(&'static str, &'static str)],
+    replacements: &[(Symbol, &'static str)],
 ) -> Option<Vec<(Span, Cow<'static, str>)>> {
     if let Some(body) = opt_body_id.map(|id| cx.tcx.hir_body(id)) {
         if let PatKind::Binding(_, binding_id, _, _) = strip_pat_refs(body.params[idx].pat).kind {
@@ -27,7 +27,7 @@ pub fn get_spans(
 fn extract_clone_suggestions<'tcx>(
     cx: &LateContext<'tcx>,
     id: HirId,
-    replace: &[(&'static str, &'static str)],
+    replace: &[(Symbol, &'static str)],
     body: &'tcx Body<'_>,
 ) -> Option<Vec<(Span, Cow<'static, str>)>> {
     let mut spans = Vec::new();
@@ -35,11 +35,11 @@ fn extract_clone_suggestions<'tcx>(
         if let ExprKind::MethodCall(seg, recv, [], _) = e.kind
             && path_to_local_id(recv, id)
         {
-            if seg.ident.as_str() == "capacity" {
+            if seg.ident.name == sym::capacity {
                 return ControlFlow::Break(());
             }
             for &(fn_name, suffix) in replace {
-                if seg.ident.as_str() == fn_name {
+                if seg.ident.name == fn_name {
                     spans.push((e.span, snippet(cx, recv.span, "_") + suffix));
                     return ControlFlow::Continue(Descend::No);
                 }
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 45da266fd8a..8e16f943e9f 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
@@ -55,7 +55,7 @@ pub fn is_min_const_fn<'tcx>(cx: &LateContext<'tcx>, body: &Body<'tcx>, msrv: Ms
 
 fn check_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, msrv: Msrv) -> McfResult {
     for arg in ty.walk() {
-        let ty = match arg.unpack() {
+        let ty = match arg.kind() {
             GenericArgKind::Type(ty) => ty,
 
             // No constraints on lifetimes or constants, except potentially
@@ -393,7 +393,8 @@ fn check_terminator<'tcx>(
     }
 }
 
-fn is_stable_const_fn(cx: &LateContext<'_>, def_id: DefId, msrv: Msrv) -> bool {
+/// Checks if the given `def_id` is a stable const fn, in respect to the given MSRV.
+pub fn is_stable_const_fn(cx: &LateContext<'_>, def_id: DefId, msrv: Msrv) -> bool {
     cx.tcx.is_const_fn(def_id)
         && cx
             .tcx
@@ -438,7 +439,7 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx>
             tcx,
             ObligationCause::dummy_with_span(body.span),
             param_env,
-            TraitRef::new(tcx, tcx.require_lang_item(LangItem::Destruct, Some(body.span)), [ty]),
+            TraitRef::new(tcx, tcx.require_lang_item(LangItem::Destruct, body.span), [ty]),
         );
 
         let mut selcx = SelectionContext::new(&infcx);
diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs
index 8645d5730fe..7f2bf99daff 100644
--- a/src/tools/clippy/clippy_utils/src/source.rs
+++ b/src/tools/clippy/clippy_utils/src/source.rs
@@ -7,13 +7,14 @@ use std::sync::Arc;
 use rustc_ast::{LitKind, StrStyle};
 use rustc_errors::Applicability;
 use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource};
+use rustc_lexer::{LiteralKind, TokenKind, tokenize};
 use rustc_lint::{EarlyContext, LateContext};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::source_map::{SourceMap, original_sp};
 use rustc_span::{
-    BytePos, DUMMY_SP, FileNameDisplayPreference, Pos, SourceFile, SourceFileAndLine, Span, SpanData, SyntaxContext,
-    hygiene,
+    BytePos, DUMMY_SP, FileNameDisplayPreference, Pos, RelativeBytePos, SourceFile, SourceFileAndLine, Span, SpanData,
+    SyntaxContext, hygiene,
 };
 use std::borrow::Cow;
 use std::fmt;
@@ -137,25 +138,25 @@ pub trait SpanRangeExt: SpanRange {
     fn map_range(
         self,
         cx: &impl HasSession,
-        f: impl for<'a> FnOnce(&'a str, Range<usize>) -> Option<Range<usize>>,
+        f: impl for<'a> FnOnce(&'a SourceFile, &'a str, Range<usize>) -> Option<Range<usize>>,
     ) -> Option<Range<BytePos>> {
         map_range(cx.sess().source_map(), self.into_range(), f)
     }
 
     #[allow(rustdoc::invalid_rust_codeblocks, reason = "The codeblock is intentionally broken")]
-    /// Extends the range to include all preceding whitespace characters, unless there
-    /// are non-whitespace characters left on the same line after `self`.
+    /// Extends the range to include all preceding whitespace characters.
+    ///
+    /// The range will not be expanded if it would cross a line boundary, the line the range would
+    /// be extended to ends with a line comment and the text after the range contains a
+    /// non-whitespace character on the same line. e.g.
     ///
-    /// This extra condition prevents a problem when removing the '}' in:
     /// ```ignore
-    ///   ( // There was an opening bracket after the parenthesis, which has been removed
-    ///     // This is a comment
-    ///    })
+    /// ( // Some comment
+    /// foo)
     /// ```
-    /// Removing the whitespaces, including the linefeed, before the '}', would put the
-    /// closing parenthesis at the end of the `// This is a comment` line, which would
-    /// make it part of the comment as well. In this case, it is best to keep the span
-    /// on the '}' alone.
+    ///
+    /// When the range points to `foo`, suggesting to remove the range after it's been extended will
+    /// cause the `)` to be placed inside the line comment as `( // Some comment)`.
     fn with_leading_whitespace(self, cx: &impl HasSession) -> Range<BytePos> {
         with_leading_whitespace(cx.sess().source_map(), self.into_range())
     }
@@ -254,11 +255,11 @@ fn with_source_text_and_range<T>(
 fn map_range(
     sm: &SourceMap,
     sp: Range<BytePos>,
-    f: impl for<'a> FnOnce(&'a str, Range<usize>) -> Option<Range<usize>>,
+    f: impl for<'a> FnOnce(&'a SourceFile, &'a str, Range<usize>) -> Option<Range<usize>>,
 ) -> Option<Range<BytePos>> {
     if let Some(src) = get_source_range(sm, sp.clone())
         && let Some(text) = &src.sf.src
-        && let Some(range) = f(text, src.range.clone())
+        && let Some(range) = f(&src.sf, text, src.range.clone())
     {
         debug_assert!(
             range.start <= text.len() && range.end <= text.len(),
@@ -275,20 +276,57 @@ fn map_range(
     }
 }
 
+fn ends_with_line_comment_or_broken(text: &str) -> bool {
+    let Some(last) = tokenize(text).last() else {
+        return false;
+    };
+    match last.kind {
+        // Will give the wrong result on text like `" // "` where the first quote ends a string
+        // started earlier. The only workaround is to lex the whole file which we don't really want
+        // to do.
+        TokenKind::LineComment { .. } | TokenKind::BlockComment { terminated: false, .. } => true,
+        TokenKind::Literal { kind, .. } => matches!(
+            kind,
+            LiteralKind::Byte { terminated: false }
+                | LiteralKind::ByteStr { terminated: false }
+                | LiteralKind::CStr { terminated: false }
+                | LiteralKind::Char { terminated: false }
+                | LiteralKind::RawByteStr { n_hashes: None }
+                | LiteralKind::RawCStr { n_hashes: None }
+                | LiteralKind::RawStr { n_hashes: None }
+        ),
+        _ => false,
+    }
+}
+
+fn with_leading_whitespace_inner(lines: &[RelativeBytePos], src: &str, range: Range<usize>) -> Option<usize> {
+    debug_assert!(lines.is_empty() || lines[0].to_u32() == 0);
+
+    let start = src.get(..range.start)?.trim_end();
+    let next_line = lines.partition_point(|&pos| pos.to_usize() <= start.len());
+    if let Some(line_end) = lines.get(next_line)
+        && line_end.to_usize() <= range.start
+        && let prev_start = lines.get(next_line - 1).map_or(0, |&x| x.to_usize())
+        && ends_with_line_comment_or_broken(&start[prev_start..])
+        && let next_line = lines.partition_point(|&pos| pos.to_usize() < range.end)
+        && let next_start = lines.get(next_line).map_or(src.len(), |&x| x.to_usize())
+        && tokenize(src.get(range.end..next_start)?).any(|t| !matches!(t.kind, TokenKind::Whitespace))
+    {
+        Some(range.start)
+    } else {
+        Some(start.len())
+    }
+}
+
 fn with_leading_whitespace(sm: &SourceMap, sp: Range<BytePos>) -> Range<BytePos> {
-    map_range(sm, sp, |src, range| {
-        let non_blank_after = src.len() - src.get(range.end..)?.trim_start().len();
-        if src.get(range.end..non_blank_after)?.contains(['\r', '\n']) {
-            Some(src.get(..range.start)?.trim_end().len()..range.end)
-        } else {
-            Some(range)
-        }
+    map_range(sm, sp.clone(), |sf, src, range| {
+        Some(with_leading_whitespace_inner(sf.lines(), src, range.clone())?..range.end)
     })
-    .unwrap()
+    .unwrap_or(sp)
 }
 
 fn trim_start(sm: &SourceMap, sp: Range<BytePos>) -> Range<BytePos> {
-    map_range(sm, sp.clone(), |src, range| {
+    map_range(sm, sp.clone(), |_, src, range| {
         let src = src.get(range.clone())?;
         Some(range.start + (src.len() - src.trim_start().len())..range.end)
     })
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index 93dec113d31..6974e6512e2 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -940,7 +940,9 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
                         // note: unable to trigger `Subslice` kind in tests
                         ProjectionKind::Subslice |
                         // Doesn't have surface syntax. Only occurs in patterns.
-                        ProjectionKind::OpaqueCast => (),
+                        ProjectionKind::OpaqueCast |
+                        // Only occurs in closure captures.
+                        ProjectionKind::UnwrapUnsafeBinder => (),
                         ProjectionKind::Deref => {
                             // Explicit derefs are typically handled later on, but
                             // some items do not need explicit deref, such as array accesses,
diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs
index 9428262b99a..f417530be36 100644
--- a/src/tools/clippy/clippy_utils/src/sym.rs
+++ b/src/tools/clippy/clippy_utils/src/sym.rs
@@ -29,172 +29,330 @@ macro_rules! generate {
     };
 }
 
+// List of extra symbols to be included in Clippy (for example, as `sym::ambiguous_glob_reexports`).
+// An alternative content can be specified using a colon after the symbol name.
+//
+// `cargo dev fmt` ensures that the content of the `generate!()` macro call stays sorted.
 generate! {
+    AsyncReadExt,
+    AsyncWriteExt,
+    BACKSLASH_SINGLE_QUOTE: r"\'",
+    Binary,
+    CLIPPY_ARGS,
+    CLIPPY_CONF_DIR,
+    CRLF: "\r\n",
+    Cargo_toml: "Cargo.toml",
+    Current,
+    DOUBLE_QUOTE: "\"",
+    Deserialize,
+    EarlyLintPass,
+    ErrorKind,
+    IntoIter,
+    Itertools,
+    LF: "\n",
+    Lazy,
+    Lint,
+    LowerExp,
+    LowerHex,
+    MAX,
+    MIN,
+    MsrvStack,
+    Octal,
+    OpenOptions,
+    Other,
+    PathLookup,
+    Regex,
+    RegexBuilder,
+    RegexSet,
+    Start,
+    Step,
+    Symbol,
+    SyntaxContext,
+    TBD,
+    UpperExp,
+    UpperHex,
+    V4,
+    V6,
+    Visitor,
+    Weak,
     abs,
     align_of,
     ambiguous_glob_reexports,
+    append,
+    arg,
     as_bytes,
-    as_deref_mut,
     as_deref,
+    as_deref_mut,
     as_mut,
-    AsyncReadExt,
-    AsyncWriteExt,
-    BACKSLASH_SINGLE_QUOTE: r"\'",
-    Binary,
+    assert_failed,
+    author,
+    borrow,
+    borrow_mut,
     build_hasher,
+    by_ref,
     bytes,
+    capacity,
     cargo_clippy: "cargo-clippy",
-    Cargo_toml: "Cargo.toml",
     cast,
+    cast_const,
+    cast_mut,
+    ceil,
+    ceil_char_boundary,
+    chain,
     chars,
-    CLIPPY_ARGS,
-    CLIPPY_CONF_DIR,
+    checked_abs,
+    checked_add,
+    checked_isqrt,
+    checked_mul,
+    checked_pow,
+    checked_rem_euclid,
+    checked_sub,
+    clamp,
     clippy_utils,
     clone_into,
     cloned,
+    cognitive_complexity,
     collect,
     const_ptr,
     contains,
     copied,
-    CRLF: "\r\n",
-    Current,
+    copy_from,
+    copy_from_nonoverlapping,
+    copy_to,
+    copy_to_nonoverlapping,
+    count_ones,
+    cycle,
+    cyclomatic_complexity,
     de,
-    Deserialize,
     diagnostics,
     disallowed_types,
-    DOUBLE_QUOTE: "\"",
-    EarlyLintPass,
+    drain,
+    dump,
     ends_with,
     enum_glob_use,
+    enumerate,
+    err,
     error,
-    ErrorKind,
     exp,
+    expect_err,
+    expn_data,
     extend,
-    finish_non_exhaustive,
+    filter,
+    filter_map,
+    find,
+    find_map,
     finish,
+    finish_non_exhaustive,
+    first,
     flat_map,
+    flatten,
+    floor,
+    floor_char_boundary,
+    fold,
     for_each,
-    from_bytes_with_nul_unchecked,
     from_bytes_with_nul,
+    from_bytes_with_nul_unchecked,
     from_ptr,
     from_raw,
     from_ref,
+    from_str,
     from_str_radix,
     fs,
+    fuse,
     futures_util,
     get,
+    get_mut,
+    get_or_insert_with,
+    get_unchecked,
+    get_unchecked_mut,
+    has_significant_drop,
     hidden_glob_reexports,
     hygiene,
+    if_chain,
     insert,
+    inspect,
     int_roundings,
+    into,
     into_bytes,
+    into_ok,
     into_owned,
-    IntoIter,
     io,
     is_ascii,
+    is_char_boundary,
+    is_digit,
     is_empty,
     is_err,
+    is_file,
     is_none,
     is_ok,
     is_some,
+    isqrt,
     itertools,
-    Itertools,
+    join,
     kw,
     last,
     lazy_static,
-    Lazy,
-    LF: "\n",
-    Lint,
     ln,
+    lock,
     lock_api,
     log,
-    LowerExp,
-    LowerHex,
+    log10,
+    log2,
     macro_use_imports,
-    map_or_else,
+    map_break,
+    map_continue,
     map_or,
+    map_or_else,
+    match_indices,
+    matches,
     max,
-    MAX,
+    max_by,
+    max_by_key,
+    max_value,
+    maximum,
     mem,
     min,
-    MIN,
+    min_by,
+    min_by_key,
+    min_value,
+    minimum,
     mode,
     module_name_repetitions,
     msrv,
     msrvs,
-    MsrvStack,
     mut_ptr,
     mutex,
     needless_return,
+    next_back,
+    next_if,
+    next_if_eq,
     next_tuple,
-    Octal,
+    nth,
+    ok,
+    ok_or,
     once_cell,
-    OpenOptions,
+    open,
     or_default,
-    Other,
+    or_else,
+    or_insert,
+    or_insert_with,
+    outer_expn,
+    panic_cold_display,
+    panic_cold_explicit,
+    panic_display,
+    panic_str,
     parse,
-    PathLookup,
+    partition,
     paths,
+    peek,
+    peek_mut,
+    peekable,
+    pow,
     powf,
     powi,
+    product,
     push,
+    read_line,
+    read_to_end,
+    read_to_string,
     redundant_pub_crate,
     regex,
-    Regex,
-    RegexBuilder,
-    RegexSet,
+    rem_euclid,
+    repeat,
+    replace,
+    replacen,
     reserve,
     resize,
     restriction,
-    rustc_lint_defs,
+    rev,
+    rfind,
+    rmatch_indices,
+    rmatches,
+    round,
+    rposition,
+    rsplit,
+    rsplit_once,
+    rsplit_terminator,
+    rsplitn,
+    rsplitn_mut,
     rustc_lint,
+    rustc_lint_defs,
     rustc_span,
     rustfmt_skip,
     rwlock,
+    saturating_abs,
+    saturating_pow,
+    scan,
+    seek,
     serde,
     set_len,
     set_mode,
     set_readonly,
     signum,
     single_component_path_imports,
+    skip_while,
+    slice_mut_unchecked,
+    slice_unchecked,
+    sort,
+    sort_by,
+    sort_unstable_by,
     span_lint_and_then,
-    split_whitespace,
     split,
+    split_at,
+    split_at_checked,
+    split_at_mut,
+    split_at_mut_checked,
+    split_inclusive,
+    split_once,
+    split_terminator,
+    split_whitespace,
+    splitn,
+    splitn_mut,
     sqrt,
-    Start,
-    Step,
+    starts_with,
+    step_by,
+    strlen,
     style,
+    subsec_micros,
+    subsec_nanos,
+    sum,
     symbol,
-    Symbol,
-    SyntaxContext,
     take,
-    TBD,
+    take_while,
+    then,
     then_some,
     to_ascii_lowercase,
     to_ascii_uppercase,
     to_digit,
     to_lowercase,
+    to_os_string,
     to_owned,
+    to_path_buf,
     to_uppercase,
     tokio,
+    trim,
+    trim_end_matches,
+    trim_start_matches,
     unreachable_pub,
     unsafe_removed_from_name,
+    unused,
     unused_braces,
     unused_extern_crates,
     unused_import_braces,
     unused_trait_names,
-    unused,
     unwrap_err,
+    unwrap_err_unchecked,
     unwrap_or_default,
     unwrap_or_else,
-    UpperExp,
-    UpperHex,
-    V4,
-    V6,
-    Visitor,
+    unwrap_unchecked,
+    unzip,
+    utils,
+    wake,
     warnings,
-    Weak,
     wildcard_imports,
     with_capacity,
     wrapping_offset,
+    write,
+    writeln,
+    zip,
 }
diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs
index 26d41cfb497..61e70b3fa0b 100644
--- a/src/tools/clippy/clippy_utils/src/ty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs
@@ -78,7 +78,7 @@ pub fn can_partially_move_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool
 /// Walks into `ty` and returns `true` if any inner type is an instance of the given adt
 /// constructor.
 pub fn contains_adt_constructor<'tcx>(ty: Ty<'tcx>, adt: AdtDef<'tcx>) -> bool {
-    ty.walk().any(|inner| match inner.unpack() {
+    ty.walk().any(|inner| match inner.kind() {
         GenericArgKind::Type(inner_ty) => inner_ty.ty_adt_def() == Some(adt),
         GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
     })
@@ -96,7 +96,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'
         needle: Ty<'tcx>,
         seen: &mut FxHashSet<DefId>,
     ) -> bool {
-        ty.walk().any(|inner| match inner.unpack() {
+        ty.walk().any(|inner| match inner.kind() {
             GenericArgKind::Type(inner_ty) => {
                 if inner_ty == needle {
                     return true;
@@ -129,7 +129,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'
                             // For `impl Trait<Assoc=U>`, it will register a predicate of `<T as Trait>::Assoc = U`,
                             // so we check the term for `U`.
                             ty::ClauseKind::Projection(projection_predicate) => {
-                                if let ty::TermKind::Ty(ty) = projection_predicate.term.unpack()
+                                if let ty::TermKind::Ty(ty) = projection_predicate.term.kind()
                                     && contains_ty_adt_constructor_opaque_inner(cx, ty, needle, seen)
                                 {
                                     return true;
@@ -526,7 +526,7 @@ pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
             args_a
                 .iter()
                 .zip(args_b.iter())
-                .all(|(arg_a, arg_b)| match (arg_a.unpack(), arg_b.unpack()) {
+                .all(|(arg_a, arg_b)| match (arg_a.kind(), arg_b.kind()) {
                     (GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => inner_a == inner_b,
                     (GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => {
                         same_type_and_consts(type_a, type_b)
@@ -996,7 +996,7 @@ fn assert_generic_args_match<'tcx>(tcx: TyCtxt<'tcx>, did: DefId, args: &[Generi
     if let Some((idx, (param, arg))) =
         params
             .clone()
-            .zip(args.iter().map(|&x| x.unpack()))
+            .zip(args.iter().map(|&x| x.kind()))
             .enumerate()
             .find(|(_, (param, arg))| match (param, arg) {
                 (GenericParamDefKind::Lifetime, GenericArgKind::Lifetime(_))
@@ -1361,3 +1361,14 @@ pub fn is_slice_like<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
         || ty.is_array()
         || matches!(ty.kind(), ty::Adt(adt_def, _) if cx.tcx.is_diagnostic_item(sym::Vec, adt_def.did()))
 }
+
+/// Gets the index of a field by name.
+pub fn get_field_idx_by_name(ty: Ty<'_>, name: Symbol) -> Option<usize> {
+    match *ty.kind() {
+        ty::Adt(def, _) if def.is_union() || def.is_struct() => {
+            def.non_enum_variant().fields.iter().position(|f| f.name == name)
+        },
+        ty::Tuple(_) => name.as_str().parse::<usize>().ok(),
+        _ => None,
+    }
+}
diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
index 6e358662327..84df36c75bf 100644
--- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
@@ -326,5 +326,5 @@ fn adt_def_id(ty: Ty<'_>) -> Option<DefId> {
 
 fn contains_param(ty: Ty<'_>, index: u32) -> bool {
     ty.walk()
-        .any(|arg| matches!(arg.unpack(), GenericArgKind::Type(ty) if ty.is_param(index)))
+        .any(|arg| matches!(arg.kind(), GenericArgKind::Type(ty) if ty.is_param(index)))
 }
diff --git a/src/tools/clippy/lintcheck/src/input.rs b/src/tools/clippy/lintcheck/src/input.rs
index 83eb0a577d6..408a2e087af 100644
--- a/src/tools/clippy/lintcheck/src/input.rs
+++ b/src/tools/clippy/lintcheck/src/input.rs
@@ -8,7 +8,7 @@ use std::time::Duration;
 use serde::Deserialize;
 use walkdir::{DirEntry, WalkDir};
 
-use crate::{Crate, LINTCHECK_DOWNLOADS, LINTCHECK_SOURCES};
+use crate::{Crate, lintcheck_sources, target_dir};
 
 const DEFAULT_DOCS_LINK: &str = "https://docs.rs/{krate}/{version}/src/{krate_}/{file}.html#{line}";
 const DEFAULT_GITHUB_LINK: &str = "{url}/blob/{hash}/src/{file}#L{line}";
@@ -201,8 +201,10 @@ impl CrateWithSource {
         let file_link = &self.file_link;
         match &self.source {
             CrateSource::CratesIo { version } => {
-                let extract_dir = PathBuf::from(LINTCHECK_SOURCES);
-                let krate_download_dir = PathBuf::from(LINTCHECK_DOWNLOADS);
+                let extract_dir = PathBuf::from(lintcheck_sources());
+                // Keep constant downloads path to avoid repeating work and
+                // filling up disk space unnecessarily.
+                let krate_download_dir = PathBuf::from("target/lintcheck/downloads/");
 
                 // url to download the crate from crates.io
                 let url = format!("https://crates.io/api/v1/crates/{name}/{version}/download");
@@ -211,7 +213,7 @@ impl CrateWithSource {
 
                 let krate_file_path = krate_download_dir.join(format!("{name}-{version}.crate.tar.gz"));
                 // don't download/extract if we already have done so
-                if !krate_file_path.is_file() {
+                if !krate_file_path.is_file() || !extract_dir.join(format!("{name}-{version}")).exists() {
                     // create a file path to download and write the crate data into
                     let mut krate_dest = fs::File::create(&krate_file_path).unwrap();
                     let mut krate_req = get(&url).unwrap().into_reader();
@@ -236,7 +238,7 @@ impl CrateWithSource {
             },
             CrateSource::Git { url, commit } => {
                 let repo_path = {
-                    let mut repo_path = PathBuf::from(LINTCHECK_SOURCES);
+                    let mut repo_path = PathBuf::from(lintcheck_sources());
                     // add a -git suffix in case we have the same crate from crates.io and a git repo
                     repo_path.push(format!("{name}-git"));
                     repo_path
@@ -286,7 +288,7 @@ impl CrateWithSource {
                 // copy path into the dest_crate_root but skip directories that contain a CACHEDIR.TAG file.
                 // The target/ directory contains a CACHEDIR.TAG file so it is the most commonly skipped directory
                 // as a result of this filter.
-                let dest_crate_root = PathBuf::from(LINTCHECK_SOURCES).join(name);
+                let dest_crate_root = PathBuf::from(lintcheck_sources()).join(name);
                 if dest_crate_root.exists() {
                     println!("Deleting existing directory at `{}`", dest_crate_root.display());
                     fs::remove_dir_all(&dest_crate_root).unwrap();
@@ -326,15 +328,16 @@ impl CrateWithSource {
 ///
 /// This function panics if creating one of the dirs fails.
 fn create_dirs(krate_download_dir: &Path, extract_dir: &Path) {
-    fs::create_dir("target/lintcheck/").unwrap_or_else(|err| {
+    fs::create_dir(format!("{}/lintcheck/", target_dir())).unwrap_or_else(|err| {
         assert_eq!(
             err.kind(),
             ErrorKind::AlreadyExists,
             "cannot create lintcheck target dir"
         );
     });
-    fs::create_dir(krate_download_dir).unwrap_or_else(|err| {
-        assert_eq!(err.kind(), ErrorKind::AlreadyExists, "cannot create crate download dir");
+    fs::create_dir_all(krate_download_dir).unwrap_or_else(|err| {
+        // We are allowed to reuse download dirs
+        assert_ne!(err.kind(), ErrorKind::AlreadyExists);
     });
     fs::create_dir(extract_dir).unwrap_or_else(|err| {
         assert_eq!(
diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs
index d4bf6cd48a1..84183831432 100644
--- a/src/tools/clippy/lintcheck/src/main.rs
+++ b/src/tools/clippy/lintcheck/src/main.rs
@@ -43,8 +43,14 @@ use input::read_crates;
 use output::{ClippyCheckOutput, ClippyWarning, RustcIce};
 use rayon::prelude::*;
 
-const LINTCHECK_DOWNLOADS: &str = "target/lintcheck/downloads";
-const LINTCHECK_SOURCES: &str = "target/lintcheck/sources";
+#[must_use]
+pub fn target_dir() -> String {
+    env::var("CARGO_TARGET_DIR").unwrap_or("target".to_owned())
+}
+
+fn lintcheck_sources() -> String {
+    format!("{}/lintcheck/sources", target_dir())
+}
 
 /// Represents the actual source code of a crate that we ran "cargo clippy" on
 #[derive(Debug)]
@@ -307,7 +313,8 @@ fn main() {
 fn lintcheck(config: LintcheckConfig) {
     let clippy_ver = build_clippy(config.perf);
     let clippy_driver_path = fs::canonicalize(format!(
-        "target/{}/clippy-driver{EXE_SUFFIX}",
+        "{}/{}/clippy-driver{EXE_SUFFIX}",
+        target_dir(),
         if config.perf { "release" } else { "debug" }
     ))
     .unwrap();
@@ -315,7 +322,8 @@ fn lintcheck(config: LintcheckConfig) {
     // assert that clippy is found
     assert!(
         clippy_driver_path.is_file(),
-        "target/{}/clippy-driver binary not found! {}",
+        "{}/{}/clippy-driver binary not found! {}",
+        target_dir(),
         if config.perf { "release" } else { "debug" },
         clippy_driver_path.display()
     );
@@ -386,7 +394,7 @@ fn lintcheck(config: LintcheckConfig) {
         .unwrap();
 
     let server = config.recursive.then(|| {
-        let _: io::Result<()> = fs::remove_dir_all("target/lintcheck/shared_target_dir/recursive");
+        let _: io::Result<()> = fs::remove_dir_all(format!("{}/lintcheck/shared_target_dir/recursive", target_dir()));
 
         LintcheckServer::spawn(recursive_options)
     });
@@ -488,7 +496,7 @@ fn clippy_project_root() -> &'static Path {
 #[must_use]
 fn shared_target_dir(qualifier: &str) -> PathBuf {
     clippy_project_root()
-        .join("target/lintcheck/shared_target_dir")
+        .join(format!("{}/lintcheck/shared_target_dir", target_dir()))
         .join(qualifier)
 }
 
diff --git a/src/tools/clippy/lintcheck/src/output.rs b/src/tools/clippy/lintcheck/src/output.rs
index dcc1ec339ef..d7fe0915121 100644
--- a/src/tools/clippy/lintcheck/src/output.rs
+++ b/src/tools/clippy/lintcheck/src/output.rs
@@ -162,9 +162,9 @@ pub fn summarize_and_print_changes(
 fn gather_stats(warnings: &[ClippyWarning]) -> (String, HashMap<&String, usize>) {
     // count lint type occurrences
     let mut counter: HashMap<&String, usize> = HashMap::new();
-    warnings
-        .iter()
-        .for_each(|wrn| *counter.entry(&wrn.name).or_insert(0) += 1);
+    for wrn in warnings {
+        *counter.entry(&wrn.name).or_insert(0) += 1;
+    }
 
     // collect into a tupled list for sorting
     let mut stats: Vec<(&&String, &usize)> = counter.iter().collect();
diff --git a/src/tools/clippy/rust-toolchain.toml b/src/tools/clippy/rust-toolchain.toml
index da41bdd27bc..b6817d9a146 100644
--- a/src/tools/clippy/rust-toolchain.toml
+++ b/src/tools/clippy/rust-toolchain.toml
@@ -1,6 +1,6 @@
 [toolchain]
 # begin autogenerated nightly
-channel = "nightly-2025-05-14"
+channel = "nightly-2025-05-31"
 # end autogenerated nightly
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
 profile = "minimal"
diff --git a/src/tools/clippy/rustfmt.toml b/src/tools/clippy/rustfmt.toml
index 0dc6adce7bf..0ed58a2dfc1 100644
--- a/src/tools/clippy/rustfmt.toml
+++ b/src/tools/clippy/rustfmt.toml
@@ -6,4 +6,8 @@ edition = "2024"
 error_on_line_overflow = true
 imports_granularity = "Module"
 style_edition = "2024"
-ignore = ["tests/ui/crashes/ice-10912.rs"]
+ignore = [
+    "tests/ui/crashes/ice-9405.rs",
+    "tests/ui/crashes/ice-10912.rs",
+    "tests/ui/non_expressive_names_error_recovery.rs",
+]
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index f8acf88cf81..37adb14169a 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -96,16 +96,11 @@ fn track_files(psess: &mut ParseSess) {
 
     // During development track the `clippy-driver` executable so that cargo will re-run clippy whenever
     // it is rebuilt
-    #[expect(
-        clippy::collapsible_if,
-        reason = "Due to a bug in let_chains this if statement can't be collapsed"
-    )]
-    if cfg!(debug_assertions) {
-        if let Ok(current_exe) = env::current_exe()
-            && let Some(current_exe) = current_exe.to_str()
-        {
-            file_depinfo.insert(Symbol::intern(current_exe));
-        }
+    if cfg!(debug_assertions)
+        && let Ok(current_exe) = env::current_exe()
+        && let Some(current_exe) = current_exe.to_str()
+    {
+        file_depinfo.insert(Symbol::intern(current_exe));
     }
 }
 
diff --git a/src/tools/clippy/tests/headers.rs b/src/tools/clippy/tests/headers.rs
deleted file mode 100644
index d1f986ef526..00000000000
--- a/src/tools/clippy/tests/headers.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-use regex::Regex;
-use std::fs;
-use walkdir::WalkDir;
-
-#[test]
-fn old_test_headers() {
-    let old_headers = Regex::new(
-        r"^//( ?\[\w+\])? ?((check|build|run|ignore|aux|only|needs|rustc|unset|no|normalize|run|compile)-|edition|incremental|revisions).*",
-    )
-    .unwrap();
-    let mut failed = false;
-
-    for entry in WalkDir::new("tests") {
-        let entry = entry.unwrap();
-        let is_hidden_file = entry
-            .file_name()
-            .to_str()
-            .expect("non-UTF-8 file name")
-            .starts_with('.');
-        if is_hidden_file || !entry.file_type().is_file() {
-            continue;
-        }
-
-        let file = fs::read_to_string(entry.path()).unwrap_or_else(|err| panic!("{}: {err}", entry.path().display()));
-
-        if let Some(header) = old_headers.find(&file) {
-            println!("Found header `{}` in {}", header.as_str(), entry.path().display());
-
-            failed = true;
-        }
-    }
-
-    assert!(!failed, "use `//@foo` style test headers instead");
-}
diff --git a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default.stderr b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default.stderr
index 50567e32b1b..a3c35a31c33 100644
--- a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default.stderr
+++ b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default.stderr
@@ -13,37 +13,37 @@ LL | const SNAKE_CASE: &str = "zzzzzzzz";
    = help: to override `-D warnings` add `#[allow(clippy::arbitrary_source_item_ordering)]`
 
 error: incorrect ordering of items (module item groupings specify another order)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:149:7
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:165:7
    |
 LL | const ZIS_SHOULD_BE_REALLY_EARLY: () = ();
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: should be placed before `TraitUnorderedItemKinds`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:136:7
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:152:7
    |
 LL | trait TraitUnorderedItemKinds {
    |       ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: incorrect ordering of items (module item groupings specify another order)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:188:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:204:5
    |
 LL | mod this_is_in_the_wrong_position {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: should be placed before `main`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:183:4
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:199:4
    |
 LL | fn main() {
    |    ^^^^
 
 error: incorrect ordering of items (module item groupings specify another order)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:198:7
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:214:7
    |
 LL | const ZIS_SHOULD_BE_EVEN_EARLIER: () = ();
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: should be placed before `ZisShouldBeBeforeZeMainFn`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:196:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:212:8
    |
 LL | struct ZisShouldBeBeforeZeMainFn;
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -61,100 +61,124 @@ LL |     C,
    |     ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:96:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:57:5
+   |
+LL |     g: u8,
+   |     ^
+   |
+note: should be placed before `r`
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:56:5
+   |
+LL |     r: u8,
+   |     ^
+
+error: incorrect ordering of items (must be alphabetically ordered)
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:59:5
+   |
+LL |     b: u8,
+   |     ^
+   |
+note: should be placed before `g`
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:57:5
+   |
+LL |     g: u8,
+   |     ^
+
+error: incorrect ordering of items (must be alphabetically ordered)
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:112:5
    |
 LL |     b: bool,
    |     ^
    |
 note: should be placed before `c`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:95:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:111:5
    |
 LL |     c: bool,
    |     ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:105:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:121:5
    |
 LL |     b: bool,
    |     ^
    |
 note: should be placed before `c`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:104:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:120:5
    |
 LL |     c: bool,
    |     ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:125:11
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:141:11
    |
 LL |     const B: bool;
    |           ^
    |
 note: should be placed before `C`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:124:11
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:140:11
    |
 LL |     const C: bool;
    |           ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:132:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:148:8
    |
 LL |     fn b();
    |        ^
    |
 note: should be placed before `c`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:131:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:147:8
    |
 LL |     fn c();
    |        ^
 
 error: incorrect ordering of trait items (defined order: [Const, Type, Fn])
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:139:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:155:5
    |
 LL |     const A: bool;
    |     ^^^^^^^^^^^^^^
    |
 note: should be placed before `SomeType`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:137:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:153:5
    |
 LL |     type SomeType;
    |     ^^^^^^^^^^^^^^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:155:11
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:171:11
    |
 LL |     const B: bool = false;
    |           ^
    |
 note: should be placed before `C`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:154:11
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:170:11
    |
 LL |     const C: bool = false;
    |           ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:162:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:178:8
    |
 LL |     fn b() {}
    |        ^
    |
 note: should be placed before `c`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:161:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:177:8
    |
 LL |     fn c() {}
    |        ^
 
 error: incorrect ordering of impl items (defined order: [Const, Type, Fn])
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:173:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:189:5
    |
 LL |     const A: bool = false;
    |     ^^^^^^^^^^^^^^^^^^^^^^
    |
 note: should be placed before `SomeType`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:171:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:187:5
    |
 LL |     type SomeType = ();
    |     ^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 13 previous errors
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default_exp.stderr b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default_exp.stderr
index 50567e32b1b..a3c35a31c33 100644
--- a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default_exp.stderr
+++ b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default_exp.stderr
@@ -13,37 +13,37 @@ LL | const SNAKE_CASE: &str = "zzzzzzzz";
    = help: to override `-D warnings` add `#[allow(clippy::arbitrary_source_item_ordering)]`
 
 error: incorrect ordering of items (module item groupings specify another order)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:149:7
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:165:7
    |
 LL | const ZIS_SHOULD_BE_REALLY_EARLY: () = ();
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: should be placed before `TraitUnorderedItemKinds`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:136:7
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:152:7
    |
 LL | trait TraitUnorderedItemKinds {
    |       ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: incorrect ordering of items (module item groupings specify another order)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:188:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:204:5
    |
 LL | mod this_is_in_the_wrong_position {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: should be placed before `main`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:183:4
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:199:4
    |
 LL | fn main() {
    |    ^^^^
 
 error: incorrect ordering of items (module item groupings specify another order)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:198:7
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:214:7
    |
 LL | const ZIS_SHOULD_BE_EVEN_EARLIER: () = ();
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: should be placed before `ZisShouldBeBeforeZeMainFn`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:196:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:212:8
    |
 LL | struct ZisShouldBeBeforeZeMainFn;
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -61,100 +61,124 @@ LL |     C,
    |     ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:96:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:57:5
+   |
+LL |     g: u8,
+   |     ^
+   |
+note: should be placed before `r`
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:56:5
+   |
+LL |     r: u8,
+   |     ^
+
+error: incorrect ordering of items (must be alphabetically ordered)
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:59:5
+   |
+LL |     b: u8,
+   |     ^
+   |
+note: should be placed before `g`
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:57:5
+   |
+LL |     g: u8,
+   |     ^
+
+error: incorrect ordering of items (must be alphabetically ordered)
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:112:5
    |
 LL |     b: bool,
    |     ^
    |
 note: should be placed before `c`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:95:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:111:5
    |
 LL |     c: bool,
    |     ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:105:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:121:5
    |
 LL |     b: bool,
    |     ^
    |
 note: should be placed before `c`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:104:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:120:5
    |
 LL |     c: bool,
    |     ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:125:11
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:141:11
    |
 LL |     const B: bool;
    |           ^
    |
 note: should be placed before `C`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:124:11
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:140:11
    |
 LL |     const C: bool;
    |           ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:132:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:148:8
    |
 LL |     fn b();
    |        ^
    |
 note: should be placed before `c`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:131:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:147:8
    |
 LL |     fn c();
    |        ^
 
 error: incorrect ordering of trait items (defined order: [Const, Type, Fn])
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:139:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:155:5
    |
 LL |     const A: bool;
    |     ^^^^^^^^^^^^^^
    |
 note: should be placed before `SomeType`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:137:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:153:5
    |
 LL |     type SomeType;
    |     ^^^^^^^^^^^^^^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:155:11
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:171:11
    |
 LL |     const B: bool = false;
    |           ^
    |
 note: should be placed before `C`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:154:11
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:170:11
    |
 LL |     const C: bool = false;
    |           ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:162:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:178:8
    |
 LL |     fn b() {}
    |        ^
    |
 note: should be placed before `c`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:161:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:177:8
    |
 LL |     fn c() {}
    |        ^
 
 error: incorrect ordering of impl items (defined order: [Const, Type, Fn])
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:173:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:189:5
    |
 LL |     const A: bool = false;
    |     ^^^^^^^^^^^^^^^^^^^^^^
    |
 note: should be placed before `SomeType`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:171:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:187:5
    |
 LL |     type SomeType = ();
    |     ^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 13 previous errors
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.ord_within.stderr b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.ord_within.stderr
index ae5261dcc6d..3fdd706fc62 100644
--- a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.ord_within.stderr
+++ b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.ord_within.stderr
@@ -25,7 +25,19 @@ LL | const SNAKE_CASE: &str = "zzzzzzzz";
    |       ^^^^^^^^^^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:71:1
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:64:8
+   |
+LL | struct EnumWithExternButAtWrongPosition {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: should be placed before `EnumWithoutExtern`
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:55:8
+   |
+LL | struct EnumWithoutExtern {
+   |        ^^^^^^^^^^^^^^^^^
+
+error: incorrect ordering of items (must be alphabetically ordered)
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:87:1
    |
 LL | / impl CloneSelf for StructOrdered {
 LL | |
@@ -36,7 +48,7 @@ LL | | }
    | |_^
    |
 note: should be placed before the following item
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:61:1
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:77:1
    |
 LL | / impl Default for StructOrdered {
 LL | |     fn default() -> Self {
@@ -47,25 +59,25 @@ LL | | }
    | |_^
 
 error: incorrect ordering of items (module item groupings specify another order)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:149:7
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:165:7
    |
 LL | const ZIS_SHOULD_BE_REALLY_EARLY: () = ();
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: should be placed before `TraitUnorderedItemKinds`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:136:7
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:152:7
    |
 LL | trait TraitUnorderedItemKinds {
    |       ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:167:1
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:183:1
    |
 LL | impl BasicEmptyTrait for StructOrdered {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: should be placed before the following item
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:152:1
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:168:1
    |
 LL | / impl TraitUnordered for StructUnordered {
 LL | |     const A: bool = false;
@@ -76,25 +88,25 @@ LL | | }
    | |_^
 
 error: incorrect ordering of items (module item groupings specify another order)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:188:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:204:5
    |
 LL | mod this_is_in_the_wrong_position {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: should be placed before `main`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:183:4
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:199:4
    |
 LL | fn main() {
    |    ^^^^
 
 error: incorrect ordering of items (module item groupings specify another order)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:198:7
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:214:7
    |
 LL | const ZIS_SHOULD_BE_EVEN_EARLIER: () = ();
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: should be placed before `ZisShouldBeBeforeZeMainFn`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:196:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:212:8
    |
 LL | struct ZisShouldBeBeforeZeMainFn;
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -124,112 +136,136 @@ LL |     C,
    |     ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:96:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:57:5
+   |
+LL |     g: u8,
+   |     ^
+   |
+note: should be placed before `r`
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:56:5
+   |
+LL |     r: u8,
+   |     ^
+
+error: incorrect ordering of items (must be alphabetically ordered)
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:59:5
+   |
+LL |     b: u8,
+   |     ^
+   |
+note: should be placed before `g`
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:57:5
+   |
+LL |     g: u8,
+   |     ^
+
+error: incorrect ordering of items (must be alphabetically ordered)
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:112:5
    |
 LL |     b: bool,
    |     ^
    |
 note: should be placed before `c`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:95:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:111:5
    |
 LL |     c: bool,
    |     ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:105:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:121:5
    |
 LL |     b: bool,
    |     ^
    |
 note: should be placed before `c`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:104:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:120:5
    |
 LL |     c: bool,
    |     ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:125:11
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:141:11
    |
 LL |     const B: bool;
    |           ^
    |
 note: should be placed before `C`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:124:11
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:140:11
    |
 LL |     const C: bool;
    |           ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:132:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:148:8
    |
 LL |     fn b();
    |        ^
    |
 note: should be placed before `c`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:131:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:147:8
    |
 LL |     fn c();
    |        ^
 
 error: incorrect ordering of trait items (defined order: [Const, Type, Fn])
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:139:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:155:5
    |
 LL |     const A: bool;
    |     ^^^^^^^^^^^^^^
    |
 note: should be placed before `SomeType`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:137:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:153:5
    |
 LL |     type SomeType;
    |     ^^^^^^^^^^^^^^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:155:11
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:171:11
    |
 LL |     const B: bool = false;
    |           ^
    |
 note: should be placed before `C`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:154:11
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:170:11
    |
 LL |     const C: bool = false;
    |           ^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:162:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:178:8
    |
 LL |     fn b() {}
    |        ^
    |
 note: should be placed before `c`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:161:8
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:177:8
    |
 LL |     fn c() {}
    |        ^
 
 error: incorrect ordering of impl items (defined order: [Const, Type, Fn])
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:173:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:189:5
    |
 LL |     const A: bool = false;
    |     ^^^^^^^^^^^^^^^^^^^^^^
    |
 note: should be placed before `SomeType`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:171:5
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:187:5
    |
 LL |     type SomeType = ();
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: incorrect ordering of items (must be alphabetically ordered)
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:191:11
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:207:11
    |
 LL |     const A: i8 = 1;
    |           ^
    |
 note: should be placed before `C`
-  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:190:11
+  --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:206:11
    |
 LL |     const C: i8 = 0;
    |           ^
 
-error: aborting due to 18 previous errors
+error: aborting due to 21 previous errors
 
diff --git a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs
index 90399470d4c..1cfed9790c1 100644
--- a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs
+++ b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs
@@ -52,6 +52,22 @@ enum EnumUnorderedAllowed {
     B,
 }
 
+struct EnumWithoutExtern {
+    r: u8,
+    g: u8,
+    //~^ arbitrary_source_item_ordering
+    b: u8,
+    //~^ arbitrary_source_item_ordering
+}
+
+#[repr(C)]
+struct EnumWithExternButAtWrongPosition {
+    //~[ord_within]^ arbitrary_source_item_ordering
+    r: u8,
+    g: u8,
+    b: u8,
+}
+
 struct StructOrdered {
     a: bool,
     b: bool,
diff --git a/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if.fixed b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if.fixed
index 6f5cc47ba6c..f695f9804d5 100644
--- a/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if.fixed
+++ b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if.fixed
@@ -13,7 +13,7 @@ fn main() {
     //~^^^^^^ collapsible_if
 
     // The following tests check for the fix of https://github.com/rust-lang/rust-clippy/issues/798
-    if x == "hello"  // Inner comment
+    if x == "hello" // Inner comment
         && y == "world" {
             println!("Hello world!");
         }
@@ -26,7 +26,7 @@ fn main() {
         }
     //~^^^^^^ collapsible_if
 
-    if x == "hello"  /* Inner comment */
+    if x == "hello" /* Inner comment */
         && y == "world" {
             println!("Hello world!");
         }
diff --git a/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if.stderr b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if.stderr
index 357ce4ad32d..a12c2112f58 100644
--- a/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if.stderr
+++ b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if.stderr
@@ -32,7 +32,7 @@ LL | |     }
    |
 help: collapse nested if block
    |
-LL ~     if x == "hello"  // Inner comment
+LL ~     if x == "hello" // Inner comment
 LL ~         && y == "world" {
 LL |             println!("Hello world!");
 LL ~         }
@@ -70,7 +70,7 @@ LL | |     }
    |
 help: collapse nested if block
    |
-LL ~     if x == "hello"  /* Inner comment */
+LL ~     if x == "hello" /* Inner comment */
 LL ~         && y == "world" {
 LL |             println!("Hello world!");
 LL ~         }
diff --git a/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs b/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs
index e953a2a4e90..2a6097fb579 100644
--- a/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs
+++ b/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs
@@ -11,9 +11,9 @@ fn issue10272() {
     // should trigger warning
     let x = Cell::new(true);
     if x.get() {
+        //~^ ifs_same_cond
     } else if !x.take() {
     } else if x.get() {
-        //~^ ifs_same_cond
     } else {
     }
 }
diff --git a/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr b/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr
index d67e7fca656..adc44358c4c 100644
--- a/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr
+++ b/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.stderr
@@ -1,14 +1,12 @@
-error: this `if` has the same condition as a previous `if`
-  --> tests/ui-toml/ifs_same_cond/ifs_same_cond.rs:15:15
-   |
-LL |     } else if x.get() {
-   |               ^^^^^^^
-   |
-note: same as this
+error: these `if` branches have the same condition
   --> tests/ui-toml/ifs_same_cond/ifs_same_cond.rs:13:8
    |
 LL |     if x.get() {
    |        ^^^^^^^
+...
+LL |     } else if x.get() {
+   |               ^^^^^^^
+   |
    = note: `-D clippy::ifs-same-cond` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::ifs_same_cond)]`
 
diff --git a/src/tools/clippy/tests/ui/assign_ops.fixed b/src/tools/clippy/tests/ui/assign_ops.fixed
index 18f0e04a880..3bc6885d7c3 100644
--- a/src/tools/clippy/tests/ui/assign_ops.fixed
+++ b/src/tools/clippy/tests/ui/assign_ops.fixed
@@ -1,7 +1,10 @@
+#![allow(clippy::useless_vec)]
+#![warn(clippy::assign_op_pattern)]
+#![feature(const_trait_impl, const_ops)]
+
 use core::num::Wrapping;
+use std::ops::{Mul, MulAssign};
 
-#[allow(dead_code, unused_assignments, clippy::useless_vec)]
-#[warn(clippy::assign_op_pattern)]
 fn main() {
     let mut a = 5;
     a += 1;
@@ -39,3 +42,65 @@ fn main() {
     v[0] = v[0] + v[1];
     let _ = || v[0] = v[0] + v[1];
 }
+
+fn cow_add_assign() {
+    use std::borrow::Cow;
+    let mut buf = Cow::Owned(String::from("bar"));
+    let cows = Cow::Borrowed("foo");
+
+    // this can be linted
+    buf += cows.clone();
+    //~^ assign_op_pattern
+
+    // this should not as cow<str> Add is not commutative
+    buf = cows + buf;
+}
+
+// check that we don't lint on op assign impls, because that's just the way to impl them
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub struct Wrap(i64);
+
+impl Mul<i64> for Wrap {
+    type Output = Self;
+
+    fn mul(self, rhs: i64) -> Self {
+        Wrap(self.0 * rhs)
+    }
+}
+
+impl MulAssign<i64> for Wrap {
+    fn mul_assign(&mut self, rhs: i64) {
+        *self = *self * rhs
+    }
+}
+
+mod issue14871 {
+
+    use std::ops::{Add, AddAssign};
+
+    pub trait Number: Copy + Add<Self, Output = Self> + AddAssign {
+        const ZERO: Self;
+        const ONE: Self;
+    }
+
+    #[const_trait]
+    pub trait NumberConstants {
+        fn constant(value: usize) -> Self;
+    }
+
+    impl<T> const NumberConstants for T
+    where
+        T: Number + ~const core::ops::Add,
+    {
+        fn constant(value: usize) -> Self {
+            let mut res = Self::ZERO;
+            let mut count = 0;
+            while count < value {
+                res = res + Self::ONE;
+                count += 1;
+            }
+            res
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/assign_ops.rs b/src/tools/clippy/tests/ui/assign_ops.rs
index 8b05c74d860..f1f8f9daff9 100644
--- a/src/tools/clippy/tests/ui/assign_ops.rs
+++ b/src/tools/clippy/tests/ui/assign_ops.rs
@@ -1,7 +1,10 @@
+#![allow(clippy::useless_vec)]
+#![warn(clippy::assign_op_pattern)]
+#![feature(const_trait_impl, const_ops)]
+
 use core::num::Wrapping;
+use std::ops::{Mul, MulAssign};
 
-#[allow(dead_code, unused_assignments, clippy::useless_vec)]
-#[warn(clippy::assign_op_pattern)]
 fn main() {
     let mut a = 5;
     a = a + 1;
@@ -39,3 +42,65 @@ fn main() {
     v[0] = v[0] + v[1];
     let _ = || v[0] = v[0] + v[1];
 }
+
+fn cow_add_assign() {
+    use std::borrow::Cow;
+    let mut buf = Cow::Owned(String::from("bar"));
+    let cows = Cow::Borrowed("foo");
+
+    // this can be linted
+    buf = buf + cows.clone();
+    //~^ assign_op_pattern
+
+    // this should not as cow<str> Add is not commutative
+    buf = cows + buf;
+}
+
+// check that we don't lint on op assign impls, because that's just the way to impl them
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub struct Wrap(i64);
+
+impl Mul<i64> for Wrap {
+    type Output = Self;
+
+    fn mul(self, rhs: i64) -> Self {
+        Wrap(self.0 * rhs)
+    }
+}
+
+impl MulAssign<i64> for Wrap {
+    fn mul_assign(&mut self, rhs: i64) {
+        *self = *self * rhs
+    }
+}
+
+mod issue14871 {
+
+    use std::ops::{Add, AddAssign};
+
+    pub trait Number: Copy + Add<Self, Output = Self> + AddAssign {
+        const ZERO: Self;
+        const ONE: Self;
+    }
+
+    #[const_trait]
+    pub trait NumberConstants {
+        fn constant(value: usize) -> Self;
+    }
+
+    impl<T> const NumberConstants for T
+    where
+        T: Number + ~const core::ops::Add,
+    {
+        fn constant(value: usize) -> Self {
+            let mut res = Self::ZERO;
+            let mut count = 0;
+            while count < value {
+                res = res + Self::ONE;
+                count += 1;
+            }
+            res
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/assign_ops.stderr b/src/tools/clippy/tests/ui/assign_ops.stderr
index 17f216ee4a0..c5e698b3ee1 100644
--- a/src/tools/clippy/tests/ui/assign_ops.stderr
+++ b/src/tools/clippy/tests/ui/assign_ops.stderr
@@ -1,5 +1,5 @@
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:7:5
+  --> tests/ui/assign_ops.rs:10:5
    |
 LL |     a = a + 1;
    |     ^^^^^^^^^ help: replace it with: `a += 1`
@@ -8,64 +8,70 @@ LL |     a = a + 1;
    = help: to override `-D warnings` add `#[allow(clippy::assign_op_pattern)]`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:9:5
+  --> tests/ui/assign_ops.rs:12:5
    |
 LL |     a = 1 + a;
    |     ^^^^^^^^^ help: replace it with: `a += 1`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:11:5
+  --> tests/ui/assign_ops.rs:14:5
    |
 LL |     a = a - 1;
    |     ^^^^^^^^^ help: replace it with: `a -= 1`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:13:5
+  --> tests/ui/assign_ops.rs:16:5
    |
 LL |     a = a * 99;
    |     ^^^^^^^^^^ help: replace it with: `a *= 99`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:15:5
+  --> tests/ui/assign_ops.rs:18:5
    |
 LL |     a = 42 * a;
    |     ^^^^^^^^^^ help: replace it with: `a *= 42`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:17:5
+  --> tests/ui/assign_ops.rs:20:5
    |
 LL |     a = a / 2;
    |     ^^^^^^^^^ help: replace it with: `a /= 2`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:19:5
+  --> tests/ui/assign_ops.rs:22:5
    |
 LL |     a = a % 5;
    |     ^^^^^^^^^ help: replace it with: `a %= 5`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:21:5
+  --> tests/ui/assign_ops.rs:24:5
    |
 LL |     a = a & 1;
    |     ^^^^^^^^^ help: replace it with: `a &= 1`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:28:5
+  --> tests/ui/assign_ops.rs:31:5
    |
 LL |     s = s + "bla";
    |     ^^^^^^^^^^^^^ help: replace it with: `s += "bla"`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:33:5
+  --> tests/ui/assign_ops.rs:36:5
    |
 LL |     a = a + Wrapping(1u32);
    |     ^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a += Wrapping(1u32)`
 
 error: manual implementation of an assign operation
-  --> tests/ui/assign_ops.rs:36:5
+  --> tests/ui/assign_ops.rs:39:5
    |
 LL |     v[0] = v[0] + v[1];
    |     ^^^^^^^^^^^^^^^^^^ help: replace it with: `v[0] += v[1]`
 
-error: aborting due to 11 previous errors
+error: manual implementation of an assign operation
+  --> tests/ui/assign_ops.rs:52:5
+   |
+LL |     buf = buf + cows.clone();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `buf += cows.clone()`
+
+error: aborting due to 12 previous errors
 
diff --git a/src/tools/clippy/tests/ui/assign_ops2.rs b/src/tools/clippy/tests/ui/assign_ops2.rs
deleted file mode 100644
index 51867fa6962..00000000000
--- a/src/tools/clippy/tests/ui/assign_ops2.rs
+++ /dev/null
@@ -1,77 +0,0 @@
-//@no-rustfix: overlapping suggestions
-#![allow(clippy::uninlined_format_args)]
-
-#[allow(unused_assignments)]
-#[warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)]
-fn main() {
-    let mut a = 5;
-    a += a + 1;
-    //~^ misrefactored_assign_op
-
-    a += 1 + a;
-    //~^ misrefactored_assign_op
-
-    a -= a - 1;
-    //~^ misrefactored_assign_op
-
-    a *= a * 99;
-    //~^ misrefactored_assign_op
-
-    a *= 42 * a;
-    //~^ misrefactored_assign_op
-
-    a /= a / 2;
-    //~^ misrefactored_assign_op
-
-    a %= a % 5;
-    //~^ misrefactored_assign_op
-
-    a &= a & 1;
-    //~^ misrefactored_assign_op
-
-    a *= a * a;
-    //~^ misrefactored_assign_op
-
-    a = a * a * a;
-    a = a * 42 * a;
-    a = a * 2 + a;
-    a -= 1 - a;
-    a /= 5 / a;
-    a %= 42 % a;
-    a <<= 6 << a;
-}
-
-// check that we don't lint on op assign impls, because that's just the way to impl them
-
-use std::ops::{Mul, MulAssign};
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub struct Wrap(i64);
-
-impl Mul<i64> for Wrap {
-    type Output = Self;
-
-    fn mul(self, rhs: i64) -> Self {
-        Wrap(self.0 * rhs)
-    }
-}
-
-impl MulAssign<i64> for Wrap {
-    fn mul_assign(&mut self, rhs: i64) {
-        *self = *self * rhs
-    }
-}
-
-fn cow_add_assign() {
-    use std::borrow::Cow;
-    let mut buf = Cow::Owned(String::from("bar"));
-    let cows = Cow::Borrowed("foo");
-
-    // this can be linted
-    buf = buf + cows.clone();
-    //~^ assign_op_pattern
-
-    // this should not as cow<str> Add is not commutative
-    buf = cows + buf;
-    println!("{}", buf);
-}
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs b/src/tools/clippy/tests/ui/auxiliary/interior_mutable_const.rs
index 96e037d4fcd..96e037d4fcd 100644
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/interior_mutable_const.rs
diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs
index 4c61c5accd3..9b8e62867f0 100644
--- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs
@@ -1,5 +1,4 @@
-#![feature(repr128, proc_macro_hygiene, proc_macro_quote, box_patterns)]
-#![allow(incomplete_features)]
+#![feature(proc_macro_hygiene, proc_macro_quote, box_patterns)]
 #![allow(clippy::useless_conversion, clippy::uninlined_format_args)]
 
 extern crate proc_macro;
diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs
index 1815dd58f51..5992d15935d 100644
--- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs
@@ -1,5 +1,4 @@
-#![feature(repr128, proc_macro_quote, proc_macro_span)]
-#![allow(incomplete_features)]
+#![feature(proc_macro_quote, proc_macro_span)]
 #![allow(clippy::field_reassign_with_default)]
 #![allow(clippy::eq_op)]
 #![allow(clippy::literal_string_with_formatting_args)]
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs
new file mode 100644
index 00000000000..0f439f78915
--- /dev/null
+++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const.rs
@@ -0,0 +1,221 @@
+//@aux-build:interior_mutable_const.rs
+
+#![deny(clippy::borrow_interior_mutable_const)]
+#![allow(
+    clippy::declare_interior_mutable_const,
+    clippy::out_of_bounds_indexing,
+    const_item_mutation,
+    unconditional_panic
+)]
+
+use core::cell::{Cell, UnsafeCell};
+use core::ops::{Deref, Index};
+
+trait ConstDefault {
+    const DEFAULT: Self;
+}
+impl ConstDefault for u32 {
+    const DEFAULT: Self = 0;
+}
+impl<T: ConstDefault> ConstDefault for Cell<T> {
+    const DEFAULT: Self = Cell::new(T::DEFAULT);
+}
+
+fn main() {
+    {
+        const C: String = String::new();
+        let _ = C;
+        let _ = &C;
+        let _ = C.len();
+        let _ = &*C;
+    }
+    {
+        const C: UnsafeCell<u32> = UnsafeCell::new(0);
+        let _ = C;
+        let _ = &C; //~ borrow_interior_mutable_const
+        let _ = C.into_inner();
+        let _ = C.get(); //~ borrow_interior_mutable_const
+    }
+    {
+        const C: Cell<u32> = Cell::new(0);
+        let _ = C;
+        let _ = &C; //~ borrow_interior_mutable_const
+        let _ = &mut C; //~ borrow_interior_mutable_const
+        let _ = C.into_inner();
+
+        let local = C;
+        C.swap(&local) //~ borrow_interior_mutable_const
+    }
+    {
+        const C: [(Cell<u32>,); 1] = [(Cell::new(0),)];
+        let _ = C;
+        let _ = &C; //~ borrow_interior_mutable_const
+        let _ = &C[0]; //~ borrow_interior_mutable_const
+        let _ = &C[0].0; //~ borrow_interior_mutable_const
+        C[0].0.set(1); //~ borrow_interior_mutable_const
+    }
+    {
+        struct S(Cell<u32>);
+        impl S {
+            const C: Self = Self(Cell::new(0));
+        }
+        impl Deref for S {
+            type Target = Cell<u32>;
+            fn deref(&self) -> &Self::Target {
+                &self.0
+            }
+        }
+        let _ = S::C;
+        let _ = S::C.0;
+        let _ = &S::C; //~ borrow_interior_mutable_const
+        let _ = &S::C.0; //~ borrow_interior_mutable_const
+        S::C.set(1); //~ borrow_interior_mutable_const
+        let _ = &*S::C; //~ borrow_interior_mutable_const
+        (*S::C).set(1); //~ borrow_interior_mutable_const
+    }
+    {
+        enum E {
+            Cell(Cell<u32>),
+            Other,
+        }
+        const CELL: E = E::Cell(Cell::new(0));
+        const OTHER: E = E::Other;
+
+        let _ = CELL;
+        let _ = &CELL; //~ borrow_interior_mutable_const
+        let E::Cell(_) = CELL else {
+            return;
+        };
+
+        let _ = OTHER;
+        let _ = &OTHER;
+        let E::Cell(ref _x) = OTHER else {
+            return;
+        };
+    }
+    {
+        struct S<T> {
+            cell: (Cell<T>, u32),
+            other: Option<T>,
+        }
+        impl<T: ConstDefault + Copy> S<T> {
+            const C: Self = Self {
+                cell: (Cell::<T>::DEFAULT, 0),
+                other: Some(T::DEFAULT),
+            };
+
+            fn f() {
+                let _ = Self::C;
+                let _ = &Self::C; //~ borrow_interior_mutable_const
+                let _ = Self::C.other;
+                let _ = &Self::C.other;
+                let _ = &Self::C.cell; //~ borrow_interior_mutable_const
+                let _ = &Self::C.cell.0; //~ borrow_interior_mutable_const
+                Self::C.cell.0.set(T::DEFAULT); //~ borrow_interior_mutable_const
+                let _ = &Self::C.cell.1;
+            }
+        }
+    }
+    {
+        trait T {
+            const VALUE: Option<Cell<u32>> = Some(Cell::new(0));
+        }
+        impl T for u32 {}
+        impl T for i32 {
+            const VALUE: Option<Cell<u32>> = None;
+        }
+
+        let _ = &u32::VALUE; //~ borrow_interior_mutable_const
+        let _ = &i32::VALUE;
+    }
+    {
+        trait Trait<T: ConstDefault> {
+            type T<U: ConstDefault>: ConstDefault;
+            const VALUE: Option<Self::T<T>> = Some(Self::T::<T>::DEFAULT);
+        }
+        impl<T: ConstDefault> Trait<T> for u32 {
+            type T<U: ConstDefault> = Cell<U>;
+        }
+        impl<T: ConstDefault> Trait<T> for i32 {
+            type T<U: ConstDefault> = Cell<U>;
+            const VALUE: Option<Cell<T>> = None;
+        }
+
+        fn f<T: ConstDefault>() {
+            let _ = &<u32 as Trait<T>>::VALUE; //~ borrow_interior_mutable_const
+            let _ = &<i32 as Trait<T>>::VALUE;
+        }
+    }
+    {
+        trait Trait {
+            const UNFROZEN: Option<Cell<u32>> = Some(Cell::new(0));
+            const FROZEN: Option<Cell<u32>> = None;
+            const NON_FREEZE: u32 = 0;
+        }
+        fn f<T: Trait>() {
+            // None of these are guaranteed to be frozen, so don't lint.
+            let _ = &T::UNFROZEN;
+            let _ = &T::FROZEN;
+            let _ = &T::NON_FREEZE;
+        }
+    }
+    {
+        struct S([Option<Cell<u32>>; 2]);
+        impl Index<usize> for S {
+            type Output = Option<Cell<u32>>;
+            fn index(&self, idx: usize) -> &Self::Output {
+                &self.0[idx]
+            }
+        }
+
+        const C: S = S([Some(Cell::new(0)), None]);
+        let _ = &C; //~ borrow_interior_mutable_const
+        let _ = &C[0]; //~ borrow_interior_mutable_const
+        let _ = &C.0[0]; //~ borrow_interior_mutable_const
+        let _ = &C.0[1];
+    }
+    {
+        const C: [Option<Cell<u32>>; 2] = [None, None];
+        let _ = &C[0];
+        let _ = &C[1];
+        let _ = &C[2];
+
+        fn f(i: usize) {
+            let _ = &C[i];
+        }
+    }
+    {
+        const C: [Option<Cell<u32>>; 2] = [None, Some(Cell::new(0))];
+        let _ = &C[0];
+        let _ = &C[1]; //~ borrow_interior_mutable_const
+        let _ = &C[2];
+
+        fn f(i: usize) {
+            let _ = &C[i]; //~ borrow_interior_mutable_const
+        }
+    }
+    {
+        let _ = &interior_mutable_const::WRAPPED_PRIVATE_UNFROZEN_VARIANT; //~ borrow_interior_mutable_const
+        let _ = &interior_mutable_const::WRAPPED_PRIVATE_FROZEN_VARIANT;
+    }
+    {
+        type Cell2<T> = Cell<T>;
+        type MyCell = Cell2<u32>;
+        struct S(Option<MyCell>);
+        trait T {
+            type Assoc;
+        }
+        struct S2<T>(T, T, u32);
+        impl T for S {
+            type Assoc = S2<Self>;
+        }
+        type Assoc<X> = <X as T>::Assoc;
+        impl S {
+            const VALUE: Assoc<Self> = S2(Self(None), Self(Some(Cell::new(0))), 0);
+        }
+        let _ = &S::VALUE; //~ borrow_interior_mutable_const
+        let _ = &S::VALUE.0;
+        let _ = &S::VALUE.1; //~ borrow_interior_mutable_const
+        let _ = &S::VALUE.2;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const.stderr
new file mode 100644
index 00000000000..e7c3f879b05
--- /dev/null
+++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const.stderr
@@ -0,0 +1,247 @@
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:35:17
+   |
+LL |         let _ = &C;
+   |                 ^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+note: the lint level is defined here
+  --> tests/ui/borrow_interior_mutable_const.rs:3:9
+   |
+LL | #![deny(clippy::borrow_interior_mutable_const)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:37:17
+   |
+LL |         let _ = C.get();
+   |                 ^
+   |
+   = note: there is a compiler inserted borrow here
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:42:17
+   |
+LL |         let _ = &C;
+   |                 ^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:43:17
+   |
+LL |         let _ = &mut C;
+   |                 ^^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:47:9
+   |
+LL |         C.swap(&local)
+   |         ^
+   |
+   = note: there is a compiler inserted borrow here
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:52:17
+   |
+LL |         let _ = &C;
+   |                 ^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:53:17
+   |
+LL |         let _ = &C[0];
+   |                 ^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:54:17
+   |
+LL |         let _ = &C[0].0;
+   |                 ^^^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:55:9
+   |
+LL |         C[0].0.set(1);
+   |         ^^^^^^
+   |
+   = note: there is a compiler inserted borrow here
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:70:17
+   |
+LL |         let _ = &S::C;
+   |                 ^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:71:17
+   |
+LL |         let _ = &S::C.0;
+   |                 ^^^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:72:9
+   |
+LL |         S::C.set(1);
+   |         ^^^^
+   |
+   = note: there is a compiler inserted call to `Deref::deref` here
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:73:18
+   |
+LL |         let _ = &*S::C;
+   |                  ^^^^^
+   |
+   = note: this deref expression is a call to `Deref::deref`
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:74:9
+   |
+LL |         (*S::C).set(1);
+   |         ^^^^^^^
+   |
+   = note: this deref expression is a call to `Deref::deref`
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:85:17
+   |
+LL |         let _ = &CELL;
+   |                 ^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:109:25
+   |
+LL |                 let _ = &Self::C;
+   |                         ^^^^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:112:25
+   |
+LL |                 let _ = &Self::C.cell;
+   |                         ^^^^^^^^^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:113:25
+   |
+LL |                 let _ = &Self::C.cell.0;
+   |                         ^^^^^^^^^^^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:114:17
+   |
+LL |                 Self::C.cell.0.set(T::DEFAULT);
+   |                 ^^^^^^^^^^^^^^
+   |
+   = note: there is a compiler inserted borrow here
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:128:17
+   |
+LL |         let _ = &u32::VALUE;
+   |                 ^^^^^^^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:145:21
+   |
+LL |             let _ = &<u32 as Trait<T>>::VALUE;
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:172:17
+   |
+LL |         let _ = &C;
+   |                 ^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:173:18
+   |
+LL |         let _ = &C[0];
+   |                  ^^^^
+   |
+   = note: this index expression is a call to `Index::index`
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:174:17
+   |
+LL |         let _ = &C.0[0];
+   |                 ^^^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:190:17
+   |
+LL |         let _ = &C[1];
+   |                 ^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:194:21
+   |
+LL |             let _ = &C[i];
+   |                     ^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:198:17
+   |
+LL |         let _ = &interior_mutable_const::WRAPPED_PRIVATE_UNFROZEN_VARIANT;
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:216:17
+   |
+LL |         let _ = &S::VALUE;
+   |                 ^^^^^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: borrow of a named constant with interior mutability
+  --> tests/ui/borrow_interior_mutable_const.rs:218:17
+   |
+LL |         let _ = &S::VALUE.1;
+   |                 ^^^^^^^^^^^
+   |
+   = help: this lint can be silenced by assigning the value to a local variable before borrowing
+
+error: aborting due to 29 previous errors
+
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.rs
deleted file mode 100644
index da940a4cfb5..00000000000
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.rs
+++ /dev/null
@@ -1,101 +0,0 @@
-//@aux-build:helper.rs
-
-#![deny(clippy::borrow_interior_mutable_const)]
-#![allow(clippy::declare_interior_mutable_const)]
-
-// this file (mostly) replicates its `declare` counterpart. Please see it for more discussions.
-
-extern crate helper;
-
-use std::cell::Cell;
-use std::sync::atomic::AtomicUsize;
-
-enum OptionalCell {
-    Unfrozen(Cell<bool>),
-    Frozen,
-}
-
-const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true));
-const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
-
-fn borrow_optional_cell() {
-    let _ = &UNFROZEN_VARIANT; //~ ERROR: interior mutability
-    let _ = &FROZEN_VARIANT;
-}
-
-trait AssocConsts {
-    const TO_BE_UNFROZEN_VARIANT: OptionalCell;
-    const TO_BE_FROZEN_VARIANT: OptionalCell;
-
-    const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
-    const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
-
-    fn function() {
-        // This is the "suboptimal behavior" mentioned in `is_value_unfrozen`
-        // caused by a similar reason to unfrozen types without any default values
-        // get linted even if it has frozen variants'.
-        let _ = &Self::TO_BE_FROZEN_VARIANT; //~ ERROR: interior mutability
-
-        // The lint ignores default values because an impl of this trait can set
-        // an unfrozen variant to `DEFAULTED_ON_FROZEN_VARIANT` and use the default impl for `function`.
-        let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; //~ ERROR: interior mutability
-    }
-}
-
-impl AssocConsts for u64 {
-    const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
-    const TO_BE_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
-
-    fn function() {
-        let _ = &<Self as AssocConsts>::TO_BE_UNFROZEN_VARIANT; //~ ERROR: interior mutability
-        let _ = &<Self as AssocConsts>::TO_BE_FROZEN_VARIANT;
-        let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT; //~ ERROR: interior mutability
-        let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT;
-    }
-}
-
-trait AssocTypes {
-    type ToBeUnfrozen;
-
-    const TO_BE_UNFROZEN_VARIANT: Option<Self::ToBeUnfrozen>;
-    const TO_BE_FROZEN_VARIANT: Option<Self::ToBeUnfrozen>;
-
-    // there's no need to test here because it's the exactly same as `trait::AssocTypes`
-    fn function();
-}
-
-impl AssocTypes for u64 {
-    type ToBeUnfrozen = AtomicUsize;
-
-    const TO_BE_UNFROZEN_VARIANT: Option<Self::ToBeUnfrozen> = Some(Self::ToBeUnfrozen::new(4));
-    const TO_BE_FROZEN_VARIANT: Option<Self::ToBeUnfrozen> = None;
-
-    fn function() {
-        let _ = &<Self as AssocTypes>::TO_BE_UNFROZEN_VARIANT; //~ ERROR: interior mutability
-        let _ = &<Self as AssocTypes>::TO_BE_FROZEN_VARIANT;
-    }
-}
-
-enum BothOfCellAndGeneric<T> {
-    Unfrozen(Cell<*const T>),
-    Generic(*const T),
-    Frozen(usize),
-}
-
-impl<T> BothOfCellAndGeneric<T> {
-    const UNFROZEN_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null()));
-    const GENERIC_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Generic(std::ptr::null());
-    const FROZEN_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Frozen(5);
-
-    fn function() {
-        let _ = &Self::UNFROZEN_VARIANT; //~ ERROR: interior mutability
-        let _ = &Self::GENERIC_VARIANT; //~ ERROR: interior mutability
-        let _ = &Self::FROZEN_VARIANT;
-    }
-}
-
-fn main() {
-    // constants defined in foreign crates
-    let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT; //~ ERROR: interior mutability
-    let _ = &helper::WRAPPED_PRIVATE_FROZEN_VARIANT;
-}
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.stderr
deleted file mode 100644
index 43850384b90..00000000000
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.stderr
+++ /dev/null
@@ -1,79 +0,0 @@
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/enums.rs:22:14
-   |
-LL |     let _ = &UNFROZEN_VARIANT;
-   |              ^^^^^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-note: the lint level is defined here
-  --> tests/ui/borrow_interior_mutable_const/enums.rs:3:9
-   |
-LL | #![deny(clippy::borrow_interior_mutable_const)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/enums.rs:37:18
-   |
-LL |         let _ = &Self::TO_BE_FROZEN_VARIANT;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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/enums.rs:41:18
-   |
-LL |         let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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/enums.rs:50:18
-   |
-LL |         let _ = &<Self as AssocConsts>::TO_BE_UNFROZEN_VARIANT;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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/enums.rs:52:18
-   |
-LL |         let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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/enums.rs:74:18
-   |
-LL |         let _ = &<Self as AssocTypes>::TO_BE_UNFROZEN_VARIANT;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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/enums.rs:91:18
-   |
-LL |         let _ = &Self::UNFROZEN_VARIANT;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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/enums.rs:92:18
-   |
-LL |         let _ = &Self::GENERIC_VARIANT;
-   |                  ^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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/enums.rs:99:14
-   |
-LL |     let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT;
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: aborting due to 9 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
deleted file mode 100644
index fa729b62d7f..00000000000
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs
+++ /dev/null
@@ -1,128 +0,0 @@
-#![deny(clippy::borrow_interior_mutable_const)]
-#![allow(clippy::declare_interior_mutable_const, clippy::needless_borrow)]
-#![allow(const_item_mutation)]
-
-use std::borrow::Cow;
-use std::cell::{Cell, UnsafeCell};
-use std::fmt::Display;
-use std::sync::Once;
-use std::sync::atomic::{AtomicUsize, Ordering};
-
-const ATOMIC: AtomicUsize = AtomicUsize::new(5);
-const CELL: Cell<usize> = Cell::new(6);
-const ATOMIC_TUPLE: ([AtomicUsize; 1], Option<Box<AtomicUsize>>, u8) = ([ATOMIC], None, 7);
-const INTEGER: u8 = 8;
-const STRING: String = String::new();
-const STR: &str = "012345";
-const COW: Cow<str> = Cow::Borrowed("abcdef");
-const NO_ANN: &dyn Display = &70;
-static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING);
-const ONCE_INIT: Once = Once::new();
-
-// This is just a pointer that can be safely dereferenced,
-// it's semantically the same as `&'static T`;
-// but it isn't allowed to make a static reference from an arbitrary integer value at the moment.
-// For more information, please see the issue #5918.
-pub struct StaticRef<T> {
-    ptr: *const T,
-}
-
-impl<T> StaticRef<T> {
-    /// Create a new `StaticRef` from a raw pointer
-    ///
-    /// ## Safety
-    ///
-    /// Callers must pass in a reference to statically allocated memory which
-    /// does not overlap with other values.
-    pub const unsafe fn new(ptr: *const T) -> StaticRef<T> {
-        StaticRef { ptr }
-    }
-}
-
-impl<T> std::ops::Deref for StaticRef<T> {
-    type Target = T;
-
-    fn deref(&self) -> &T {
-        unsafe { &*self.ptr }
-    }
-}
-
-// 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()) };
-
-fn main() {
-    ATOMIC.store(1, Ordering::SeqCst);
-    //~^ borrow_interior_mutable_const
-    assert_eq!(ATOMIC.load(Ordering::SeqCst), 5);
-    //~^ borrow_interior_mutable_const
-
-    let _once = ONCE_INIT;
-    let _once_ref = &ONCE_INIT;
-    //~^ borrow_interior_mutable_const
-    let _once_ref_2 = &&ONCE_INIT;
-    //~^ borrow_interior_mutable_const
-    let _once_ref_4 = &&&&ONCE_INIT;
-    //~^ borrow_interior_mutable_const
-    let _once_mut = &mut ONCE_INIT;
-    //~^ borrow_interior_mutable_const
-    let _atomic_into_inner = ATOMIC.into_inner();
-    // these should be all fine.
-    let _twice = (ONCE_INIT, ONCE_INIT);
-    let _ref_twice = &(ONCE_INIT, ONCE_INIT);
-    let _ref_once = &(ONCE_INIT, ONCE_INIT).0;
-    let _array_twice = [ONCE_INIT, ONCE_INIT];
-    let _ref_array_twice = &[ONCE_INIT, ONCE_INIT];
-    let _ref_array_once = &[ONCE_INIT, ONCE_INIT][0];
-
-    // referencing projection is still bad.
-    let _ = &ATOMIC_TUPLE;
-    //~^ borrow_interior_mutable_const
-    let _ = &ATOMIC_TUPLE.0;
-    //~^ borrow_interior_mutable_const
-    let _ = &(&&&&ATOMIC_TUPLE).0;
-    //~^ borrow_interior_mutable_const
-    let _ = &ATOMIC_TUPLE.0[0];
-    //~^ borrow_interior_mutable_const
-    let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst);
-    //~^ borrow_interior_mutable_const
-    let _ = &ATOMIC_TUPLE.2;
-    let _ = (&&&&ATOMIC_TUPLE).0;
-    let _ = (&&&&ATOMIC_TUPLE).2;
-    let _ = ATOMIC_TUPLE.0;
-    let _ = ATOMIC_TUPLE.0[0];
-    //~^ borrow_interior_mutable_const
-    let _ = ATOMIC_TUPLE.1.into_iter();
-    let _ = ATOMIC_TUPLE.2;
-    let _ = &{ ATOMIC_TUPLE };
-
-    CELL.set(2);
-    //~^ borrow_interior_mutable_const
-    assert_eq!(CELL.get(), 6);
-    //~^ borrow_interior_mutable_const
-
-    assert_eq!(INTEGER, 8);
-    assert!(STRING.is_empty());
-
-    let a = ATOMIC;
-    a.store(4, Ordering::SeqCst);
-    assert_eq!(a.load(Ordering::SeqCst), 4);
-
-    STATIC_TUPLE.0.store(3, Ordering::SeqCst);
-    assert_eq!(STATIC_TUPLE.0.load(Ordering::SeqCst), 3);
-    assert!(STATIC_TUPLE.1.is_empty());
-
-    assert_eq!(NO_ANN.to_string(), "70"); // should never lint this.
-
-    let _ = &CELL_REF.0;
-}
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
deleted file mode 100644
index decea153f71..00000000000
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr
+++ /dev/null
@@ -1,119 +0,0 @@
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:65:5
-   |
-LL |     ATOMIC.store(1, Ordering::SeqCst);
-   |     ^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-note: the lint level is defined here
-  --> tests/ui/borrow_interior_mutable_const/others.rs:1:9
-   |
-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:67:16
-   |
-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:71:22
-   |
-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:73:25
-   |
-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:75:27
-   |
-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:77:26
-   |
-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:89:14
-   |
-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:91:14
-   |
-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:93:19
-   |
-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:95:14
-   |
-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:97:13
-   |
-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:103:13
-   |
-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:109:5
-   |
-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:111:16
-   |
-LL |     assert_eq!(CELL.get(), 6);
-   |                ^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: aborting due to 14 previous errors
-
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/projections.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/projections.rs
deleted file mode 100644
index bbe5538fbe1..00000000000
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/projections.rs
+++ /dev/null
@@ -1,42 +0,0 @@
-#![deny(clippy::borrow_interior_mutable_const)]
-#![deny(clippy::declare_interior_mutable_const)]
-
-// Inspired by https://github.com/rust-lang/rust/pull/130543#issuecomment-2364828139
-
-use std::cell::UnsafeCell;
-
-trait Trait {
-    type Assoc;
-}
-
-type Assoc<T> = <T as Trait>::Assoc;
-
-impl Trait for u8 {
-    type Assoc = UnsafeCell<u8>;
-}
-
-impl Trait for () {
-    type Assoc = ();
-}
-
-enum MaybeMutable {
-    Mutable(Assoc<u8>),
-    Immutable(Assoc<()>),
-}
-
-const CELL: Assoc<u8> = UnsafeCell::new(0); //~ ERROR: interior mutable
-const UNIT: Assoc<()> = ();
-const MUTABLE: MaybeMutable = MaybeMutable::Mutable(CELL); //~ ERROR: interior mutable
-const IMMUTABLE: MaybeMutable = MaybeMutable::Immutable(UNIT);
-
-fn print_ref<T>(t: &T) {
-    let p: *const T = t;
-    println!("{p:p}")
-}
-
-fn main() {
-    print_ref(&CELL); //~ ERROR: interior mutability
-    print_ref(&UNIT);
-    print_ref(&MUTABLE); //~ ERROR: interior mutability
-    print_ref(&IMMUTABLE);
-}
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/projections.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/projections.stderr
deleted file mode 100644
index eabaf66560a..00000000000
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/projections.stderr
+++ /dev/null
@@ -1,44 +0,0 @@
-error: a `const` item should not be interior mutable
-  --> tests/ui/borrow_interior_mutable_const/projections.rs:27:1
-   |
-LL | const CELL: Assoc<u8> = UnsafeCell::new(0);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider making this `Sync` so that it can go in a static item or using a `thread_local`
-note: the lint level is defined here
-  --> tests/ui/borrow_interior_mutable_const/projections.rs:2:9
-   |
-LL | #![deny(clippy::declare_interior_mutable_const)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/borrow_interior_mutable_const/projections.rs:29:1
-   |
-LL | const MUTABLE: MaybeMutable = MaybeMutable::Mutable(CELL);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider making this `Sync` so that it can go in a static item or using a `thread_local`
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/projections.rs:38:16
-   |
-LL |     print_ref(&CELL);
-   |                ^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-note: the lint level is defined here
-  --> tests/ui/borrow_interior_mutable_const/projections.rs:1:9
-   |
-LL | #![deny(clippy::borrow_interior_mutable_const)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/projections.rs:40:16
-   |
-LL |     print_ref(&MUTABLE);
-   |                ^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: aborting due to 4 previous errors
-
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.rs
deleted file mode 100644
index c4878dbe57b..00000000000
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.rs
+++ /dev/null
@@ -1,219 +0,0 @@
-#![deny(clippy::borrow_interior_mutable_const)]
-#![allow(clippy::declare_interior_mutable_const)]
-
-// this file replicates its `declare` counterpart. Please see it for more discussions.
-
-use std::borrow::Cow;
-use std::cell::Cell;
-use std::sync::atomic::{AtomicUsize, Ordering};
-
-trait ConcreteTypes {
-    const ATOMIC: AtomicUsize;
-    const STRING: String;
-
-    fn function() {
-        let _ = &Self::ATOMIC;
-        //~^ borrow_interior_mutable_const
-        let _ = &Self::STRING;
-    }
-}
-
-impl ConcreteTypes for u64 {
-    const ATOMIC: AtomicUsize = AtomicUsize::new(9);
-    const STRING: String = String::new();
-
-    fn function() {
-        // Lint this again since implementers can choose not to borrow it.
-        let _ = &Self::ATOMIC;
-        //~^ borrow_interior_mutable_const
-        let _ = &Self::STRING;
-    }
-}
-
-// a helper trait used below
-trait ConstDefault {
-    const DEFAULT: Self;
-}
-
-trait GenericTypes<T, U> {
-    const TO_REMAIN_GENERIC: T;
-    const TO_BE_CONCRETE: U;
-
-    fn function() {
-        let _ = &Self::TO_REMAIN_GENERIC;
-    }
-}
-
-impl<T: ConstDefault> GenericTypes<T, AtomicUsize> for Vec<T> {
-    const TO_REMAIN_GENERIC: T = T::DEFAULT;
-    const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11);
-
-    fn function() {
-        let _ = &Self::TO_REMAIN_GENERIC;
-        let _ = &Self::TO_BE_CONCRETE;
-        //~^ borrow_interior_mutable_const
-    }
-}
-
-// a helper type used below
-pub struct Wrapper<T>(T);
-
-trait AssocTypes {
-    type ToBeFrozen;
-    type ToBeUnfrozen;
-    type ToBeGenericParam;
-
-    const TO_BE_FROZEN: Self::ToBeFrozen;
-    const TO_BE_UNFROZEN: Self::ToBeUnfrozen;
-    const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen>;
-    const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper<Self::ToBeGenericParam>;
-
-    fn function() {
-        let _ = &Self::TO_BE_FROZEN;
-        let _ = &Self::WRAPPED_TO_BE_UNFROZEN;
-    }
-}
-
-impl<T: ConstDefault> AssocTypes for Vec<T> {
-    type ToBeFrozen = u16;
-    type ToBeUnfrozen = AtomicUsize;
-    type ToBeGenericParam = T;
-
-    const TO_BE_FROZEN: Self::ToBeFrozen = 12;
-    const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13);
-    const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen> = Wrapper(AtomicUsize::new(14));
-    const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper<Self::ToBeGenericParam> = Wrapper(T::DEFAULT);
-
-    fn function() {
-        let _ = &Self::TO_BE_FROZEN;
-        let _ = &Self::TO_BE_UNFROZEN;
-        //~^ borrow_interior_mutable_const
-        let _ = &Self::WRAPPED_TO_BE_UNFROZEN;
-        //~^ borrow_interior_mutable_const
-        let _ = &Self::WRAPPED_TO_BE_GENERIC_PARAM;
-    }
-}
-
-// a helper trait used below
-trait AssocTypesHelper {
-    type NotToBeBounded;
-    type ToBeBounded;
-
-    const NOT_TO_BE_BOUNDED: Self::NotToBeBounded;
-}
-
-trait AssocTypesFromGenericParam<T>
-where
-    T: AssocTypesHelper<ToBeBounded = AtomicUsize>,
-{
-    const NOT_BOUNDED: T::NotToBeBounded;
-    const BOUNDED: T::ToBeBounded;
-
-    fn function() {
-        let _ = &Self::NOT_BOUNDED;
-        let _ = &Self::BOUNDED;
-        //~^ borrow_interior_mutable_const
-    }
-}
-
-impl<T> AssocTypesFromGenericParam<T> for Vec<T>
-where
-    T: AssocTypesHelper<ToBeBounded = AtomicUsize>,
-{
-    const NOT_BOUNDED: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED;
-    const BOUNDED: T::ToBeBounded = AtomicUsize::new(15);
-
-    fn function() {
-        let _ = &Self::NOT_BOUNDED;
-        let _ = &Self::BOUNDED;
-        //~^ borrow_interior_mutable_const
-    }
-}
-
-trait SelfType: Sized {
-    const SELF: Self;
-    const WRAPPED_SELF: Option<Self>;
-
-    fn function() {
-        let _ = &Self::SELF;
-        let _ = &Self::WRAPPED_SELF;
-    }
-}
-
-impl SelfType for u64 {
-    const SELF: Self = 16;
-    const WRAPPED_SELF: Option<Self> = Some(20);
-
-    fn function() {
-        let _ = &Self::SELF;
-        let _ = &Self::WRAPPED_SELF;
-    }
-}
-
-impl SelfType for AtomicUsize {
-    const SELF: Self = AtomicUsize::new(17);
-    const WRAPPED_SELF: Option<Self> = Some(AtomicUsize::new(21));
-
-    fn function() {
-        let _ = &Self::SELF;
-        //~^ borrow_interior_mutable_const
-        let _ = &Self::WRAPPED_SELF;
-        //~^ borrow_interior_mutable_const
-    }
-}
-
-trait BothOfCellAndGeneric<T> {
-    const DIRECT: Cell<T>;
-    const INDIRECT: Cell<*const T>;
-
-    fn function() {
-        let _ = &Self::DIRECT;
-        //~^ borrow_interior_mutable_const
-        let _ = &Self::INDIRECT;
-        //~^ borrow_interior_mutable_const
-    }
-}
-
-impl<T: ConstDefault> BothOfCellAndGeneric<T> for Vec<T> {
-    const DIRECT: Cell<T> = Cell::new(T::DEFAULT);
-    const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null());
-
-    fn function() {
-        let _ = &Self::DIRECT;
-        //~^ borrow_interior_mutable_const
-        let _ = &Self::INDIRECT;
-        //~^ borrow_interior_mutable_const
-    }
-}
-
-struct Local<T>(T);
-
-impl<T> Local<T>
-where
-    T: ConstDefault + AssocTypesHelper<ToBeBounded = AtomicUsize>,
-{
-    const ATOMIC: AtomicUsize = AtomicUsize::new(18);
-    const COW: Cow<'static, str> = Cow::Borrowed("tuvwxy");
-
-    const GENERIC_TYPE: T = T::DEFAULT;
-
-    const ASSOC_TYPE: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED;
-    const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19);
-
-    fn function() {
-        let _ = &Self::ATOMIC;
-        //~^ borrow_interior_mutable_const
-        let _ = &Self::COW;
-        let _ = &Self::GENERIC_TYPE;
-        let _ = &Self::ASSOC_TYPE;
-        let _ = &Self::BOUNDED_ASSOC_TYPE;
-        //~^ borrow_interior_mutable_const
-    }
-}
-
-fn main() {
-    u64::ATOMIC.store(5, Ordering::SeqCst);
-    //~^ borrow_interior_mutable_const
-    assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9);
-    //~^ borrow_interior_mutable_const
-}
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.stderr
deleted file mode 100644
index cad68ca9260..00000000000
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.stderr
+++ /dev/null
@@ -1,143 +0,0 @@
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:15:18
-   |
-LL |         let _ = &Self::ATOMIC;
-   |                  ^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-note: the lint level is defined here
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:1:9
-   |
-LL | #![deny(clippy::borrow_interior_mutable_const)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:27:18
-   |
-LL |         let _ = &Self::ATOMIC;
-   |                  ^^^^^^^^^^^^
-   |
-   = 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/traits.rs:53:18
-   |
-LL |         let _ = &Self::TO_BE_CONCRETE;
-   |                  ^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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/traits.rs:89:18
-   |
-LL |         let _ = &Self::TO_BE_UNFROZEN;
-   |                  ^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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/traits.rs:91:18
-   |
-LL |         let _ = &Self::WRAPPED_TO_BE_UNFROZEN;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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/traits.rs:114:18
-   |
-LL |         let _ = &Self::BOUNDED;
-   |                  ^^^^^^^^^^^^^
-   |
-   = 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/traits.rs:128:18
-   |
-LL |         let _ = &Self::BOUNDED;
-   |                  ^^^^^^^^^^^^^
-   |
-   = 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/traits.rs:158:18
-   |
-LL |         let _ = &Self::SELF;
-   |                  ^^^^^^^^^^
-   |
-   = 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/traits.rs:160:18
-   |
-LL |         let _ = &Self::WRAPPED_SELF;
-   |                  ^^^^^^^^^^^^^^^^^^
-   |
-   = 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/traits.rs:170:18
-   |
-LL |         let _ = &Self::DIRECT;
-   |                  ^^^^^^^^^^^^
-   |
-   = 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/traits.rs:172:18
-   |
-LL |         let _ = &Self::INDIRECT;
-   |                  ^^^^^^^^^^^^^^
-   |
-   = 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/traits.rs:182:18
-   |
-LL |         let _ = &Self::DIRECT;
-   |                  ^^^^^^^^^^^^
-   |
-   = 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/traits.rs:184:18
-   |
-LL |         let _ = &Self::INDIRECT;
-   |                  ^^^^^^^^^^^^^^
-   |
-   = 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/traits.rs:204:18
-   |
-LL |         let _ = &Self::ATOMIC;
-   |                  ^^^^^^^^^^^^
-   |
-   = 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/traits.rs:209:18
-   |
-LL |         let _ = &Self::BOUNDED_ASSOC_TYPE;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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/traits.rs:215:5
-   |
-LL |     u64::ATOMIC.store(5, 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/traits.rs:217:16
-   |
-LL |     assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9);
-   |                ^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: aborting due to 17 previous errors
-
diff --git a/src/tools/clippy/tests/ui/cast.rs b/src/tools/clippy/tests/ui/cast.rs
index 88c2549f4dc..525be821650 100644
--- a/src/tools/clippy/tests/ui/cast.rs
+++ b/src/tools/clippy/tests/ui/cast.rs
@@ -1,7 +1,5 @@
-//@no-rustfix
+//@no-rustfix: only some diagnostics have suggestions
 
-#![feature(repr128)]
-#![allow(incomplete_features)]
 #![warn(
     clippy::cast_precision_loss,
     clippy::cast_possible_truncation,
diff --git a/src/tools/clippy/tests/ui/cast.stderr b/src/tools/clippy/tests/ui/cast.stderr
index 4d03282f667..1cb30d95667 100644
--- a/src/tools/clippy/tests/ui/cast.stderr
+++ b/src/tools/clippy/tests/ui/cast.stderr
@@ -1,5 +1,5 @@
 error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast.rs:25:5
+  --> tests/ui/cast.rs:23:5
    |
 LL |     x0 as f32;
    |     ^^^^^^^^^
@@ -8,37 +8,37 @@ LL |     x0 as f32;
    = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]`
 
 error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast.rs:29:5
+  --> tests/ui/cast.rs:27:5
    |
 LL |     x1 as f32;
    |     ^^^^^^^^^
 
 error: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
-  --> tests/ui/cast.rs:32:5
+  --> tests/ui/cast.rs:30:5
    |
 LL |     x1 as f64;
    |     ^^^^^^^^^
 
 error: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast.rs:36:5
+  --> tests/ui/cast.rs:34:5
    |
 LL |     x2 as f32;
    |     ^^^^^^^^^
 
 error: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast.rs:40:5
+  --> tests/ui/cast.rs:38:5
    |
 LL |     x3 as f32;
    |     ^^^^^^^^^
 
 error: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
-  --> tests/ui/cast.rs:43:5
+  --> tests/ui/cast.rs:41:5
    |
 LL |     x3 as f64;
    |     ^^^^^^^^^
 
 error: casting `f32` to `i32` may truncate the value
-  --> tests/ui/cast.rs:47:5
+  --> tests/ui/cast.rs:45:5
    |
 LL |     1f32 as i32;
    |     ^^^^^^^^^^^
@@ -48,7 +48,7 @@ LL |     1f32 as i32;
    = help: to override `-D warnings` add `#[allow(clippy::cast_possible_truncation)]`
 
 error: casting `f32` to `u32` may truncate the value
-  --> tests/ui/cast.rs:50:5
+  --> tests/ui/cast.rs:48:5
    |
 LL |     1f32 as u32;
    |     ^^^^^^^^^^^
@@ -56,7 +56,7 @@ LL |     1f32 as u32;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:50:5
+  --> tests/ui/cast.rs:48:5
    |
 LL |     1f32 as u32;
    |     ^^^^^^^^^^^
@@ -65,7 +65,7 @@ LL |     1f32 as u32;
    = help: to override `-D warnings` add `#[allow(clippy::cast_sign_loss)]`
 
 error: casting `f64` to `f32` may truncate the value
-  --> tests/ui/cast.rs:54:5
+  --> tests/ui/cast.rs:52:5
    |
 LL |     1f64 as f32;
    |     ^^^^^^^^^^^
@@ -73,7 +73,7 @@ LL |     1f64 as f32;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `i32` to `i8` may truncate the value
-  --> tests/ui/cast.rs:57:5
+  --> tests/ui/cast.rs:55:5
    |
 LL |     1i32 as i8;
    |     ^^^^^^^^^^
@@ -86,7 +86,7 @@ LL +     i8::try_from(1i32);
    |
 
 error: casting `i32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:60:5
+  --> tests/ui/cast.rs:58:5
    |
 LL |     1i32 as u8;
    |     ^^^^^^^^^^
@@ -99,7 +99,7 @@ LL +     u8::try_from(1i32);
    |
 
 error: casting `f64` to `isize` may truncate the value
-  --> tests/ui/cast.rs:63:5
+  --> tests/ui/cast.rs:61:5
    |
 LL |     1f64 as isize;
    |     ^^^^^^^^^^^^^
@@ -107,7 +107,7 @@ LL |     1f64 as isize;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f64` to `usize` may truncate the value
-  --> tests/ui/cast.rs:66:5
+  --> tests/ui/cast.rs:64:5
    |
 LL |     1f64 as usize;
    |     ^^^^^^^^^^^^^
@@ -115,13 +115,13 @@ LL |     1f64 as usize;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f64` to `usize` may lose the sign of the value
-  --> tests/ui/cast.rs:66:5
+  --> tests/ui/cast.rs:64:5
    |
 LL |     1f64 as usize;
    |     ^^^^^^^^^^^^^
 
 error: casting `u32` to `u16` may truncate the value
-  --> tests/ui/cast.rs:70:5
+  --> tests/ui/cast.rs:68:5
    |
 LL |     1f32 as u32 as u16;
    |     ^^^^^^^^^^^^^^^^^^
@@ -134,7 +134,7 @@ LL +     u16::try_from(1f32 as u32);
    |
 
 error: casting `f32` to `u32` may truncate the value
-  --> tests/ui/cast.rs:70:5
+  --> tests/ui/cast.rs:68:5
    |
 LL |     1f32 as u32 as u16;
    |     ^^^^^^^^^^^
@@ -142,13 +142,13 @@ LL |     1f32 as u32 as u16;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:70:5
+  --> tests/ui/cast.rs:68:5
    |
 LL |     1f32 as u32 as u16;
    |     ^^^^^^^^^^^
 
 error: casting `i32` to `i8` may truncate the value
-  --> tests/ui/cast.rs:76:22
+  --> tests/ui/cast.rs:74:22
    |
 LL |         let _x: i8 = 1i32 as _;
    |                      ^^^^^^^^^
@@ -161,7 +161,7 @@ LL +         let _x: i8 = 1i32.try_into();
    |
 
 error: casting `f32` to `i32` may truncate the value
-  --> tests/ui/cast.rs:79:9
+  --> tests/ui/cast.rs:77:9
    |
 LL |         1f32 as i32;
    |         ^^^^^^^^^^^
@@ -169,7 +169,7 @@ LL |         1f32 as i32;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f64` to `i32` may truncate the value
-  --> tests/ui/cast.rs:82:9
+  --> tests/ui/cast.rs:80:9
    |
 LL |         1f64 as i32;
    |         ^^^^^^^^^^^
@@ -177,7 +177,7 @@ LL |         1f64 as i32;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:85:9
+  --> tests/ui/cast.rs:83:9
    |
 LL |         1f32 as u8;
    |         ^^^^^^^^^^
@@ -185,13 +185,13 @@ LL |         1f32 as u8;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f32` to `u8` may lose the sign of the value
-  --> tests/ui/cast.rs:85:9
+  --> tests/ui/cast.rs:83:9
    |
 LL |         1f32 as u8;
    |         ^^^^^^^^^^
 
 error: casting `u8` to `i8` may wrap around the value
-  --> tests/ui/cast.rs:90:5
+  --> tests/ui/cast.rs:88:5
    |
 LL |     1u8 as i8;
    |     ^^^^^^^^^
@@ -200,31 +200,31 @@ LL |     1u8 as i8;
    = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]`
 
 error: casting `u16` to `i16` may wrap around the value
-  --> tests/ui/cast.rs:93:5
+  --> tests/ui/cast.rs:91:5
    |
 LL |     1u16 as i16;
    |     ^^^^^^^^^^^
 
 error: casting `u32` to `i32` may wrap around the value
-  --> tests/ui/cast.rs:96:5
+  --> tests/ui/cast.rs:94:5
    |
 LL |     1u32 as i32;
    |     ^^^^^^^^^^^
 
 error: casting `u64` to `i64` may wrap around the value
-  --> tests/ui/cast.rs:99:5
+  --> tests/ui/cast.rs:97:5
    |
 LL |     1u64 as i64;
    |     ^^^^^^^^^^^
 
 error: casting `usize` to `isize` may wrap around the value
-  --> tests/ui/cast.rs:102:5
+  --> tests/ui/cast.rs:100:5
    |
 LL |     1usize as isize;
    |     ^^^^^^^^^^^^^^^
 
 error: casting `usize` to `i8` may truncate the value
-  --> tests/ui/cast.rs:106:5
+  --> tests/ui/cast.rs:104:5
    |
 LL |     1usize as i8;
    |     ^^^^^^^^^^^^
@@ -237,7 +237,7 @@ LL +     i8::try_from(1usize);
    |
 
 error: casting `usize` to `i16` may truncate the value
-  --> tests/ui/cast.rs:110:5
+  --> tests/ui/cast.rs:108:5
    |
 LL |     1usize as i16;
    |     ^^^^^^^^^^^^^
@@ -250,7 +250,7 @@ LL +     i16::try_from(1usize);
    |
 
 error: casting `usize` to `i16` may wrap around the value on targets with 16-bit wide pointers
-  --> tests/ui/cast.rs:110:5
+  --> tests/ui/cast.rs:108:5
    |
 LL |     1usize as i16;
    |     ^^^^^^^^^^^^^
@@ -259,7 +259,7 @@ LL |     1usize as i16;
    = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types
 
 error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers
-  --> tests/ui/cast.rs:115:5
+  --> tests/ui/cast.rs:113:5
    |
 LL |     1usize as i32;
    |     ^^^^^^^^^^^^^
@@ -272,19 +272,19 @@ LL +     i32::try_from(1usize);
    |
 
 error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:115:5
+  --> tests/ui/cast.rs:113:5
    |
 LL |     1usize as i32;
    |     ^^^^^^^^^^^^^
 
 error: casting `usize` to `i64` may wrap around the value on targets with 64-bit wide pointers
-  --> tests/ui/cast.rs:120:5
+  --> tests/ui/cast.rs:118:5
    |
 LL |     1usize as i64;
    |     ^^^^^^^^^^^^^
 
 error: casting `u16` to `isize` may wrap around the value on targets with 16-bit wide pointers
-  --> tests/ui/cast.rs:126:5
+  --> tests/ui/cast.rs:124:5
    |
 LL |     1u16 as isize;
    |     ^^^^^^^^^^^^^
@@ -293,13 +293,13 @@ LL |     1u16 as isize;
    = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types
 
 error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:130:5
+  --> tests/ui/cast.rs:128:5
    |
 LL |     1u32 as isize;
    |     ^^^^^^^^^^^^^
 
 error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:134:5
+  --> tests/ui/cast.rs:132:5
    |
 LL |     1u64 as isize;
    |     ^^^^^^^^^^^^^
@@ -312,55 +312,55 @@ LL +     isize::try_from(1u64);
    |
 
 error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers
-  --> tests/ui/cast.rs:134:5
+  --> tests/ui/cast.rs:132:5
    |
 LL |     1u64 as isize;
    |     ^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:140:5
+  --> tests/ui/cast.rs:138:5
    |
 LL |     -1i32 as u32;
    |     ^^^^^^^^^^^^
 
 error: casting `isize` to `usize` may lose the sign of the value
-  --> tests/ui/cast.rs:144:5
+  --> tests/ui/cast.rs:142:5
    |
 LL |     -1isize as usize;
    |     ^^^^^^^^^^^^^^^^
 
 error: casting `i8` to `u8` may lose the sign of the value
-  --> tests/ui/cast.rs:156:5
+  --> tests/ui/cast.rs:154:5
    |
 LL |     (i8::MIN).abs() as u8;
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i64` to `u64` may lose the sign of the value
-  --> tests/ui/cast.rs:161:5
+  --> tests/ui/cast.rs:159:5
    |
 LL |     (-1i64).abs() as u64;
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: casting `isize` to `usize` may lose the sign of the value
-  --> tests/ui/cast.rs:163:5
+  --> tests/ui/cast.rs:161:5
    |
 LL |     (-1isize).abs() as usize;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i64` to `u64` may lose the sign of the value
-  --> tests/ui/cast.rs:171:5
+  --> tests/ui/cast.rs:169:5
    |
 LL |     (unsafe { (-1i64).checked_abs().unwrap_unchecked() }) as u64;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i64` to `u64` may lose the sign of the value
-  --> tests/ui/cast.rs:187:5
+  --> tests/ui/cast.rs:185:5
    |
 LL |     (unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }) as u64;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i64` to `i8` may truncate the value
-  --> tests/ui/cast.rs:239:5
+  --> tests/ui/cast.rs:237:5
    |
 LL |     (-99999999999i64).min(1) as i8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -373,7 +373,7 @@ LL +     i8::try_from((-99999999999i64).min(1));
    |
 
 error: casting `u64` to `u8` may truncate the value
-  --> tests/ui/cast.rs:253:5
+  --> tests/ui/cast.rs:251:5
    |
 LL |     999999u64.clamp(0, 256) as u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -386,7 +386,7 @@ LL +     u8::try_from(999999u64.clamp(0, 256));
    |
 
 error: casting `main::E2` to `u8` may truncate the value
-  --> tests/ui/cast.rs:276:21
+  --> tests/ui/cast.rs:274:21
    |
 LL |             let _ = self as u8;
    |                     ^^^^^^^^^^
@@ -399,7 +399,7 @@ LL +             let _ = u8::try_from(self);
    |
 
 error: casting `main::E2::B` to `u8` will truncate the value
-  --> tests/ui/cast.rs:279:21
+  --> tests/ui/cast.rs:277:21
    |
 LL |             let _ = Self::B as u8;
    |                     ^^^^^^^^^^^^^
@@ -408,7 +408,7 @@ LL |             let _ = Self::B as u8;
    = help: to override `-D warnings` add `#[allow(clippy::cast_enum_truncation)]`
 
 error: casting `main::E5` to `i8` may truncate the value
-  --> tests/ui/cast.rs:321:21
+  --> tests/ui/cast.rs:319:21
    |
 LL |             let _ = self as i8;
    |                     ^^^^^^^^^^
@@ -421,13 +421,13 @@ LL +             let _ = i8::try_from(self);
    |
 
 error: casting `main::E5::A` to `i8` will truncate the value
-  --> tests/ui/cast.rs:324:21
+  --> tests/ui/cast.rs:322:21
    |
 LL |             let _ = Self::A as i8;
    |                     ^^^^^^^^^^^^^
 
 error: casting `main::E6` to `i16` may truncate the value
-  --> tests/ui/cast.rs:342:21
+  --> tests/ui/cast.rs:340:21
    |
 LL |             let _ = self as i16;
    |                     ^^^^^^^^^^^
@@ -440,7 +440,7 @@ LL +             let _ = i16::try_from(self);
    |
 
 error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:362:21
+  --> tests/ui/cast.rs:360:21
    |
 LL |             let _ = self as usize;
    |                     ^^^^^^^^^^^^^
@@ -453,7 +453,7 @@ LL +             let _ = usize::try_from(self);
    |
 
 error: casting `main::E10` to `u16` may truncate the value
-  --> tests/ui/cast.rs:410:21
+  --> tests/ui/cast.rs:408:21
    |
 LL |             let _ = self as u16;
    |                     ^^^^^^^^^^^
@@ -466,7 +466,7 @@ LL +             let _ = u16::try_from(self);
    |
 
 error: casting `u32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:422:13
+  --> tests/ui/cast.rs:420:13
    |
 LL |     let c = (q >> 16) as u8;
    |             ^^^^^^^^^^^^^^^
@@ -479,7 +479,7 @@ LL +     let c = u8::try_from(q >> 16);
    |
 
 error: casting `u32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:427:13
+  --> tests/ui/cast.rs:425:13
    |
 LL |     let c = (q / 1000) as u8;
    |             ^^^^^^^^^^^^^^^^
@@ -492,85 +492,85 @@ LL +     let c = u8::try_from(q / 1000);
    |
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:440:9
+  --> tests/ui/cast.rs:438:9
    |
 LL |         (x * x) as u32;
    |         ^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:446:32
+  --> tests/ui/cast.rs:444:32
    |
 LL |     let _a = |x: i32| -> u32 { (x * x * x * x) as u32 };
    |                                ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:449:5
+  --> tests/ui/cast.rs:447:5
    |
 LL |     (2_i32).checked_pow(3).unwrap() as u32;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:451:5
+  --> tests/ui/cast.rs:449:5
    |
 LL |     (-2_i32).pow(3) as u32;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:456:5
+  --> tests/ui/cast.rs:454:5
    |
 LL |     (-5_i32 % 2) as u32;
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:459:5
+  --> tests/ui/cast.rs:457:5
    |
 LL |     (-5_i32 % -2) as u32;
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:463:5
+  --> tests/ui/cast.rs:461:5
    |
 LL |     (-2_i32 >> 1) as u32;
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:467:5
+  --> tests/ui/cast.rs:465:5
    |
 LL |     (x * x) as u32;
    |     ^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:469:5
+  --> tests/ui/cast.rs:467:5
    |
 LL |     (x * x * x) as u32;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:473:5
+  --> tests/ui/cast.rs:471:5
    |
 LL |     (y * y * y * y * -2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:476:5
+  --> tests/ui/cast.rs:474:5
    |
 LL |     (y * y * y / y * 2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:478:5
+  --> tests/ui/cast.rs:476:5
    |
 LL |     (y * y / y * 2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:481:5
+  --> tests/ui/cast.rs:479:5
    |
 LL |     (y / y * y * -2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `/`
-  --> tests/ui/cast.rs:481:6
+  --> tests/ui/cast.rs:479:6
    |
 LL |     (y / y * y * -2) as u16;
    |      ^^^^^
@@ -578,97 +578,97 @@ LL |     (y / y * y * -2) as u16;
    = note: `#[deny(clippy::eq_op)]` on by default
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:485:5
+  --> tests/ui/cast.rs:483:5
    |
 LL |     (y + y + y + -2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:488:5
+  --> tests/ui/cast.rs:486:5
    |
 LL |     (y + y + y + 2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:492:5
+  --> tests/ui/cast.rs:490:5
    |
 LL |     (z + -2) as u16;
    |     ^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:495:5
+  --> tests/ui/cast.rs:493:5
    |
 LL |     (z + z + 2) as u16;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:499:9
+  --> tests/ui/cast.rs:497:9
    |
 LL |         (a * a * b * b * c * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:501:9
+  --> tests/ui/cast.rs:499:9
    |
 LL |         (a * b * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:504:9
+  --> tests/ui/cast.rs:502:9
    |
 LL |         (a * -b * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:507:9
+  --> tests/ui/cast.rs:505:9
    |
 LL |         (a * b * c * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:509:9
+  --> tests/ui/cast.rs:507:9
    |
 LL |         (a * -2) as u32;
    |         ^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:512:9
+  --> tests/ui/cast.rs:510:9
    |
 LL |         (a * b * c * -2) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:515:9
+  --> tests/ui/cast.rs:513:9
    |
 LL |         (a / b) as u32;
    |         ^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:517:9
+  --> tests/ui/cast.rs:515:9
    |
 LL |         (a / b * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:520:9
+  --> tests/ui/cast.rs:518:9
    |
 LL |         (a / b + b * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:523:9
+  --> tests/ui/cast.rs:521:9
    |
 LL |         a.saturating_pow(3) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:526:9
+  --> tests/ui/cast.rs:524:9
    |
 LL |         (a.abs() * b.pow(2) / c.abs()) as u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:534:21
+  --> tests/ui/cast.rs:532:21
    |
 LL |             let _ = i32::MIN as u32; // cast_sign_loss
    |                     ^^^^^^^^^^^^^^^
@@ -679,7 +679,7 @@ LL |     m!();
    = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: casting `u32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:537:21
+  --> tests/ui/cast.rs:535:21
    |
 LL |             let _ = u32::MAX as u8; // cast_possible_truncation
    |                     ^^^^^^^^^^^^^^
@@ -696,7 +696,7 @@ LL +             let _ = u8::try_from(u32::MAX); // cast_possible_truncation
    |
 
 error: casting `f64` to `f32` may truncate the value
-  --> tests/ui/cast.rs:540:21
+  --> tests/ui/cast.rs:538:21
    |
 LL |             let _ = std::f64::consts::PI as f32; // cast_possible_truncation
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -708,7 +708,7 @@ LL |     m!();
    = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:551:5
+  --> tests/ui/cast.rs:549:5
    |
 LL |     bar.unwrap().unwrap() as usize
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -721,13 +721,13 @@ LL +     usize::try_from(bar.unwrap().unwrap())
    |
 
 error: casting `i64` to `usize` may lose the sign of the value
-  --> tests/ui/cast.rs:551:5
+  --> tests/ui/cast.rs:549:5
    |
 LL |     bar.unwrap().unwrap() as usize
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `u64` to `u8` may truncate the value
-  --> tests/ui/cast.rs:568:5
+  --> tests/ui/cast.rs:566:5
    |
 LL |     (256 & 999999u64) as u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
@@ -740,7 +740,7 @@ LL +     u8::try_from(256 & 999999u64);
    |
 
 error: casting `u64` to `u8` may truncate the value
-  --> tests/ui/cast.rs:571:5
+  --> tests/ui/cast.rs:569:5
    |
 LL |     (255 % 999999u64) as u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/cast_size.rs b/src/tools/clippy/tests/ui/cast_size.rs
index e9240180886..e5bef2a99d5 100644
--- a/src/tools/clippy/tests/ui/cast_size.rs
+++ b/src/tools/clippy/tests/ui/cast_size.rs
@@ -1,7 +1,7 @@
 //@revisions: 32bit 64bit
 //@[32bit]ignore-bitwidth: 64
 //@[64bit]ignore-bitwidth: 32
-//@no-rustfix
+//@no-rustfix: only some diagnostics have suggestions
 
 #![warn(
     clippy::cast_precision_loss,
diff --git a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.rs b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.rs
index 145885702a9..7635f848cb3 100644
--- a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.rs
+++ b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.rs
@@ -4,7 +4,7 @@
     clippy::branches_sharing_code,
     clippy::unnecessary_literal_unwrap
 )]
-//@no-rustfix
+//@no-rustfix: has placeholders
 fn test_nested() {
     fn nested() {
         let x = Some(());
diff --git a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs
index ba0d36d85fe..785b2473c05 100644
--- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs
+++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs
@@ -1,4 +1,4 @@
-//@no-rustfix: overlapping suggestions
+//@no-rustfix: has placeholders
 #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
 #![allow(
     clippy::if_same_then_else,
diff --git a/src/tools/clippy/tests/ui/comparison_chain.rs b/src/tools/clippy/tests/ui/comparison_chain.rs
index 669690a4d42..6db75a4f364 100644
--- a/src/tools/clippy/tests/ui/comparison_chain.rs
+++ b/src/tools/clippy/tests/ui/comparison_chain.rs
@@ -1,4 +1,4 @@
-//@no-rustfix
+//@no-rustfix: has placeholders
 #![allow(dead_code)]
 #![warn(clippy::comparison_chain)]
 
@@ -12,11 +12,10 @@ fn f(x: u8, y: u8, z: u8) {
         a()
     }
 
-    if x > y {
-        //~^ comparison_chain
-
+    // Ignored: Not all cases are covered
+    if x < y {
         a()
-    } else if x < y {
+    } else if x > y {
         b()
     }
 
@@ -123,9 +122,8 @@ fn g(x: f64, y: f64, z: f64) {
 }
 
 fn h<T: Ord>(x: T, y: T, z: T) {
+    // Ignored: Not all cases are covered
     if x > y {
-        //~^ comparison_chain
-
         a()
     } else if x < y {
         b()
diff --git a/src/tools/clippy/tests/ui/comparison_chain.stderr b/src/tools/clippy/tests/ui/comparison_chain.stderr
index 0256573d0d9..ce580bd54a1 100644
--- a/src/tools/clippy/tests/ui/comparison_chain.stderr
+++ b/src/tools/clippy/tests/ui/comparison_chain.stderr
@@ -1,12 +1,12 @@
 error: `if` chain can be rewritten with `match`
-  --> tests/ui/comparison_chain.rs:15:5
+  --> tests/ui/comparison_chain.rs:29:5
    |
 LL | /     if x > y {
 LL | |
 LL | |
 LL | |         a()
-LL | |     } else if x < y {
-LL | |         b()
+...  |
+LL | |         c()
 LL | |     }
    | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}`
    |
@@ -14,19 +14,7 @@ LL | |     }
    = help: to override `-D warnings` add `#[allow(clippy::comparison_chain)]`
 
 error: `if` chain can be rewritten with `match`
-  --> tests/ui/comparison_chain.rs:30:5
-   |
-LL | /     if x > y {
-LL | |
-LL | |
-LL | |         a()
-...  |
-LL | |         c()
-LL | |     }
-   | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}`
-
-error: `if` chain can be rewritten with `match`
-  --> tests/ui/comparison_chain.rs:40:5
+  --> tests/ui/comparison_chain.rs:39:5
    |
 LL | /     if x > y {
 LL | |
@@ -38,7 +26,7 @@ LL | |     }
    | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}`
 
 error: `if` chain can be rewritten with `match`
-  --> tests/ui/comparison_chain.rs:50:5
+  --> tests/ui/comparison_chain.rs:49:5
    |
 LL | /     if x > 1 {
 LL | |
@@ -50,19 +38,7 @@ LL | |     }
    | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&1) {...}`
 
 error: `if` chain can be rewritten with `match`
-  --> tests/ui/comparison_chain.rs:126:5
-   |
-LL | /     if x > y {
-LL | |
-LL | |
-LL | |         a()
-LL | |     } else if x < y {
-LL | |         b()
-LL | |     }
-   | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}`
-
-error: `if` chain can be rewritten with `match`
-  --> tests/ui/comparison_chain.rs:134:5
+  --> tests/ui/comparison_chain.rs:132:5
    |
 LL | /     if x > y {
 LL | |
@@ -74,7 +50,7 @@ LL | |     }
    | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}`
 
 error: `if` chain can be rewritten with `match`
-  --> tests/ui/comparison_chain.rs:144:5
+  --> tests/ui/comparison_chain.rs:142:5
    |
 LL | /     if x > y {
 LL | |
@@ -86,7 +62,7 @@ LL | |     }
    | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}`
 
 error: `if` chain can be rewritten with `match`
-  --> tests/ui/comparison_chain.rs:251:5
+  --> tests/ui/comparison_chain.rs:249:5
    |
 LL | /     if x + 1 > y * 2 {
 LL | |
@@ -97,5 +73,5 @@ LL | |         "cc"
 LL | |     }
    | |_____^ help: consider rewriting the `if` chain with `match`: `match (x + 1).cmp(&(y * 2)) {...}`
 
-error: aborting due to 8 previous errors
+error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs b/src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs
index 5dffddc119a..cf37a4c5c4b 100644
--- a/src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs
+++ b/src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs
@@ -1,6 +1,3 @@
-#![feature(repr128)]
-#![allow(incomplete_features)]
-
 extern crate proc_macro;
 
 use proc_macro::{Delimiter, Group, Ident, Span, TokenStream, TokenTree};
diff --git a/src/tools/clippy/tests/ui/crashes/ice-12491.fixed b/src/tools/clippy/tests/ui/crashes/ice-12491.fixed
index ab9c61463e9..8a31eb9550b 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-12491.fixed
+++ b/src/tools/clippy/tests/ui/crashes/ice-12491.fixed
@@ -3,6 +3,6 @@
 fn main() {
     if (true) {
         // anything一些中文
-        //~^^ needless_return
+        //~^ needless_return
     }
 }
diff --git a/src/tools/clippy/tests/ui/crashes/ice-12491.rs b/src/tools/clippy/tests/ui/crashes/ice-12491.rs
index b774bd3788a..013aadadce5 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-12491.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-12491.rs
@@ -4,6 +4,6 @@ fn main() {
     if (true) {
         // anything一些中文
         return;
-        //~^^ needless_return
+        //~^ needless_return
     }
 }
diff --git a/src/tools/clippy/tests/ui/crashes/ice-12491.stderr b/src/tools/clippy/tests/ui/crashes/ice-12491.stderr
index 7cc418898e8..4b77299dd5e 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-12491.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-12491.stderr
@@ -1,10 +1,8 @@
 error: unneeded `return` statement
-  --> tests/ui/crashes/ice-12491.rs:5:24
+  --> tests/ui/crashes/ice-12491.rs:6:9
    |
-LL |           // anything一些中文
-   |  ____________________________^
-LL | |         return;
-   | |______________^
+LL |         return;
+   |         ^^^^^^
    |
    = note: `-D clippy::needless-return` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::needless_return)]`
diff --git a/src/tools/clippy/tests/ui/crashes/ice-12979.1.fixed b/src/tools/clippy/tests/ui/crashes/ice-12979.1.fixed
new file mode 100644
index 00000000000..e68f1c20a8e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-12979.1.fixed
@@ -0,0 +1,2 @@
+#[deny(clippy::declare_interior_mutable_const)] //~ empty_line_after_outer_attr
+const FOO: u8 = 0;
diff --git a/src/tools/clippy/tests/ui/crashes/ice-12979.2.fixed b/src/tools/clippy/tests/ui/crashes/ice-12979.2.fixed
new file mode 100644
index 00000000000..e89fa636d4b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-12979.2.fixed
@@ -0,0 +1,3 @@
+#![deny(clippy::declare_interior_mutable_const)] //~ empty_line_after_outer_attr
+
+const FOO: u8 = 0;
diff --git a/src/tools/clippy/tests/ui/crashes/ice-12979.rs b/src/tools/clippy/tests/ui/crashes/ice-12979.rs
new file mode 100644
index 00000000000..a2787291d9e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-12979.rs
@@ -0,0 +1,3 @@
+#[deny(clippy::declare_interior_mutable_const)] //~ empty_line_after_outer_attr
+
+const FOO: u8 = 0;
diff --git a/src/tools/clippy/tests/ui/crashes/ice-12979.stderr b/src/tools/clippy/tests/ui/crashes/ice-12979.stderr
new file mode 100644
index 00000000000..5e760816164
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-12979.stderr
@@ -0,0 +1,19 @@
+error: empty line after outer attribute
+  --> tests/ui/crashes/ice-12979.rs:1:1
+   |
+LL | / #[deny(clippy::declare_interior_mutable_const)]
+LL | |
+   | |_^
+LL |   const FOO: u8 = 0;
+   |   --------- the attribute applies to this constant item
+   |
+   = note: `-D clippy::empty-line-after-outer-attr` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::empty_line_after_outer_attr)]`
+   = help: if the empty line is unintentional, remove it
+help: if the attribute should apply to the crate use an inner attribute
+   |
+LL | #![deny(clippy::declare_interior_mutable_const)]
+   |  +
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6840.rs b/src/tools/clippy/tests/ui/crashes/ice-6840.rs
index 94481f24899..f30d83e1eee 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-6840.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-6840.rs
@@ -2,6 +2,7 @@
 //! This is a reproducer for the ICE 6840: https://github.com/rust-lang/rust-clippy/issues/6840.
 //! The ICE is caused by `TyCtxt::layout_of` and `is_normalizable` not being strict enough
 #![allow(dead_code)]
+#![deny(clippy::zero_sized_map_values)] // For ICE 14822
 use std::collections::HashMap;
 
 pub trait Rule {
diff --git a/src/tools/clippy/tests/ui/crashes/ice-9445.rs b/src/tools/clippy/tests/ui/crashes/ice-9445.rs
deleted file mode 100644
index 232b8e4a795..00000000000
--- a/src/tools/clippy/tests/ui/crashes/ice-9445.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-const UNINIT: core::mem::MaybeUninit<core::cell::Cell<&'static ()>> = core::mem::MaybeUninit::uninit();
-//~^ declare_interior_mutable_const
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-9445.stderr b/src/tools/clippy/tests/ui/crashes/ice-9445.stderr
deleted file mode 100644
index 76689cd6f5c..00000000000
--- a/src/tools/clippy/tests/ui/crashes/ice-9445.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error: a `const` item should not be interior mutable
-  --> tests/ui/crashes/ice-9445.rs:1:1
-   |
-LL | const UNINIT: core::mem::MaybeUninit<core::cell::Cell<&'static ()>> = core::mem::MaybeUninit::uninit();
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider making this `Sync` so that it can go in a static item or using a `thread_local`
-   = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]`
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.fixed b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.fixed
index 3b9dee81898..5993c2faf0d 100644
--- a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.fixed
+++ b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.fixed
@@ -123,3 +123,19 @@ mod issue12131 {
         //~^ dbg_macro
     }
 }
+
+mod issue14914 {
+    use std::future::Future;
+
+    fn takes_async_fn<F, Fut>(_f: F)
+    where
+        F: FnOnce(i32) -> Fut,
+        Fut: Future<Output = i32>,
+    {
+    }
+
+    fn should_not_panic() {
+        takes_async_fn(async |val| val);
+        //~^ dbg_macro
+    }
+}
diff --git a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.rs b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.rs
index 1dbbc6fe984..58d7e106e23 100644
--- a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.rs
+++ b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.rs
@@ -123,3 +123,19 @@ mod issue12131 {
         //~^ dbg_macro
     }
 }
+
+mod issue14914 {
+    use std::future::Future;
+
+    fn takes_async_fn<F, Fut>(_f: F)
+    where
+        F: FnOnce(i32) -> Fut,
+        Fut: Future<Output = i32>,
+    {
+    }
+
+    fn should_not_panic() {
+        takes_async_fn(async |val| dbg!(val));
+        //~^ dbg_macro
+    }
+}
diff --git a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr
index f1412023cc8..5a65b38a85c 100644
--- a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr
+++ b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr
@@ -230,5 +230,17 @@ LL -         print!("{}", dbg!(s));
 LL +         print!("{}", s);
    |
 
-error: aborting due to 19 previous errors
+error: the `dbg!` macro is intended as a debugging tool
+  --> tests/ui/dbg_macro/dbg_macro.rs:138:36
+   |
+LL |         takes_async_fn(async |val| dbg!(val));
+   |                                    ^^^^^^^^^
+   |
+help: remove the invocation before committing it to a version control system
+   |
+LL -         takes_async_fn(async |val| dbg!(val));
+LL +         takes_async_fn(async |val| val);
+   |
+
+error: aborting due to 20 previous errors
 
diff --git a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.rs b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.rs
index 1a5119651b5..96b35c9a20c 100644
--- a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.rs
+++ b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.rs
@@ -1,4 +1,4 @@
-//@no-rustfix
+//@no-rustfix: overlapping suggestions
 //@error-in-other-file:
 #![warn(clippy::dbg_macro)]
 
diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const.rs b/src/tools/clippy/tests/ui/declare_interior_mutable_const.rs
new file mode 100644
index 00000000000..c65df275038
--- /dev/null
+++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const.rs
@@ -0,0 +1,200 @@
+#![deny(clippy::declare_interior_mutable_const)]
+#![allow(clippy::missing_const_for_thread_local)]
+
+use core::cell::{Cell, RefCell, UnsafeCell};
+use core::mem::{ManuallyDrop, MaybeUninit};
+use core::ptr;
+use core::sync::atomic::AtomicUsize;
+
+fn main() {}
+
+const _: Cell<u32> = Cell::new(0);
+const UNSAFE_CELL: UnsafeCell<u32> = UnsafeCell::new(0); //~ declare_interior_mutable_const
+const REF_CELL: RefCell<u32> = RefCell::new(0); //~ declare_interior_mutable_const
+const CELL: Cell<u32> = Cell::new(0); //~ declare_interior_mutable_const
+
+// Constants can't contain pointers or references to type with interior mutability.
+const fn make_ptr() -> *const Cell<u32> {
+    ptr::null()
+}
+const PTR: *const Cell<u32> = make_ptr();
+
+const fn casted_to_cell_ptr() -> *const Cell<u32> {
+    const VALUE: u32 = 0;
+    &VALUE as *const _ as *const Cell<u32>
+}
+const TRANSMUTED_PTR: *const Cell<u32> = casted_to_cell_ptr();
+
+const CELL_TUPLE: (bool, Cell<u32>) = (true, Cell::new(0)); //~ declare_interior_mutable_const
+const CELL_ARRAY: [Cell<u32>; 2] = [Cell::new(0), Cell::new(0)]; //~ declare_interior_mutable_const
+
+const UNINIT_CELL: MaybeUninit<Cell<&'static ()>> = MaybeUninit::uninit();
+
+struct CellStruct {
+    x: u32,
+    cell: Cell<u32>,
+}
+//~v declare_interior_mutable_const
+const CELL_STRUCT: CellStruct = CellStruct {
+    x: 0,
+    cell: Cell::new(0),
+};
+
+enum CellEnum {
+    Cell(Cell<u32>),
+}
+const CELL_ENUM: CellEnum = CellEnum::Cell(Cell::new(0)); //~ declare_interior_mutable_const
+
+const NONE_CELL: Option<Cell<u32>> = None;
+const SOME_CELL: Option<Cell<u32>> = Some(Cell::new(0)); //~ declare_interior_mutable_const
+
+struct NestedCell([(Option<Cell<u32>>,); 1]);
+const NONE_NESTED_CELL: NestedCell = NestedCell([(None,)]);
+const SOME_NESTED_CELL: NestedCell = NestedCell([(Some(Cell::new(0)),)]); //~ declare_interior_mutable_const
+
+union UnionCell {
+    cell: ManuallyDrop<Cell<u32>>,
+    x: u32,
+}
+//~v declare_interior_mutable_const
+const UNION_CELL: UnionCell = UnionCell {
+    cell: ManuallyDrop::new(Cell::new(0)),
+};
+// Access to either union field is valid so we have to be conservative here.
+const UNION_U32: UnionCell = UnionCell { x: 0 }; //~ declare_interior_mutable_const
+
+struct Assoc;
+impl Assoc {
+    const SELF: Self = Self;
+    const CELL: Cell<u32> = Cell::new(0); //~ declare_interior_mutable_const
+}
+
+struct AssocCell(Cell<u32>);
+impl AssocCell {
+    const SELF: Self = Self(Cell::new(0)); //~ declare_interior_mutable_const
+    const NONE_SELF: Option<Self> = None;
+    const SOME_SELF: Option<Self> = Some(Self(Cell::new(0))); //~ declare_interior_mutable_const
+}
+
+trait ConstDefault {
+    // May or may not be `Freeze`
+    const DEFAULT: Self;
+}
+impl ConstDefault for u32 {
+    const DEFAULT: Self = 0;
+}
+impl<T: ConstDefault> ConstDefault for Cell<T> {
+    // Interior mutability is forced by the trait.
+    const DEFAULT: Self = Cell::new(T::DEFAULT);
+}
+impl<T: ConstDefault> ConstDefault for Option<Cell<T>> {
+    // Could have been `None`
+    const DEFAULT: Self = Some(Cell::new(T::DEFAULT)); //~ declare_interior_mutable_const
+}
+
+enum GenericEnumCell<T> {
+    Cell(Cell<T>),
+    Other(T),
+}
+impl<T: ConstDefault> ConstDefault for GenericEnumCell<T> {
+    const DEFAULT: Self = Self::Cell(Cell::new(T::DEFAULT)); //~ declare_interior_mutable_const
+}
+impl<T: ConstDefault> GenericEnumCell<T> {
+    const CELL: Self = Self::DEFAULT; //~ declare_interior_mutable_const
+    const CELL_BY_DEFAULT: Self = Self::Cell(Cell::DEFAULT); //~ declare_interior_mutable_const
+    const OTHER: Self = Self::Other(T::DEFAULT);
+    const FROM_OTHER: Self = Self::OTHER;
+}
+
+enum GenericNestedEnumCell<T> {
+    GenericEnumCell(GenericEnumCell<T>),
+    EnumCell(GenericEnumCell<u32>),
+    Other(T),
+}
+impl<T: ConstDefault> GenericNestedEnumCell<T> {
+    const GENERIC_OTHER: Self = Self::GenericEnumCell(GenericEnumCell::<T>::FROM_OTHER);
+    const GENERIC_CELL: Self = Self::GenericEnumCell(GenericEnumCell::<T>::CELL); //~ declare_interior_mutable_const
+    const ENUM_OTHER: Self = Self::EnumCell(GenericEnumCell::<u32>::FROM_OTHER);
+    const ENUM_CELL: Self = Self::EnumCell(GenericEnumCell::<u32>::CELL); //~ declare_interior_mutable_const
+}
+
+trait CellTrait: ConstDefault + Sized {
+    // Must be non-`Freeze` due to the type
+    const CELL: Cell<Self>; //~ declare_interior_mutable_const
+    // May be non-`Freeze`, but may not be
+    const OPTION_CELL: Option<Cell<Self>>;
+    // May get redefined by the impl, but the default is non-`Freeze`.
+    const SOME_CELL: Option<Cell<Self>> = Some(Cell::new(Self::DEFAULT)); //~ declare_interior_mutable_const
+    // May get redefined by the impl, but the default is `Freeze`.
+    const NONE_CELL: Option<Cell<Self>> = None;
+}
+
+trait CellWithAssoc {
+    type T;
+    const DEFAULT: Self::T;
+    // Must be non-`Freeze` due to the type
+    const CELL: Cell<Self::T>; //~ declare_interior_mutable_const
+    // May be non-`Freeze`, but may not be
+    const OPTION_CELL: Option<Cell<Self::T>>;
+    // May get redefined by the impl, but the default is non-`Freeze`.
+    const SOME_CELL: Option<Cell<Self::T>> = Some(Cell::new(Self::DEFAULT)); //~ declare_interior_mutable_const
+    // May get redefined by the impl, but the default is `Freeze`.
+    const NONE_CELL: Option<Cell<Self::T>> = None;
+}
+
+impl CellWithAssoc for () {
+    type T = u32;
+    const DEFAULT: Self::T = 0;
+    const CELL: Cell<Self::T> = Cell::new(0);
+    const OPTION_CELL: Option<Cell<Self::T>> = None;
+}
+
+trait WithAssoc {
+    type T;
+    const VALUE: Self::T;
+}
+
+impl WithAssoc for u32 {
+    type T = Cell<u32>;
+    // The cell comes from the impl block, not the trait.
+    const VALUE: Self::T = Cell::new(0); //~ declare_interior_mutable_const
+}
+
+trait WithLayeredAssoc {
+    type T: WithAssoc;
+    const VALUE: <Self::T as WithAssoc>::T;
+}
+
+impl WithLayeredAssoc for u32 {
+    type T = u32;
+    // The cell comes from the impl block, not the trait.
+    const VALUE: <Self::T as WithAssoc>::T = Cell::new(0); //~ declare_interior_mutable_const
+}
+
+trait WithGenericAssoc {
+    type T<U>;
+    const VALUE: Self::T<u32>;
+}
+
+impl WithGenericAssoc for u32 {
+    type T<U> = Cell<U>;
+    const VALUE: Self::T<u32> = Cell::new(0); //~ declare_interior_mutable_const
+}
+
+trait WithGenericAssocCell {
+    type T<U>;
+    const VALUE: Self::T<Cell<u32>>;
+}
+
+impl WithGenericAssocCell for u32 {
+    type T<U> = Option<U>;
+    const VALUE: Self::T<Cell<u32>> = None;
+}
+
+impl WithGenericAssocCell for i32 {
+    type T<U> = Option<U>;
+    const VALUE: Self::T<Cell<u32>> = Some(Cell::new(0)); //~ declare_interior_mutable_const
+}
+
+thread_local!(static THREAD_LOCAL_CELL: Cell<u32> = const { Cell::new(0) });
+thread_local!(static THREAD_LOCAL_CELL2: Cell<u32> = Cell::new(0));
diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const.stderr b/src/tools/clippy/tests/ui/declare_interior_mutable_const.stderr
new file mode 100644
index 00000000000..9742c17486c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const.stderr
@@ -0,0 +1,197 @@
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:12:7
+   |
+LL | const UNSAFE_CELL: UnsafeCell<u32> = UnsafeCell::new(0);
+   |       ^^^^^^^^^^^
+   |
+   = help: did you mean to make this a `thread_local!` item
+note: the lint level is defined here
+  --> tests/ui/declare_interior_mutable_const.rs:1:9
+   |
+LL | #![deny(clippy::declare_interior_mutable_const)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:13:7
+   |
+LL | const REF_CELL: RefCell<u32> = RefCell::new(0);
+   |       ^^^^^^^^
+   |
+   = help: did you mean to make this a `thread_local!` item
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:14:7
+   |
+LL | const CELL: Cell<u32> = Cell::new(0);
+   |       ^^^^
+   |
+   = help: did you mean to make this a `thread_local!` item
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:28:7
+   |
+LL | const CELL_TUPLE: (bool, Cell<u32>) = (true, Cell::new(0));
+   |       ^^^^^^^^^^
+   |
+   = help: did you mean to make this a `thread_local!` item
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:29:7
+   |
+LL | const CELL_ARRAY: [Cell<u32>; 2] = [Cell::new(0), Cell::new(0)];
+   |       ^^^^^^^^^^
+   |
+   = help: did you mean to make this a `thread_local!` item
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:38:7
+   |
+LL | const CELL_STRUCT: CellStruct = CellStruct {
+   |       ^^^^^^^^^^^
+   |
+   = help: did you mean to make this a `thread_local!` item
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:46:7
+   |
+LL | const CELL_ENUM: CellEnum = CellEnum::Cell(Cell::new(0));
+   |       ^^^^^^^^^
+   |
+   = help: did you mean to make this a `thread_local!` item
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:49:7
+   |
+LL | const SOME_CELL: Option<Cell<u32>> = Some(Cell::new(0));
+   |       ^^^^^^^^^
+   |
+   = help: did you mean to make this a `thread_local!` item
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:53:7
+   |
+LL | const SOME_NESTED_CELL: NestedCell = NestedCell([(Some(Cell::new(0)),)]);
+   |       ^^^^^^^^^^^^^^^^
+   |
+   = help: did you mean to make this a `thread_local!` item
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:60:7
+   |
+LL | const UNION_CELL: UnionCell = UnionCell {
+   |       ^^^^^^^^^^
+   |
+   = help: did you mean to make this a `thread_local!` item
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:64:7
+   |
+LL | const UNION_U32: UnionCell = UnionCell { x: 0 };
+   |       ^^^^^^^^^
+   |
+   = help: did you mean to make this a `thread_local!` item
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:69:11
+   |
+LL |     const CELL: Cell<u32> = Cell::new(0);
+   |           ^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:74:11
+   |
+LL |     const SELF: Self = Self(Cell::new(0));
+   |           ^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:76:11
+   |
+LL |     const SOME_SELF: Option<Self> = Some(Self(Cell::new(0)));
+   |           ^^^^^^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:92:11
+   |
+LL |     const DEFAULT: Self = Some(Cell::new(T::DEFAULT));
+   |           ^^^^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:100:11
+   |
+LL |     const DEFAULT: Self = Self::Cell(Cell::new(T::DEFAULT));
+   |           ^^^^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:103:11
+   |
+LL |     const CELL: Self = Self::DEFAULT;
+   |           ^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:104:11
+   |
+LL |     const CELL_BY_DEFAULT: Self = Self::Cell(Cell::DEFAULT);
+   |           ^^^^^^^^^^^^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:116:11
+   |
+LL |     const GENERIC_CELL: Self = Self::GenericEnumCell(GenericEnumCell::<T>::CELL);
+   |           ^^^^^^^^^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:118:11
+   |
+LL |     const ENUM_CELL: Self = Self::EnumCell(GenericEnumCell::<u32>::CELL);
+   |           ^^^^^^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:123:11
+   |
+LL |     const CELL: Cell<Self>;
+   |           ^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:127:11
+   |
+LL |     const SOME_CELL: Option<Cell<Self>> = Some(Cell::new(Self::DEFAULT));
+   |           ^^^^^^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:136:11
+   |
+LL |     const CELL: Cell<Self::T>;
+   |           ^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:140:11
+   |
+LL |     const SOME_CELL: Option<Cell<Self::T>> = Some(Cell::new(Self::DEFAULT));
+   |           ^^^^^^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:160:11
+   |
+LL |     const VALUE: Self::T = Cell::new(0);
+   |           ^^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:171:11
+   |
+LL |     const VALUE: <Self::T as WithAssoc>::T = Cell::new(0);
+   |           ^^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:181:11
+   |
+LL |     const VALUE: Self::T<u32> = Cell::new(0);
+   |           ^^^^^
+
+error: named constant with interior mutability
+  --> tests/ui/declare_interior_mutable_const.rs:196:11
+   |
+LL |     const VALUE: Self::T<Cell<u32>> = Some(Cell::new(0));
+   |           ^^^^^
+
+error: aborting due to 28 previous errors
+
diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.rs b/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.rs
deleted file mode 100644
index c87468277fb..00000000000
--- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.rs
+++ /dev/null
@@ -1,135 +0,0 @@
-#![warn(clippy::declare_interior_mutable_const)]
-
-use std::cell::Cell;
-use std::sync::atomic::AtomicUsize;
-
-enum OptionalCell {
-    Unfrozen(Cell<bool>),
-    Frozen,
-}
-
-// a constant with enums should be linted only when the used variant is unfrozen (#3962).
-const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true));
-//~^ declare_interior_mutable_const
-const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
-
-const fn unfrozen_variant() -> OptionalCell {
-    OptionalCell::Unfrozen(Cell::new(false))
-}
-
-const fn frozen_variant() -> OptionalCell {
-    OptionalCell::Frozen
-}
-
-const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant();
-//~^ declare_interior_mutable_const
-const FROZEN_VARIANT_FROM_FN: OptionalCell = frozen_variant();
-
-enum NestedInnermost {
-    Unfrozen(AtomicUsize),
-    Frozen,
-}
-
-struct NestedInner {
-    inner: NestedInnermost,
-}
-
-enum NestedOuter {
-    NestedInner(NestedInner),
-    NotNested(usize),
-}
-
-struct NestedOutermost {
-    outer: NestedOuter,
-}
-
-// a constant with enums should be linted according to its value, no matter how structs involve.
-const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost {
-    //~^ declare_interior_mutable_const
-    outer: NestedOuter::NestedInner(NestedInner {
-        inner: NestedInnermost::Unfrozen(AtomicUsize::new(2)),
-    }),
-};
-const NESTED_FROZEN_VARIANT: NestedOutermost = NestedOutermost {
-    outer: NestedOuter::NestedInner(NestedInner {
-        inner: NestedInnermost::Frozen,
-    }),
-};
-
-trait AssocConsts {
-    // When there's no default value, lint it only according to its type.
-    // Further details are on the corresponding code (`NonCopyConst::check_trait_item`).
-    const TO_BE_UNFROZEN_VARIANT: OptionalCell;
-    //~^ declare_interior_mutable_const
-    const TO_BE_FROZEN_VARIANT: OptionalCell;
-    //~^ declare_interior_mutable_const
-
-    // Lint default values accordingly.
-    const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
-    //~^ declare_interior_mutable_const
-    const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
-}
-
-// The lint doesn't trigger for an assoc constant in a trait impl with an unfrozen type even if it
-// has enums. Further details are on the corresponding code in 'NonCopyConst::check_impl_item'.
-impl AssocConsts for u64 {
-    const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
-    const TO_BE_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
-
-    // even if this sets an unfrozen variant, the lint ignores it.
-    const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
-}
-
-// At first, I thought I'd need to check every patterns in `trait.rs`; but, what matters
-// here are values; and I think substituted generics at definitions won't appear in MIR.
-trait AssocTypes {
-    type ToBeUnfrozen;
-
-    const TO_BE_UNFROZEN_VARIANT: Option<Self::ToBeUnfrozen>;
-    const TO_BE_FROZEN_VARIANT: Option<Self::ToBeUnfrozen>;
-}
-
-impl AssocTypes for u64 {
-    type ToBeUnfrozen = AtomicUsize;
-
-    const TO_BE_UNFROZEN_VARIANT: Option<Self::ToBeUnfrozen> = Some(Self::ToBeUnfrozen::new(4));
-    //~^ declare_interior_mutable_const
-    const TO_BE_FROZEN_VARIANT: Option<Self::ToBeUnfrozen> = None;
-}
-
-// Use raw pointers since direct generics have a false negative at the type level.
-enum BothOfCellAndGeneric<T> {
-    Unfrozen(Cell<*const T>),
-    Generic(*const T),
-    Frozen(usize),
-}
-
-impl<T> BothOfCellAndGeneric<T> {
-    const UNFROZEN_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null()));
-    //~^ declare_interior_mutable_const
-
-    // This is a false positive. The argument about this is on `is_value_unfrozen_raw`
-    const GENERIC_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Generic(std::ptr::null());
-    //~^ declare_interior_mutable_const
-
-    const FROZEN_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Frozen(5);
-
-    // This is what is likely to be a false negative when one tries to fix
-    // the `GENERIC_VARIANT` false positive.
-    const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null());
-    //~^ declare_interior_mutable_const
-}
-
-// associated types here is basically the same as the one above.
-trait BothOfCellAndGenericWithAssocType {
-    type AssocType;
-
-    const UNFROZEN_VARIANT: BothOfCellAndGeneric<Self::AssocType> =
-        //~^ declare_interior_mutable_const
-        BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null()));
-    const GENERIC_VARIANT: BothOfCellAndGeneric<Self::AssocType> = BothOfCellAndGeneric::Generic(std::ptr::null());
-    //~^ declare_interior_mutable_const
-    const FROZEN_VARIANT: BothOfCellAndGeneric<Self::AssocType> = BothOfCellAndGeneric::Frozen(5);
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.stderr b/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.stderr
deleted file mode 100644
index 32839d14f0e..00000000000
--- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.stderr
+++ /dev/null
@@ -1,89 +0,0 @@
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:12:1
-   |
-LL | const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true));
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider making this `Sync` so that it can go in a static item or using a `thread_local`
-   = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]`
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:24:1
-   |
-LL | const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant();
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider making this `Sync` so that it can go in a static item or using a `thread_local`
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:47:1
-   |
-LL | / const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost {
-LL | |
-LL | |     outer: NestedOuter::NestedInner(NestedInner {
-LL | |         inner: NestedInnermost::Unfrozen(AtomicUsize::new(2)),
-LL | |     }),
-LL | | };
-   | |__^
-   |
-   = help: consider making this a static item
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:62:5
-   |
-LL |     const TO_BE_UNFROZEN_VARIANT: OptionalCell;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:64:5
-   |
-LL |     const TO_BE_FROZEN_VARIANT: OptionalCell;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:68:5
-   |
-LL |     const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:95:5
-   |
-LL |     const TO_BE_UNFROZEN_VARIANT: Option<Self::ToBeUnfrozen> = Some(Self::ToBeUnfrozen::new(4));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:108:5
-   |
-LL |     const UNFROZEN_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null()));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:112:5
-   |
-LL |     const GENERIC_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Generic(std::ptr::null());
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:119:5
-   |
-LL |     const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null());
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:127:5
-   |
-LL | /     const UNFROZEN_VARIANT: BothOfCellAndGeneric<Self::AssocType> =
-LL | |
-LL | |         BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null()));
-   | |____________________________________________________________________^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:130:5
-   |
-LL |     const GENERIC_VARIANT: BothOfCellAndGeneric<Self::AssocType> = BothOfCellAndGeneric::Generic(std::ptr::null());
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 12 previous errors
-
diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs b/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs
deleted file mode 100644
index 7ce04a3f2c3..00000000000
--- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs
+++ /dev/null
@@ -1,76 +0,0 @@
-#![warn(clippy::declare_interior_mutable_const)]
-
-use std::borrow::Cow;
-use std::cell::Cell;
-use std::fmt::Display;
-use std::ptr;
-use std::sync::Once;
-use std::sync::atomic::AtomicUsize;
-
-const ATOMIC: AtomicUsize = AtomicUsize::new(5);
-//~^ declare_interior_mutable_const
-const CELL: Cell<usize> = Cell::new(6);
-//~^ declare_interior_mutable_const
-const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], Vec::new(), 7);
-//~^ declare_interior_mutable_const
-
-macro_rules! declare_const {
-    ($name:ident: $ty:ty = $e:expr) => {
-        const $name: $ty = $e;
-        //~^ declare_interior_mutable_const
-    };
-}
-declare_const!(_ONCE: Once = Once::new());
-
-// const ATOMIC_REF: &AtomicUsize = &AtomicUsize::new(7); // This will simply trigger E0492.
-
-const INTEGER: u8 = 8;
-const STRING: String = String::new();
-const STR: &str = "012345";
-const COW: Cow<str> = Cow::Borrowed("abcdef");
-// note: a const item of Cow is used in the `postgres` package.
-
-const NO_ANN: &dyn Display = &70;
-
-static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING);
-// there should be no lints on the line above line
-
-mod issue_8493 {
-    use std::cell::Cell;
-
-    thread_local! {
-        static _BAR: Cell<i32> = const { Cell::new(0) };
-    }
-
-    macro_rules! issue_8493 {
-        () => {
-            const _BAZ: Cell<usize> = Cell::new(0);
-            //~^ declare_interior_mutable_const
-            static _FOOBAR: () = {
-                thread_local! {
-                    static _VAR: Cell<i32> = const { Cell::new(0) };
-                }
-            };
-        };
-    }
-
-    issue_8493!();
-}
-
-#[repr(C, align(8))]
-struct NoAtomic(usize);
-#[repr(C, align(8))]
-struct WithAtomic(AtomicUsize);
-
-const fn with_non_null() -> *const WithAtomic {
-    const NO_ATOMIC: NoAtomic = NoAtomic(0);
-    (&NO_ATOMIC as *const NoAtomic).cast()
-}
-const WITH_ATOMIC: *const WithAtomic = with_non_null();
-
-struct Generic<T>(T);
-impl<T> Generic<T> {
-    const RAW_POINTER: *const Cell<T> = ptr::null();
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr b/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr
deleted file mode 100644
index 09299b29041..00000000000
--- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr
+++ /dev/null
@@ -1,50 +0,0 @@
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/others.rs:10:1
-   |
-LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider making this a static item
-   = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]`
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/others.rs:12:1
-   |
-LL | const CELL: Cell<usize> = Cell::new(6);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider making this `Sync` so that it can go in a static item or using a `thread_local`
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/others.rs:14:1
-   |
-LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], Vec::new(), 7);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider making this a static item
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/others.rs:19:9
-   |
-LL |         const $name: $ty = $e;
-   |         ^^^^^^^^^^^^^^^^^^^^^^
-...
-LL | declare_const!(_ONCE: Once = Once::new());
-   | ----------------------------------------- in this macro invocation
-   |
-   = note: this error originates in the macro `declare_const` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/others.rs:47:13
-   |
-LL |             const _BAZ: Cell<usize> = Cell::new(0);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-...
-LL |     issue_8493!();
-   |     ------------- in this macro invocation
-   |
-   = note: this error originates in the macro `issue_8493` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 5 previous errors
-
diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.rs b/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.rs
deleted file mode 100644
index d3139be6859..00000000000
--- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.rs
+++ /dev/null
@@ -1,162 +0,0 @@
-#![warn(clippy::declare_interior_mutable_const)]
-
-use std::borrow::Cow;
-use std::cell::Cell;
-use std::sync::atomic::AtomicUsize;
-
-macro_rules! declare_const {
-    ($name:ident: $ty:ty = $e:expr) => {
-        const $name: $ty = $e;
-        //~^ declare_interior_mutable_const
-    };
-}
-
-// a constant whose type is a concrete type should be linted at the definition site.
-trait ConcreteTypes {
-    const ATOMIC: AtomicUsize;
-    //~^ declare_interior_mutable_const
-    const INTEGER: u64;
-    const STRING: String;
-    declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC);
-}
-
-impl ConcreteTypes for u64 {
-    const ATOMIC: AtomicUsize = AtomicUsize::new(9);
-    const INTEGER: u64 = 10;
-    const STRING: String = String::new();
-}
-
-// a helper trait used below
-trait ConstDefault {
-    const DEFAULT: Self;
-}
-
-// a constant whose type is a generic type should be linted at the implementation site.
-trait GenericTypes<T, U> {
-    const TO_REMAIN_GENERIC: T;
-    const TO_BE_CONCRETE: U;
-
-    const HAVING_DEFAULT: T = Self::TO_REMAIN_GENERIC;
-    declare_const!(IN_MACRO: T = Self::TO_REMAIN_GENERIC);
-}
-
-impl<T: ConstDefault> GenericTypes<T, AtomicUsize> for u64 {
-    const TO_REMAIN_GENERIC: T = T::DEFAULT;
-    const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11);
-    //~^ declare_interior_mutable_const
-}
-
-// a helper type used below
-struct Wrapper<T>(T);
-
-// a constant whose type is an associated type should be linted at the implementation site, too.
-trait AssocTypes {
-    type ToBeFrozen;
-    type ToBeUnfrozen;
-    type ToBeGenericParam;
-
-    const TO_BE_FROZEN: Self::ToBeFrozen;
-    const TO_BE_UNFROZEN: Self::ToBeUnfrozen;
-    const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen>;
-    // to ensure it can handle things when a generic type remains after normalization.
-    const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper<Self::ToBeGenericParam>;
-}
-
-impl<T: ConstDefault> AssocTypes for Vec<T> {
-    type ToBeFrozen = u16;
-    type ToBeUnfrozen = AtomicUsize;
-    type ToBeGenericParam = T;
-
-    const TO_BE_FROZEN: Self::ToBeFrozen = 12;
-    const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13);
-    //~^ declare_interior_mutable_const
-    const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen> = Wrapper(AtomicUsize::new(14));
-    //~^ declare_interior_mutable_const
-    const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper<Self::ToBeGenericParam> = Wrapper(T::DEFAULT);
-}
-
-// a helper trait used below
-trait AssocTypesHelper {
-    type NotToBeBounded;
-    type ToBeBounded;
-
-    const NOT_TO_BE_BOUNDED: Self::NotToBeBounded;
-}
-
-// a constant whose type is an assoc type originated from a generic param bounded at the definition
-// site should be linted at there.
-trait AssocTypesFromGenericParam<T>
-where
-    T: AssocTypesHelper<ToBeBounded = AtomicUsize>,
-{
-    const NOT_BOUNDED: T::NotToBeBounded;
-    const BOUNDED: T::ToBeBounded;
-    //~^ declare_interior_mutable_const
-}
-
-impl<T> AssocTypesFromGenericParam<T> for u64
-where
-    T: AssocTypesHelper<ToBeBounded = AtomicUsize>,
-{
-    // an associated type could remain unknown in a trait impl.
-    const NOT_BOUNDED: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED;
-    const BOUNDED: T::ToBeBounded = AtomicUsize::new(15);
-}
-
-// a constant whose type is `Self` should be linted at the implementation site as well.
-// (`Option` requires `Sized` bound.)
-trait SelfType: Sized {
-    const SELF: Self;
-    // this was the one in the original issue (#5050).
-    const WRAPPED_SELF: Option<Self>;
-}
-
-impl SelfType for u64 {
-    const SELF: Self = 16;
-    const WRAPPED_SELF: Option<Self> = Some(20);
-}
-
-impl SelfType for AtomicUsize {
-    // this (interior mutable `Self` const) exists in `parking_lot`.
-    // `const_trait_impl` will replace it in the future, hopefully.
-    const SELF: Self = AtomicUsize::new(17);
-    //~^ declare_interior_mutable_const
-    const WRAPPED_SELF: Option<Self> = Some(AtomicUsize::new(21));
-    //~^ declare_interior_mutable_const
-}
-
-// Even though a constant contains a generic type, if it also have an interior mutable type,
-// it should be linted at the definition site.
-trait BothOfCellAndGeneric<T> {
-    const DIRECT: Cell<T>;
-    //~^ declare_interior_mutable_const
-    const INDIRECT: Cell<*const T>;
-    //~^ declare_interior_mutable_const
-}
-
-impl<T: ConstDefault> BothOfCellAndGeneric<T> for u64 {
-    const DIRECT: Cell<T> = Cell::new(T::DEFAULT);
-    //~^ declare_interior_mutable_const
-    const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null());
-}
-
-struct Local<T>(T);
-
-// a constant in an inherent impl are essentially the same as a normal const item
-// except there can be a generic or associated type.
-impl<T> Local<T>
-where
-    T: ConstDefault + AssocTypesHelper<ToBeBounded = AtomicUsize>,
-{
-    const ATOMIC: AtomicUsize = AtomicUsize::new(18);
-    //~^ declare_interior_mutable_const
-    const COW: Cow<'static, str> = Cow::Borrowed("tuvwxy");
-
-    const GENERIC_TYPE: T = T::DEFAULT;
-
-    const ASSOC_TYPE: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED;
-    const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19);
-    //~^ declare_interior_mutable_const
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr b/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr
deleted file mode 100644
index b03dd7a0840..00000000000
--- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr
+++ /dev/null
@@ -1,88 +0,0 @@
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:16:5
-   |
-LL |     const ATOMIC: AtomicUsize;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]`
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:9:9
-   |
-LL |         const $name: $ty = $e;
-   |         ^^^^^^^^^^^^^^^^^^^^^^
-...
-LL |     declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC);
-   |     ---------------------------------------------------------- in this macro invocation
-   |
-   = note: this error originates in the macro `declare_const` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:45:5
-   |
-LL |     const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:71:5
-   |
-LL |     const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:73:5
-   |
-LL |     const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen> = Wrapper(AtomicUsize::new(14));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:93:5
-   |
-LL |     const BOUNDED: T::ToBeBounded;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:122:5
-   |
-LL |     const SELF: Self = AtomicUsize::new(17);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:124:5
-   |
-LL |     const WRAPPED_SELF: Option<Self> = Some(AtomicUsize::new(21));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:131:5
-   |
-LL |     const DIRECT: Cell<T>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:133:5
-   |
-LL |     const INDIRECT: Cell<*const T>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:138:5
-   |
-LL |     const DIRECT: Cell<T> = Cell::new(T::DEFAULT);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:151:5
-   |
-LL |     const ATOMIC: AtomicUsize = AtomicUsize::new(18);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:158:5
-   |
-LL |     const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 13 previous errors
-
diff --git a/src/tools/clippy/tests/ui/deprecated.rs b/src/tools/clippy/tests/ui/deprecated.rs
index 2787f6406fe..6b69bdd29ce 100644
--- a/src/tools/clippy/tests/ui/deprecated.rs
+++ b/src/tools/clippy/tests/ui/deprecated.rs
@@ -2,20 +2,20 @@
 // Use that command to update this file and do not edit by hand.
 // Manual edits will be overwritten.
 
-#![warn(clippy::should_assert_eq)] //~ ERROR: lint `clippy::should_assert_eq`
+#![warn(clippy::assign_ops)] //~ ERROR: lint `clippy::assign_ops`
 #![warn(clippy::extend_from_slice)] //~ ERROR: lint `clippy::extend_from_slice`
-#![warn(clippy::range_step_by_zero)] //~ ERROR: lint `clippy::range_step_by_zero`
-#![warn(clippy::unstable_as_slice)] //~ ERROR: lint `clippy::unstable_as_slice`
-#![warn(clippy::unstable_as_mut_slice)] //~ ERROR: lint `clippy::unstable_as_mut_slice`
+#![warn(clippy::match_on_vec_items)] //~ ERROR: lint `clippy::match_on_vec_items`
 #![warn(clippy::misaligned_transmute)] //~ ERROR: lint `clippy::misaligned_transmute`
-#![warn(clippy::assign_ops)] //~ ERROR: lint `clippy::assign_ops`
+#![warn(clippy::option_map_or_err_ok)] //~ ERROR: lint `clippy::option_map_or_err_ok`
+#![warn(clippy::pub_enum_variant_names)] //~ ERROR: lint `clippy::pub_enum_variant_names`
+#![warn(clippy::range_step_by_zero)] //~ ERROR: lint `clippy::range_step_by_zero`
+#![warn(clippy::regex_macro)] //~ ERROR: lint `clippy::regex_macro`
+#![warn(clippy::replace_consts)] //~ ERROR: lint `clippy::replace_consts`
+#![warn(clippy::should_assert_eq)] //~ ERROR: lint `clippy::should_assert_eq`
 #![warn(clippy::unsafe_vector_initialization)] //~ ERROR: lint `clippy::unsafe_vector_initialization`
+#![warn(clippy::unstable_as_mut_slice)] //~ ERROR: lint `clippy::unstable_as_mut_slice`
+#![warn(clippy::unstable_as_slice)] //~ ERROR: lint `clippy::unstable_as_slice`
 #![warn(clippy::unused_collect)] //~ ERROR: lint `clippy::unused_collect`
-#![warn(clippy::replace_consts)] //~ ERROR: lint `clippy::replace_consts`
-#![warn(clippy::regex_macro)] //~ ERROR: lint `clippy::regex_macro`
-#![warn(clippy::pub_enum_variant_names)] //~ ERROR: lint `clippy::pub_enum_variant_names`
 #![warn(clippy::wrong_pub_self_convention)] //~ ERROR: lint `clippy::wrong_pub_self_convention`
-#![warn(clippy::option_map_or_err_ok)] //~ ERROR: lint `clippy::option_map_or_err_ok`
-#![warn(clippy::match_on_vec_items)] //~ ERROR: lint `clippy::match_on_vec_items`
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/deprecated.stderr b/src/tools/clippy/tests/ui/deprecated.stderr
index 604732405c3..07e59d33d60 100644
--- a/src/tools/clippy/tests/ui/deprecated.stderr
+++ b/src/tools/clippy/tests/ui/deprecated.stderr
@@ -1,8 +1,8 @@
-error: lint `clippy::should_assert_eq` has been removed: `assert!(a == b)` can now print the values the same way `assert_eq!(a, b) can
+error: lint `clippy::assign_ops` has been removed: compound operators are harmless and linting on them is not in scope for clippy
   --> tests/ui/deprecated.rs:5:9
    |
-LL | #![warn(clippy::should_assert_eq)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::assign_ops)]
+   |         ^^^^^^^^^^^^^^^^^^
    |
    = note: `-D renamed-and-removed-lints` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]`
@@ -13,83 +13,83 @@ error: lint `clippy::extend_from_slice` has been removed: `Vec::extend_from_slic
 LL | #![warn(clippy::extend_from_slice)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::range_step_by_zero` has been removed: `Iterator::step_by(0)` now panics and is no longer an infinite iterator
+error: lint `clippy::match_on_vec_items` has been removed: `clippy::indexing_slicing` covers indexing and slicing on `Vec<_>`
   --> tests/ui/deprecated.rs:7:9
    |
-LL | #![warn(clippy::range_step_by_zero)]
+LL | #![warn(clippy::match_on_vec_items)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` is now stable
+error: lint `clippy::misaligned_transmute` has been removed: split into `clippy::cast_ptr_alignment` and `clippy::transmute_ptr_to_ptr`
   --> tests/ui/deprecated.rs:8:9
    |
-LL | #![warn(clippy::unstable_as_slice)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::misaligned_transmute)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` is now stable
+error: lint `clippy::option_map_or_err_ok` has been removed: `clippy::manual_ok_or` covers this case
   --> tests/ui/deprecated.rs:9:9
    |
-LL | #![warn(clippy::unstable_as_mut_slice)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::option_map_or_err_ok)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::misaligned_transmute` has been removed: split into `clippy::cast_ptr_alignment` and `clippy::transmute_ptr_to_ptr`
+error: lint `clippy::pub_enum_variant_names` has been removed: `clippy::enum_variant_names` now covers this case via the `avoid-breaking-exported-api` config
   --> tests/ui/deprecated.rs:10:9
    |
-LL | #![warn(clippy::misaligned_transmute)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::pub_enum_variant_names)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::assign_ops` has been removed: compound operators are harmless and linting on them is not in scope for clippy
+error: lint `clippy::range_step_by_zero` has been removed: `Iterator::step_by(0)` now panics and is no longer an infinite iterator
   --> tests/ui/deprecated.rs:11:9
    |
-LL | #![warn(clippy::assign_ops)]
-   |         ^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::range_step_by_zero)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::unsafe_vector_initialization` has been removed: the suggested alternative could be substantially slower
+error: lint `clippy::regex_macro` has been removed: the `regex!` macro was removed from the regex crate in 2018
   --> tests/ui/deprecated.rs:12:9
    |
-LL | #![warn(clippy::unsafe_vector_initialization)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::regex_macro)]
+   |         ^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::unused_collect` has been removed: `Iterator::collect` is now marked as `#[must_use]`
+error: lint `clippy::replace_consts` has been removed: `min_value` and `max_value` are now deprecated
   --> tests/ui/deprecated.rs:13:9
    |
-LL | #![warn(clippy::unused_collect)]
+LL | #![warn(clippy::replace_consts)]
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::replace_consts` has been removed: `min_value` and `max_value` are now deprecated
+error: lint `clippy::should_assert_eq` has been removed: `assert!(a == b)` can now print the values the same way `assert_eq!(a, b) can
   --> tests/ui/deprecated.rs:14:9
    |
-LL | #![warn(clippy::replace_consts)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::should_assert_eq)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::regex_macro` has been removed: the `regex!` macro was removed from the regex crate in 2018
+error: lint `clippy::unsafe_vector_initialization` has been removed: the suggested alternative could be substantially slower
   --> tests/ui/deprecated.rs:15:9
    |
-LL | #![warn(clippy::regex_macro)]
-   |         ^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::unsafe_vector_initialization)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::pub_enum_variant_names` has been removed: `clippy::enum_variant_names` now covers this case via the `avoid-breaking-exported-api` config
+error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` is now stable
   --> tests/ui/deprecated.rs:16:9
    |
-LL | #![warn(clippy::pub_enum_variant_names)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::unstable_as_mut_slice)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::wrong_pub_self_convention` has been removed: `clippy::wrong_self_convention` now covers this case via the `avoid-breaking-exported-api` config
+error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` is now stable
   --> tests/ui/deprecated.rs:17:9
    |
-LL | #![warn(clippy::wrong_pub_self_convention)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::unstable_as_slice)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::option_map_or_err_ok` has been removed: `clippy::manual_ok_or` covers this case
+error: lint `clippy::unused_collect` has been removed: `Iterator::collect` is now marked as `#[must_use]`
   --> tests/ui/deprecated.rs:18:9
    |
-LL | #![warn(clippy::option_map_or_err_ok)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::unused_collect)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
 
-error: lint `clippy::match_on_vec_items` has been removed: `clippy::indexing_slicing` covers indexing and slicing on `Vec<_>`
+error: lint `clippy::wrong_pub_self_convention` has been removed: `clippy::wrong_self_convention` now covers this case via the `avoid-breaking-exported-api` config
   --> tests/ui/deprecated.rs:19:9
    |
-LL | #![warn(clippy::match_on_vec_items)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::wrong_pub_self_convention)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/doc/doc_markdown-issue_13097.fixed b/src/tools/clippy/tests/ui/doc/doc_markdown-issue_13097.fixed
index fb0f40b34a4..e0136584f3d 100644
--- a/src/tools/clippy/tests/ui/doc/doc_markdown-issue_13097.fixed
+++ b/src/tools/clippy/tests/ui/doc/doc_markdown-issue_13097.fixed
@@ -1,11 +1,37 @@
-// This test checks that words starting with capital letters and ending with "ified" don't
-// trigger the lint.
-
 #![deny(clippy::doc_markdown)]
+#![allow(clippy::doc_lazy_continuation)]
+
+mod issue13097 {
+    // This test checks that words starting with capital letters and ending with "ified" don't
+    // trigger the lint.
+    pub enum OutputFormat {
+        /// `HumaNified`
+        //~^ ERROR: item in documentation is missing backticks
+        Plain,
+        // Should not warn!
+        /// JSONified console output
+        Json,
+    }
+}
 
+#[rustfmt::skip]
 pub enum OutputFormat {
-    /// `HumaNified`
-    //~^ ERROR: item in documentation is missing backticks
+    /**
+     * `HumaNified`
+     //~^ ERROR: item in documentation is missing backticks
+     * Before \u{08888} `HumaNified` \{u08888} After
+     //~^ ERROR: item in documentation is missing backticks
+     * meow meow \[`meow_meow`\] meow meow?
+     //~^ ERROR: item in documentation is missing backticks
+     * \u{08888} `meow_meow` \[meow meow] meow?
+     //~^ ERROR: item in documentation is missing backticks
+     * Above
+     * \u{08888}
+     * \[hi\](<https://example.com>) `HumaNified` \[example](<https://example.com>)
+     //~^ ERROR: item in documentation is missing backticks
+     * \u{08888}
+     * Below
+     */
     Plain,
     // Should not warn!
     /// JSONified console output
diff --git a/src/tools/clippy/tests/ui/doc/doc_markdown-issue_13097.rs b/src/tools/clippy/tests/ui/doc/doc_markdown-issue_13097.rs
index 8c1e1a3cd6c..2e89fe6c56b 100644
--- a/src/tools/clippy/tests/ui/doc/doc_markdown-issue_13097.rs
+++ b/src/tools/clippy/tests/ui/doc/doc_markdown-issue_13097.rs
@@ -1,11 +1,37 @@
-// This test checks that words starting with capital letters and ending with "ified" don't
-// trigger the lint.
-
 #![deny(clippy::doc_markdown)]
+#![allow(clippy::doc_lazy_continuation)]
+
+mod issue13097 {
+    // This test checks that words starting with capital letters and ending with "ified" don't
+    // trigger the lint.
+    pub enum OutputFormat {
+        /// HumaNified
+        //~^ ERROR: item in documentation is missing backticks
+        Plain,
+        // Should not warn!
+        /// JSONified console output
+        Json,
+    }
+}
 
+#[rustfmt::skip]
 pub enum OutputFormat {
-    /// HumaNified
-    //~^ ERROR: item in documentation is missing backticks
+    /**
+     * HumaNified
+     //~^ ERROR: item in documentation is missing backticks
+     * Before \u{08888} HumaNified \{u08888} After
+     //~^ ERROR: item in documentation is missing backticks
+     * meow meow \[meow_meow\] meow meow?
+     //~^ ERROR: item in documentation is missing backticks
+     * \u{08888} meow_meow \[meow meow] meow?
+     //~^ ERROR: item in documentation is missing backticks
+     * Above
+     * \u{08888}
+     * \[hi\](<https://example.com>) HumaNified \[example](<https://example.com>)
+     //~^ ERROR: item in documentation is missing backticks
+     * \u{08888}
+     * Below
+     */
     Plain,
     // Should not warn!
     /// JSONified console output
diff --git a/src/tools/clippy/tests/ui/doc/doc_markdown-issue_13097.stderr b/src/tools/clippy/tests/ui/doc/doc_markdown-issue_13097.stderr
index 65b8f2ed80b..cea788301d4 100644
--- a/src/tools/clippy/tests/ui/doc/doc_markdown-issue_13097.stderr
+++ b/src/tools/clippy/tests/ui/doc/doc_markdown-issue_13097.stderr
@@ -1,19 +1,79 @@
 error: item in documentation is missing backticks
-  --> tests/ui/doc/doc_markdown-issue_13097.rs:7:9
+  --> tests/ui/doc/doc_markdown-issue_13097.rs:8:13
    |
-LL |     /// HumaNified
-   |         ^^^^^^^^^^
+LL |         /// HumaNified
+   |             ^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> tests/ui/doc/doc_markdown-issue_13097.rs:4:9
+  --> tests/ui/doc/doc_markdown-issue_13097.rs:1:9
    |
 LL | #![deny(clippy::doc_markdown)]
    |         ^^^^^^^^^^^^^^^^^^^^
 help: try
    |
-LL -     /// HumaNified
-LL +     /// `HumaNified`
+LL -         /// HumaNified
+LL +         /// `HumaNified`
    |
 
-error: aborting due to 1 previous error
+error: item in documentation is missing backticks
+  --> tests/ui/doc/doc_markdown-issue_13097.rs:20:8
+   |
+LL |      * HumaNified
+   |        ^^^^^^^^^^
+   |
+help: try
+   |
+LL -      * HumaNified
+LL +      * `HumaNified`
+   |
+
+error: item in documentation is missing backticks
+  --> tests/ui/doc/doc_markdown-issue_13097.rs:22:25
+   |
+LL |      * Before \u{08888} HumaNified \{u08888} After
+   |                         ^^^^^^^^^^
+   |
+help: try
+   |
+LL -      * Before \u{08888} HumaNified \{u08888} After
+LL +      * Before \u{08888} `HumaNified` \{u08888} After
+   |
+
+error: item in documentation is missing backticks
+  --> tests/ui/doc/doc_markdown-issue_13097.rs:24:20
+   |
+LL |      * meow meow \[meow_meow\] meow meow?
+   |                    ^^^^^^^^^
+   |
+help: try
+   |
+LL -      * meow meow \[meow_meow\] meow meow?
+LL +      * meow meow \[`meow_meow`\] meow meow?
+   |
+
+error: item in documentation is missing backticks
+  --> tests/ui/doc/doc_markdown-issue_13097.rs:26:18
+   |
+LL |      * \u{08888} meow_meow \[meow meow] meow?
+   |                  ^^^^^^^^^
+   |
+help: try
+   |
+LL -      * \u{08888} meow_meow \[meow meow] meow?
+LL +      * \u{08888} `meow_meow` \[meow meow] meow?
+   |
+
+error: item in documentation is missing backticks
+  --> tests/ui/doc/doc_markdown-issue_13097.rs:30:38
+   |
+LL |      * \[hi\](<https://example.com>) HumaNified \[example](<https://example.com>)
+   |                                      ^^^^^^^^^^
+   |
+help: try
+   |
+LL -      * \[hi\](<https://example.com>) HumaNified \[example](<https://example.com>)
+LL +      * \[hi\](<https://example.com>) `HumaNified` \[example](<https://example.com>)
+   |
+
+error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs b/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs
index e9218bbb409..73f62ac1246 100644
--- a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs
+++ b/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs
@@ -1,4 +1,4 @@
-//@no-rustfix
+//@no-rustfix: requires manual changes
 #![warn(clippy::double_ended_iterator_last)]
 
 // Should not be linted because applying the lint would move the original iterator. This can only be
diff --git a/src/tools/clippy/tests/ui/duplicated_attributes.rs b/src/tools/clippy/tests/ui/duplicated_attributes.rs
index 874f5d22075..3ca91d6f182 100644
--- a/src/tools/clippy/tests/ui/duplicated_attributes.rs
+++ b/src/tools/clippy/tests/ui/duplicated_attributes.rs
@@ -21,7 +21,7 @@ fn foo() {}
 fn bar() {}
 
 // No warning:
-#[rustc_on_unimplemented(on(_Self = "&str", label = "`a"), on(_Self = "alloc::string::String", label = "a"))]
+#[rustc_on_unimplemented(on(Self = "&str", label = "`a"), on(Self = "alloc::string::String", label = "a"))]
 trait Abc {}
 
 #[proc_macro_attr::duplicated_attr()] // Should not warn!
diff --git a/src/tools/clippy/tests/ui/empty_structs_with_brackets.fixed b/src/tools/clippy/tests/ui/empty_structs_with_brackets.fixed
index b1600862a8f..419cf2354f8 100644
--- a/src/tools/clippy/tests/ui/empty_structs_with_brackets.fixed
+++ b/src/tools/clippy/tests/ui/empty_structs_with_brackets.fixed
@@ -23,4 +23,12 @@ struct MyTupleStruct(usize, String); // should not trigger lint
 struct MySingleTupleStruct(usize); // should not trigger lint
 struct MyUnitLikeStruct; // should not trigger lint
 
+macro_rules! empty_struct {
+    ($s:ident) => {
+        struct $s {}
+    };
+}
+
+empty_struct!(FromMacro);
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/empty_structs_with_brackets.rs b/src/tools/clippy/tests/ui/empty_structs_with_brackets.rs
index 1f69c4be9ec..90c415c1220 100644
--- a/src/tools/clippy/tests/ui/empty_structs_with_brackets.rs
+++ b/src/tools/clippy/tests/ui/empty_structs_with_brackets.rs
@@ -23,4 +23,12 @@ struct MyTupleStruct(usize, String); // should not trigger lint
 struct MySingleTupleStruct(usize); // should not trigger lint
 struct MyUnitLikeStruct; // should not trigger lint
 
+macro_rules! empty_struct {
+    ($s:ident) => {
+        struct $s {}
+    };
+}
+
+empty_struct!(FromMacro);
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/entry_unfixable.rs b/src/tools/clippy/tests/ui/entry_unfixable.rs
index dbdacf95056..c4c05557208 100644
--- a/src/tools/clippy/tests/ui/entry_unfixable.rs
+++ b/src/tools/clippy/tests/ui/entry_unfixable.rs
@@ -1,6 +1,5 @@
-#![allow(unused, clippy::needless_pass_by_value, clippy::collapsible_if)]
+#![allow(clippy::needless_pass_by_value, clippy::collapsible_if)]
 #![warn(clippy::map_entry)]
-//@no-rustfix
 
 use std::collections::HashMap;
 use std::hash::Hash;
diff --git a/src/tools/clippy/tests/ui/entry_unfixable.stderr b/src/tools/clippy/tests/ui/entry_unfixable.stderr
index 9f9956d351b..0197d2ab4cf 100644
--- a/src/tools/clippy/tests/ui/entry_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/entry_unfixable.stderr
@@ -1,5 +1,5 @@
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> tests/ui/entry_unfixable.rs:28:13
+  --> tests/ui/entry_unfixable.rs:27:13
    |
 LL | /             if !self.values.contains_key(&name) {
 LL | |
@@ -14,7 +14,7 @@ LL | |             }
    = help: to override `-D warnings` add `#[allow(clippy::map_entry)]`
 
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> tests/ui/entry_unfixable.rs:43:5
+  --> tests/ui/entry_unfixable.rs:42:5
    |
 LL | /     if hm.contains_key(&key) {
 LL | |
@@ -26,7 +26,7 @@ LL | |     }
    | |_____^
 
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> tests/ui/entry_unfixable.rs:81:13
+  --> tests/ui/entry_unfixable.rs:80:13
    |
 LL | /             if self.globals.contains_key(&name) {
 LL | |
diff --git a/src/tools/clippy/tests/ui/excessive_precision.fixed b/src/tools/clippy/tests/ui/excessive_precision.fixed
index 99d09774d16..8a8c2e1939c 100644
--- a/src/tools/clippy/tests/ui/excessive_precision.fixed
+++ b/src/tools/clippy/tests/ui/excessive_precision.fixed
@@ -79,6 +79,9 @@ fn main() {
     // issue #2840
     let num = 0.000_000_000_01e-10f64;
 
+    // issue #6341
+    let exponential: f64 = 4.886506780521244E-03;
+
     // issue #7744
     let _ = 2.225_073_858_507_201e-308_f64;
     //~^ excessive_precision
diff --git a/src/tools/clippy/tests/ui/excessive_precision.rs b/src/tools/clippy/tests/ui/excessive_precision.rs
index a542fb2e7e3..5dcf55cb927 100644
--- a/src/tools/clippy/tests/ui/excessive_precision.rs
+++ b/src/tools/clippy/tests/ui/excessive_precision.rs
@@ -79,6 +79,9 @@ fn main() {
     // issue #2840
     let num = 0.000_000_000_01e-10f64;
 
+    // issue #6341
+    let exponential: f64 = 4.886506780521244E-03;
+
     // issue #7744
     let _ = 2.225_073_858_507_201_1e-308_f64;
     //~^ excessive_precision
diff --git a/src/tools/clippy/tests/ui/excessive_precision.stderr b/src/tools/clippy/tests/ui/excessive_precision.stderr
index 934a367e106..f5eeadf0c8c 100644
--- a/src/tools/clippy/tests/ui/excessive_precision.stderr
+++ b/src/tools/clippy/tests/ui/excessive_precision.stderr
@@ -157,7 +157,7 @@ LL +     let bad_bige32: f32 = 1.123_456_8E-10;
    |
 
 error: float has excessive precision
-  --> tests/ui/excessive_precision.rs:83:13
+  --> tests/ui/excessive_precision.rs:86:13
    |
 LL |     let _ = 2.225_073_858_507_201_1e-308_f64;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -169,7 +169,7 @@ LL +     let _ = 2.225_073_858_507_201e-308_f64;
    |
 
 error: float has excessive precision
-  --> tests/ui/excessive_precision.rs:87:13
+  --> tests/ui/excessive_precision.rs:90:13
    |
 LL |     let _ = 1.000_000_000_000_001e-324_f64;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -181,7 +181,7 @@ LL +     let _ = 0_f64;
    |
 
 error: float has excessive precision
-  --> tests/ui/excessive_precision.rs:98:20
+  --> tests/ui/excessive_precision.rs:101:20
    |
 LL |     const _: f64 = 3.0000000000000000e+00;
    |                    ^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/explicit_counter_loop.rs b/src/tools/clippy/tests/ui/explicit_counter_loop.rs
index 8340d99ace2..13934785d7b 100644
--- a/src/tools/clippy/tests/ui/explicit_counter_loop.rs
+++ b/src/tools/clippy/tests/ui/explicit_counter_loop.rs
@@ -1,6 +1,6 @@
 #![warn(clippy::explicit_counter_loop)]
 #![allow(clippy::uninlined_format_args, clippy::useless_vec)]
-//@no-rustfix
+//@no-rustfix: suggestion does not remove the `+= 1`
 fn main() {
     let mut vec = vec![1, 2, 3, 4];
     let mut _index = 0;
diff --git a/src/tools/clippy/tests/ui/explicit_deref_methods.fixed b/src/tools/clippy/tests/ui/explicit_deref_methods.fixed
index 0d1a5f80f3d..52c4d1b1f30 100644
--- a/src/tools/clippy/tests/ui/explicit_deref_methods.fixed
+++ b/src/tools/clippy/tests/ui/explicit_deref_methods.fixed
@@ -8,7 +8,8 @@
     clippy::needless_borrow,
     clippy::no_effect,
     clippy::uninlined_format_args,
-    clippy::unnecessary_literal_unwrap
+    clippy::unnecessary_literal_unwrap,
+    clippy::deref_addrof
 )]
 
 use std::ops::{Deref, DerefMut};
@@ -80,15 +81,10 @@ fn main() {
     let b: String = concat(just_return(a));
     //~^ explicit_deref_methods
 
-    let b: &str = &**a;
-    //~^ explicit_deref_methods
+    let b: &str = a.deref().deref();
 
     let opt_a = Some(a.clone());
-    let b = &*opt_a.unwrap();
-    //~^ explicit_deref_methods
-
-    // make sure `Aaa::deref` instead of `aaa.deref()` is not linted, as well as fully qualified
-    // syntax
+    let b = opt_a.unwrap().deref();
 
     Aaa::deref(&Aaa);
     Aaa::deref_mut(&mut Aaa);
@@ -139,4 +135,9 @@ fn main() {
     let no_lint = NoLint(42);
     let b = no_lint.deref();
     let b = no_lint.deref_mut();
+
+    let _ = &*&"foo"; //~ explicit_deref_methods
+    let mut x = String::new();
+    let _ = &&mut **&mut x; //~ explicit_deref_methods
+    let _ = &&mut ***(&mut &mut x); //~ explicit_deref_methods
 }
diff --git a/src/tools/clippy/tests/ui/explicit_deref_methods.rs b/src/tools/clippy/tests/ui/explicit_deref_methods.rs
index 8d4a899cd26..706d6cb2b79 100644
--- a/src/tools/clippy/tests/ui/explicit_deref_methods.rs
+++ b/src/tools/clippy/tests/ui/explicit_deref_methods.rs
@@ -8,7 +8,8 @@
     clippy::needless_borrow,
     clippy::no_effect,
     clippy::uninlined_format_args,
-    clippy::unnecessary_literal_unwrap
+    clippy::unnecessary_literal_unwrap,
+    clippy::deref_addrof
 )]
 
 use std::ops::{Deref, DerefMut};
@@ -81,14 +82,9 @@ fn main() {
     //~^ explicit_deref_methods
 
     let b: &str = a.deref().deref();
-    //~^ explicit_deref_methods
 
     let opt_a = Some(a.clone());
     let b = opt_a.unwrap().deref();
-    //~^ explicit_deref_methods
-
-    // make sure `Aaa::deref` instead of `aaa.deref()` is not linted, as well as fully qualified
-    // syntax
 
     Aaa::deref(&Aaa);
     Aaa::deref_mut(&mut Aaa);
@@ -139,4 +135,9 @@ fn main() {
     let no_lint = NoLint(42);
     let b = no_lint.deref();
     let b = no_lint.deref_mut();
+
+    let _ = &Deref::deref(&"foo"); //~ explicit_deref_methods
+    let mut x = String::new();
+    let _ = &DerefMut::deref_mut(&mut x); //~ explicit_deref_methods
+    let _ = &DerefMut::deref_mut((&mut &mut x).deref_mut()); //~ explicit_deref_methods
 }
diff --git a/src/tools/clippy/tests/ui/explicit_deref_methods.stderr b/src/tools/clippy/tests/ui/explicit_deref_methods.stderr
index 2ca376cba00..5036884366c 100644
--- a/src/tools/clippy/tests/ui/explicit_deref_methods.stderr
+++ b/src/tools/clippy/tests/ui/explicit_deref_methods.stderr
@@ -1,5 +1,5 @@
 error: explicit `deref` method call
-  --> tests/ui/explicit_deref_methods.rs:54:19
+  --> tests/ui/explicit_deref_methods.rs:55:19
    |
 LL |     let b: &str = a.deref();
    |                   ^^^^^^^^^ help: try: `&*a`
@@ -8,70 +8,76 @@ LL |     let b: &str = a.deref();
    = help: to override `-D warnings` add `#[allow(clippy::explicit_deref_methods)]`
 
 error: explicit `deref_mut` method call
-  --> tests/ui/explicit_deref_methods.rs:57:23
+  --> tests/ui/explicit_deref_methods.rs:58:23
    |
 LL |     let b: &mut str = a.deref_mut();
    |                       ^^^^^^^^^^^^^ help: try: `&mut **a`
 
 error: explicit `deref` method call
-  --> tests/ui/explicit_deref_methods.rs:61:39
+  --> tests/ui/explicit_deref_methods.rs:62:39
    |
 LL |     let b: String = format!("{}, {}", a.deref(), a.deref());
    |                                       ^^^^^^^^^ help: try: `&*a`
 
 error: explicit `deref` method call
-  --> tests/ui/explicit_deref_methods.rs:61:50
+  --> tests/ui/explicit_deref_methods.rs:62:50
    |
 LL |     let b: String = format!("{}, {}", a.deref(), a.deref());
    |                                                  ^^^^^^^^^ help: try: `&*a`
 
 error: explicit `deref` method call
-  --> tests/ui/explicit_deref_methods.rs:65:20
+  --> tests/ui/explicit_deref_methods.rs:66:20
    |
 LL |     println!("{}", a.deref());
    |                    ^^^^^^^^^ help: try: `&*a`
 
 error: explicit `deref` method call
-  --> tests/ui/explicit_deref_methods.rs:69:11
+  --> tests/ui/explicit_deref_methods.rs:70:11
    |
 LL |     match a.deref() {
    |           ^^^^^^^^^ help: try: `&*a`
 
 error: explicit `deref` method call
-  --> tests/ui/explicit_deref_methods.rs:74:28
+  --> tests/ui/explicit_deref_methods.rs:75:28
    |
 LL |     let b: String = concat(a.deref());
    |                            ^^^^^^^^^ help: try: `&*a`
 
 error: explicit `deref` method call
-  --> tests/ui/explicit_deref_methods.rs:77:13
+  --> tests/ui/explicit_deref_methods.rs:78:13
    |
 LL |     let b = just_return(a).deref();
    |             ^^^^^^^^^^^^^^^^^^^^^^ help: try: `just_return(a)`
 
 error: explicit `deref` method call
-  --> tests/ui/explicit_deref_methods.rs:80:28
+  --> tests/ui/explicit_deref_methods.rs:81:28
    |
 LL |     let b: String = concat(just_return(a).deref());
    |                            ^^^^^^^^^^^^^^^^^^^^^^ help: try: `just_return(a)`
 
 error: explicit `deref` method call
-  --> tests/ui/explicit_deref_methods.rs:83:19
+  --> tests/ui/explicit_deref_methods.rs:121:31
    |
-LL |     let b: &str = a.deref().deref();
-   |                   ^^^^^^^^^^^^^^^^^ help: try: `&**a`
+LL |     let b: &str = expr_deref!(a.deref());
+   |                               ^^^^^^^^^ help: try: `&*a`
 
 error: explicit `deref` method call
-  --> tests/ui/explicit_deref_methods.rs:87:13
+  --> tests/ui/explicit_deref_methods.rs:139:14
    |
-LL |     let b = opt_a.unwrap().deref();
-   |             ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*opt_a.unwrap()`
+LL |     let _ = &Deref::deref(&"foo");
+   |              ^^^^^^^^^^^^^^^^^^^^ help: try: `*&"foo"`
 
-error: explicit `deref` method call
-  --> tests/ui/explicit_deref_methods.rs:125:31
+error: explicit `deref_mut` method call
+  --> tests/ui/explicit_deref_methods.rs:141:14
    |
-LL |     let b: &str = expr_deref!(a.deref());
-   |                               ^^^^^^^^^ help: try: `&*a`
+LL |     let _ = &DerefMut::deref_mut(&mut x);
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut **&mut x`
+
+error: explicit `deref_mut` method call
+  --> tests/ui/explicit_deref_methods.rs:142:14
+   |
+LL |     let _ = &DerefMut::deref_mut((&mut &mut x).deref_mut());
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut ***(&mut &mut x)`
 
-error: aborting due to 12 previous errors
+error: aborting due to 13 previous errors
 
diff --git a/src/tools/clippy/tests/ui/explicit_into_iter_loop.fixed b/src/tools/clippy/tests/ui/explicit_into_iter_loop.fixed
index 2b68906ae39..c1b3c478eeb 100644
--- a/src/tools/clippy/tests/ui/explicit_into_iter_loop.fixed
+++ b/src/tools/clippy/tests/ui/explicit_into_iter_loop.fixed
@@ -73,3 +73,16 @@ fn main() {
 
     for _ in S.into_iter::<u32>() {}
 }
+
+fn issue14630() {
+    macro_rules! mac {
+        (into_iter $e:expr) => {
+            $e.into_iter()
+        };
+    }
+
+    for _ in dbg!([1, 2]) {}
+    //~^ explicit_into_iter_loop
+
+    for _ in mac!(into_iter [1, 2]) {}
+}
diff --git a/src/tools/clippy/tests/ui/explicit_into_iter_loop.rs b/src/tools/clippy/tests/ui/explicit_into_iter_loop.rs
index ca335b62d90..581e0dadcec 100644
--- a/src/tools/clippy/tests/ui/explicit_into_iter_loop.rs
+++ b/src/tools/clippy/tests/ui/explicit_into_iter_loop.rs
@@ -73,3 +73,16 @@ fn main() {
 
     for _ in S.into_iter::<u32>() {}
 }
+
+fn issue14630() {
+    macro_rules! mac {
+        (into_iter $e:expr) => {
+            $e.into_iter()
+        };
+    }
+
+    for _ in dbg!([1, 2]).into_iter() {}
+    //~^ explicit_into_iter_loop
+
+    for _ in mac!(into_iter [1, 2]) {}
+}
diff --git a/src/tools/clippy/tests/ui/explicit_into_iter_loop.stderr b/src/tools/clippy/tests/ui/explicit_into_iter_loop.stderr
index 1c3156755d4..26fb11e0048 100644
--- a/src/tools/clippy/tests/ui/explicit_into_iter_loop.stderr
+++ b/src/tools/clippy/tests/ui/explicit_into_iter_loop.stderr
@@ -37,5 +37,11 @@ error: it is more concise to loop over containers instead of using explicit iter
 LL |     for _ in mr.into_iter() {}
    |              ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut *mr`
 
-error: aborting due to 6 previous errors
+error: it is more concise to loop over containers instead of using explicit iteration methods
+  --> tests/ui/explicit_into_iter_loop.rs:84:14
+   |
+LL |     for _ in dbg!([1, 2]).into_iter() {}
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `dbg!([1, 2])`
+
+error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui/explicit_iter_loop.fixed b/src/tools/clippy/tests/ui/explicit_iter_loop.fixed
index cd0898dfc36..bffa1c4cf40 100644
--- a/src/tools/clippy/tests/ui/explicit_iter_loop.fixed
+++ b/src/tools/clippy/tests/ui/explicit_iter_loop.fixed
@@ -77,11 +77,11 @@ fn main() {
 
     struct NoIntoIter();
     impl NoIntoIter {
-        fn iter(&self) -> slice::Iter<u8> {
+        fn iter(&self) -> slice::Iter<'_, u8> {
             unimplemented!()
         }
 
-        fn iter_mut(&mut self) -> slice::IterMut<u8> {
+        fn iter_mut(&mut self) -> slice::IterMut<'_, u8> {
             unimplemented!()
         }
     }
@@ -183,3 +183,16 @@ pub fn issue_13184() {
     let rvalues = &values;
     for _ in rvalues.iter() {}
 }
+
+fn issue14630() {
+    macro_rules! mac {
+        (iter $e:expr) => {
+            $e.into_iter()
+        };
+    }
+
+    for _ in &dbg!([1, 2]) {}
+    //~^ explicit_iter_loop
+
+    for _ in mac!(iter [1, 2]) {}
+}
diff --git a/src/tools/clippy/tests/ui/explicit_iter_loop.rs b/src/tools/clippy/tests/ui/explicit_iter_loop.rs
index 02405280ce4..6a5a3dd00ba 100644
--- a/src/tools/clippy/tests/ui/explicit_iter_loop.rs
+++ b/src/tools/clippy/tests/ui/explicit_iter_loop.rs
@@ -77,11 +77,11 @@ fn main() {
 
     struct NoIntoIter();
     impl NoIntoIter {
-        fn iter(&self) -> slice::Iter<u8> {
+        fn iter(&self) -> slice::Iter<'_, u8> {
             unimplemented!()
         }
 
-        fn iter_mut(&mut self) -> slice::IterMut<u8> {
+        fn iter_mut(&mut self) -> slice::IterMut<'_, u8> {
             unimplemented!()
         }
     }
@@ -183,3 +183,16 @@ pub fn issue_13184() {
     let rvalues = &values;
     for _ in rvalues.iter() {}
 }
+
+fn issue14630() {
+    macro_rules! mac {
+        (iter $e:expr) => {
+            $e.into_iter()
+        };
+    }
+
+    for _ in dbg!([1, 2]).iter() {}
+    //~^ explicit_iter_loop
+
+    for _ in mac!(iter [1, 2]) {}
+}
diff --git a/src/tools/clippy/tests/ui/explicit_iter_loop.stderr b/src/tools/clippy/tests/ui/explicit_iter_loop.stderr
index 3816bb4db98..575dbe7813d 100644
--- a/src/tools/clippy/tests/ui/explicit_iter_loop.stderr
+++ b/src/tools/clippy/tests/ui/explicit_iter_loop.stderr
@@ -112,5 +112,11 @@ error: it is more concise to loop over references to containers instead of using
 LL |     for _ in r.iter() {}
    |              ^^^^^^^^ help: to write this more concisely, try: `r`
 
-error: aborting due to 18 previous errors
+error: it is more concise to loop over references to containers instead of using explicit iteration methods
+  --> tests/ui/explicit_iter_loop.rs:194:14
+   |
+LL |     for _ in dbg!([1, 2]).iter() {}
+   |              ^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&dbg!([1, 2])`
+
+error: aborting due to 19 previous errors
 
diff --git a/src/tools/clippy/tests/ui/filter_map_bool_then_unfixable.rs b/src/tools/clippy/tests/ui/filter_map_bool_then_unfixable.rs
index 68294292502..5d29e0317bb 100644
--- a/src/tools/clippy/tests/ui/filter_map_bool_then_unfixable.rs
+++ b/src/tools/clippy/tests/ui/filter_map_bool_then_unfixable.rs
@@ -1,6 +1,5 @@
-#![allow(clippy::question_mark, unused)]
+#![allow(clippy::question_mark)]
 #![warn(clippy::filter_map_bool_then)]
-//@no-rustfix
 
 fn issue11617() {
     let mut x: Vec<usize> = vec![0; 10];
diff --git a/src/tools/clippy/tests/ui/filter_map_bool_then_unfixable.stderr b/src/tools/clippy/tests/ui/filter_map_bool_then_unfixable.stderr
index 2025958136b..2990423973e 100644
--- a/src/tools/clippy/tests/ui/filter_map_bool_then_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/filter_map_bool_then_unfixable.stderr
@@ -1,5 +1,5 @@
 error: usage of `bool::then` in `filter_map`
-  --> tests/ui/filter_map_bool_then_unfixable.rs:7:48
+  --> tests/ui/filter_map_bool_then_unfixable.rs:6:48
    |
 LL |       let _ = (0..x.len()).zip(x.clone().iter()).filter_map(|(i, v)| {
    |  ________________________________________________^
@@ -16,7 +16,7 @@ LL | |     });
    = help: to override `-D warnings` add `#[allow(clippy::filter_map_bool_then)]`
 
 error: usage of `bool::then` in `filter_map`
-  --> tests/ui/filter_map_bool_then_unfixable.rs:23:26
+  --> tests/ui/filter_map_bool_then_unfixable.rs:22:26
    |
 LL |         let _ = x.iter().filter_map(|&x| x?.then(|| do_something(())));
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -24,7 +24,7 @@ LL |         let _ = x.iter().filter_map(|&x| x?.then(|| do_something(())));
    = help: consider using `filter` then `map` instead
 
 error: usage of `bool::then` in `filter_map`
-  --> tests/ui/filter_map_bool_then_unfixable.rs:27:14
+  --> tests/ui/filter_map_bool_then_unfixable.rs:26:14
    |
 LL |             .filter_map(|&x| if let Some(x) = x { x } else { return None }.then(|| do_something(())));
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -32,7 +32,7 @@ LL |             .filter_map(|&x| if let Some(x) = x { x } else { return None }.
    = help: consider using `filter` then `map` instead
 
 error: usage of `bool::then` in `filter_map`
-  --> tests/ui/filter_map_bool_then_unfixable.rs:29:26
+  --> tests/ui/filter_map_bool_then_unfixable.rs:28:26
    |
 LL |           let _ = x.iter().filter_map(|&x| {
    |  __________________________^
@@ -47,7 +47,7 @@ LL | |         });
    = help: consider using `filter` then `map` instead
 
 error: usage of `bool::then` in `filter_map`
-  --> tests/ui/filter_map_bool_then_unfixable.rs:47:26
+  --> tests/ui/filter_map_bool_then_unfixable.rs:46:26
    |
 LL |           let _ = x.iter().filter_map(|&x| {
    |  __________________________^
diff --git a/src/tools/clippy/tests/ui/ifs_same_cond.rs b/src/tools/clippy/tests/ui/ifs_same_cond.rs
index ebc3acb1b77..7067434953d 100644
--- a/src/tools/clippy/tests/ui/ifs_same_cond.rs
+++ b/src/tools/clippy/tests/ui/ifs_same_cond.rs
@@ -6,19 +6,25 @@ fn ifs_same_cond() {
     let b = false;
 
     if b {
+        //~^ ifs_same_cond
     } else if b {
+    }
+
+    if b {
         //~^ ifs_same_cond
+    } else if b {
+    } else if b {
     }
 
     if a == 1 {
-    } else if a == 1 {
         //~^ ifs_same_cond
+    } else if a == 1 {
     }
 
     if 2 * a == 1 {
+        //~^ ifs_same_cond
     } else if 2 * a == 2 {
     } else if 2 * a == 1 {
-        //~^ ifs_same_cond
     } else if a == 1 {
     }
 
@@ -50,8 +56,8 @@ fn ifs_same_cond() {
 fn issue10272() {
     let a = String::from("ha");
     if a.contains("ah") {
-    } else if a.contains("ah") {
         //~^ ifs_same_cond
+    } else if a.contains("ah") {
 
         // Trigger this lint
     } else if a.contains("ha") {
diff --git a/src/tools/clippy/tests/ui/ifs_same_cond.stderr b/src/tools/clippy/tests/ui/ifs_same_cond.stderr
index df21e6f1b82..7acbc1a6399 100644
--- a/src/tools/clippy/tests/ui/ifs_same_cond.stderr
+++ b/src/tools/clippy/tests/ui/ifs_same_cond.stderr
@@ -1,52 +1,52 @@
-error: this `if` has the same condition as a previous `if`
-  --> tests/ui/ifs_same_cond.rs:9:15
-   |
-LL |     } else if b {
-   |               ^
-   |
-note: same as this
+error: these `if` branches have the same condition
   --> tests/ui/ifs_same_cond.rs:8:8
    |
 LL |     if b {
    |        ^
+LL |
+LL |     } else if b {
+   |               ^
+   |
    = note: `-D clippy::ifs-same-cond` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::ifs_same_cond)]`
 
-error: this `if` has the same condition as a previous `if`
-  --> tests/ui/ifs_same_cond.rs:14:15
-   |
-LL |     } else if a == 1 {
-   |               ^^^^^^
-   |
-note: same as this
+error: these `if` branches have the same condition
   --> tests/ui/ifs_same_cond.rs:13:8
    |
+LL |     if b {
+   |        ^
+LL |
+LL |     } else if b {
+   |               ^
+LL |     } else if b {
+   |               ^
+
+error: these `if` branches have the same condition
+  --> tests/ui/ifs_same_cond.rs:19:8
+   |
 LL |     if a == 1 {
    |        ^^^^^^
+LL |
+LL |     } else if a == 1 {
+   |               ^^^^^^
 
-error: this `if` has the same condition as a previous `if`
-  --> tests/ui/ifs_same_cond.rs:20:15
-   |
-LL |     } else if 2 * a == 1 {
-   |               ^^^^^^^^^^
-   |
-note: same as this
-  --> tests/ui/ifs_same_cond.rs:18:8
+error: these `if` branches have the same condition
+  --> tests/ui/ifs_same_cond.rs:24:8
    |
 LL |     if 2 * a == 1 {
    |        ^^^^^^^^^^
+...
+LL |     } else if 2 * a == 1 {
+   |               ^^^^^^^^^^
 
-error: this `if` has the same condition as a previous `if`
-  --> tests/ui/ifs_same_cond.rs:53:15
-   |
-LL |     } else if a.contains("ah") {
-   |               ^^^^^^^^^^^^^^^^
-   |
-note: same as this
-  --> tests/ui/ifs_same_cond.rs:52:8
+error: these `if` branches have the same condition
+  --> tests/ui/ifs_same_cond.rs:58:8
    |
 LL |     if a.contains("ah") {
    |        ^^^^^^^^^^^^^^^^
+LL |
+LL |     } else if a.contains("ah") {
+   |               ^^^^^^^^^^^^^^^^
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/impl_trait_in_params.rs b/src/tools/clippy/tests/ui/impl_trait_in_params.rs
index 2039f6339a8..72e3e068c9c 100644
--- a/src/tools/clippy/tests/ui/impl_trait_in_params.rs
+++ b/src/tools/clippy/tests/ui/impl_trait_in_params.rs
@@ -1,7 +1,7 @@
 #![allow(unused)]
 #![warn(clippy::impl_trait_in_params)]
 
-//@no-rustfix
+//@no-rustfix: has placeholders
 pub trait Trait {}
 pub trait AnotherTrait<T> {}
 
diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.rs b/src/tools/clippy/tests/ui/indexing_slicing_index.rs
index cfa1c2f7c75..ab6a8235008 100644
--- a/src/tools/clippy/tests/ui/indexing_slicing_index.rs
+++ b/src/tools/clippy/tests/ui/indexing_slicing_index.rs
@@ -68,7 +68,7 @@ fn main() {
     // This should be linted, since `suppress-restriction-lint-in-const` default is false.
     const { &ARR[idx4()] };
     //~^ ERROR: indexing may panic
-    //~| ERROR: evaluation of `main
+    //~| ERROR: index out of bounds
 
     let y = &x;
     // Ok, referencing shouldn't affect this lint. See the issue 6021
diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr
index 50ee9b9edc7..8e24b898ed5 100644
--- a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr
+++ b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr
@@ -9,11 +9,11 @@ LL | const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-re
    = note: `-D clippy::indexing-slicing` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]`
 
-error[E0080]: evaluation of `main::{constant#3}` failed
+error[E0080]: index out of bounds: the length is 2 but the index is 4
   --> tests/ui/indexing_slicing_index.rs:69:14
    |
 LL |     const { &ARR[idx4()] };
-   |              ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
+   |              ^^^^^^^^^^^ evaluation of `main::{constant#3}` failed here
 
 note: erroneous constant encountered
   --> tests/ui/indexing_slicing_index.rs:69:5
diff --git a/src/tools/clippy/tests/ui/infinite_loop.rs b/src/tools/clippy/tests/ui/infinite_loop.rs
index 4a0968918bf..8ff7f3b0c18 100644
--- a/src/tools/clippy/tests/ui/infinite_loop.rs
+++ b/src/tools/clippy/tests/ui/infinite_loop.rs
@@ -1,5 +1,3 @@
-//@no-rustfix
-
 fn fn_val(i: i32) -> i32 {
     unimplemented!()
 }
diff --git a/src/tools/clippy/tests/ui/infinite_loop.stderr b/src/tools/clippy/tests/ui/infinite_loop.stderr
index 7ba1374d64f..04da9776c30 100644
--- a/src/tools/clippy/tests/ui/infinite_loop.stderr
+++ b/src/tools/clippy/tests/ui/infinite_loop.stderr
@@ -1,5 +1,5 @@
 error: variables in the condition are not mutated in the loop body
-  --> tests/ui/infinite_loop.rs:22:11
+  --> tests/ui/infinite_loop.rs:20:11
    |
 LL |     while y < 10 {
    |           ^^^^^^
@@ -8,7 +8,7 @@ LL |     while y < 10 {
    = note: `#[deny(clippy::while_immutable_condition)]` on by default
 
 error: variables in the condition are not mutated in the loop body
-  --> tests/ui/infinite_loop.rs:29:11
+  --> tests/ui/infinite_loop.rs:27:11
    |
 LL |     while y < 10 && x < 3 {
    |           ^^^^^^^^^^^^^^^
@@ -16,7 +16,7 @@ LL |     while y < 10 && x < 3 {
    = note: this may lead to an infinite or to a never running loop
 
 error: variables in the condition are not mutated in the loop body
-  --> tests/ui/infinite_loop.rs:38:11
+  --> tests/ui/infinite_loop.rs:36:11
    |
 LL |     while !cond {
    |           ^^^^^
@@ -24,7 +24,7 @@ LL |     while !cond {
    = note: this may lead to an infinite or to a never running loop
 
 error: variables in the condition are not mutated in the loop body
-  --> tests/ui/infinite_loop.rs:84:11
+  --> tests/ui/infinite_loop.rs:82:11
    |
 LL |     while i < 3 {
    |           ^^^^^
@@ -32,7 +32,7 @@ LL |     while i < 3 {
    = note: this may lead to an infinite or to a never running loop
 
 error: variables in the condition are not mutated in the loop body
-  --> tests/ui/infinite_loop.rs:91:11
+  --> tests/ui/infinite_loop.rs:89:11
    |
 LL |     while i < 3 && j > 0 {
    |           ^^^^^^^^^^^^^^
@@ -40,7 +40,7 @@ LL |     while i < 3 && j > 0 {
    = note: this may lead to an infinite or to a never running loop
 
 error: variables in the condition are not mutated in the loop body
-  --> tests/ui/infinite_loop.rs:97:11
+  --> tests/ui/infinite_loop.rs:95:11
    |
 LL |     while i < 3 {
    |           ^^^^^
@@ -48,7 +48,7 @@ LL |     while i < 3 {
    = note: this may lead to an infinite or to a never running loop
 
 error: variables in the condition are not mutated in the loop body
-  --> tests/ui/infinite_loop.rs:114:11
+  --> tests/ui/infinite_loop.rs:112:11
    |
 LL |     while i < 3 {
    |           ^^^^^
@@ -56,7 +56,7 @@ LL |     while i < 3 {
    = note: this may lead to an infinite or to a never running loop
 
 error: variables in the condition are not mutated in the loop body
-  --> tests/ui/infinite_loop.rs:121:11
+  --> tests/ui/infinite_loop.rs:119:11
    |
 LL |     while i < 3 {
    |           ^^^^^
@@ -64,7 +64,7 @@ LL |     while i < 3 {
    = note: this may lead to an infinite or to a never running loop
 
 error: variables in the condition are not mutated in the loop body
-  --> tests/ui/infinite_loop.rs:189:15
+  --> tests/ui/infinite_loop.rs:187:15
    |
 LL |         while self.count < n {
    |               ^^^^^^^^^^^^^^
@@ -72,7 +72,7 @@ LL |         while self.count < n {
    = note: this may lead to an infinite or to a never running loop
 
 error: variables in the condition are not mutated in the loop body
-  --> tests/ui/infinite_loop.rs:199:11
+  --> tests/ui/infinite_loop.rs:197:11
    |
 LL |     while y < 10 {
    |           ^^^^^^
@@ -82,7 +82,7 @@ LL |     while y < 10 {
    = help: rewrite it as `if cond { loop { } }`
 
 error: variables in the condition are not mutated in the loop body
-  --> tests/ui/infinite_loop.rs:208:11
+  --> tests/ui/infinite_loop.rs:206:11
    |
 LL |     while y < 10 {
    |           ^^^^^^
diff --git a/src/tools/clippy/tests/ui/infinite_loops.rs b/src/tools/clippy/tests/ui/infinite_loops.rs
index eaa8d008806..fcd1f795fff 100644
--- a/src/tools/clippy/tests/ui/infinite_loops.rs
+++ b/src/tools/clippy/tests/ui/infinite_loops.rs
@@ -1,4 +1,4 @@
-//@no-rustfix
+//@no-rustfix: multiple suggestions add `-> !` to the same fn
 //@aux-build:proc_macros.rs
 
 #![allow(clippy::never_loop)]
diff --git a/src/tools/clippy/tests/ui/into_iter_without_iter.rs b/src/tools/clippy/tests/ui/into_iter_without_iter.rs
index 45e34b3930a..f0b86e5620e 100644
--- a/src/tools/clippy/tests/ui/into_iter_without_iter.rs
+++ b/src/tools/clippy/tests/ui/into_iter_without_iter.rs
@@ -1,4 +1,4 @@
-//@no-rustfix
+//@no-rustfix: suggestions reference out of scope lifetimes/types
 //@aux-build:proc_macros.rs
 #![warn(clippy::into_iter_without_iter)]
 extern crate proc_macros;
diff --git a/src/tools/clippy/tests/ui/iter_next_loop.rs b/src/tools/clippy/tests/ui/iter_next_loop.rs
index 32711c7ef62..969c51006af 100644
--- a/src/tools/clippy/tests/ui/iter_next_loop.rs
+++ b/src/tools/clippy/tests/ui/iter_next_loop.rs
@@ -8,10 +8,23 @@ fn main() {
 
     struct Unrelated(&'static [u8]);
     impl Unrelated {
-        fn next(&self) -> std::slice::Iter<u8> {
+        fn next(&self) -> std::slice::Iter<'_, u8> {
             self.0.iter()
         }
     }
     let u = Unrelated(&[0]);
     for _v in u.next() {} // no error
 }
+
+fn issue14630() {
+    macro_rules! mac {
+        (next $e:expr) => {
+            $e.iter().next()
+        };
+    }
+
+    for _ in dbg!([1, 2].iter()).next() {}
+    //~^ iter_next_loop
+
+    for _ in mac!(next [1, 2]) {}
+}
diff --git a/src/tools/clippy/tests/ui/iter_next_loop.stderr b/src/tools/clippy/tests/ui/iter_next_loop.stderr
index acc55031c3b..c076e86db93 100644
--- a/src/tools/clippy/tests/ui/iter_next_loop.stderr
+++ b/src/tools/clippy/tests/ui/iter_next_loop.stderr
@@ -7,5 +7,11 @@ LL |     for _ in x.iter().next() {}
    = note: `-D clippy::iter-next-loop` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::iter_next_loop)]`
 
-error: aborting due to 1 previous error
+error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want
+  --> tests/ui/iter_next_loop.rs:26:14
+   |
+LL |     for _ in dbg!([1, 2].iter()).next() {}
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/iter_not_returning_iterator.rs b/src/tools/clippy/tests/ui/iter_not_returning_iterator.rs
index 5c8c8eb4a43..d2497ed4330 100644
--- a/src/tools/clippy/tests/ui/iter_not_returning_iterator.rs
+++ b/src/tools/clippy/tests/ui/iter_not_returning_iterator.rs
@@ -71,7 +71,7 @@ impl S {
 
 struct S2([u8]);
 impl S2 {
-    fn iter(&self) -> core::slice::Iter<u8> {
+    fn iter(&self) -> core::slice::Iter<'_, u8> {
         self.0.iter()
     }
 }
diff --git a/src/tools/clippy/tests/ui/iter_out_of_bounds.rs b/src/tools/clippy/tests/ui/iter_out_of_bounds.rs
index b34e4ad7824..6458b1342dc 100644
--- a/src/tools/clippy/tests/ui/iter_out_of_bounds.rs
+++ b/src/tools/clippy/tests/ui/iter_out_of_bounds.rs
@@ -1,5 +1,3 @@
-//@no-rustfix
-
 #![deny(clippy::iter_out_of_bounds)]
 #![allow(clippy::useless_vec)]
 
diff --git a/src/tools/clippy/tests/ui/iter_out_of_bounds.stderr b/src/tools/clippy/tests/ui/iter_out_of_bounds.stderr
index 19ac60b9d0a..1b3a99e1e94 100644
--- a/src/tools/clippy/tests/ui/iter_out_of_bounds.stderr
+++ b/src/tools/clippy/tests/ui/iter_out_of_bounds.stderr
@@ -1,18 +1,18 @@
 error: this `.skip()` call skips more items than the iterator will produce
-  --> tests/ui/iter_out_of_bounds.rs:12:14
+  --> tests/ui/iter_out_of_bounds.rs:10:14
    |
 LL |     for _ in [1, 2, 3].iter().skip(4) {
    |              ^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: this operation is useless and will create an empty iterator
 note: the lint level is defined here
-  --> tests/ui/iter_out_of_bounds.rs:3:9
+  --> tests/ui/iter_out_of_bounds.rs:1:9
    |
 LL | #![deny(clippy::iter_out_of_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this `.take()` call takes more items than the iterator will produce
-  --> tests/ui/iter_out_of_bounds.rs:17:19
+  --> tests/ui/iter_out_of_bounds.rs:15:19
    |
 LL |     for (i, _) in [1, 2, 3].iter().take(4).enumerate() {
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -20,7 +20,7 @@ LL |     for (i, _) in [1, 2, 3].iter().take(4).enumerate() {
    = note: this operation is useless and the returned iterator will simply yield the same items
 
 error: this `.take()` call takes more items than the iterator will produce
-  --> tests/ui/iter_out_of_bounds.rs:24:14
+  --> tests/ui/iter_out_of_bounds.rs:22:14
    |
 LL |     for _ in (&&&&&&[1, 2, 3]).iter().take(4) {}
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -28,7 +28,7 @@ LL |     for _ in (&&&&&&[1, 2, 3]).iter().take(4) {}
    = note: this operation is useless and the returned iterator will simply yield the same items
 
 error: this `.skip()` call skips more items than the iterator will produce
-  --> tests/ui/iter_out_of_bounds.rs:27:14
+  --> tests/ui/iter_out_of_bounds.rs:25:14
    |
 LL |     for _ in [1, 2, 3].iter().skip(4) {}
    |              ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -36,7 +36,7 @@ LL |     for _ in [1, 2, 3].iter().skip(4) {}
    = note: this operation is useless and will create an empty iterator
 
 error: this `.skip()` call skips more items than the iterator will produce
-  --> tests/ui/iter_out_of_bounds.rs:30:14
+  --> tests/ui/iter_out_of_bounds.rs:28:14
    |
 LL |     for _ in [1; 3].iter().skip(4) {}
    |              ^^^^^^^^^^^^^^^^^^^^^
@@ -44,7 +44,7 @@ LL |     for _ in [1; 3].iter().skip(4) {}
    = note: this operation is useless and will create an empty iterator
 
 error: this `.skip()` call skips more items than the iterator will produce
-  --> tests/ui/iter_out_of_bounds.rs:36:14
+  --> tests/ui/iter_out_of_bounds.rs:34:14
    |
 LL |     for _ in vec![1, 2, 3].iter().skip(4) {}
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -52,7 +52,7 @@ LL |     for _ in vec![1, 2, 3].iter().skip(4) {}
    = note: this operation is useless and will create an empty iterator
 
 error: this `.skip()` call skips more items than the iterator will produce
-  --> tests/ui/iter_out_of_bounds.rs:39:14
+  --> tests/ui/iter_out_of_bounds.rs:37:14
    |
 LL |     for _ in vec![1; 3].iter().skip(4) {}
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -60,7 +60,7 @@ LL |     for _ in vec![1; 3].iter().skip(4) {}
    = note: this operation is useless and will create an empty iterator
 
 error: this `.skip()` call skips more items than the iterator will produce
-  --> tests/ui/iter_out_of_bounds.rs:43:14
+  --> tests/ui/iter_out_of_bounds.rs:41:14
    |
 LL |     for _ in x.iter().skip(4) {}
    |              ^^^^^^^^^^^^^^^^
@@ -68,7 +68,7 @@ LL |     for _ in x.iter().skip(4) {}
    = note: this operation is useless and will create an empty iterator
 
 error: this `.skip()` call skips more items than the iterator will produce
-  --> tests/ui/iter_out_of_bounds.rs:47:14
+  --> tests/ui/iter_out_of_bounds.rs:45:14
    |
 LL |     for _ in x.iter().skip(n) {}
    |              ^^^^^^^^^^^^^^^^
@@ -76,7 +76,7 @@ LL |     for _ in x.iter().skip(n) {}
    = note: this operation is useless and will create an empty iterator
 
 error: this `.skip()` call skips more items than the iterator will produce
-  --> tests/ui/iter_out_of_bounds.rs:52:14
+  --> tests/ui/iter_out_of_bounds.rs:50:14
    |
 LL |     for _ in empty().skip(1) {}
    |              ^^^^^^^^^^^^^^^
@@ -84,7 +84,7 @@ LL |     for _ in empty().skip(1) {}
    = note: this operation is useless and will create an empty iterator
 
 error: this `.take()` call takes more items than the iterator will produce
-  --> tests/ui/iter_out_of_bounds.rs:55:14
+  --> tests/ui/iter_out_of_bounds.rs:53:14
    |
 LL |     for _ in empty().take(1) {}
    |              ^^^^^^^^^^^^^^^
@@ -92,7 +92,7 @@ LL |     for _ in empty().take(1) {}
    = note: this operation is useless and the returned iterator will simply yield the same items
 
 error: this `.skip()` call skips more items than the iterator will produce
-  --> tests/ui/iter_out_of_bounds.rs:58:14
+  --> tests/ui/iter_out_of_bounds.rs:56:14
    |
 LL |     for _ in std::iter::once(1).skip(2) {}
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -100,7 +100,7 @@ LL |     for _ in std::iter::once(1).skip(2) {}
    = note: this operation is useless and will create an empty iterator
 
 error: this `.take()` call takes more items than the iterator will produce
-  --> tests/ui/iter_out_of_bounds.rs:61:14
+  --> tests/ui/iter_out_of_bounds.rs:59:14
    |
 LL |     for _ in std::iter::once(1).take(2) {}
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -108,7 +108,7 @@ LL |     for _ in std::iter::once(1).take(2) {}
    = note: this operation is useless and the returned iterator will simply yield the same items
 
 error: this `.take()` call takes more items than the iterator will produce
-  --> tests/ui/iter_out_of_bounds.rs:64:14
+  --> tests/ui/iter_out_of_bounds.rs:62:14
    |
 LL |     for x in [].iter().take(1) {
    |              ^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/manual_find_fixable.fixed b/src/tools/clippy/tests/ui/manual_find_fixable.fixed
index 5e6849a4dfb..01b3ebacbeb 100644
--- a/src/tools/clippy/tests/ui/manual_find_fixable.fixed
+++ b/src/tools/clippy/tests/ui/manual_find_fixable.fixed
@@ -179,3 +179,13 @@ fn two_bindings(v: Vec<(u8, u8)>) -> Option<u8> {
 }
 
 fn main() {}
+
+mod issue14826 {
+    fn adjust_fixable(needle: &str) -> Option<&'static str> {
+        ["foo", "bar"].iter().find(|&candidate| candidate.eq_ignore_ascii_case(needle)).map(|v| v as _)
+    }
+
+    fn adjust_unfixable(needle: &str) -> Option<*const str> {
+        ["foo", "bar"].iter().find(|&&candidate| candidate.eq_ignore_ascii_case(needle)).copied().map(|v| v as _)
+    }
+}
diff --git a/src/tools/clippy/tests/ui/manual_find_fixable.rs b/src/tools/clippy/tests/ui/manual_find_fixable.rs
index 08a7dd2c6ee..ce62a4beba1 100644
--- a/src/tools/clippy/tests/ui/manual_find_fixable.rs
+++ b/src/tools/clippy/tests/ui/manual_find_fixable.rs
@@ -251,3 +251,25 @@ fn two_bindings(v: Vec<(u8, u8)>) -> Option<u8> {
 }
 
 fn main() {}
+
+mod issue14826 {
+    fn adjust_fixable(needle: &str) -> Option<&'static str> {
+        for candidate in &["foo", "bar"] {
+            //~^ manual_find
+            if candidate.eq_ignore_ascii_case(needle) {
+                return Some(candidate);
+            }
+        }
+        None
+    }
+
+    fn adjust_unfixable(needle: &str) -> Option<*const str> {
+        for &candidate in &["foo", "bar"] {
+            //~^ manual_find
+            if candidate.eq_ignore_ascii_case(needle) {
+                return Some(candidate);
+            }
+        }
+        None
+    }
+}
diff --git a/src/tools/clippy/tests/ui/manual_find_fixable.stderr b/src/tools/clippy/tests/ui/manual_find_fixable.stderr
index afa453c5a87..020635d90bb 100644
--- a/src/tools/clippy/tests/ui/manual_find_fixable.stderr
+++ b/src/tools/clippy/tests/ui/manual_find_fixable.stderr
@@ -139,5 +139,27 @@ LL | |                 return Some(x);
 LL | |         None
    | |____________^ help: replace with an iterator: `arr.into_iter().find(|&x| x < 1)`
 
-error: aborting due to 12 previous errors
+error: manual implementation of `Iterator::find`
+  --> tests/ui/manual_find_fixable.rs:257:9
+   |
+LL | /         for candidate in &["foo", "bar"] {
+LL | |
+LL | |             if candidate.eq_ignore_ascii_case(needle) {
+LL | |                 return Some(candidate);
+...  |
+LL | |         None
+   | |____________^ help: replace with an iterator: `["foo", "bar"].iter().find(|&candidate| candidate.eq_ignore_ascii_case(needle)).map(|v| v as _)`
+
+error: manual implementation of `Iterator::find`
+  --> tests/ui/manual_find_fixable.rs:267:9
+   |
+LL | /         for &candidate in &["foo", "bar"] {
+LL | |
+LL | |             if candidate.eq_ignore_ascii_case(needle) {
+LL | |                 return Some(candidate);
+...  |
+LL | |         None
+   | |____________^ help: replace with an iterator: `["foo", "bar"].iter().find(|&&candidate| candidate.eq_ignore_ascii_case(needle)).copied().map(|v| v as _)`
+
+error: aborting due to 14 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_flatten.rs b/src/tools/clippy/tests/ui/manual_flatten.rs
index 97f35c36e24..f1a0053ef38 100644
--- a/src/tools/clippy/tests/ui/manual_flatten.rs
+++ b/src/tools/clippy/tests/ui/manual_flatten.rs
@@ -123,6 +123,13 @@ fn main() {
         println!("{}", n);
     }
 
+    // Using nested `Some` pattern should not trigger the lint
+    for n in vec![Some((1, Some(2)))] {
+        if let Some((_, Some(n))) = n {
+            println!("{}", n);
+        }
+    }
+
     run_unformatted_tests();
 }
 
diff --git a/src/tools/clippy/tests/ui/manual_flatten.stderr b/src/tools/clippy/tests/ui/manual_flatten.stderr
index 5ab25658017..9a846fe17f3 100644
--- a/src/tools/clippy/tests/ui/manual_flatten.stderr
+++ b/src/tools/clippy/tests/ui/manual_flatten.stderr
@@ -178,7 +178,7 @@ LL | |         }
    | |_________^
 
 error: unnecessary `if let` since only the `Some` variant of the iterator element is used
-  --> tests/ui/manual_flatten.rs:132:5
+  --> tests/ui/manual_flatten.rs:139:5
    |
 LL | /     for n in vec![
 LL | |
@@ -189,7 +189,7 @@ LL | |     }
    | |_____^
    |
 help: remove the `if let` statement in the for loop and then...
-  --> tests/ui/manual_flatten.rs:139:9
+  --> tests/ui/manual_flatten.rs:146:9
    |
 LL | /         if let Some(n) = n {
 LL | |             println!("{:?}", n);
diff --git a/src/tools/clippy/tests/ui/manual_inspect.fixed b/src/tools/clippy/tests/ui/manual_inspect.fixed
index ec87fe217ae..9b768dbad70 100644
--- a/src/tools/clippy/tests/ui/manual_inspect.fixed
+++ b/src/tools/clippy/tests/ui/manual_inspect.fixed
@@ -107,7 +107,7 @@ fn main() {
             let _ = || {
                 let _x = x;
             };
-            return ;
+            return;
         }
         println!("test");
     });
diff --git a/src/tools/clippy/tests/ui/manual_inspect.stderr b/src/tools/clippy/tests/ui/manual_inspect.stderr
index eb98f9f5995..78b085fdfca 100644
--- a/src/tools/clippy/tests/ui/manual_inspect.stderr
+++ b/src/tools/clippy/tests/ui/manual_inspect.stderr
@@ -98,7 +98,7 @@ LL |         if x.is_empty() {
 LL |             let _ = || {
 LL ~                 let _x = x;
 LL |             };
-LL ~             return ;
+LL ~             return;
 LL |         }
 LL ~         println!("test");
    |
diff --git a/src/tools/clippy/tests/ui/manual_is_variant_and.fixed b/src/tools/clippy/tests/ui/manual_is_variant_and.fixed
index c9c184561dd..18a72188ab5 100644
--- a/src/tools/clippy/tests/ui/manual_is_variant_and.fixed
+++ b/src/tools/clippy/tests/ui/manual_is_variant_and.fixed
@@ -4,6 +4,44 @@
 #[macro_use]
 extern crate option_helpers;
 
+struct Foo<T>(T);
+
+impl<T> Foo<T> {
+    fn map<F: FnMut(T) -> bool>(self, mut f: F) -> Option<bool> {
+        Some(f(self.0))
+    }
+}
+
+fn foo() -> Option<bool> {
+    Some(true)
+}
+
+macro_rules! some_true {
+    () => {
+        Some(true)
+    };
+}
+macro_rules! some_false {
+    () => {
+        Some(false)
+    };
+}
+
+macro_rules! mac {
+    (some $e:expr) => {
+        Some($e)
+    };
+    (some_map $e:expr) => {
+        Some($e).map(|x| x % 2 == 0)
+    };
+    (map $e:expr) => {
+        $e.map(|x| x % 2 == 0)
+    };
+    (eq $a:expr, $b:expr) => {
+        $a == $b
+    };
+}
+
 #[rustfmt::skip]
 fn option_methods() {
     let opt = Some(1);
@@ -21,6 +59,15 @@ fn option_methods() {
     let _ = opt
         .is_some_and(|x| x > 1);
 
+    let _ = Some(2).is_some_and(|x| x % 2 == 0);
+    //~^ manual_is_variant_and
+    let _ = Some(2).is_none_or(|x| x % 2 == 0);
+    //~^ manual_is_variant_and
+    let _ = Some(2).is_some_and(|x| x % 2 == 0);
+    //~^ manual_is_variant_and
+    let _ = Some(2).is_none_or(|x| x % 2 == 0);
+    //~^ manual_is_variant_and
+
     // won't fix because the return type of the closure is not `bool`
     let _ = opt.map(|x| x + 1).unwrap_or_default();
 
@@ -28,6 +75,14 @@ fn option_methods() {
     let _ = opt2.is_some_and(char::is_alphanumeric); // should lint
     //~^ manual_is_variant_and
     let _ = opt_map!(opt2, |x| x == 'a').unwrap_or_default(); // should not lint
+
+    // Should not lint.
+    let _ = Foo::<u32>(0).map(|x| x % 2 == 0) == Some(true);
+    let _ = Some(2).map(|x| x % 2 == 0) != foo();
+    let _ = mac!(eq Some(2).map(|x| x % 2 == 0), Some(true));
+    let _ = mac!(some 2).map(|x| x % 2 == 0) == Some(true);
+    let _ = mac!(some_map 2) == Some(true);
+    let _ = mac!(map Some(2)) == Some(true);
 }
 
 #[rustfmt::skip]
@@ -41,6 +96,13 @@ fn result_methods() {
     });
     let _ = res.is_ok_and(|x| x > 1);
 
+    let _ = Ok::<usize, ()>(2).is_ok_and(|x| x % 2 == 0);
+    //~^ manual_is_variant_and
+    let _ = !Ok::<usize, ()>(2).is_ok_and(|x| x % 2 == 0);
+    //~^ manual_is_variant_and
+    let _ = !Ok::<usize, ()>(2).is_ok_and(|x| x % 2 == 0);
+    //~^ manual_is_variant_and
+
     // won't fix because the return type of the closure is not `bool`
     let _ = res.map(|x| x + 1).unwrap_or_default();
 
diff --git a/src/tools/clippy/tests/ui/manual_is_variant_and.rs b/src/tools/clippy/tests/ui/manual_is_variant_and.rs
index 52c7b56804c..a92f7c04369 100644
--- a/src/tools/clippy/tests/ui/manual_is_variant_and.rs
+++ b/src/tools/clippy/tests/ui/manual_is_variant_and.rs
@@ -4,6 +4,44 @@
 #[macro_use]
 extern crate option_helpers;
 
+struct Foo<T>(T);
+
+impl<T> Foo<T> {
+    fn map<F: FnMut(T) -> bool>(self, mut f: F) -> Option<bool> {
+        Some(f(self.0))
+    }
+}
+
+fn foo() -> Option<bool> {
+    Some(true)
+}
+
+macro_rules! some_true {
+    () => {
+        Some(true)
+    };
+}
+macro_rules! some_false {
+    () => {
+        Some(false)
+    };
+}
+
+macro_rules! mac {
+    (some $e:expr) => {
+        Some($e)
+    };
+    (some_map $e:expr) => {
+        Some($e).map(|x| x % 2 == 0)
+    };
+    (map $e:expr) => {
+        $e.map(|x| x % 2 == 0)
+    };
+    (eq $a:expr, $b:expr) => {
+        $a == $b
+    };
+}
+
 #[rustfmt::skip]
 fn option_methods() {
     let opt = Some(1);
@@ -27,6 +65,15 @@ fn option_methods() {
         //~^ manual_is_variant_and
         .unwrap_or_default();
 
+    let _ = Some(2).map(|x| x % 2 == 0) == Some(true);
+    //~^ manual_is_variant_and
+    let _ = Some(2).map(|x| x % 2 == 0) != Some(true);
+    //~^ manual_is_variant_and
+    let _ = Some(2).map(|x| x % 2 == 0) == some_true!();
+    //~^ manual_is_variant_and
+    let _ = Some(2).map(|x| x % 2 == 0) != some_false!();
+    //~^ manual_is_variant_and
+
     // won't fix because the return type of the closure is not `bool`
     let _ = opt.map(|x| x + 1).unwrap_or_default();
 
@@ -34,6 +81,14 @@ fn option_methods() {
     let _ = opt2.map(char::is_alphanumeric).unwrap_or_default(); // should lint
     //~^ manual_is_variant_and
     let _ = opt_map!(opt2, |x| x == 'a').unwrap_or_default(); // should not lint
+
+    // Should not lint.
+    let _ = Foo::<u32>(0).map(|x| x % 2 == 0) == Some(true);
+    let _ = Some(2).map(|x| x % 2 == 0) != foo();
+    let _ = mac!(eq Some(2).map(|x| x % 2 == 0), Some(true));
+    let _ = mac!(some 2).map(|x| x % 2 == 0) == Some(true);
+    let _ = mac!(some_map 2) == Some(true);
+    let _ = mac!(map Some(2)) == Some(true);
 }
 
 #[rustfmt::skip]
@@ -50,6 +105,13 @@ fn result_methods() {
     //~^ manual_is_variant_and
         .unwrap_or_default();
 
+    let _ = Ok::<usize, ()>(2).map(|x| x % 2 == 0) == Ok(true);
+    //~^ manual_is_variant_and
+    let _ = Ok::<usize, ()>(2).map(|x| x % 2 == 0) != Ok(true);
+    //~^ manual_is_variant_and
+    let _ = Ok::<usize, ()>(2).map(|x| x % 2 == 0) != Ok(true);
+    //~^ manual_is_variant_and
+
     // won't fix because the return type of the closure is not `bool`
     let _ = res.map(|x| x + 1).unwrap_or_default();
 
diff --git a/src/tools/clippy/tests/ui/manual_is_variant_and.stderr b/src/tools/clippy/tests/ui/manual_is_variant_and.stderr
index a4fa500580d..1fb437a8bc7 100644
--- a/src/tools/clippy/tests/ui/manual_is_variant_and.stderr
+++ b/src/tools/clippy/tests/ui/manual_is_variant_and.stderr
@@ -1,5 +1,5 @@
 error: called `map(<f>).unwrap_or_default()` on an `Option` value
-  --> tests/ui/manual_is_variant_and.rs:13:17
+  --> tests/ui/manual_is_variant_and.rs:51:17
    |
 LL |       let _ = opt.map(|x| x > 1)
    |  _________________^
@@ -11,7 +11,7 @@ LL | |         .unwrap_or_default();
    = help: to override `-D warnings` add `#[allow(clippy::manual_is_variant_and)]`
 
 error: called `map(<f>).unwrap_or_default()` on an `Option` value
-  --> tests/ui/manual_is_variant_and.rs:18:17
+  --> tests/ui/manual_is_variant_and.rs:56:17
    |
 LL |       let _ = opt.map(|x| {
    |  _________________^
@@ -30,13 +30,13 @@ LL ~     });
    |
 
 error: called `map(<f>).unwrap_or_default()` on an `Option` value
-  --> tests/ui/manual_is_variant_and.rs:23:17
+  --> tests/ui/manual_is_variant_and.rs:61:17
    |
 LL |     let _ = opt.map(|x| x > 1).unwrap_or_default();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `is_some_and(|x| x > 1)`
 
 error: called `map(<f>).unwrap_or_default()` on an `Option` value
-  --> tests/ui/manual_is_variant_and.rs:26:10
+  --> tests/ui/manual_is_variant_and.rs:64:10
    |
 LL |           .map(|x| x > 1)
    |  __________^
@@ -44,14 +44,38 @@ LL | |
 LL | |         .unwrap_or_default();
    | |____________________________^ help: use: `is_some_and(|x| x > 1)`
 
+error: called `.map() == Some()`
+  --> tests/ui/manual_is_variant_and.rs:68:13
+   |
+LL |     let _ = Some(2).map(|x| x % 2 == 0) == Some(true);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `Some(2).is_some_and(|x| x % 2 == 0)`
+
+error: called `.map() != Some()`
+  --> tests/ui/manual_is_variant_and.rs:70:13
+   |
+LL |     let _ = Some(2).map(|x| x % 2 == 0) != Some(true);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `Some(2).is_none_or(|x| x % 2 == 0)`
+
+error: called `.map() == Some()`
+  --> tests/ui/manual_is_variant_and.rs:72:13
+   |
+LL |     let _ = Some(2).map(|x| x % 2 == 0) == some_true!();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `Some(2).is_some_and(|x| x % 2 == 0)`
+
+error: called `.map() != Some()`
+  --> tests/ui/manual_is_variant_and.rs:74:13
+   |
+LL |     let _ = Some(2).map(|x| x % 2 == 0) != some_false!();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `Some(2).is_none_or(|x| x % 2 == 0)`
+
 error: called `map(<f>).unwrap_or_default()` on an `Option` value
-  --> tests/ui/manual_is_variant_and.rs:34:18
+  --> tests/ui/manual_is_variant_and.rs:81:18
    |
 LL |     let _ = opt2.map(char::is_alphanumeric).unwrap_or_default(); // should lint
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `is_some_and(char::is_alphanumeric)`
 
 error: called `map(<f>).unwrap_or_default()` on a `Result` value
-  --> tests/ui/manual_is_variant_and.rs:44:17
+  --> tests/ui/manual_is_variant_and.rs:99:17
    |
 LL |       let _ = res.map(|x| {
    |  _________________^
@@ -70,7 +94,7 @@ LL ~     });
    |
 
 error: called `map(<f>).unwrap_or_default()` on a `Result` value
-  --> tests/ui/manual_is_variant_and.rs:49:17
+  --> tests/ui/manual_is_variant_and.rs:104:17
    |
 LL |       let _ = res.map(|x| x > 1)
    |  _________________^
@@ -78,11 +102,29 @@ LL | |
 LL | |         .unwrap_or_default();
    | |____________________________^ help: use: `is_ok_and(|x| x > 1)`
 
+error: called `.map() == Ok()`
+  --> tests/ui/manual_is_variant_and.rs:108:13
+   |
+LL |     let _ = Ok::<usize, ()>(2).map(|x| x % 2 == 0) == Ok(true);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `Ok::<usize, ()>(2).is_ok_and(|x| x % 2 == 0)`
+
+error: called `.map() != Ok()`
+  --> tests/ui/manual_is_variant_and.rs:110:13
+   |
+LL |     let _ = Ok::<usize, ()>(2).map(|x| x % 2 == 0) != Ok(true);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `!Ok::<usize, ()>(2).is_ok_and(|x| x % 2 == 0)`
+
+error: called `.map() != Ok()`
+  --> tests/ui/manual_is_variant_and.rs:112:13
+   |
+LL |     let _ = Ok::<usize, ()>(2).map(|x| x % 2 == 0) != Ok(true);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `!Ok::<usize, ()>(2).is_ok_and(|x| x % 2 == 0)`
+
 error: called `map(<f>).unwrap_or_default()` on a `Result` value
-  --> tests/ui/manual_is_variant_and.rs:57:18
+  --> tests/ui/manual_is_variant_and.rs:119:18
    |
 LL |     let _ = res2.map(char::is_alphanumeric).unwrap_or_default(); // should lint
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `is_ok_and(char::is_alphanumeric)`
 
-error: aborting due to 8 previous errors
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_slice_size_calculation.fixed b/src/tools/clippy/tests/ui/manual_slice_size_calculation.fixed
index 294d1e1506d..090f0fd30c5 100644
--- a/src/tools/clippy/tests/ui/manual_slice_size_calculation.fixed
+++ b/src/tools/clippy/tests/ui/manual_slice_size_calculation.fixed
@@ -60,7 +60,26 @@ fn main() {
     let _ = size_of::<i32>() * 5 * s_i32.len(); // Ok (MISSED OPPORTUNITY)
 }
 
-const fn _const(s_i32: &[i32]) {
-    // True negative:
-    let _ = s_i32.len() * size_of::<i32>(); // Ok, can't use size_of_val in const
+#[clippy::msrv = "1.85"]
+const fn const_ok(s_i32: &[i32]) {
+    let _ = std::mem::size_of_val(s_i32);
+    //~^ manual_slice_size_calculation
+}
+
+#[clippy::msrv = "1.84"]
+const fn const_before_msrv(s_i32: &[i32]) {
+    let _ = s_i32.len() * size_of::<i32>();
+}
+
+fn issue_14802() {
+    struct IcedSlice {
+        dst: [u8],
+    }
+
+    impl IcedSlice {
+        fn get_len(&self) -> usize {
+            std::mem::size_of_val(&self.dst)
+            //~^ manual_slice_size_calculation
+        }
+    }
 }
diff --git a/src/tools/clippy/tests/ui/manual_slice_size_calculation.rs b/src/tools/clippy/tests/ui/manual_slice_size_calculation.rs
index ae522566313..3c19a0eb5ce 100644
--- a/src/tools/clippy/tests/ui/manual_slice_size_calculation.rs
+++ b/src/tools/clippy/tests/ui/manual_slice_size_calculation.rs
@@ -60,7 +60,26 @@ fn main() {
     let _ = size_of::<i32>() * 5 * s_i32.len(); // Ok (MISSED OPPORTUNITY)
 }
 
-const fn _const(s_i32: &[i32]) {
-    // True negative:
-    let _ = s_i32.len() * size_of::<i32>(); // Ok, can't use size_of_val in const
+#[clippy::msrv = "1.85"]
+const fn const_ok(s_i32: &[i32]) {
+    let _ = s_i32.len() * size_of::<i32>();
+    //~^ manual_slice_size_calculation
+}
+
+#[clippy::msrv = "1.84"]
+const fn const_before_msrv(s_i32: &[i32]) {
+    let _ = s_i32.len() * size_of::<i32>();
+}
+
+fn issue_14802() {
+    struct IcedSlice {
+        dst: [u8],
+    }
+
+    impl IcedSlice {
+        fn get_len(&self) -> usize {
+            self.dst.len() * size_of::<u8>()
+            //~^ manual_slice_size_calculation
+        }
+    }
 }
diff --git a/src/tools/clippy/tests/ui/manual_slice_size_calculation.stderr b/src/tools/clippy/tests/ui/manual_slice_size_calculation.stderr
index f07e97a1c86..8e9b49e4bf2 100644
--- a/src/tools/clippy/tests/ui/manual_slice_size_calculation.stderr
+++ b/src/tools/clippy/tests/ui/manual_slice_size_calculation.stderr
@@ -55,5 +55,17 @@ error: manual slice size calculation
 LL |     let _ = external!(&[1u64][..]).len() * size_of::<u64>();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(external!(&[1u64][..]))`
 
-error: aborting due to 9 previous errors
+error: manual slice size calculation
+  --> tests/ui/manual_slice_size_calculation.rs:65:13
+   |
+LL |     let _ = s_i32.len() * size_of::<i32>();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)`
+
+error: manual slice size calculation
+  --> tests/ui/manual_slice_size_calculation.rs:81:13
+   |
+LL |             self.dst.len() * size_of::<u8>()
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(&self.dst)`
+
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/map_flatten.rs b/src/tools/clippy/tests/ui/map_flatten.rs
index d7e9c9d9900..0970da8039a 100644
--- a/src/tools/clippy/tests/ui/map_flatten.rs
+++ b/src/tools/clippy/tests/ui/map_flatten.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::map_flatten)]
-#![feature(result_flattening)]
+
 //@no-rustfix
 // issue #8506, multi-line
 #[rustfmt::skip]
diff --git a/src/tools/clippy/tests/ui/map_flatten_fixable.fixed b/src/tools/clippy/tests/ui/map_flatten_fixable.fixed
index f8379ed23c5..6d8a27d3018 100644
--- a/src/tools/clippy/tests/ui/map_flatten_fixable.fixed
+++ b/src/tools/clippy/tests/ui/map_flatten_fixable.fixed
@@ -1,4 +1,3 @@
-#![feature(result_flattening)]
 #![allow(
     clippy::let_underscore_untyped,
     clippy::missing_docs_in_private_items,
diff --git a/src/tools/clippy/tests/ui/map_flatten_fixable.rs b/src/tools/clippy/tests/ui/map_flatten_fixable.rs
index 040a9ca85f6..845e3a79ae2 100644
--- a/src/tools/clippy/tests/ui/map_flatten_fixable.rs
+++ b/src/tools/clippy/tests/ui/map_flatten_fixable.rs
@@ -1,4 +1,3 @@
-#![feature(result_flattening)]
 #![allow(
     clippy::let_underscore_untyped,
     clippy::missing_docs_in_private_items,
diff --git a/src/tools/clippy/tests/ui/map_flatten_fixable.stderr b/src/tools/clippy/tests/ui/map_flatten_fixable.stderr
index fe68eb7e4ab..05d4d9a6ad8 100644
--- a/src/tools/clippy/tests/ui/map_flatten_fixable.stderr
+++ b/src/tools/clippy/tests/ui/map_flatten_fixable.stderr
@@ -1,5 +1,5 @@
 error: called `map(..).flatten()` on `Iterator`
-  --> tests/ui/map_flatten_fixable.rs:17:47
+  --> tests/ui/map_flatten_fixable.rs:16:47
    |
 LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect();
    |                                               ^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id)`
@@ -8,43 +8,43 @@ LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().coll
    = help: to override `-D warnings` add `#[allow(clippy::map_flatten)]`
 
 error: called `map(..).flatten()` on `Iterator`
-  --> tests/ui/map_flatten_fixable.rs:19:47
+  --> tests/ui/map_flatten_fixable.rs:18:47
    |
 LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect();
    |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id_ref)`
 
 error: called `map(..).flatten()` on `Iterator`
-  --> tests/ui/map_flatten_fixable.rs:21:47
+  --> tests/ui/map_flatten_fixable.rs:20:47
    |
 LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect();
    |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id_closure)`
 
 error: called `map(..).flatten()` on `Iterator`
-  --> tests/ui/map_flatten_fixable.rs:23:47
+  --> tests/ui/map_flatten_fixable.rs:22:47
    |
 LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect();
    |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(|x| x.checked_add(1))`
 
 error: called `map(..).flatten()` on `Iterator`
-  --> tests/ui/map_flatten_fixable.rs:27:47
+  --> tests/ui/map_flatten_fixable.rs:26:47
    |
 LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect();
    |                                               ^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `flat_map` and remove the `.flatten()`: `flat_map(|x| 0..x)`
 
 error: called `map(..).flatten()` on `Option`
-  --> tests/ui/map_flatten_fixable.rs:31:40
+  --> tests/ui/map_flatten_fixable.rs:30:40
    |
 LL |     let _: Option<_> = (Some(Some(1))).map(|x| x).flatten();
    |                                        ^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `and_then` and remove the `.flatten()`: `and_then(|x| x)`
 
 error: called `map(..).flatten()` on `Result`
-  --> tests/ui/map_flatten_fixable.rs:35:42
+  --> tests/ui/map_flatten_fixable.rs:34:42
    |
 LL |     let _: Result<_, &str> = (Ok(Ok(1))).map(|x| x).flatten();
    |                                          ^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `and_then` and remove the `.flatten()`: `and_then(|x| x)`
 
 error: called `map(..).flatten()` on `Iterator`
-  --> tests/ui/map_flatten_fixable.rs:45:10
+  --> tests/ui/map_flatten_fixable.rs:44:10
    |
 LL |           .map(|n| match n {
    |  __________^
@@ -74,7 +74,7 @@ LL ~         });
    |
 
 error: called `map(..).flatten()` on `Option`
-  --> tests/ui/map_flatten_fixable.rs:66:10
+  --> tests/ui/map_flatten_fixable.rs:65:10
    |
 LL |           .map(|_| {
    |  __________^
diff --git a/src/tools/clippy/tests/ui/match_same_arms.fixed b/src/tools/clippy/tests/ui/match_same_arms.fixed
new file mode 100644
index 00000000000..31684a5759f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/match_same_arms.fixed
@@ -0,0 +1,142 @@
+#![allow(clippy::manual_range_patterns)]
+#![warn(clippy::match_same_arms)]
+
+pub enum Abc {
+    A,
+    B,
+    C,
+}
+
+fn match_same_arms() {
+    let _ = match Abc::A {
+        Abc::B => 1,
+        _ => 0,
+        //~^ match_same_arms
+    };
+
+    match 0 {
+        1 => 'a',
+        _ => 'b',
+        //~^ match_same_arms
+    };
+
+    match (1, 2, 3) {
+        (1, .., 3) | (.., 3) => 42,
+        //~^ match_same_arms
+        _ => 0,
+    };
+
+    let _ = match 42 {
+        //~^ match_same_arms
+        42 | 51 => 1,
+        41 | 52 => 2,
+        //~^ match_same_arms
+        _ => 0,
+    };
+
+    let _ = match 42 {
+        //~^ match_same_arms
+        1 | 2 | 3 => 2,
+        4 => 3,
+        _ => 0,
+    };
+}
+
+mod issue4244 {
+    #[derive(PartialEq, PartialOrd, Eq, Ord)]
+    pub enum CommandInfo {
+        BuiltIn { name: String, about: Option<String> },
+        External { name: String, path: std::path::PathBuf },
+    }
+
+    impl CommandInfo {
+        pub fn name(&self) -> String {
+            match self {
+                //~^ match_same_arms
+                CommandInfo::BuiltIn { name, .. } | CommandInfo::External { name, .. } => name.to_string(),
+            }
+        }
+    }
+}
+
+macro_rules! m {
+    (foo) => {};
+    (bar) => {};
+}
+macro_rules! foo {
+    () => {
+        1
+    };
+}
+macro_rules! bar {
+    () => {
+        1
+    };
+}
+
+fn main() {
+    let x = 0;
+    let _ = match 0 {
+        0 => {
+            m!(foo);
+            x
+        },
+        1 => {
+            m!(bar);
+            x
+        },
+        _ => 1,
+    };
+
+    let _ = match 0 {
+        0 => {
+            m!(foo);
+            0
+        },
+        1 => {
+            m!(bar);
+            0
+        },
+        _ => 1,
+    };
+
+    let _ = match 0 {
+        0 => {
+            let mut x = 0;
+            #[cfg(not_enabled)]
+            {
+                x = 5;
+            }
+            #[cfg(not(not_enabled))]
+            {
+                x = 6;
+            }
+            x
+        },
+        1 => {
+            let mut x = 0;
+            #[cfg(also_not_enabled)]
+            {
+                x = 5;
+            }
+            #[cfg(not(also_not_enabled))]
+            {
+                x = 6;
+            }
+            x
+        },
+        _ => 0,
+    };
+
+    let _ = match 0 {
+        0 => foo!(),
+        1 => bar!(),
+        _ => 1,
+    };
+
+    let _ = match 0 {
+        0 => cfg!(not_enabled),
+        1 => cfg!(also_not_enabled),
+        _ => false,
+    };
+}
diff --git a/src/tools/clippy/tests/ui/match_same_arms.rs b/src/tools/clippy/tests/ui/match_same_arms.rs
index 55441948e91..39bee01bac2 100644
--- a/src/tools/clippy/tests/ui/match_same_arms.rs
+++ b/src/tools/clippy/tests/ui/match_same_arms.rs
@@ -1,4 +1,4 @@
-//@no-rustfix: overlapping suggestions
+#![allow(clippy::manual_range_patterns)]
 #![warn(clippy::match_same_arms)]
 
 pub enum Abc {
@@ -10,9 +10,17 @@ pub enum Abc {
 fn match_same_arms() {
     let _ = match Abc::A {
         Abc::A => 0,
-        //~^ match_same_arms
         Abc::B => 1,
         _ => 0,
+        //~^ match_same_arms
+    };
+
+    match 0 {
+        1 => 'a',
+        2 => 'b',
+        3 => 'b',
+        _ => 'b',
+        //~^ match_same_arms
     };
 
     match (1, 2, 3) {
@@ -24,8 +32,8 @@ fn match_same_arms() {
 
     let _ = match 42 {
         42 => 1,
-        51 => 1,
         //~^ match_same_arms
+        51 => 1,
         41 => 2,
         //~^ match_same_arms
         52 => 2,
@@ -34,11 +42,9 @@ fn match_same_arms() {
 
     let _ = match 42 {
         1 => 2,
-        2 => 2,
         //~^ match_same_arms
-        //~| match_same_arms
+        2 => 2,
         3 => 2,
-        //~^ match_same_arms
         4 => 3,
         _ => 0,
     };
@@ -55,8 +61,8 @@ mod issue4244 {
         pub fn name(&self) -> String {
             match self {
                 CommandInfo::BuiltIn { name, .. } => name.to_string(),
-                CommandInfo::External { name, .. } => name.to_string(),
                 //~^ match_same_arms
+                CommandInfo::External { name, .. } => name.to_string(),
             }
         }
     }
diff --git a/src/tools/clippy/tests/ui/match_same_arms.stderr b/src/tools/clippy/tests/ui/match_same_arms.stderr
index 3744b83d89c..8aa60f83576 100644
--- a/src/tools/clippy/tests/ui/match_same_arms.stderr
+++ b/src/tools/clippy/tests/ui/match_same_arms.stderr
@@ -1,118 +1,121 @@
-error: this match arm has an identical body to the `_` wildcard arm
+error: these match arms have identical bodies
   --> tests/ui/match_same_arms.rs:12:9
    |
-LL | /         Abc::A => 0,
-LL | |
-   | |________^ help: try removing the arm
-   |
-   = help: or try changing either arm body
-note: `_` wildcard arm here
-  --> tests/ui/match_same_arms.rs:15:9
-   |
+LL |         Abc::A => 0,
+   |         ^^^^^^^^^^^
+LL |         Abc::B => 1,
 LL |         _ => 0,
-   |         ^^^^^^
+   |         ^^^^^^ the wildcard arm
+   |
+   = help: if this is unintentional make the arms return different values
    = note: `-D clippy::match-same-arms` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::match_same_arms)]`
+help: otherwise remove the non-wildcard arm
+   |
+LL -         Abc::A => 0,
+   |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms.rs:19:9
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms.rs:20:9
+   |
+LL |         2 => 'b',
+   |         ^^^^^^^^
+LL |         3 => 'b',
+   |         ^^^^^^^^
+LL |         _ => 'b',
+   |         ^^^^^^^^ the wildcard arm
+   |
+   = help: if this is unintentional make the arms return different values
+help: otherwise remove the non-wildcard arms
+   |
+LL -         2 => 'b',
+LL -         3 => 'b',
+LL +         _ => 'b',
+   |
+
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms.rs:27:9
    |
 LL |         (1, .., 3) => 42,
    |         ^^^^^^^^^^^^^^^^
+LL |
+LL |         (.., 3) => 42,
+   |         ^^^^^^^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
 LL ~         (1, .., 3) | (.., 3) => 42,
 LL |
 LL ~         _ => 0,
    |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms.rs:27:9
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms.rs:34:9
    |
+LL |         42 => 1,
+   |         ^^^^^^^
+LL |
 LL |         51 => 1,
    |         ^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
-LL -         42 => 1,
-LL -         51 => 1,
-LL +         51 | 42 => 1,
+LL ~
+LL ~         42 | 51 => 1,
    |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms.rs:29:9
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms.rs:37:9
    |
 LL |         41 => 2,
    |         ^^^^^^^
+LL |
+LL |         52 => 2,
+   |         ^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
 LL ~         41 | 52 => 2,
 LL |
 LL ~         _ => 0,
    |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms.rs:37:9
-   |
-LL |         2 => 2,
-   |         ^^^^^^
-   |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
-   |
-LL -         1 => 2,
-LL -         2 => 2,
-LL +         2 | 1 => 2,
-   |
-
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms.rs:40:9
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms.rs:44:9
    |
-LL |         3 => 2,
+LL |         1 => 2,
    |         ^^^^^^
-   |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
-   |
-LL ~         2 => 2,
-LL |
 LL |
-LL ~         3 | 1 => 2,
-   |
-
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms.rs:37:9
-   |
 LL |         2 => 2,
    |         ^^^^^^
+LL |         3 => 2,
+   |         ^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
-LL ~         2 | 3 => 2,
-LL |
-LL |
 LL ~
+LL ~         1 | 2 | 3 => 2,
    |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms.rs:58:17
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms.rs:63:17
    |
+LL |                 CommandInfo::BuiltIn { name, .. } => name.to_string(),
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
 LL |                 CommandInfo::External { name, .. } => name.to_string(),
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
-LL -                 CommandInfo::BuiltIn { name, .. } => name.to_string(),
-LL -                 CommandInfo::External { name, .. } => name.to_string(),
-LL +                 CommandInfo::External { name, .. } | CommandInfo::BuiltIn { name, .. } => name.to_string(),
+LL ~
+LL ~                 CommandInfo::BuiltIn { name, .. } | CommandInfo::External { name, .. } => name.to_string(),
    |
 
-error: aborting due to 8 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui/match_same_arms2.fixed b/src/tools/clippy/tests/ui/match_same_arms2.fixed
index 0d93e2c728d..cb860cef1e6 100644
--- a/src/tools/clippy/tests/ui/match_same_arms2.fixed
+++ b/src/tools/clippy/tests/ui/match_same_arms2.fixed
@@ -14,7 +14,7 @@ fn foo() -> bool {
 
 fn match_same_arms() {
     let _ = match 42 {
-        //~^^^^^^^^^ match_same_arms
+        //~v match_same_arms
         _ => {
             foo();
             let mut a = 42 + [23].len() as i32;
@@ -27,14 +27,14 @@ fn match_same_arms() {
     };
 
     let _ = match 42 {
-        51 | 42 => foo(),
         //~^ match_same_arms
+        42 | 51 => foo(),
         _ => true,
     };
 
     let _ = match Some(42) {
-        None | Some(_) => 24,
         //~^ match_same_arms
+        Some(_) | None => 24,
     };
 
     let _ = match Some(42) {
@@ -55,8 +55,8 @@ fn match_same_arms() {
     };
 
     match (Some(42), Some(42)) {
-        (None, Some(a)) | (Some(a), None) => bar(a),
         //~^ match_same_arms
+        (Some(a), None) | (None, Some(a)) => bar(a),
         _ => (),
     }
 
@@ -69,8 +69,8 @@ fn match_same_arms() {
     };
 
     let _ = match (Some(42), Some(42)) {
-        (None, Some(a)) | (Some(a), None) if a == 42 => a,
         //~^ match_same_arms
+        (Some(a), None) | (None, Some(a)) if a == 42 => a,
         _ => 0,
     };
 
@@ -124,8 +124,8 @@ fn match_same_arms() {
     // False negative #2251.
     match x {
         Ok(_tmp) => println!("ok"),
-        Ok(_) | Ok(3) => println!("ok"),
         //~^ match_same_arms
+        Ok(3) | Ok(_) => println!("ok"),
         Err(_) => {
             unreachable!();
         },
@@ -149,10 +149,10 @@ fn match_same_arms() {
 
     // still lint if the tokens are the same
     match 0 {
-        1 | 0 => {
+        //~^^^ match_same_arms
+        0 | 1 => {
             empty!(0);
         },
-        //~^^^ match_same_arms
         x => {
             empty!(x);
         },
@@ -208,9 +208,9 @@ fn main() {
 
     // Suggest moving `Foo::X(0)` down.
     let _ = match Foo::X(0) {
-        Foo::Y(_) | Foo::Z(0) => 2,
-        Foo::Z(_) | Foo::X(0) => 1,
         //~^ match_same_arms
+        Foo::Y(_) | Foo::Z(0) => 2,
+        Foo::X(0) | Foo::Z(_) => 1,
         _ => 0,
     };
 
@@ -230,10 +230,10 @@ fn main() {
 
     // Lint.
     let _ = match None {
+        //~^ match_same_arms
         Some(Bar { y: 10, z: 0, .. }) => 2,
         None => 50,
-        Some(Bar { y: 0, x: 5, .. }) | Some(Bar { x: 0, y: 5, .. }) => 1,
-        //~^ match_same_arms
+        Some(Bar { x: 0, y: 5, .. }) | Some(Bar { y: 0, x: 5, .. }) => 1,
         _ => 200,
     };
 
@@ -246,8 +246,8 @@ fn main() {
     };
 
     let _ = match 0 {
-        1 | 0 => cfg!(not_enable),
         //~^ match_same_arms
+        0 | 1 => cfg!(not_enable),
         _ => false,
     };
 }
@@ -262,9 +262,34 @@ mod with_lifetime {
     impl<'a> MaybeStaticStr<'a> {
         fn get(&self) -> &'a str {
             match *self {
-                MaybeStaticStr::Borrowed(s) | MaybeStaticStr::Static(s) => s,
                 //~^ match_same_arms
+                MaybeStaticStr::Static(s) | MaybeStaticStr::Borrowed(s) => s,
             }
         }
     }
 }
+
+fn lint_levels() {
+    match 1 {
+        0 => "a",
+        1 => "b",
+        #[expect(clippy::match_same_arms)]
+        _ => "b",
+    };
+
+    match 2 {
+        0 => "a",
+        1 | 2 => "b",
+        //~^ match_same_arms
+        #[allow(clippy::match_same_arms)]
+        _ => "b",
+    };
+
+    match 3 {
+        0 => "a",
+        1 | 2 => "b",
+        //~^ match_same_arms
+        #[expect(clippy::match_same_arms)]
+        _ => "b",
+    };
+}
diff --git a/src/tools/clippy/tests/ui/match_same_arms2.rs b/src/tools/clippy/tests/ui/match_same_arms2.rs
index b0ebc4784f3..0fd5d76e7d3 100644
--- a/src/tools/clippy/tests/ui/match_same_arms2.rs
+++ b/src/tools/clippy/tests/ui/match_same_arms2.rs
@@ -23,7 +23,7 @@ fn match_same_arms() {
             a = -31 - a;
             a
         },
-        //~^^^^^^^^^ match_same_arms
+        //~v match_same_arms
         _ => {
             foo();
             let mut a = 42 + [23].len() as i32;
@@ -37,15 +37,15 @@ fn match_same_arms() {
 
     let _ = match 42 {
         42 => foo(),
-        51 => foo(),
         //~^ match_same_arms
+        51 => foo(),
         _ => true,
     };
 
     let _ = match Some(42) {
         Some(_) => 24,
-        None => 24,
         //~^ match_same_arms
+        None => 24,
     };
 
     let _ = match Some(42) {
@@ -67,8 +67,8 @@ fn match_same_arms() {
 
     match (Some(42), Some(42)) {
         (Some(a), None) => bar(a),
-        (None, Some(a)) => bar(a),
         //~^ match_same_arms
+        (None, Some(a)) => bar(a),
         _ => (),
     }
 
@@ -82,8 +82,8 @@ fn match_same_arms() {
 
     let _ = match (Some(42), Some(42)) {
         (Some(a), None) if a == 42 => a,
-        (None, Some(a)) if a == 42 => a,
         //~^ match_same_arms
+        (None, Some(a)) if a == 42 => a,
         _ => 0,
     };
 
@@ -140,8 +140,8 @@ fn match_same_arms() {
     match x {
         Ok(_tmp) => println!("ok"),
         Ok(3) => println!("ok"),
-        Ok(_) => println!("ok"),
         //~^ match_same_arms
+        Ok(_) => println!("ok"),
         Err(_) => {
             unreachable!();
         },
@@ -168,10 +168,10 @@ fn match_same_arms() {
         0 => {
             empty!(0);
         },
+        //~^^^ match_same_arms
         1 => {
             empty!(0);
         },
-        //~^^^ match_same_arms
         x => {
             empty!(x);
         },
@@ -229,9 +229,9 @@ fn main() {
     // Suggest moving `Foo::X(0)` down.
     let _ = match Foo::X(0) {
         Foo::X(0) => 1,
+        //~^ match_same_arms
         Foo::Y(_) | Foo::Z(0) => 2,
         Foo::Z(_) => 1,
-        //~^ match_same_arms
         _ => 0,
     };
 
@@ -252,10 +252,10 @@ fn main() {
     // Lint.
     let _ = match None {
         Some(Bar { x: 0, y: 5, .. }) => 1,
+        //~^ match_same_arms
         Some(Bar { y: 10, z: 0, .. }) => 2,
         None => 50,
         Some(Bar { y: 0, x: 5, .. }) => 1,
-        //~^ match_same_arms
         _ => 200,
     };
 
@@ -269,8 +269,8 @@ fn main() {
 
     let _ = match 0 {
         0 => cfg!(not_enable),
-        1 => cfg!(not_enable),
         //~^ match_same_arms
+        1 => cfg!(not_enable),
         _ => false,
     };
 }
@@ -286,9 +286,36 @@ mod with_lifetime {
         fn get(&self) -> &'a str {
             match *self {
                 MaybeStaticStr::Static(s) => s,
-                MaybeStaticStr::Borrowed(s) => s,
                 //~^ match_same_arms
+                MaybeStaticStr::Borrowed(s) => s,
             }
         }
     }
 }
+
+fn lint_levels() {
+    match 1 {
+        0 => "a",
+        1 => "b",
+        #[expect(clippy::match_same_arms)]
+        _ => "b",
+    };
+
+    match 2 {
+        0 => "a",
+        1 => "b",
+        //~^ match_same_arms
+        2 => "b",
+        #[allow(clippy::match_same_arms)]
+        _ => "b",
+    };
+
+    match 3 {
+        0 => "a",
+        1 => "b",
+        //~^ match_same_arms
+        2 => "b",
+        #[expect(clippy::match_same_arms)]
+        _ => "b",
+    };
+}
diff --git a/src/tools/clippy/tests/ui/match_same_arms2.stderr b/src/tools/clippy/tests/ui/match_same_arms2.stderr
index 21a8743cc32..f3031619cce 100644
--- a/src/tools/clippy/tests/ui/match_same_arms2.stderr
+++ b/src/tools/clippy/tests/ui/match_same_arms2.stderr
@@ -1,4 +1,4 @@
-error: this match arm has an identical body to the `_` wildcard arm
+error: these match arms have identical bodies
   --> tests/ui/match_same_arms2.rs:17:9
    |
 LL | /         42 => {
@@ -6,14 +6,10 @@ LL | |             foo();
 LL | |             let mut a = 42 + [23].len() as i32;
 LL | |             if true {
 ...  |
+LL | |             a
 LL | |         },
-LL | |
-   | |________^ help: try removing the arm
-   |
-   = help: or try changing either arm body
-note: `_` wildcard arm here
-  --> tests/ui/match_same_arms2.rs:27:9
-   |
+   | |_________^
+LL |
 LL | /         _ => {
 LL | |             foo();
 LL | |             let mut a = 42 + [23].len() as i32;
@@ -21,134 +17,169 @@ LL | |             if true {
 ...  |
 LL | |             a
 LL | |         },
-   | |_________^
+   | |_________^ the wildcard arm
+   |
+   = help: if this is unintentional make the arms return different values
    = note: `-D clippy::match-same-arms` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::match_same_arms)]`
+help: otherwise remove the non-wildcard arm
+   |
+LL -         42 => {
+LL -             foo();
+LL -             let mut a = 42 + [23].len() as i32;
+LL -             if true {
+LL -                 a += 7;
+LL -             }
+LL -             a = -31 - a;
+LL -             a
+LL -         },
+   |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:40:9
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms2.rs:39:9
    |
+LL |         42 => foo(),
+   |         ^^^^^^^^^^^
+LL |
 LL |         51 => foo(),
    |         ^^^^^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
-LL -         42 => foo(),
-LL -         51 => foo(),
-LL +         51 | 42 => foo(),
+LL ~
+LL ~         42 | 51 => foo(),
    |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:47:9
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms2.rs:46:9
    |
+LL |         Some(_) => 24,
+   |         ^^^^^^^^^^^^^
+LL |
 LL |         None => 24,
    |         ^^^^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
-LL -         Some(_) => 24,
-LL -         None => 24,
-LL +         None | Some(_) => 24,
+LL ~
+LL ~         Some(_) | None => 24,
    |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:70:9
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms2.rs:69:9
    |
+LL |         (Some(a), None) => bar(a),
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
 LL |         (None, Some(a)) => bar(a),
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
-LL -         (Some(a), None) => bar(a),
-LL -         (None, Some(a)) => bar(a),
-LL +         (None, Some(a)) | (Some(a), None) => bar(a),
+LL ~
+LL ~         (Some(a), None) | (None, Some(a)) => bar(a),
    |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:85:9
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms2.rs:84:9
    |
+LL |         (Some(a), None) if a == 42 => a,
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
 LL |         (None, Some(a)) if a == 42 => a,
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
-LL -         (Some(a), None) if a == 42 => a,
-LL -         (None, Some(a)) if a == 42 => a,
-LL +         (None, Some(a)) | (Some(a), None) if a == 42 => a,
+LL ~
+LL ~         (Some(a), None) | (None, Some(a)) if a == 42 => a,
    |
 
-error: this match arm has an identical body to another arm
+error: these match arms have identical bodies
   --> tests/ui/match_same_arms2.rs:91:9
    |
 LL |         (Some(a), ..) => bar(a),
    |         ^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL |         (.., Some(a)) => bar(a),
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
 LL ~         (Some(a), ..) | (.., Some(a)) => bar(a),
 LL |
 LL ~         _ => (),
    |
 
-error: this match arm has an identical body to another arm
+error: these match arms have identical bodies
   --> tests/ui/match_same_arms2.rs:126:9
    |
 LL |         (Ok(x), Some(_)) => println!("ok {}", x),
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL |         (Ok(_), Some(x)) => println!("ok {}", x),
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
 LL ~         (Ok(x), Some(_)) | (Ok(_), Some(x)) => println!("ok {}", x),
 LL |
 LL ~         _ => println!("err"),
    |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:143:9
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms2.rs:142:9
    |
+LL |         Ok(3) => println!("ok"),
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
+LL |
 LL |         Ok(_) => println!("ok"),
    |         ^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
-LL -         Ok(3) => println!("ok"),
-LL -         Ok(_) => println!("ok"),
-LL +         Ok(_) | Ok(3) => println!("ok"),
+LL ~
+LL ~         Ok(3) | Ok(_) => println!("ok"),
    |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:171:9
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms2.rs:168:9
    |
+LL | /         0 => {
+LL | |             empty!(0);
+LL | |         },
+   | |_________^
+LL |
 LL | /         1 => {
 LL | |             empty!(0);
 LL | |         },
    | |_________^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
-LL -         0 => {
-LL -             empty!(0);
-LL -         },
-LL -         1 => {
-LL +         1 | 0 => {
+LL ~
+LL ~         0 | 1 => {
    |
 
-error: this match arm has an identical body to another arm
+error: these match arms have identical bodies
   --> tests/ui/match_same_arms2.rs:222:9
    |
 LL |         Foo::X(0) => 1,
    |         ^^^^^^^^^^^^^^
+...
+LL |         Foo::Z(_) => 1,
+   |         ^^^^^^^^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
 LL ~         Foo::X(0) | Foo::Z(_) => 1,
 LL |
@@ -156,60 +187,106 @@ LL |         Foo::X(_) | Foo::Y(_) => 2,
 LL ~         _ => 0,
    |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:233:9
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms2.rs:231:9
    |
+LL |         Foo::X(0) => 1,
+   |         ^^^^^^^^^^^^^^
+...
 LL |         Foo::Z(_) => 1,
    |         ^^^^^^^^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
-LL ~         Foo::Y(_) | Foo::Z(0) => 2,
-LL ~         Foo::Z(_) | Foo::X(0) => 1,
+LL ~
+LL |         Foo::Y(_) | Foo::Z(0) => 2,
+LL ~         Foo::X(0) | Foo::Z(_) => 1,
    |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:257:9
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms2.rs:254:9
    |
+LL |         Some(Bar { x: 0, y: 5, .. }) => 1,
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
 LL |         Some(Bar { y: 0, x: 5, .. }) => 1,
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
-LL ~         Some(Bar { y: 10, z: 0, .. }) => 2,
+LL ~
+LL |         Some(Bar { y: 10, z: 0, .. }) => 2,
 LL |         None => 50,
-LL ~         Some(Bar { y: 0, x: 5, .. }) | Some(Bar { x: 0, y: 5, .. }) => 1,
+LL ~         Some(Bar { x: 0, y: 5, .. }) | Some(Bar { y: 0, x: 5, .. }) => 1,
    |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:272:9
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms2.rs:271:9
    |
+LL |         0 => cfg!(not_enable),
+   |         ^^^^^^^^^^^^^^^^^^^^^
+LL |
 LL |         1 => cfg!(not_enable),
    |         ^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
-LL -         0 => cfg!(not_enable),
-LL -         1 => cfg!(not_enable),
-LL +         1 | 0 => cfg!(not_enable),
+LL ~
+LL ~         0 | 1 => cfg!(not_enable),
    |
 
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:289:17
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms2.rs:288:17
    |
+LL |                 MaybeStaticStr::Static(s) => s,
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
 LL |                 MaybeStaticStr::Borrowed(s) => s,
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: try changing either arm body
-help: or try merging the arm patterns and removing the obsolete arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
+   |
+LL ~
+LL ~                 MaybeStaticStr::Static(s) | MaybeStaticStr::Borrowed(s) => s,
    |
-LL -                 MaybeStaticStr::Static(s) => s,
-LL -                 MaybeStaticStr::Borrowed(s) => s,
-LL +                 MaybeStaticStr::Borrowed(s) | MaybeStaticStr::Static(s) => s,
+
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms2.rs:306:9
+   |
+LL |         1 => "b",
+   |         ^^^^^^^^
+LL |
+LL |         2 => "b",
+   |         ^^^^^^^^
+   |
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
+   |
+LL ~         1 | 2 => "b",
+LL |
+LL ~         #[allow(clippy::match_same_arms)]
+   |
+
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms2.rs:315:9
+   |
+LL |         1 => "b",
+   |         ^^^^^^^^
+LL |
+LL |         2 => "b",
+   |         ^^^^^^^^
+   |
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
+   |
+LL ~         1 | 2 => "b",
+LL |
+LL ~         #[expect(clippy::match_same_arms)]
    |
 
-error: aborting due to 14 previous errors
+error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.fixed b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.fixed
index 0c9398933b8..61a5bd0323a 100644
--- a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.fixed
+++ b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.fixed
@@ -7,14 +7,22 @@ fn repeat() -> ! {
     panic!()
 }
 
+#[deny(non_exhaustive_omitted_patterns)]
 pub fn f(x: Ordering) {
-    #[deny(non_exhaustive_omitted_patterns)]
     match x {
         Ordering::Relaxed => println!("relaxed"),
         Ordering::Release => println!("release"),
         Ordering::Acquire => println!("acquire"),
-        Ordering::AcqRel | Ordering::SeqCst => repeat(),
-        _ => repeat(),
+        //~^ match_same_arms
+        Ordering::AcqRel | Ordering::SeqCst | _ => repeat(),
+    }
+
+    match x {
+        Ordering::Relaxed => println!("relaxed"),
+        Ordering::Release => println!("release"),
+        Ordering::Acquire => println!("acquire"),
+        //~^ match_same_arms
+        Ordering::AcqRel | Ordering::SeqCst | _ => repeat(),
     }
 }
 
@@ -28,21 +36,21 @@ mod f {
             Ordering::Relaxed => println!("relaxed"),
             Ordering::Release => println!("release"),
             Ordering::Acquire => println!("acquire"),
-            Ordering::AcqRel | Ordering::SeqCst => repeat(),
-            _ => repeat(),
+            //~^ match_same_arms
+            Ordering::AcqRel | Ordering::SeqCst | _ => repeat(),
         }
     }
 }
 
-// Below should still lint
+// Below can still suggest removing the other patterns
 
 pub fn g(x: Ordering) {
     match x {
         Ordering::Relaxed => println!("relaxed"),
         Ordering::Release => println!("release"),
         Ordering::Acquire => println!("acquire"),
-        //~^ match_same_arms
         _ => repeat(),
+        //~^ match_same_arms
     }
 }
 
@@ -54,8 +62,8 @@ mod g {
             Ordering::Relaxed => println!("relaxed"),
             Ordering::Release => println!("release"),
             Ordering::Acquire => println!("acquire"),
-            //~^ match_same_arms
             _ => repeat(),
+            //~^ match_same_arms
         }
     }
 }
diff --git a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs
index 304a9e5c28e..66f65eb39d0 100644
--- a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs
+++ b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs
@@ -7,15 +7,25 @@ fn repeat() -> ! {
     panic!()
 }
 
+#[deny(non_exhaustive_omitted_patterns)]
 pub fn f(x: Ordering) {
-    #[deny(non_exhaustive_omitted_patterns)]
     match x {
         Ordering::Relaxed => println!("relaxed"),
         Ordering::Release => println!("release"),
         Ordering::Acquire => println!("acquire"),
         Ordering::AcqRel | Ordering::SeqCst => repeat(),
+        //~^ match_same_arms
         _ => repeat(),
     }
+
+    match x {
+        Ordering::Relaxed => println!("relaxed"),
+        Ordering::Release => println!("release"),
+        Ordering::Acquire => println!("acquire"),
+        Ordering::AcqRel => repeat(),
+        //~^ match_same_arms
+        Ordering::SeqCst | _ => repeat(),
+    }
 }
 
 mod f {
@@ -29,12 +39,13 @@ mod f {
             Ordering::Release => println!("release"),
             Ordering::Acquire => println!("acquire"),
             Ordering::AcqRel | Ordering::SeqCst => repeat(),
+            //~^ match_same_arms
             _ => repeat(),
         }
     }
 }
 
-// Below should still lint
+// Below can still suggest removing the other patterns
 
 pub fn g(x: Ordering) {
     match x {
@@ -42,8 +53,8 @@ pub fn g(x: Ordering) {
         Ordering::Release => println!("release"),
         Ordering::Acquire => println!("acquire"),
         Ordering::AcqRel | Ordering::SeqCst => repeat(),
-        //~^ match_same_arms
         _ => repeat(),
+        //~^ match_same_arms
     }
 }
 
@@ -56,8 +67,8 @@ mod g {
             Ordering::Release => println!("release"),
             Ordering::Acquire => println!("acquire"),
             Ordering::AcqRel | Ordering::SeqCst => repeat(),
-            //~^ match_same_arms
             _ => repeat(),
+            //~^ match_same_arms
         }
     }
 }
diff --git a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr
index aa7f8c95dce..03252f346c6 100644
--- a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr
+++ b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr
@@ -1,32 +1,80 @@
-error: this match arm has an identical body to the `_` wildcard arm
-  --> tests/ui/match_same_arms_non_exhaustive.rs:44:9
-   |
-LL | /         Ordering::AcqRel | Ordering::SeqCst => repeat(),
-LL | |
-   | |________^ help: try removing the arm
-   |
-   = help: or try changing either arm body
-note: `_` wildcard arm here
-  --> tests/ui/match_same_arms_non_exhaustive.rs:46:9
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms_non_exhaustive.rs:16:9
    |
+LL |         Ordering::AcqRel | Ordering::SeqCst => repeat(),
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
 LL |         _ => repeat(),
    |         ^^^^^^^^^^^^^
+   |
+   = help: if this is unintentional make the arms return different values
    = note: `-D clippy::match-same-arms` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::match_same_arms)]`
+help: otherwise merge the patterns into a single arm
+   |
+LL ~
+LL ~         Ordering::AcqRel | Ordering::SeqCst | _ => repeat(),
+   |
 
-error: this match arm has an identical body to the `_` wildcard arm
-  --> tests/ui/match_same_arms_non_exhaustive.rs:58:13
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms_non_exhaustive.rs:25:9
+   |
+LL |         Ordering::AcqRel => repeat(),
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL |         Ordering::SeqCst | _ => repeat(),
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-LL | /             Ordering::AcqRel | Ordering::SeqCst => repeat(),
-LL | |
-   | |____________^ help: try removing the arm
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
    |
-   = help: or try changing either arm body
-note: `_` wildcard arm here
-  --> tests/ui/match_same_arms_non_exhaustive.rs:60:13
+LL ~
+LL ~         Ordering::AcqRel | Ordering::SeqCst | _ => repeat(),
    |
+
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms_non_exhaustive.rs:41:13
+   |
+LL |             Ordering::AcqRel | Ordering::SeqCst => repeat(),
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
 LL |             _ => repeat(),
    |             ^^^^^^^^^^^^^
+   |
+   = help: if this is unintentional make the arms return different values
+help: otherwise merge the patterns into a single arm
+   |
+LL ~
+LL ~             Ordering::AcqRel | Ordering::SeqCst | _ => repeat(),
+   |
+
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms_non_exhaustive.rs:55:9
+   |
+LL |         Ordering::AcqRel | Ordering::SeqCst => repeat(),
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         _ => repeat(),
+   |         ^^^^^^^^^^^^^ the wildcard arm
+   |
+   = help: if this is unintentional make the arms return different values
+help: otherwise remove the non-wildcard arm
+   |
+LL -         Ordering::AcqRel | Ordering::SeqCst => repeat(),
+   |
+
+error: these match arms have identical bodies
+  --> tests/ui/match_same_arms_non_exhaustive.rs:69:13
+   |
+LL |             Ordering::AcqRel | Ordering::SeqCst => repeat(),
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |             _ => repeat(),
+   |             ^^^^^^^^^^^^^ the wildcard arm
+   |
+   = help: if this is unintentional make the arms return different values
+help: otherwise remove the non-wildcard arm
+   |
+LL -             Ordering::AcqRel | Ordering::SeqCst => repeat(),
+   |
 
-error: aborting due to 2 previous errors
+error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/methods.rs b/src/tools/clippy/tests/ui/methods.rs
index 2f4004181f6..f73fe288b0f 100644
--- a/src/tools/clippy/tests/ui/methods.rs
+++ b/src/tools/clippy/tests/ui/methods.rs
@@ -49,7 +49,7 @@ struct Lt2<'a> {
 
 impl<'a> Lt2<'a> {
     // The lifetime is different, but that’s irrelevant; see issue #734.
-    pub fn new(s: &str) -> Lt2 {
+    pub fn new(s: &str) -> Lt2<'_> {
         unimplemented!()
     }
 }
diff --git a/src/tools/clippy/tests/ui/misrefactored_assign_op.1.fixed b/src/tools/clippy/tests/ui/misrefactored_assign_op.1.fixed
new file mode 100644
index 00000000000..882ff6bf894
--- /dev/null
+++ b/src/tools/clippy/tests/ui/misrefactored_assign_op.1.fixed
@@ -0,0 +1,40 @@
+#![allow(clippy::eq_op)]
+#![warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)]
+
+fn main() {
+    let mut a = 5;
+    a += 1;
+    //~^ misrefactored_assign_op
+
+    a += 1;
+    //~^ misrefactored_assign_op
+
+    a -= 1;
+    //~^ misrefactored_assign_op
+
+    a *= 99;
+    //~^ misrefactored_assign_op
+
+    a *= 42;
+    //~^ misrefactored_assign_op
+
+    a /= 2;
+    //~^ misrefactored_assign_op
+
+    a %= 5;
+    //~^ misrefactored_assign_op
+
+    a &= 1;
+    //~^ misrefactored_assign_op
+
+    a *= a;
+    //~^ misrefactored_assign_op
+
+    a = a * a * a;
+    a = a * 42 * a;
+    a = a * 2 + a;
+    a -= 1 - a;
+    a /= 5 / a;
+    a %= 42 % a;
+    a <<= 6 << a;
+}
diff --git a/src/tools/clippy/tests/ui/misrefactored_assign_op.2.fixed b/src/tools/clippy/tests/ui/misrefactored_assign_op.2.fixed
new file mode 100644
index 00000000000..de3a0f1710d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/misrefactored_assign_op.2.fixed
@@ -0,0 +1,40 @@
+#![allow(clippy::eq_op)]
+#![warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)]
+
+fn main() {
+    let mut a = 5;
+    a = a + a + 1;
+    //~^ misrefactored_assign_op
+
+    a = a + 1 + a;
+    //~^ misrefactored_assign_op
+
+    a = a - (a - 1);
+    //~^ misrefactored_assign_op
+
+    a = a * a * 99;
+    //~^ misrefactored_assign_op
+
+    a = a * 42 * a;
+    //~^ misrefactored_assign_op
+
+    a = a / (a / 2);
+    //~^ misrefactored_assign_op
+
+    a = a % (a % 5);
+    //~^ misrefactored_assign_op
+
+    a = a & a & 1;
+    //~^ misrefactored_assign_op
+
+    a = a * a * a;
+    //~^ misrefactored_assign_op
+
+    a = a * a * a;
+    a = a * 42 * a;
+    a = a * 2 + a;
+    a -= 1 - a;
+    a /= 5 / a;
+    a %= 42 % a;
+    a <<= 6 << a;
+}
diff --git a/src/tools/clippy/tests/ui/misrefactored_assign_op.rs b/src/tools/clippy/tests/ui/misrefactored_assign_op.rs
new file mode 100644
index 00000000000..62d83d1619c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/misrefactored_assign_op.rs
@@ -0,0 +1,40 @@
+#![allow(clippy::eq_op)]
+#![warn(clippy::misrefactored_assign_op, clippy::assign_op_pattern)]
+
+fn main() {
+    let mut a = 5;
+    a += a + 1;
+    //~^ misrefactored_assign_op
+
+    a += 1 + a;
+    //~^ misrefactored_assign_op
+
+    a -= a - 1;
+    //~^ misrefactored_assign_op
+
+    a *= a * 99;
+    //~^ misrefactored_assign_op
+
+    a *= 42 * a;
+    //~^ misrefactored_assign_op
+
+    a /= a / 2;
+    //~^ misrefactored_assign_op
+
+    a %= a % 5;
+    //~^ misrefactored_assign_op
+
+    a &= a & 1;
+    //~^ misrefactored_assign_op
+
+    a *= a * a;
+    //~^ misrefactored_assign_op
+
+    a = a * a * a;
+    a = a * 42 * a;
+    a = a * 2 + a;
+    a -= 1 - a;
+    a /= 5 / a;
+    a %= 42 % a;
+    a <<= 6 << a;
+}
diff --git a/src/tools/clippy/tests/ui/assign_ops2.stderr b/src/tools/clippy/tests/ui/misrefactored_assign_op.stderr
index d9ecd3f8b23..63f3a3e28f1 100644
--- a/src/tools/clippy/tests/ui/assign_ops2.stderr
+++ b/src/tools/clippy/tests/ui/misrefactored_assign_op.stderr
@@ -1,5 +1,5 @@
 error: variable appears on both sides of an assignment operation
-  --> tests/ui/assign_ops2.rs:8:5
+  --> tests/ui/misrefactored_assign_op.rs:6:5
    |
 LL |     a += a + 1;
    |     ^^^^^^^^^^
@@ -18,7 +18,7 @@ LL +     a = a + a + 1;
    |
 
 error: variable appears on both sides of an assignment operation
-  --> tests/ui/assign_ops2.rs:11:5
+  --> tests/ui/misrefactored_assign_op.rs:9:5
    |
 LL |     a += 1 + a;
    |     ^^^^^^^^^^
@@ -35,7 +35,7 @@ LL +     a = a + 1 + a;
    |
 
 error: variable appears on both sides of an assignment operation
-  --> tests/ui/assign_ops2.rs:14:5
+  --> tests/ui/misrefactored_assign_op.rs:12:5
    |
 LL |     a -= a - 1;
    |     ^^^^^^^^^^
@@ -52,7 +52,7 @@ LL +     a = a - (a - 1);
    |
 
 error: variable appears on both sides of an assignment operation
-  --> tests/ui/assign_ops2.rs:17:5
+  --> tests/ui/misrefactored_assign_op.rs:15:5
    |
 LL |     a *= a * 99;
    |     ^^^^^^^^^^^
@@ -69,7 +69,7 @@ LL +     a = a * a * 99;
    |
 
 error: variable appears on both sides of an assignment operation
-  --> tests/ui/assign_ops2.rs:20:5
+  --> tests/ui/misrefactored_assign_op.rs:18:5
    |
 LL |     a *= 42 * a;
    |     ^^^^^^^^^^^
@@ -86,7 +86,7 @@ LL +     a = a * 42 * a;
    |
 
 error: variable appears on both sides of an assignment operation
-  --> tests/ui/assign_ops2.rs:23:5
+  --> tests/ui/misrefactored_assign_op.rs:21:5
    |
 LL |     a /= a / 2;
    |     ^^^^^^^^^^
@@ -103,7 +103,7 @@ LL +     a = a / (a / 2);
    |
 
 error: variable appears on both sides of an assignment operation
-  --> tests/ui/assign_ops2.rs:26:5
+  --> tests/ui/misrefactored_assign_op.rs:24:5
    |
 LL |     a %= a % 5;
    |     ^^^^^^^^^^
@@ -120,7 +120,7 @@ LL +     a = a % (a % 5);
    |
 
 error: variable appears on both sides of an assignment operation
-  --> tests/ui/assign_ops2.rs:29:5
+  --> tests/ui/misrefactored_assign_op.rs:27:5
    |
 LL |     a &= a & 1;
    |     ^^^^^^^^^^
@@ -137,7 +137,7 @@ LL +     a = a & a & 1;
    |
 
 error: variable appears on both sides of an assignment operation
-  --> tests/ui/assign_ops2.rs:32:5
+  --> tests/ui/misrefactored_assign_op.rs:30:5
    |
 LL |     a *= a * a;
    |     ^^^^^^^^^^
@@ -153,14 +153,5 @@ LL -     a *= a * a;
 LL +     a = a * a * a;
    |
 
-error: manual implementation of an assign operation
-  --> tests/ui/assign_ops2.rs:71:5
-   |
-LL |     buf = buf + cows.clone();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `buf += cows.clone()`
-   |
-   = note: `-D clippy::assign-op-pattern` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::assign_op_pattern)]`
-
-error: aborting due to 10 previous errors
+error: aborting due to 9 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_borrow.fixed b/src/tools/clippy/tests/ui/needless_borrow.fixed
index d7d344452c5..54cad2e393f 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.fixed
+++ b/src/tools/clippy/tests/ui/needless_borrow.fixed
@@ -107,9 +107,6 @@ fn main() {
     let x = (1, 2);
     let _ = x.0;
     //~^ needless_borrow
-    let x = &x as *const (i32, i32);
-    let _ = unsafe { (*x).0 };
-    //~^ needless_borrow
 
     // Issue #8367
     trait Foo {
@@ -289,3 +286,15 @@ fn issue_12268() {
 
     // compiler
 }
+
+fn issue_14743<T>(slice: &[T]) {
+    let _ = slice.len();
+    //~^ needless_borrow
+
+    let slice = slice as *const [T];
+    let _ = unsafe { (&*slice).len() };
+
+    // Check that rustc would actually warn if Clippy had suggested removing the reference
+    #[expect(dangerous_implicit_autorefs)]
+    let _ = unsafe { (*slice).len() };
+}
diff --git a/src/tools/clippy/tests/ui/needless_borrow.rs b/src/tools/clippy/tests/ui/needless_borrow.rs
index 1f05b90b472..b698c6bfc96 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.rs
+++ b/src/tools/clippy/tests/ui/needless_borrow.rs
@@ -107,9 +107,6 @@ fn main() {
     let x = (1, 2);
     let _ = (&x).0;
     //~^ needless_borrow
-    let x = &x as *const (i32, i32);
-    let _ = unsafe { (&*x).0 };
-    //~^ needless_borrow
 
     // Issue #8367
     trait Foo {
@@ -289,3 +286,15 @@ fn issue_12268() {
 
     // compiler
 }
+
+fn issue_14743<T>(slice: &[T]) {
+    let _ = (&slice).len();
+    //~^ needless_borrow
+
+    let slice = slice as *const [T];
+    let _ = unsafe { (&*slice).len() };
+
+    // Check that rustc would actually warn if Clippy had suggested removing the reference
+    #[expect(dangerous_implicit_autorefs)]
+    let _ = unsafe { (*slice).len() };
+}
diff --git a/src/tools/clippy/tests/ui/needless_borrow.stderr b/src/tools/clippy/tests/ui/needless_borrow.stderr
index b036b1e47d1..172d36bd73a 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.stderr
+++ b/src/tools/clippy/tests/ui/needless_borrow.stderr
@@ -103,71 +103,71 @@ error: this expression borrows a value the compiler would automatically borrow
 LL |     let _ = (&x).0;
    |             ^^^^ help: change this to: `x`
 
-error: this expression borrows a value the compiler would automatically borrow
-  --> tests/ui/needless_borrow.rs:111:22
-   |
-LL |     let _ = unsafe { (&*x).0 };
-   |                      ^^^^^ help: change this to: `(*x)`
-
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:122:5
+  --> tests/ui/needless_borrow.rs:119:5
    |
 LL |     (&&()).foo();
    |     ^^^^^^ help: change this to: `(&())`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:132:5
+  --> tests/ui/needless_borrow.rs:129:5
    |
 LL |     (&&5).foo();
    |     ^^^^^ help: change this to: `(&5)`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:159:23
+  --> tests/ui/needless_borrow.rs:156:23
    |
 LL |     let x: (&str,) = (&"",);
    |                       ^^^ help: change this to: `""`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> tests/ui/needless_borrow.rs:202:13
+  --> tests/ui/needless_borrow.rs:199:13
    |
 LL |             (&self.f)()
    |             ^^^^^^^^^ help: change this to: `(self.f)`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> tests/ui/needless_borrow.rs:212:13
+  --> tests/ui/needless_borrow.rs:209:13
    |
 LL |             (&mut self.f)()
    |             ^^^^^^^^^^^^^ help: change this to: `(self.f)`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> tests/ui/needless_borrow.rs:250:22
+  --> tests/ui/needless_borrow.rs:247:22
    |
 LL |         let _ = &mut (&mut { x.u }).x;
    |                      ^^^^^^^^^^^^^^ help: change this to: `{ x.u }`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> tests/ui/needless_borrow.rs:258:22
+  --> tests/ui/needless_borrow.rs:255:22
    |
 LL |         let _ = &mut (&mut { x.u }).x;
    |                      ^^^^^^^^^^^^^^ help: change this to: `{ x.u }`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> tests/ui/needless_borrow.rs:263:22
+  --> tests/ui/needless_borrow.rs:260:22
    |
 LL |         let _ = &mut (&mut x.u).x;
    |                      ^^^^^^^^^^ help: change this to: `x.u`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> tests/ui/needless_borrow.rs:265:22
+  --> tests/ui/needless_borrow.rs:262:22
    |
 LL |         let _ = &mut (&mut { x.u }).x;
    |                      ^^^^^^^^^^^^^^ help: change this to: `{ x.u }`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> tests/ui/needless_borrow.rs:287:23
+  --> tests/ui/needless_borrow.rs:284:23
    |
 LL |     option.unwrap_or((&x.0,));
    |                       ^^^^ help: change this to: `x.0`
 
+error: this expression creates a reference which is immediately dereferenced by the compiler
+  --> tests/ui/needless_borrow.rs:291:13
+   |
+LL |     let _ = (&slice).len();
+   |             ^^^^^^^^ help: change this to: `slice`
+
 error: aborting due to 28 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed b/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed
index fa23e18318f..a73aff55639 100644
--- a/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed
+++ b/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed
@@ -128,3 +128,18 @@ fn should_not_lint() {
 }
 
 fn main() {}
+
+mod issue14734 {
+    fn let_desugar(rows: &[u8]) {
+        let mut v = vec![];
+        for x in rows.iter() { _ = v.push(x) }
+        //~^ needless_for_each
+    }
+
+    fn do_something(_: &u8, _: u8) {}
+
+    fn single_expr(rows: &[u8]) {
+        for x in rows.iter() { do_something(x, 1u8); }
+        //~^ needless_for_each
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_for_each_fixable.rs b/src/tools/clippy/tests/ui/needless_for_each_fixable.rs
index 2c7e68a6f51..d92f055d3f4 100644
--- a/src/tools/clippy/tests/ui/needless_for_each_fixable.rs
+++ b/src/tools/clippy/tests/ui/needless_for_each_fixable.rs
@@ -128,3 +128,18 @@ fn should_not_lint() {
 }
 
 fn main() {}
+
+mod issue14734 {
+    fn let_desugar(rows: &[u8]) {
+        let mut v = vec![];
+        rows.iter().for_each(|x| _ = v.push(x));
+        //~^ needless_for_each
+    }
+
+    fn do_something(_: &u8, _: u8) {}
+
+    fn single_expr(rows: &[u8]) {
+        rows.iter().for_each(|x| do_something(x, 1u8));
+        //~^ needless_for_each
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_for_each_fixable.stderr b/src/tools/clippy/tests/ui/needless_for_each_fixable.stderr
index 013a3fa3e36..f8014456097 100644
--- a/src/tools/clippy/tests/ui/needless_for_each_fixable.stderr
+++ b/src/tools/clippy/tests/ui/needless_for_each_fixable.stderr
@@ -136,5 +136,17 @@ LL +         acc += elem;
 LL +     }
    |
 
-error: aborting due to 8 previous errors
+error: needless use of `for_each`
+  --> tests/ui/needless_for_each_fixable.rs:135:9
+   |
+LL |         rows.iter().for_each(|x| _ = v.push(x));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in rows.iter() { _ = v.push(x) }`
+
+error: needless use of `for_each`
+  --> tests/ui/needless_for_each_fixable.rs:142:9
+   |
+LL |         rows.iter().for_each(|x| do_something(x, 1u8));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in rows.iter() { do_something(x, 1u8); }`
+
+error: aborting due to 10 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.fixed b/src/tools/clippy/tests/ui/needless_lifetimes.fixed
index e9d811986aa..ceea4480d0d 100644
--- a/src/tools/clippy/tests/ui/needless_lifetimes.fixed
+++ b/src/tools/clippy/tests/ui/needless_lifetimes.fixed
@@ -10,7 +10,7 @@
     clippy::unnecessary_wraps,
     dyn_drop,
     clippy::get_first,
-    elided_named_lifetimes
+    mismatched_lifetime_syntaxes,
 )]
 
 extern crate proc_macros;
diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.rs b/src/tools/clippy/tests/ui/needless_lifetimes.rs
index 0b6eb9755b9..8432f9e6d2f 100644
--- a/src/tools/clippy/tests/ui/needless_lifetimes.rs
+++ b/src/tools/clippy/tests/ui/needless_lifetimes.rs
@@ -10,7 +10,7 @@
     clippy::unnecessary_wraps,
     dyn_drop,
     clippy::get_first,
-    elided_named_lifetimes
+    mismatched_lifetime_syntaxes,
 )]
 
 extern crate proc_macros;
diff --git a/src/tools/clippy/tests/ui/needless_match.fixed b/src/tools/clippy/tests/ui/needless_match.fixed
index b2c2bbfaa36..41acf44023f 100644
--- a/src/tools/clippy/tests/ui/needless_match.fixed
+++ b/src/tools/clippy/tests/ui/needless_match.fixed
@@ -301,4 +301,16 @@ pub fn issue13574() -> Option<()> {
     None
 }
 
+fn issue14754(t: Result<i32, &'static str>) -> Result<i32, &'static str> {
+    let _ = match t {
+        Ok(v) => Ok::<_, &'static str>(v),
+        err @ Err(_) => return err,
+    };
+    println!("Still here");
+    let x = t;
+    //~^^^^ needless_match
+    println!("Still here");
+    x
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_match.rs b/src/tools/clippy/tests/ui/needless_match.rs
index 1cb670edc60..936653b961b 100644
--- a/src/tools/clippy/tests/ui/needless_match.rs
+++ b/src/tools/clippy/tests/ui/needless_match.rs
@@ -364,4 +364,19 @@ pub fn issue13574() -> Option<()> {
     None
 }
 
+fn issue14754(t: Result<i32, &'static str>) -> Result<i32, &'static str> {
+    let _ = match t {
+        Ok(v) => Ok::<_, &'static str>(v),
+        err @ Err(_) => return err,
+    };
+    println!("Still here");
+    let x = match t {
+        Ok(v) => Ok::<_, &'static str>(v),
+        err @ Err(_) => err,
+    };
+    //~^^^^ needless_match
+    println!("Still here");
+    x
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_match.stderr b/src/tools/clippy/tests/ui/needless_match.stderr
index 719b0ef8846..5195ecdfa55 100644
--- a/src/tools/clippy/tests/ui/needless_match.stderr
+++ b/src/tools/clippy/tests/ui/needless_match.stderr
@@ -151,5 +151,15 @@ LL | |             None
 LL | |         }
    | |_________^ help: replace it with: `A`
 
-error: aborting due to 14 previous errors
+error: this match expression is unnecessary
+  --> tests/ui/needless_match.rs:373:13
+   |
+LL |       let x = match t {
+   |  _____________^
+LL | |         Ok(v) => Ok::<_, &'static str>(v),
+LL | |         err @ Err(_) => err,
+LL | |     };
+   | |_____^ help: replace it with: `t`
+
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed
index ad625ad6d50..d571b97f519 100644
--- a/src/tools/clippy/tests/ui/needless_return.fixed
+++ b/src/tools/clippy/tests/ui/needless_return.fixed
@@ -84,14 +84,14 @@ fn test_macro_call() -> i32 {
 }
 
 fn test_void_fun() {
-    //~^^ needless_return
+    //~^ needless_return
 }
 
 fn test_void_if_fun(b: bool) {
     if b {
-        //~^^ needless_return
+        //~^ needless_return
     } else {
-        //~^^ needless_return
+        //~^ needless_return
     }
 }
 
@@ -108,7 +108,7 @@ fn test_nested_match(x: u32) {
         0 => (),
         1 => {
             let _ = 42;
-            //~^^ needless_return
+            //~^ needless_return
         },
         _ => (),
         //~^ needless_return
@@ -156,7 +156,7 @@ mod issue6501 {
 
     fn test_closure() {
         let _ = || {
-            //~^^ needless_return
+            //~^ needless_return
         };
         let _ = || {};
         //~^ needless_return
@@ -220,14 +220,14 @@ async fn async_test_macro_call() -> i32 {
 }
 
 async fn async_test_void_fun() {
-    //~^^ needless_return
+    //~^ needless_return
 }
 
 async fn async_test_void_if_fun(b: bool) {
     if b {
-        //~^^ needless_return
+        //~^ needless_return
     } else {
-        //~^^ needless_return
+        //~^ needless_return
     }
 }
 
@@ -354,7 +354,7 @@ fn issue9503(x: usize) -> isize {
 mod issue9416 {
     pub fn with_newline() {
         let _ = 42;
-        //~^^ needless_return
+        //~^ needless_return
     }
 
     #[rustfmt::skip]
@@ -452,3 +452,68 @@ pub unsafe fn issue_12157() -> *const i32 {
     (unsafe { todo() } as *const i32)
     //~^ needless_return
 }
+
+mod else_ifs {
+    fn test1(a: i32) -> u32 {
+        if a == 0 {
+            1
+        //~^ needless_return
+        } else if a < 10 {
+            2
+        //~^ needless_return
+        } else {
+            3
+            //~^ needless_return
+        }
+    }
+
+    fn test2(a: i32) -> u32 {
+        if a == 0 {
+            1
+        //~^ needless_return
+        } else if a < 10 {
+            2
+        } else {
+            3
+            //~^ needless_return
+        }
+    }
+
+    fn test3(a: i32) -> u32 {
+        if a == 0 {
+            1
+        //~^ needless_return
+        } else if a < 10 {
+            2
+        } else {
+            3
+            //~^ needless_return
+        }
+    }
+
+    #[allow(clippy::match_single_binding, clippy::redundant_pattern)]
+    fn test4(a: i32) -> u32 {
+        if a == 0 {
+            1
+            //~^ needless_return
+        } else if if if a > 0x1_1 {
+            return 2;
+        } else {
+            return 5;
+        } {
+            true
+        } else {
+            true
+        } {
+            0xDEADC0DE
+        } else if match a {
+            b @ _ => {
+                return 1;
+            },
+        } {
+            0xDEADBEEF
+        } else {
+            1
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs
index 41d7e5bdd50..2e4348ea338 100644
--- a/src/tools/clippy/tests/ui/needless_return.rs
+++ b/src/tools/clippy/tests/ui/needless_return.rs
@@ -85,16 +85,16 @@ fn test_macro_call() -> i32 {
 
 fn test_void_fun() {
     return;
-    //~^^ needless_return
+    //~^ needless_return
 }
 
 fn test_void_if_fun(b: bool) {
     if b {
         return;
-        //~^^ needless_return
+        //~^ needless_return
     } else {
         return;
-        //~^^ needless_return
+        //~^ needless_return
     }
 }
 
@@ -112,7 +112,7 @@ fn test_nested_match(x: u32) {
         1 => {
             let _ = 42;
             return;
-            //~^^ needless_return
+            //~^ needless_return
         },
         _ => return,
         //~^ needless_return
@@ -161,7 +161,7 @@ mod issue6501 {
     fn test_closure() {
         let _ = || {
             return;
-            //~^^ needless_return
+            //~^ needless_return
         };
         let _ = || return;
         //~^ needless_return
@@ -226,16 +226,16 @@ async fn async_test_macro_call() -> i32 {
 
 async fn async_test_void_fun() {
     return;
-    //~^^ needless_return
+    //~^ needless_return
 }
 
 async fn async_test_void_if_fun(b: bool) {
     if b {
         return;
-        //~^^ needless_return
+        //~^ needless_return
     } else {
         return;
-        //~^^ needless_return
+        //~^ needless_return
     }
 }
 
@@ -363,7 +363,7 @@ mod issue9416 {
     pub fn with_newline() {
         let _ = 42;
         return;
-        //~^^ needless_return
+        //~^ needless_return
     }
 
     #[rustfmt::skip]
@@ -461,3 +461,68 @@ pub unsafe fn issue_12157() -> *const i32 {
     return unsafe { todo() } as *const i32;
     //~^ needless_return
 }
+
+mod else_ifs {
+    fn test1(a: i32) -> u32 {
+        if a == 0 {
+            return 1;
+        //~^ needless_return
+        } else if a < 10 {
+            return 2;
+        //~^ needless_return
+        } else {
+            return 3;
+            //~^ needless_return
+        }
+    }
+
+    fn test2(a: i32) -> u32 {
+        if a == 0 {
+            return 1;
+        //~^ needless_return
+        } else if a < 10 {
+            2
+        } else {
+            return 3;
+            //~^ needless_return
+        }
+    }
+
+    fn test3(a: i32) -> u32 {
+        if a == 0 {
+            return 1;
+        //~^ needless_return
+        } else if a < 10 {
+            2
+        } else {
+            return 3;
+            //~^ needless_return
+        }
+    }
+
+    #[allow(clippy::match_single_binding, clippy::redundant_pattern)]
+    fn test4(a: i32) -> u32 {
+        if a == 0 {
+            return 1;
+            //~^ needless_return
+        } else if if if a > 0x1_1 {
+            return 2;
+        } else {
+            return 5;
+        } {
+            true
+        } else {
+            true
+        } {
+            0xDEADC0DE
+        } else if match a {
+            b @ _ => {
+                return 1;
+            },
+        } {
+            0xDEADBEEF
+        } else {
+            1
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr
index 80863b9b62b..206bd8ee5af 100644
--- a/src/tools/clippy/tests/ui/needless_return.stderr
+++ b/src/tools/clippy/tests/ui/needless_return.stderr
@@ -133,12 +133,10 @@ LL +     the_answer!()
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:86:21
+  --> tests/ui/needless_return.rs:87:5
    |
-LL |   fn test_void_fun() {
-   |  _____________________^
-LL | |     return;
-   | |__________^
+LL |     return;
+   |     ^^^^^^
    |
 help: remove `return`
    |
@@ -148,12 +146,10 @@ LL + fn test_void_fun() {
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:92:11
+  --> tests/ui/needless_return.rs:93:9
    |
-LL |       if b {
-   |  ___________^
-LL | |         return;
-   | |______________^
+LL |         return;
+   |         ^^^^^^
    |
 help: remove `return`
    |
@@ -163,12 +159,10 @@ LL +     if b {
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:95:13
+  --> tests/ui/needless_return.rs:96:9
    |
-LL |       } else {
-   |  _____________^
-LL | |         return;
-   | |______________^
+LL |         return;
+   |         ^^^^^^
    |
 help: remove `return`
    |
@@ -190,12 +184,10 @@ LL +         _ => (),
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:113:24
+  --> tests/ui/needless_return.rs:114:13
    |
-LL |               let _ = 42;
-   |  ________________________^
-LL | |             return;
-   | |__________________^
+LL |             return;
+   |             ^^^^^^
    |
 help: remove `return`
    |
@@ -253,12 +245,10 @@ LL +         bar.unwrap_or_else(|_| {})
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:162:21
+  --> tests/ui/needless_return.rs:163:13
    |
-LL |           let _ = || {
-   |  _____________________^
-LL | |             return;
-   | |__________________^
+LL |             return;
+   |             ^^^^^^
    |
 help: remove `return`
    |
@@ -400,12 +390,10 @@ LL +     the_answer!()
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:227:33
+  --> tests/ui/needless_return.rs:228:5
    |
-LL |   async fn async_test_void_fun() {
-   |  _________________________________^
-LL | |     return;
-   | |__________^
+LL |     return;
+   |     ^^^^^^
    |
 help: remove `return`
    |
@@ -415,12 +403,10 @@ LL + async fn async_test_void_fun() {
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:233:11
+  --> tests/ui/needless_return.rs:234:9
    |
-LL |       if b {
-   |  ___________^
-LL | |         return;
-   | |______________^
+LL |         return;
+   |         ^^^^^^
    |
 help: remove `return`
    |
@@ -430,12 +416,10 @@ LL +     if b {
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:236:13
+  --> tests/ui/needless_return.rs:237:9
    |
-LL |       } else {
-   |  _____________^
-LL | |         return;
-   | |______________^
+LL |         return;
+   |         ^^^^^^
    |
 help: remove `return`
    |
@@ -593,12 +577,10 @@ LL ~     }
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:364:20
+  --> tests/ui/needless_return.rs:365:9
    |
-LL |           let _ = 42;
-   |  ____________________^
-LL | |         return;
-   | |______________^
+LL |         return;
+   |         ^^^^^^
    |
 help: remove `return`
    |
@@ -608,10 +590,10 @@ LL +         let _ = 42;
    |
 
 error: unneeded `return` statement
-  --> tests/ui/needless_return.rs:371:20
+  --> tests/ui/needless_return.rs:371:21
    |
 LL |         let _ = 42; return;
-   |                    ^^^^^^^
+   |                     ^^^^^^
    |
 help: remove `return`
    |
@@ -703,5 +685,101 @@ LL -     return unsafe { todo() } as *const i32;
 LL +     (unsafe { todo() } as *const i32)
    |
 
-error: aborting due to 55 previous errors
+error: unneeded `return` statement
+  --> tests/ui/needless_return.rs:468:13
+   |
+LL |             return 1;
+   |             ^^^^^^^^
+   |
+help: remove `return`
+   |
+LL -             return 1;
+LL +             1
+   |
+
+error: unneeded `return` statement
+  --> tests/ui/needless_return.rs:471:13
+   |
+LL |             return 2;
+   |             ^^^^^^^^
+   |
+help: remove `return`
+   |
+LL -             return 2;
+LL +             2
+   |
+
+error: unneeded `return` statement
+  --> tests/ui/needless_return.rs:474:13
+   |
+LL |             return 3;
+   |             ^^^^^^^^
+   |
+help: remove `return`
+   |
+LL -             return 3;
+LL +             3
+   |
+
+error: unneeded `return` statement
+  --> tests/ui/needless_return.rs:481:13
+   |
+LL |             return 1;
+   |             ^^^^^^^^
+   |
+help: remove `return`
+   |
+LL -             return 1;
+LL +             1
+   |
+
+error: unneeded `return` statement
+  --> tests/ui/needless_return.rs:486:13
+   |
+LL |             return 3;
+   |             ^^^^^^^^
+   |
+help: remove `return`
+   |
+LL -             return 3;
+LL +             3
+   |
+
+error: unneeded `return` statement
+  --> tests/ui/needless_return.rs:493:13
+   |
+LL |             return 1;
+   |             ^^^^^^^^
+   |
+help: remove `return`
+   |
+LL -             return 1;
+LL +             1
+   |
+
+error: unneeded `return` statement
+  --> tests/ui/needless_return.rs:498:13
+   |
+LL |             return 3;
+   |             ^^^^^^^^
+   |
+help: remove `return`
+   |
+LL -             return 3;
+LL +             3
+   |
+
+error: unneeded `return` statement
+  --> tests/ui/needless_return.rs:506:13
+   |
+LL |             return 1;
+   |             ^^^^^^^^
+   |
+help: remove `return`
+   |
+LL -             return 1;
+LL +             1
+   |
+
+error: aborting due to 63 previous errors
 
diff --git a/src/tools/clippy/tests/ui/no_effect.rs b/src/tools/clippy/tests/ui/no_effect.rs
index 703c2a3d984..4ab5bc9acde 100644
--- a/src/tools/clippy/tests/ui/no_effect.rs
+++ b/src/tools/clippy/tests/ui/no_effect.rs
@@ -221,3 +221,56 @@ fn main() {
     Cout << 142;
     -Cout;
 }
+
+fn issue14592() {
+    struct MyStruct {
+        _inner: MyInner,
+    }
+    struct MyInner {}
+
+    impl Drop for MyInner {
+        fn drop(&mut self) {
+            println!("dropping");
+        }
+    }
+
+    let x = MyStruct { _inner: MyInner {} };
+
+    let closure = || {
+        // Do not lint: dropping the assignment or assigning to `_` would
+        // change the output.
+        let _x = x;
+    };
+
+    println!("1");
+    closure();
+    println!("2");
+
+    struct Innocuous {
+        a: i32,
+    }
+
+    // Do not lint: one of the fields has a side effect.
+    let x = MyInner {};
+    let closure = || {
+        let _x = Innocuous {
+            a: {
+                x;
+                10
+            },
+        };
+    };
+
+    // Do not lint: the base has a side effect.
+    let x = MyInner {};
+    let closure = || {
+        let _x = Innocuous {
+            ..Innocuous {
+                a: {
+                    x;
+                    10
+                },
+            }
+        };
+    };
+}
diff --git a/src/tools/clippy/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.fixed b/src/tools/clippy/tests/ui/non_expressive_names_error_recovery.fixed
index c96a53ba2cd..c96a53ba2cd 100644
--- a/src/tools/clippy/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.fixed
+++ b/src/tools/clippy/tests/ui/non_expressive_names_error_recovery.fixed
diff --git a/src/tools/clippy/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.rs b/src/tools/clippy/tests/ui/non_expressive_names_error_recovery.rs
index a3a35eb26d1..a3a35eb26d1 100644
--- a/src/tools/clippy/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.rs
+++ b/src/tools/clippy/tests/ui/non_expressive_names_error_recovery.rs
diff --git a/src/tools/clippy/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.stderr b/src/tools/clippy/tests/ui/non_expressive_names_error_recovery.stderr
index e334ca5241e..28d9a42a9a1 100644
--- a/src/tools/clippy/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.stderr
+++ b/src/tools/clippy/tests/ui/non_expressive_names_error_recovery.stderr
@@ -1,5 +1,5 @@
 error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `)`
-  --> tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.rs:6:19
+  --> tests/ui/non_expressive_names_error_recovery.rs:6:19
    |
 LL | fn aa(a: Aa<String) {
    |                   ^ expected one of 7 possible tokens
diff --git a/src/tools/clippy/tests/ui/ptr_arg.rs b/src/tools/clippy/tests/ui/ptr_arg.rs
index 2d77bf06ff9..65f3f05d6cb 100644
--- a/src/tools/clippy/tests/ui/ptr_arg.rs
+++ b/src/tools/clippy/tests/ui/ptr_arg.rs
@@ -312,7 +312,7 @@ mod issue_9218 {
 
     // Inferred to be `&'a str`, afaik.
     fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str {
-        //~^ ERROR: elided lifetime has a name
+        //~^ ERROR: lifetime flowing from input to output with different syntax
         todo!()
     }
 }
diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr
index 741e60cbd74..600343754e1 100644
--- a/src/tools/clippy/tests/ui/ptr_arg.stderr
+++ b/src/tools/clippy/tests/ui/ptr_arg.stderr
@@ -1,12 +1,3 @@
-error: elided lifetime has a name
-  --> tests/ui/ptr_arg.rs:314:56
-   |
-LL |     fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str {
-   |                        -- lifetime `'a` declared here  ^ this elided lifetime gets resolved as `'a`
-   |
-   = note: `-D elided-named-lifetimes` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(elided_named_lifetimes)]`
-
 error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
   --> tests/ui/ptr_arg.rs:13:14
    |
@@ -240,5 +231,21 @@ error: writing `&String` instead of `&str` involves a new object where a slice w
 LL |     fn good(v1: &String, v2: &String) {
    |                              ^^^^^^^ help: change this to: `&str`
 
+error: lifetime flowing from input to output with different syntax can be confusing
+  --> tests/ui/ptr_arg.rs:314:36
+   |
+LL |     fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str {
+   |                                    ^^     ^^           ---- the lifetime gets resolved as `'a`
+   |                                    |      |
+   |                                    |      these lifetimes flow to the output
+   |                                    these lifetimes flow to the output
+   |
+   = note: `-D mismatched-lifetime-syntaxes` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(mismatched_lifetime_syntaxes)]`
+help: one option is to consistently use `'a`
+   |
+LL |     fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &'a str {
+   |                                                         ++
+
 error: aborting due to 27 previous errors
 
diff --git a/src/tools/clippy/tests/ui/question_mark.fixed b/src/tools/clippy/tests/ui/question_mark.fixed
index 507bc2b29d8..60dc1c101b6 100644
--- a/src/tools/clippy/tests/ui/question_mark.fixed
+++ b/src/tools/clippy/tests/ui/question_mark.fixed
@@ -443,3 +443,13 @@ fn issue_14615(a: MutexGuard<Option<u32>>) -> Option<String> {
     //~^^^ question_mark
     Some(format!("{a}"))
 }
+
+fn const_in_pattern(x: Option<(i32, i32)>) -> Option<()> {
+    const N: i32 = 0;
+
+    let Some((x, N)) = x else {
+        return None;
+    };
+
+    None
+}
diff --git a/src/tools/clippy/tests/ui/question_mark.rs b/src/tools/clippy/tests/ui/question_mark.rs
index 64b51b849ed..99d0122a98f 100644
--- a/src/tools/clippy/tests/ui/question_mark.rs
+++ b/src/tools/clippy/tests/ui/question_mark.rs
@@ -539,3 +539,13 @@ fn issue_14615(a: MutexGuard<Option<u32>>) -> Option<String> {
     //~^^^ question_mark
     Some(format!("{a}"))
 }
+
+fn const_in_pattern(x: Option<(i32, i32)>) -> Option<()> {
+    const N: i32 = 0;
+
+    let Some((x, N)) = x else {
+        return None;
+    };
+
+    None
+}
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index 55e287b9159..ff81c642602 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -7,85 +7,107 @@
 #![allow(clippy::disallowed_names)]
 #![allow(clippy::blocks_in_conditions)]
 #![allow(clippy::box_collection)]
+#![allow(invalid_reference_casting)]
+#![allow(suspicious_double_ref_op)]
+#![allow(invalid_nan_comparisons)]
 #![allow(clippy::redundant_static_lifetimes)]
 #![allow(clippy::cognitive_complexity)]
 #![allow(clippy::derived_hash_with_manual_eq)]
 #![allow(clippy::disallowed_methods)]
 #![allow(clippy::disallowed_types)]
+#![allow(double_negations)]
+#![allow(drop_bounds)]
+#![allow(dropping_copy_types)]
+#![allow(dropping_references)]
 #![allow(clippy::mixed_read_write_in_expression)]
-#![allow(clippy::manual_find_map)]
 #![allow(clippy::manual_filter_map)]
+#![allow(clippy::manual_find_map)]
 #![allow(unpredictable_function_pointer_comparisons)]
+#![allow(useless_ptr_null_checks)]
+#![allow(for_loops_over_fallibles)]
+#![allow(forgetting_copy_types)]
+#![allow(forgetting_references)]
 #![allow(clippy::useless_conversion)]
 #![allow(clippy::redundant_pattern_matching)]
 #![allow(clippy::match_result_ok)]
 #![allow(clippy::non_canonical_clone_impl)]
 #![allow(clippy::non_canonical_partial_ord_impl)]
 #![allow(clippy::arithmetic_side_effects)]
+#![allow(array_into_iter)]
+#![allow(invalid_atomic_ordering)]
+#![allow(invalid_null_arguments)]
+#![allow(invalid_value)]
+#![allow(invalid_from_utf8_unchecked)]
+#![allow(let_underscore_drop)]
 #![allow(clippy::overly_complex_bool_expr)]
+#![allow(unexpected_cfgs)]
+#![allow(enum_intrinsics_non_enums)]
 #![allow(clippy::new_without_default)]
 #![allow(clippy::bind_instead_of_map)]
 #![allow(clippy::expect_used)]
 #![allow(clippy::map_unwrap_or)]
 #![allow(clippy::unwrap_used)]
 #![allow(clippy::panicking_overflow_checks)]
+#![allow(non_fmt_panics)]
+#![allow(named_arguments_used_positionally)]
 #![allow(clippy::needless_borrow)]
+#![allow(clippy::reversed_empty_ranges)]
 #![allow(clippy::single_char_add_str)]
 #![allow(clippy::module_name_repetitions)]
+#![allow(dangling_pointers_from_temporaries)]
 #![allow(clippy::missing_const_for_thread_local)]
 #![allow(clippy::recursive_format_impl)]
-#![allow(clippy::unwrap_or_default)]
-#![allow(clippy::invisible_characters)]
-#![allow(invalid_reference_casting)]
-#![allow(suspicious_double_ref_op)]
-#![allow(invalid_nan_comparisons)]
-#![allow(invalid_null_arguments)]
-#![allow(double_negations)]
-#![allow(drop_bounds)]
-#![allow(dropping_copy_types)]
-#![allow(dropping_references)]
-#![allow(useless_ptr_null_checks)]
-#![allow(for_loops_over_fallibles)]
-#![allow(forgetting_copy_types)]
-#![allow(forgetting_references)]
-#![allow(array_into_iter)]
-#![allow(invalid_atomic_ordering)]
-#![allow(invalid_value)]
-#![allow(invalid_from_utf8_unchecked)]
-#![allow(let_underscore_drop)]
-#![allow(unexpected_cfgs)]
-#![allow(enum_intrinsics_non_enums)]
-#![allow(non_fmt_panics)]
-#![allow(named_arguments_used_positionally)]
-#![allow(dangling_pointers_from_temporaries)]
+#![allow(unnecessary_transmutes)]
 #![allow(undropped_manually_drops)]
 #![allow(unknown_lints)]
 #![allow(unused_labels)]
+#![allow(clippy::unwrap_or_default)]
 #![allow(ambiguous_wide_pointer_comparisons)]
-#![allow(clippy::reversed_empty_ranges)]
-#![allow(unnecessary_transmutes)]
+#![allow(clippy::invisible_characters)]
 #![warn(clippy::almost_complete_range)] //~ ERROR: lint `clippy::almost_complete_letter_range`
 #![warn(clippy::disallowed_names)] //~ ERROR: lint `clippy::blacklisted_name`
 #![warn(clippy::blocks_in_conditions)] //~ ERROR: lint `clippy::block_in_if_condition_expr`
 #![warn(clippy::blocks_in_conditions)] //~ ERROR: lint `clippy::block_in_if_condition_stmt`
 #![warn(clippy::blocks_in_conditions)] //~ ERROR: lint `clippy::blocks_in_if_conditions`
 #![warn(clippy::box_collection)] //~ ERROR: lint `clippy::box_vec`
+#![warn(invalid_reference_casting)] //~ ERROR: lint `clippy::cast_ref_to_mut`
+#![warn(suspicious_double_ref_op)] //~ ERROR: lint `clippy::clone_double_ref`
+#![warn(invalid_nan_comparisons)] //~ ERROR: lint `clippy::cmp_nan`
 #![warn(clippy::redundant_static_lifetimes)] //~ ERROR: lint `clippy::const_static_lifetime`
 #![warn(clippy::cognitive_complexity)] //~ ERROR: lint `clippy::cyclomatic_complexity`
 #![warn(clippy::derived_hash_with_manual_eq)] //~ ERROR: lint `clippy::derive_hash_xor_eq`
 #![warn(clippy::disallowed_methods)] //~ ERROR: lint `clippy::disallowed_method`
 #![warn(clippy::disallowed_types)] //~ ERROR: lint `clippy::disallowed_type`
+#![warn(double_negations)] //~ ERROR: lint `clippy::double_neg`
+#![warn(drop_bounds)] //~ ERROR: lint `clippy::drop_bounds`
+#![warn(dropping_copy_types)] //~ ERROR: lint `clippy::drop_copy`
+#![warn(dropping_references)] //~ ERROR: lint `clippy::drop_ref`
 #![warn(clippy::mixed_read_write_in_expression)] //~ ERROR: lint `clippy::eval_order_dependence`
-#![warn(clippy::manual_find_map)] //~ ERROR: lint `clippy::find_map`
 #![warn(clippy::manual_filter_map)] //~ ERROR: lint `clippy::filter_map`
+#![warn(clippy::manual_find_map)] //~ ERROR: lint `clippy::find_map`
 #![warn(unpredictable_function_pointer_comparisons)] //~ ERROR: lint `clippy::fn_address_comparisons`
+#![warn(useless_ptr_null_checks)] //~ ERROR: lint `clippy::fn_null_check`
+#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loop_over_option`
+#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loop_over_result`
+#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loops_over_fallibles`
+#![warn(forgetting_copy_types)] //~ ERROR: lint `clippy::forget_copy`
+#![warn(forgetting_references)] //~ ERROR: lint `clippy::forget_ref`
 #![warn(clippy::useless_conversion)] //~ ERROR: lint `clippy::identity_conversion`
 #![warn(clippy::redundant_pattern_matching)] //~ ERROR: lint `clippy::if_let_redundant_pattern_matching`
 #![warn(clippy::match_result_ok)] //~ ERROR: lint `clippy::if_let_some_result`
 #![warn(clippy::non_canonical_clone_impl)] //~ ERROR: lint `clippy::incorrect_clone_impl_on_copy_type`
 #![warn(clippy::non_canonical_partial_ord_impl)] //~ ERROR: lint `clippy::incorrect_partial_ord_impl_on_ord_type`
 #![warn(clippy::arithmetic_side_effects)] //~ ERROR: lint `clippy::integer_arithmetic`
+#![warn(array_into_iter)] //~ ERROR: lint `clippy::into_iter_on_array`
+#![warn(invalid_atomic_ordering)] //~ ERROR: lint `clippy::invalid_atomic_ordering`
+#![warn(invalid_null_arguments)] //~ ERROR: lint `clippy::invalid_null_ptr_usage`
+#![warn(invalid_value)] //~ ERROR: lint `clippy::invalid_ref`
+#![warn(invalid_from_utf8_unchecked)] //~ ERROR: lint `clippy::invalid_utf8_in_unchecked`
+#![warn(let_underscore_drop)] //~ ERROR: lint `clippy::let_underscore_drop`
 #![warn(clippy::overly_complex_bool_expr)] //~ ERROR: lint `clippy::logic_bug`
+#![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::maybe_misused_cfg`
+#![warn(enum_intrinsics_non_enums)] //~ ERROR: lint `clippy::mem_discriminant_non_enum`
+#![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::mismatched_target_os`
 #![warn(clippy::new_without_default)] //~ ERROR: lint `clippy::new_without_default_derive`
 #![warn(clippy::bind_instead_of_map)] //~ ERROR: lint `clippy::option_and_then_some`
 #![warn(clippy::expect_used)] //~ ERROR: lint `clippy::option_expect_used`
@@ -93,49 +115,27 @@
 #![warn(clippy::map_unwrap_or)] //~ ERROR: lint `clippy::option_map_unwrap_or_else`
 #![warn(clippy::unwrap_used)] //~ ERROR: lint `clippy::option_unwrap_used`
 #![warn(clippy::panicking_overflow_checks)] //~ ERROR: lint `clippy::overflow_check_conditional`
+#![warn(non_fmt_panics)] //~ ERROR: lint `clippy::panic_params`
+#![warn(named_arguments_used_positionally)] //~ ERROR: lint `clippy::positional_named_format_parameters`
 #![warn(clippy::needless_borrow)] //~ ERROR: lint `clippy::ref_in_deref`
 #![warn(clippy::expect_used)] //~ ERROR: lint `clippy::result_expect_used`
 #![warn(clippy::map_unwrap_or)] //~ ERROR: lint `clippy::result_map_unwrap_or_else`
 #![warn(clippy::unwrap_used)] //~ ERROR: lint `clippy::result_unwrap_used`
+#![warn(clippy::reversed_empty_ranges)] //~ ERROR: lint `clippy::reverse_range_loop`
 #![warn(clippy::single_char_add_str)] //~ ERROR: lint `clippy::single_char_push_str`
 #![warn(clippy::module_name_repetitions)] //~ ERROR: lint `clippy::stutter`
+#![warn(dangling_pointers_from_temporaries)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr`
 #![warn(clippy::missing_const_for_thread_local)] //~ ERROR: lint `clippy::thread_local_initializer_can_be_made_const`
 #![warn(clippy::recursive_format_impl)] //~ ERROR: lint `clippy::to_string_in_display`
-#![warn(clippy::unwrap_or_default)] //~ ERROR: lint `clippy::unwrap_or_else_default`
-#![warn(clippy::invisible_characters)] //~ ERROR: lint `clippy::zero_width_space`
-#![warn(invalid_reference_casting)] //~ ERROR: lint `clippy::cast_ref_to_mut`
-#![warn(suspicious_double_ref_op)] //~ ERROR: lint `clippy::clone_double_ref`
-#![warn(invalid_nan_comparisons)] //~ ERROR: lint `clippy::cmp_nan`
-#![warn(invalid_null_arguments)] //~ ERROR: lint `clippy::invalid_null_ptr_usage`
-#![warn(double_negations)] //~ ERROR: lint `clippy::double_neg`
-#![warn(drop_bounds)] //~ ERROR: lint `clippy::drop_bounds`
-#![warn(dropping_copy_types)] //~ ERROR: lint `clippy::drop_copy`
-#![warn(dropping_references)] //~ ERROR: lint `clippy::drop_ref`
-#![warn(useless_ptr_null_checks)] //~ ERROR: lint `clippy::fn_null_check`
-#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loop_over_option`
-#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loop_over_result`
-#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loops_over_fallibles`
-#![warn(forgetting_copy_types)] //~ ERROR: lint `clippy::forget_copy`
-#![warn(forgetting_references)] //~ ERROR: lint `clippy::forget_ref`
-#![warn(array_into_iter)] //~ ERROR: lint `clippy::into_iter_on_array`
-#![warn(invalid_atomic_ordering)] //~ ERROR: lint `clippy::invalid_atomic_ordering`
-#![warn(invalid_value)] //~ ERROR: lint `clippy::invalid_ref`
-#![warn(invalid_from_utf8_unchecked)] //~ ERROR: lint `clippy::invalid_utf8_in_unchecked`
-#![warn(let_underscore_drop)] //~ ERROR: lint `clippy::let_underscore_drop`
-#![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::maybe_misused_cfg`
-#![warn(enum_intrinsics_non_enums)] //~ ERROR: lint `clippy::mem_discriminant_non_enum`
-#![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::mismatched_target_os`
-#![warn(non_fmt_panics)] //~ ERROR: lint `clippy::panic_params`
-#![warn(named_arguments_used_positionally)] //~ ERROR: lint `clippy::positional_named_format_parameters`
-#![warn(dangling_pointers_from_temporaries)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr`
+#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_float_to_int`
+#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_int_to_char`
+#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_int_to_float`
+#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_num_to_bytes`
 #![warn(undropped_manually_drops)] //~ ERROR: lint `clippy::undropped_manually_drops`
 #![warn(unknown_lints)] //~ ERROR: lint `clippy::unknown_clippy_lints`
 #![warn(unused_labels)] //~ ERROR: lint `clippy::unused_label`
+#![warn(clippy::unwrap_or_default)] //~ ERROR: lint `clippy::unwrap_or_else_default`
 #![warn(ambiguous_wide_pointer_comparisons)] //~ ERROR: lint `clippy::vtable_address_comparisons`
-#![warn(clippy::reversed_empty_ranges)] //~ ERROR: lint `clippy::reverse_range_loop`
-#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_int_to_float`
-#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_int_to_char`
-#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_float_to_int`
-#![warn(unnecessary_transmutes)] //~ ERROR: lint `clippy::transmute_num_to_bytes`
+#![warn(clippy::invisible_characters)] //~ ERROR: lint `clippy::zero_width_space`
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index 31dcd2cea08..b5d5d07e639 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -7,85 +7,107 @@
 #![allow(clippy::disallowed_names)]
 #![allow(clippy::blocks_in_conditions)]
 #![allow(clippy::box_collection)]
+#![allow(invalid_reference_casting)]
+#![allow(suspicious_double_ref_op)]
+#![allow(invalid_nan_comparisons)]
 #![allow(clippy::redundant_static_lifetimes)]
 #![allow(clippy::cognitive_complexity)]
 #![allow(clippy::derived_hash_with_manual_eq)]
 #![allow(clippy::disallowed_methods)]
 #![allow(clippy::disallowed_types)]
+#![allow(double_negations)]
+#![allow(drop_bounds)]
+#![allow(dropping_copy_types)]
+#![allow(dropping_references)]
 #![allow(clippy::mixed_read_write_in_expression)]
-#![allow(clippy::manual_find_map)]
 #![allow(clippy::manual_filter_map)]
+#![allow(clippy::manual_find_map)]
 #![allow(unpredictable_function_pointer_comparisons)]
+#![allow(useless_ptr_null_checks)]
+#![allow(for_loops_over_fallibles)]
+#![allow(forgetting_copy_types)]
+#![allow(forgetting_references)]
 #![allow(clippy::useless_conversion)]
 #![allow(clippy::redundant_pattern_matching)]
 #![allow(clippy::match_result_ok)]
 #![allow(clippy::non_canonical_clone_impl)]
 #![allow(clippy::non_canonical_partial_ord_impl)]
 #![allow(clippy::arithmetic_side_effects)]
+#![allow(array_into_iter)]
+#![allow(invalid_atomic_ordering)]
+#![allow(invalid_null_arguments)]
+#![allow(invalid_value)]
+#![allow(invalid_from_utf8_unchecked)]
+#![allow(let_underscore_drop)]
 #![allow(clippy::overly_complex_bool_expr)]
+#![allow(unexpected_cfgs)]
+#![allow(enum_intrinsics_non_enums)]
 #![allow(clippy::new_without_default)]
 #![allow(clippy::bind_instead_of_map)]
 #![allow(clippy::expect_used)]
 #![allow(clippy::map_unwrap_or)]
 #![allow(clippy::unwrap_used)]
 #![allow(clippy::panicking_overflow_checks)]
+#![allow(non_fmt_panics)]
+#![allow(named_arguments_used_positionally)]
 #![allow(clippy::needless_borrow)]
+#![allow(clippy::reversed_empty_ranges)]
 #![allow(clippy::single_char_add_str)]
 #![allow(clippy::module_name_repetitions)]
+#![allow(dangling_pointers_from_temporaries)]
 #![allow(clippy::missing_const_for_thread_local)]
 #![allow(clippy::recursive_format_impl)]
-#![allow(clippy::unwrap_or_default)]
-#![allow(clippy::invisible_characters)]
-#![allow(invalid_reference_casting)]
-#![allow(suspicious_double_ref_op)]
-#![allow(invalid_nan_comparisons)]
-#![allow(invalid_null_arguments)]
-#![allow(double_negations)]
-#![allow(drop_bounds)]
-#![allow(dropping_copy_types)]
-#![allow(dropping_references)]
-#![allow(useless_ptr_null_checks)]
-#![allow(for_loops_over_fallibles)]
-#![allow(forgetting_copy_types)]
-#![allow(forgetting_references)]
-#![allow(array_into_iter)]
-#![allow(invalid_atomic_ordering)]
-#![allow(invalid_value)]
-#![allow(invalid_from_utf8_unchecked)]
-#![allow(let_underscore_drop)]
-#![allow(unexpected_cfgs)]
-#![allow(enum_intrinsics_non_enums)]
-#![allow(non_fmt_panics)]
-#![allow(named_arguments_used_positionally)]
-#![allow(dangling_pointers_from_temporaries)]
+#![allow(unnecessary_transmutes)]
 #![allow(undropped_manually_drops)]
 #![allow(unknown_lints)]
 #![allow(unused_labels)]
+#![allow(clippy::unwrap_or_default)]
 #![allow(ambiguous_wide_pointer_comparisons)]
-#![allow(clippy::reversed_empty_ranges)]
-#![allow(unnecessary_transmutes)]
+#![allow(clippy::invisible_characters)]
 #![warn(clippy::almost_complete_letter_range)] //~ ERROR: lint `clippy::almost_complete_letter_range`
 #![warn(clippy::blacklisted_name)] //~ ERROR: lint `clippy::blacklisted_name`
 #![warn(clippy::block_in_if_condition_expr)] //~ ERROR: lint `clippy::block_in_if_condition_expr`
 #![warn(clippy::block_in_if_condition_stmt)] //~ ERROR: lint `clippy::block_in_if_condition_stmt`
 #![warn(clippy::blocks_in_if_conditions)] //~ ERROR: lint `clippy::blocks_in_if_conditions`
 #![warn(clippy::box_vec)] //~ ERROR: lint `clippy::box_vec`
+#![warn(clippy::cast_ref_to_mut)] //~ ERROR: lint `clippy::cast_ref_to_mut`
+#![warn(clippy::clone_double_ref)] //~ ERROR: lint `clippy::clone_double_ref`
+#![warn(clippy::cmp_nan)] //~ ERROR: lint `clippy::cmp_nan`
 #![warn(clippy::const_static_lifetime)] //~ ERROR: lint `clippy::const_static_lifetime`
 #![warn(clippy::cyclomatic_complexity)] //~ ERROR: lint `clippy::cyclomatic_complexity`
 #![warn(clippy::derive_hash_xor_eq)] //~ ERROR: lint `clippy::derive_hash_xor_eq`
 #![warn(clippy::disallowed_method)] //~ ERROR: lint `clippy::disallowed_method`
 #![warn(clippy::disallowed_type)] //~ ERROR: lint `clippy::disallowed_type`
+#![warn(clippy::double_neg)] //~ ERROR: lint `clippy::double_neg`
+#![warn(clippy::drop_bounds)] //~ ERROR: lint `clippy::drop_bounds`
+#![warn(clippy::drop_copy)] //~ ERROR: lint `clippy::drop_copy`
+#![warn(clippy::drop_ref)] //~ ERROR: lint `clippy::drop_ref`
 #![warn(clippy::eval_order_dependence)] //~ ERROR: lint `clippy::eval_order_dependence`
-#![warn(clippy::find_map)] //~ ERROR: lint `clippy::find_map`
 #![warn(clippy::filter_map)] //~ ERROR: lint `clippy::filter_map`
+#![warn(clippy::find_map)] //~ ERROR: lint `clippy::find_map`
 #![warn(clippy::fn_address_comparisons)] //~ ERROR: lint `clippy::fn_address_comparisons`
+#![warn(clippy::fn_null_check)] //~ ERROR: lint `clippy::fn_null_check`
+#![warn(clippy::for_loop_over_option)] //~ ERROR: lint `clippy::for_loop_over_option`
+#![warn(clippy::for_loop_over_result)] //~ ERROR: lint `clippy::for_loop_over_result`
+#![warn(clippy::for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loops_over_fallibles`
+#![warn(clippy::forget_copy)] //~ ERROR: lint `clippy::forget_copy`
+#![warn(clippy::forget_ref)] //~ ERROR: lint `clippy::forget_ref`
 #![warn(clippy::identity_conversion)] //~ ERROR: lint `clippy::identity_conversion`
 #![warn(clippy::if_let_redundant_pattern_matching)] //~ ERROR: lint `clippy::if_let_redundant_pattern_matching`
 #![warn(clippy::if_let_some_result)] //~ ERROR: lint `clippy::if_let_some_result`
 #![warn(clippy::incorrect_clone_impl_on_copy_type)] //~ ERROR: lint `clippy::incorrect_clone_impl_on_copy_type`
 #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)] //~ ERROR: lint `clippy::incorrect_partial_ord_impl_on_ord_type`
 #![warn(clippy::integer_arithmetic)] //~ ERROR: lint `clippy::integer_arithmetic`
+#![warn(clippy::into_iter_on_array)] //~ ERROR: lint `clippy::into_iter_on_array`
+#![warn(clippy::invalid_atomic_ordering)] //~ ERROR: lint `clippy::invalid_atomic_ordering`
+#![warn(clippy::invalid_null_ptr_usage)] //~ ERROR: lint `clippy::invalid_null_ptr_usage`
+#![warn(clippy::invalid_ref)] //~ ERROR: lint `clippy::invalid_ref`
+#![warn(clippy::invalid_utf8_in_unchecked)] //~ ERROR: lint `clippy::invalid_utf8_in_unchecked`
+#![warn(clippy::let_underscore_drop)] //~ ERROR: lint `clippy::let_underscore_drop`
 #![warn(clippy::logic_bug)] //~ ERROR: lint `clippy::logic_bug`
+#![warn(clippy::maybe_misused_cfg)] //~ ERROR: lint `clippy::maybe_misused_cfg`
+#![warn(clippy::mem_discriminant_non_enum)] //~ ERROR: lint `clippy::mem_discriminant_non_enum`
+#![warn(clippy::mismatched_target_os)] //~ ERROR: lint `clippy::mismatched_target_os`
 #![warn(clippy::new_without_default_derive)] //~ ERROR: lint `clippy::new_without_default_derive`
 #![warn(clippy::option_and_then_some)] //~ ERROR: lint `clippy::option_and_then_some`
 #![warn(clippy::option_expect_used)] //~ ERROR: lint `clippy::option_expect_used`
@@ -93,49 +115,27 @@
 #![warn(clippy::option_map_unwrap_or_else)] //~ ERROR: lint `clippy::option_map_unwrap_or_else`
 #![warn(clippy::option_unwrap_used)] //~ ERROR: lint `clippy::option_unwrap_used`
 #![warn(clippy::overflow_check_conditional)] //~ ERROR: lint `clippy::overflow_check_conditional`
+#![warn(clippy::panic_params)] //~ ERROR: lint `clippy::panic_params`
+#![warn(clippy::positional_named_format_parameters)] //~ ERROR: lint `clippy::positional_named_format_parameters`
 #![warn(clippy::ref_in_deref)] //~ ERROR: lint `clippy::ref_in_deref`
 #![warn(clippy::result_expect_used)] //~ ERROR: lint `clippy::result_expect_used`
 #![warn(clippy::result_map_unwrap_or_else)] //~ ERROR: lint `clippy::result_map_unwrap_or_else`
 #![warn(clippy::result_unwrap_used)] //~ ERROR: lint `clippy::result_unwrap_used`
+#![warn(clippy::reverse_range_loop)] //~ ERROR: lint `clippy::reverse_range_loop`
 #![warn(clippy::single_char_push_str)] //~ ERROR: lint `clippy::single_char_push_str`
 #![warn(clippy::stutter)] //~ ERROR: lint `clippy::stutter`
+#![warn(clippy::temporary_cstring_as_ptr)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr`
 #![warn(clippy::thread_local_initializer_can_be_made_const)] //~ ERROR: lint `clippy::thread_local_initializer_can_be_made_const`
 #![warn(clippy::to_string_in_display)] //~ ERROR: lint `clippy::to_string_in_display`
-#![warn(clippy::unwrap_or_else_default)] //~ ERROR: lint `clippy::unwrap_or_else_default`
-#![warn(clippy::zero_width_space)] //~ ERROR: lint `clippy::zero_width_space`
-#![warn(clippy::cast_ref_to_mut)] //~ ERROR: lint `clippy::cast_ref_to_mut`
-#![warn(clippy::clone_double_ref)] //~ ERROR: lint `clippy::clone_double_ref`
-#![warn(clippy::cmp_nan)] //~ ERROR: lint `clippy::cmp_nan`
-#![warn(clippy::invalid_null_ptr_usage)] //~ ERROR: lint `clippy::invalid_null_ptr_usage`
-#![warn(clippy::double_neg)] //~ ERROR: lint `clippy::double_neg`
-#![warn(clippy::drop_bounds)] //~ ERROR: lint `clippy::drop_bounds`
-#![warn(clippy::drop_copy)] //~ ERROR: lint `clippy::drop_copy`
-#![warn(clippy::drop_ref)] //~ ERROR: lint `clippy::drop_ref`
-#![warn(clippy::fn_null_check)] //~ ERROR: lint `clippy::fn_null_check`
-#![warn(clippy::for_loop_over_option)] //~ ERROR: lint `clippy::for_loop_over_option`
-#![warn(clippy::for_loop_over_result)] //~ ERROR: lint `clippy::for_loop_over_result`
-#![warn(clippy::for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loops_over_fallibles`
-#![warn(clippy::forget_copy)] //~ ERROR: lint `clippy::forget_copy`
-#![warn(clippy::forget_ref)] //~ ERROR: lint `clippy::forget_ref`
-#![warn(clippy::into_iter_on_array)] //~ ERROR: lint `clippy::into_iter_on_array`
-#![warn(clippy::invalid_atomic_ordering)] //~ ERROR: lint `clippy::invalid_atomic_ordering`
-#![warn(clippy::invalid_ref)] //~ ERROR: lint `clippy::invalid_ref`
-#![warn(clippy::invalid_utf8_in_unchecked)] //~ ERROR: lint `clippy::invalid_utf8_in_unchecked`
-#![warn(clippy::let_underscore_drop)] //~ ERROR: lint `clippy::let_underscore_drop`
-#![warn(clippy::maybe_misused_cfg)] //~ ERROR: lint `clippy::maybe_misused_cfg`
-#![warn(clippy::mem_discriminant_non_enum)] //~ ERROR: lint `clippy::mem_discriminant_non_enum`
-#![warn(clippy::mismatched_target_os)] //~ ERROR: lint `clippy::mismatched_target_os`
-#![warn(clippy::panic_params)] //~ ERROR: lint `clippy::panic_params`
-#![warn(clippy::positional_named_format_parameters)] //~ ERROR: lint `clippy::positional_named_format_parameters`
-#![warn(clippy::temporary_cstring_as_ptr)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr`
+#![warn(clippy::transmute_float_to_int)] //~ ERROR: lint `clippy::transmute_float_to_int`
+#![warn(clippy::transmute_int_to_char)] //~ ERROR: lint `clippy::transmute_int_to_char`
+#![warn(clippy::transmute_int_to_float)] //~ ERROR: lint `clippy::transmute_int_to_float`
+#![warn(clippy::transmute_num_to_bytes)] //~ ERROR: lint `clippy::transmute_num_to_bytes`
 #![warn(clippy::undropped_manually_drops)] //~ ERROR: lint `clippy::undropped_manually_drops`
 #![warn(clippy::unknown_clippy_lints)] //~ ERROR: lint `clippy::unknown_clippy_lints`
 #![warn(clippy::unused_label)] //~ ERROR: lint `clippy::unused_label`
+#![warn(clippy::unwrap_or_else_default)] //~ ERROR: lint `clippy::unwrap_or_else_default`
 #![warn(clippy::vtable_address_comparisons)] //~ ERROR: lint `clippy::vtable_address_comparisons`
-#![warn(clippy::reverse_range_loop)] //~ ERROR: lint `clippy::reverse_range_loop`
-#![warn(clippy::transmute_int_to_float)] //~ ERROR: lint `clippy::transmute_int_to_float`
-#![warn(clippy::transmute_int_to_char)] //~ ERROR: lint `clippy::transmute_int_to_char`
-#![warn(clippy::transmute_float_to_int)] //~ ERROR: lint `clippy::transmute_float_to_int`
-#![warn(clippy::transmute_num_to_bytes)] //~ ERROR: lint `clippy::transmute_num_to_bytes`
+#![warn(clippy::zero_width_space)] //~ ERROR: lint `clippy::zero_width_space`
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index a8d5c96acc3..2487dfc8eba 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -37,407 +37,407 @@ error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
 LL | #![warn(clippy::box_vec)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
 
-error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
+error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting`
   --> tests/ui/rename.rs:73:9
    |
+LL | #![warn(clippy::cast_ref_to_mut)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting`
+
+error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op`
+  --> tests/ui/rename.rs:74:9
+   |
+LL | #![warn(clippy::clone_double_ref)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op`
+
+error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons`
+  --> tests/ui/rename.rs:75:9
+   |
+LL | #![warn(clippy::cmp_nan)]
+   |         ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons`
+
+error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
+  --> tests/ui/rename.rs:76:9
+   |
 LL | #![warn(clippy::const_static_lifetime)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
 
 error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
-  --> tests/ui/rename.rs:74:9
+  --> tests/ui/rename.rs:77:9
    |
 LL | #![warn(clippy::cyclomatic_complexity)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
 
 error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq`
-  --> tests/ui/rename.rs:75:9
+  --> tests/ui/rename.rs:78:9
    |
 LL | #![warn(clippy::derive_hash_xor_eq)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq`
 
 error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
-  --> tests/ui/rename.rs:76:9
+  --> tests/ui/rename.rs:79:9
    |
 LL | #![warn(clippy::disallowed_method)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
 
 error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
-  --> tests/ui/rename.rs:77:9
+  --> tests/ui/rename.rs:80:9
    |
 LL | #![warn(clippy::disallowed_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
 
-error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
-  --> tests/ui/rename.rs:78:9
-   |
-LL | #![warn(clippy::eval_order_dependence)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
-
-error: lint `clippy::find_map` has been renamed to `clippy::manual_find_map`
-  --> tests/ui/rename.rs:79:9
-   |
-LL | #![warn(clippy::find_map)]
-   |         ^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_find_map`
-
-error: lint `clippy::filter_map` has been renamed to `clippy::manual_filter_map`
-  --> tests/ui/rename.rs:80:9
-   |
-LL | #![warn(clippy::filter_map)]
-   |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_filter_map`
-
-error: lint `clippy::fn_address_comparisons` has been renamed to `unpredictable_function_pointer_comparisons`
+error: lint `clippy::double_neg` has been renamed to `double_negations`
   --> tests/ui/rename.rs:81:9
    |
-LL | #![warn(clippy::fn_address_comparisons)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unpredictable_function_pointer_comparisons`
+LL | #![warn(clippy::double_neg)]
+   |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `double_negations`
 
-error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
+error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
   --> tests/ui/rename.rs:82:9
    |
-LL | #![warn(clippy::identity_conversion)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
+LL | #![warn(clippy::drop_bounds)]
+   |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
-error: lint `clippy::if_let_redundant_pattern_matching` has been renamed to `clippy::redundant_pattern_matching`
+error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types`
   --> tests/ui/rename.rs:83:9
    |
-LL | #![warn(clippy::if_let_redundant_pattern_matching)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_pattern_matching`
+LL | #![warn(clippy::drop_copy)]
+   |         ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types`
 
-error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
+error: lint `clippy::drop_ref` has been renamed to `dropping_references`
   --> tests/ui/rename.rs:84:9
    |
-LL | #![warn(clippy::if_let_some_result)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
+LL | #![warn(clippy::drop_ref)]
+   |         ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references`
 
-error: lint `clippy::incorrect_clone_impl_on_copy_type` has been renamed to `clippy::non_canonical_clone_impl`
+error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
   --> tests/ui/rename.rs:85:9
    |
-LL | #![warn(clippy::incorrect_clone_impl_on_copy_type)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_clone_impl`
+LL | #![warn(clippy::eval_order_dependence)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
 
-error: lint `clippy::incorrect_partial_ord_impl_on_ord_type` has been renamed to `clippy::non_canonical_partial_ord_impl`
+error: lint `clippy::filter_map` has been renamed to `clippy::manual_filter_map`
   --> tests/ui/rename.rs:86:9
    |
-LL | #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_partial_ord_impl`
+LL | #![warn(clippy::filter_map)]
+   |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_filter_map`
 
-error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects`
+error: lint `clippy::find_map` has been renamed to `clippy::manual_find_map`
   --> tests/ui/rename.rs:87:9
    |
-LL | #![warn(clippy::integer_arithmetic)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects`
+LL | #![warn(clippy::find_map)]
+   |         ^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_find_map`
 
-error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
+error: lint `clippy::fn_address_comparisons` has been renamed to `unpredictable_function_pointer_comparisons`
   --> tests/ui/rename.rs:88:9
    |
-LL | #![warn(clippy::logic_bug)]
-   |         ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
+LL | #![warn(clippy::fn_address_comparisons)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unpredictable_function_pointer_comparisons`
 
-error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
+error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks`
   --> tests/ui/rename.rs:89:9
    |
-LL | #![warn(clippy::new_without_default_derive)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
+LL | #![warn(clippy::fn_null_check)]
+   |         ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks`
 
-error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
+error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
   --> tests/ui/rename.rs:90:9
    |
-LL | #![warn(clippy::option_and_then_some)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
+LL | #![warn(clippy::for_loop_over_option)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
-error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
+error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
   --> tests/ui/rename.rs:91:9
    |
-LL | #![warn(clippy::option_expect_used)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
+LL | #![warn(clippy::for_loop_over_result)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
-error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
+error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
   --> tests/ui/rename.rs:92:9
    |
-LL | #![warn(clippy::option_map_unwrap_or)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
+LL | #![warn(clippy::for_loops_over_fallibles)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
-error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
+error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types`
   --> tests/ui/rename.rs:93:9
    |
-LL | #![warn(clippy::option_map_unwrap_or_else)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
+LL | #![warn(clippy::forget_copy)]
+   |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types`
 
-error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
+error: lint `clippy::forget_ref` has been renamed to `forgetting_references`
   --> tests/ui/rename.rs:94:9
    |
-LL | #![warn(clippy::option_unwrap_used)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
+LL | #![warn(clippy::forget_ref)]
+   |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references`
 
-error: lint `clippy::overflow_check_conditional` has been renamed to `clippy::panicking_overflow_checks`
+error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
   --> tests/ui/rename.rs:95:9
    |
-LL | #![warn(clippy::overflow_check_conditional)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::panicking_overflow_checks`
+LL | #![warn(clippy::identity_conversion)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
 
-error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
+error: lint `clippy::if_let_redundant_pattern_matching` has been renamed to `clippy::redundant_pattern_matching`
   --> tests/ui/rename.rs:96:9
    |
-LL | #![warn(clippy::ref_in_deref)]
-   |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
+LL | #![warn(clippy::if_let_redundant_pattern_matching)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_pattern_matching`
 
-error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
+error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
   --> tests/ui/rename.rs:97:9
    |
-LL | #![warn(clippy::result_expect_used)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
+LL | #![warn(clippy::if_let_some_result)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
 
-error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
+error: lint `clippy::incorrect_clone_impl_on_copy_type` has been renamed to `clippy::non_canonical_clone_impl`
   --> tests/ui/rename.rs:98:9
    |
-LL | #![warn(clippy::result_map_unwrap_or_else)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
+LL | #![warn(clippy::incorrect_clone_impl_on_copy_type)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_clone_impl`
 
-error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
+error: lint `clippy::incorrect_partial_ord_impl_on_ord_type` has been renamed to `clippy::non_canonical_partial_ord_impl`
   --> tests/ui/rename.rs:99:9
    |
-LL | #![warn(clippy::result_unwrap_used)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
+LL | #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_partial_ord_impl`
 
-error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
+error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects`
   --> tests/ui/rename.rs:100:9
    |
-LL | #![warn(clippy::single_char_push_str)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
+LL | #![warn(clippy::integer_arithmetic)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects`
 
-error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
+error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
   --> tests/ui/rename.rs:101:9
    |
-LL | #![warn(clippy::stutter)]
-   |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
+LL | #![warn(clippy::into_iter_on_array)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
 
-error: lint `clippy::thread_local_initializer_can_be_made_const` has been renamed to `clippy::missing_const_for_thread_local`
+error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
   --> tests/ui/rename.rs:102:9
    |
-LL | #![warn(clippy::thread_local_initializer_can_be_made_const)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::missing_const_for_thread_local`
+LL | #![warn(clippy::invalid_atomic_ordering)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
 
-error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
+error: lint `clippy::invalid_null_ptr_usage` has been renamed to `invalid_null_arguments`
   --> tests/ui/rename.rs:103:9
    |
-LL | #![warn(clippy::to_string_in_display)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
+LL | #![warn(clippy::invalid_null_ptr_usage)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_null_arguments`
 
-error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default`
+error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
   --> tests/ui/rename.rs:104:9
    |
-LL | #![warn(clippy::unwrap_or_else_default)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default`
+LL | #![warn(clippy::invalid_ref)]
+   |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
-error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
+error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked`
   --> tests/ui/rename.rs:105:9
    |
-LL | #![warn(clippy::zero_width_space)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
+LL | #![warn(clippy::invalid_utf8_in_unchecked)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked`
 
-error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting`
+error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
   --> tests/ui/rename.rs:106:9
    |
-LL | #![warn(clippy::cast_ref_to_mut)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting`
+LL | #![warn(clippy::let_underscore_drop)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
 
-error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op`
+error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
   --> tests/ui/rename.rs:107:9
    |
-LL | #![warn(clippy::clone_double_ref)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op`
+LL | #![warn(clippy::logic_bug)]
+   |         ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
 
-error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons`
+error: lint `clippy::maybe_misused_cfg` has been renamed to `unexpected_cfgs`
   --> tests/ui/rename.rs:108:9
    |
-LL | #![warn(clippy::cmp_nan)]
-   |         ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons`
+LL | #![warn(clippy::maybe_misused_cfg)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs`
 
-error: lint `clippy::invalid_null_ptr_usage` has been renamed to `invalid_null_arguments`
+error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
   --> tests/ui/rename.rs:109:9
    |
-LL | #![warn(clippy::invalid_null_ptr_usage)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_null_arguments`
+LL | #![warn(clippy::mem_discriminant_non_enum)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
-error: lint `clippy::double_neg` has been renamed to `double_negations`
+error: lint `clippy::mismatched_target_os` has been renamed to `unexpected_cfgs`
   --> tests/ui/rename.rs:110:9
    |
-LL | #![warn(clippy::double_neg)]
-   |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `double_negations`
+LL | #![warn(clippy::mismatched_target_os)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs`
 
-error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
+error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
   --> tests/ui/rename.rs:111:9
    |
-LL | #![warn(clippy::drop_bounds)]
-   |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
+LL | #![warn(clippy::new_without_default_derive)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
 
-error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types`
+error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
   --> tests/ui/rename.rs:112:9
    |
-LL | #![warn(clippy::drop_copy)]
-   |         ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types`
+LL | #![warn(clippy::option_and_then_some)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
 
-error: lint `clippy::drop_ref` has been renamed to `dropping_references`
+error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
   --> tests/ui/rename.rs:113:9
    |
-LL | #![warn(clippy::drop_ref)]
-   |         ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references`
+LL | #![warn(clippy::option_expect_used)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
-error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks`
+error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
   --> tests/ui/rename.rs:114:9
    |
-LL | #![warn(clippy::fn_null_check)]
-   |         ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks`
+LL | #![warn(clippy::option_map_unwrap_or)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
-error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
+error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
   --> tests/ui/rename.rs:115:9
    |
-LL | #![warn(clippy::for_loop_over_option)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
+LL | #![warn(clippy::option_map_unwrap_or_else)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
-error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
+error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
   --> tests/ui/rename.rs:116:9
    |
-LL | #![warn(clippy::for_loop_over_result)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
+LL | #![warn(clippy::option_unwrap_used)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
-error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
+error: lint `clippy::overflow_check_conditional` has been renamed to `clippy::panicking_overflow_checks`
   --> tests/ui/rename.rs:117:9
    |
-LL | #![warn(clippy::for_loops_over_fallibles)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
+LL | #![warn(clippy::overflow_check_conditional)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::panicking_overflow_checks`
 
-error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types`
+error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
   --> tests/ui/rename.rs:118:9
    |
-LL | #![warn(clippy::forget_copy)]
-   |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types`
+LL | #![warn(clippy::panic_params)]
+   |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
-error: lint `clippy::forget_ref` has been renamed to `forgetting_references`
+error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
   --> tests/ui/rename.rs:119:9
    |
-LL | #![warn(clippy::forget_ref)]
-   |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references`
+LL | #![warn(clippy::positional_named_format_parameters)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
 
-error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
+error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
   --> tests/ui/rename.rs:120:9
    |
-LL | #![warn(clippy::into_iter_on_array)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
+LL | #![warn(clippy::ref_in_deref)]
+   |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
 
-error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
+error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
   --> tests/ui/rename.rs:121:9
    |
-LL | #![warn(clippy::invalid_atomic_ordering)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
+LL | #![warn(clippy::result_expect_used)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
-error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
+error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
   --> tests/ui/rename.rs:122:9
    |
-LL | #![warn(clippy::invalid_ref)]
-   |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
+LL | #![warn(clippy::result_map_unwrap_or_else)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
-error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked`
+error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
   --> tests/ui/rename.rs:123:9
    |
-LL | #![warn(clippy::invalid_utf8_in_unchecked)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked`
+LL | #![warn(clippy::result_unwrap_used)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
-error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
+error: lint `clippy::reverse_range_loop` has been renamed to `clippy::reversed_empty_ranges`
   --> tests/ui/rename.rs:124:9
    |
-LL | #![warn(clippy::let_underscore_drop)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
+LL | #![warn(clippy::reverse_range_loop)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges`
 
-error: lint `clippy::maybe_misused_cfg` has been renamed to `unexpected_cfgs`
+error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
   --> tests/ui/rename.rs:125:9
    |
-LL | #![warn(clippy::maybe_misused_cfg)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs`
+LL | #![warn(clippy::single_char_push_str)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
 
-error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
+error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
   --> tests/ui/rename.rs:126:9
    |
-LL | #![warn(clippy::mem_discriminant_non_enum)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
+LL | #![warn(clippy::stutter)]
+   |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
 
-error: lint `clippy::mismatched_target_os` has been renamed to `unexpected_cfgs`
+error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
   --> tests/ui/rename.rs:127:9
    |
-LL | #![warn(clippy::mismatched_target_os)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs`
+LL | #![warn(clippy::temporary_cstring_as_ptr)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
 
-error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
+error: lint `clippy::thread_local_initializer_can_be_made_const` has been renamed to `clippy::missing_const_for_thread_local`
   --> tests/ui/rename.rs:128:9
    |
-LL | #![warn(clippy::panic_params)]
-   |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
+LL | #![warn(clippy::thread_local_initializer_can_be_made_const)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::missing_const_for_thread_local`
 
-error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
+error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
   --> tests/ui/rename.rs:129:9
    |
-LL | #![warn(clippy::positional_named_format_parameters)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
+LL | #![warn(clippy::to_string_in_display)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
 
-error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
+error: lint `clippy::transmute_float_to_int` has been renamed to `unnecessary_transmutes`
   --> tests/ui/rename.rs:130:9
    |
-LL | #![warn(clippy::temporary_cstring_as_ptr)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
+LL | #![warn(clippy::transmute_float_to_int)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes`
 
-error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops`
+error: lint `clippy::transmute_int_to_char` has been renamed to `unnecessary_transmutes`
   --> tests/ui/rename.rs:131:9
    |
-LL | #![warn(clippy::undropped_manually_drops)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops`
+LL | #![warn(clippy::transmute_int_to_char)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes`
 
-error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
+error: lint `clippy::transmute_int_to_float` has been renamed to `unnecessary_transmutes`
   --> tests/ui/rename.rs:132:9
    |
-LL | #![warn(clippy::unknown_clippy_lints)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
+LL | #![warn(clippy::transmute_int_to_float)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes`
 
-error: lint `clippy::unused_label` has been renamed to `unused_labels`
+error: lint `clippy::transmute_num_to_bytes` has been renamed to `unnecessary_transmutes`
   --> tests/ui/rename.rs:133:9
    |
-LL | #![warn(clippy::unused_label)]
-   |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
+LL | #![warn(clippy::transmute_num_to_bytes)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes`
 
-error: lint `clippy::vtable_address_comparisons` has been renamed to `ambiguous_wide_pointer_comparisons`
+error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops`
   --> tests/ui/rename.rs:134:9
    |
-LL | #![warn(clippy::vtable_address_comparisons)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons`
+LL | #![warn(clippy::undropped_manually_drops)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops`
 
-error: lint `clippy::reverse_range_loop` has been renamed to `clippy::reversed_empty_ranges`
+error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
   --> tests/ui/rename.rs:135:9
    |
-LL | #![warn(clippy::reverse_range_loop)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges`
+LL | #![warn(clippy::unknown_clippy_lints)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
 
-error: lint `clippy::transmute_int_to_float` has been renamed to `unnecessary_transmutes`
+error: lint `clippy::unused_label` has been renamed to `unused_labels`
   --> tests/ui/rename.rs:136:9
    |
-LL | #![warn(clippy::transmute_int_to_float)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes`
+LL | #![warn(clippy::unused_label)]
+   |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
 
-error: lint `clippy::transmute_int_to_char` has been renamed to `unnecessary_transmutes`
+error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default`
   --> tests/ui/rename.rs:137:9
    |
-LL | #![warn(clippy::transmute_int_to_char)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes`
+LL | #![warn(clippy::unwrap_or_else_default)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default`
 
-error: lint `clippy::transmute_float_to_int` has been renamed to `unnecessary_transmutes`
+error: lint `clippy::vtable_address_comparisons` has been renamed to `ambiguous_wide_pointer_comparisons`
   --> tests/ui/rename.rs:138:9
    |
-LL | #![warn(clippy::transmute_float_to_int)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes`
+LL | #![warn(clippy::vtable_address_comparisons)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons`
 
-error: lint `clippy::transmute_num_to_bytes` has been renamed to `unnecessary_transmutes`
+error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
   --> tests/ui/rename.rs:139:9
    |
-LL | #![warn(clippy::transmute_num_to_bytes)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unnecessary_transmutes`
+LL | #![warn(clippy::zero_width_space)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
 
 error: aborting due to 73 previous errors
 
diff --git a/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs b/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs
index a98b73c9e1c..3f205b322ab 100644
--- a/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs
+++ b/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs
@@ -31,34 +31,34 @@ fn ifs_same_cond_fn() {
     let obj = Struct;
 
     if function() {
-    } else if function() {
         //~^ same_functions_in_if_condition
+    } else if function() {
     }
 
     if fn_arg(a) {
-    } else if fn_arg(a) {
         //~^ same_functions_in_if_condition
+    } else if fn_arg(a) {
     }
 
     if obj.method() {
-    } else if obj.method() {
         //~^ same_functions_in_if_condition
+    } else if obj.method() {
     }
 
     if obj.method_arg(a) {
-    } else if obj.method_arg(a) {
         //~^ same_functions_in_if_condition
+    } else if obj.method_arg(a) {
     }
 
     let mut v = vec![1];
     if v.pop().is_none() {
-    } else if v.pop().is_none() {
         //~^ same_functions_in_if_condition
+    } else if v.pop().is_none() {
     }
 
     if v.len() == 42 {
-    } else if v.len() == 42 {
         //~^ same_functions_in_if_condition
+    } else if v.len() == 42 {
     }
 
     if v.len() == 1 {
diff --git a/src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr b/src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr
index 35dcbadce59..59f4511757d 100644
--- a/src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr
+++ b/src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr
@@ -1,79 +1,62 @@
-error: this `if` has the same function call as a previous `if`
-  --> tests/ui/same_functions_in_if_condition.rs:34:15
-   |
-LL |     } else if function() {
-   |               ^^^^^^^^^^
-   |
-note: same as this
+error: these `if` branches have the same function call
   --> tests/ui/same_functions_in_if_condition.rs:33:8
    |
 LL |     if function() {
    |        ^^^^^^^^^^
+LL |
+LL |     } else if function() {
+   |               ^^^^^^^^^^
+   |
 note: the lint level is defined here
   --> tests/ui/same_functions_in_if_condition.rs:2:9
    |
 LL | #![deny(clippy::same_functions_in_if_condition)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: this `if` has the same function call as a previous `if`
-  --> tests/ui/same_functions_in_if_condition.rs:39:15
-   |
-LL |     } else if fn_arg(a) {
-   |               ^^^^^^^^^
-   |
-note: same as this
+error: these `if` branches have the same function call
   --> tests/ui/same_functions_in_if_condition.rs:38:8
    |
 LL |     if fn_arg(a) {
    |        ^^^^^^^^^
+LL |
+LL |     } else if fn_arg(a) {
+   |               ^^^^^^^^^
 
-error: this `if` has the same function call as a previous `if`
-  --> tests/ui/same_functions_in_if_condition.rs:44:15
-   |
-LL |     } else if obj.method() {
-   |               ^^^^^^^^^^^^
-   |
-note: same as this
+error: these `if` branches have the same function call
   --> tests/ui/same_functions_in_if_condition.rs:43:8
    |
 LL |     if obj.method() {
    |        ^^^^^^^^^^^^
+LL |
+LL |     } else if obj.method() {
+   |               ^^^^^^^^^^^^
 
-error: this `if` has the same function call as a previous `if`
-  --> tests/ui/same_functions_in_if_condition.rs:49:15
-   |
-LL |     } else if obj.method_arg(a) {
-   |               ^^^^^^^^^^^^^^^^^
-   |
-note: same as this
+error: these `if` branches have the same function call
   --> tests/ui/same_functions_in_if_condition.rs:48:8
    |
 LL |     if obj.method_arg(a) {
    |        ^^^^^^^^^^^^^^^^^
-
-error: this `if` has the same function call as a previous `if`
-  --> tests/ui/same_functions_in_if_condition.rs:55:15
-   |
-LL |     } else if v.pop().is_none() {
+LL |
+LL |     } else if obj.method_arg(a) {
    |               ^^^^^^^^^^^^^^^^^
-   |
-note: same as this
+
+error: these `if` branches have the same function call
   --> tests/ui/same_functions_in_if_condition.rs:54:8
    |
 LL |     if v.pop().is_none() {
    |        ^^^^^^^^^^^^^^^^^
+LL |
+LL |     } else if v.pop().is_none() {
+   |               ^^^^^^^^^^^^^^^^^
 
-error: this `if` has the same function call as a previous `if`
-  --> tests/ui/same_functions_in_if_condition.rs:60:15
-   |
-LL |     } else if v.len() == 42 {
-   |               ^^^^^^^^^^^^^
-   |
-note: same as this
+error: these `if` branches have the same function call
   --> tests/ui/same_functions_in_if_condition.rs:59:8
    |
 LL |     if v.len() == 42 {
    |        ^^^^^^^^^^^^^
+LL |
+LL |     } else if v.len() == 42 {
+   |               ^^^^^^^^^^^^^
 
 error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs
index 4f65a06680d..78fc365bd5b 100644
--- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs
+++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs
@@ -191,7 +191,7 @@ struct CounterWrapper<'a> {
 }
 
 impl<'a> CounterWrapper<'a> {
-    fn new(counter: &Counter) -> CounterWrapper {
+    fn new(counter: &Counter) -> CounterWrapper<'_> {
         counter.i.fetch_add(1, Ordering::Relaxed);
         CounterWrapper { counter }
     }
@@ -204,7 +204,7 @@ impl<'a> Drop for CounterWrapper<'a> {
 }
 
 impl Counter {
-    fn temp_increment(&self) -> Vec<CounterWrapper> {
+    fn temp_increment(&self) -> Vec<CounterWrapper<'_>> {
         vec![CounterWrapper::new(self), CounterWrapper::new(self)]
     }
 }
@@ -480,7 +480,7 @@ impl StateWithBoxedMutexGuard {
     fn new() -> StateWithBoxedMutexGuard {
         StateWithBoxedMutexGuard { u: Mutex::new(42) }
     }
-    fn lock(&self) -> Box<MutexGuard<u64>> {
+    fn lock(&self) -> Box<MutexGuard<'_, u64>> {
         Box::new(self.u.lock().unwrap())
     }
 }
@@ -507,7 +507,7 @@ impl StateStringWithBoxedMutexGuard {
             s: Mutex::new("A String".to_owned()),
         }
     }
-    fn lock(&self) -> Box<MutexGuard<String>> {
+    fn lock(&self) -> Box<MutexGuard<'_, String>> {
         Box::new(self.s.lock().unwrap())
     }
 }
@@ -686,11 +686,11 @@ struct Guard<'a, T>(MutexGuard<'a, T>);
 struct Ref<'a, T>(&'a T);
 
 impl<'a, T> Guard<'a, T> {
-    fn guard(&self) -> &MutexGuard<T> {
+    fn guard(&self) -> &MutexGuard<'_, T> {
         &self.0
     }
 
-    fn guard_ref(&self) -> Ref<MutexGuard<T>> {
+    fn guard_ref(&self) -> Ref<'_, MutexGuard<'_, T>> {
         Ref(&self.0)
     }
 
diff --git a/src/tools/clippy/tests/ui/single_range_in_vec_init.rs b/src/tools/clippy/tests/ui/single_range_in_vec_init.rs
index c6c0cb347dc..25884450b08 100644
--- a/src/tools/clippy/tests/ui/single_range_in_vec_init.rs
+++ b/src/tools/clippy/tests/ui/single_range_in_vec_init.rs
@@ -1,6 +1,6 @@
 //@aux-build:proc_macros.rs
 //@no-rustfix: overlapping suggestions
-#![allow(clippy::no_effect, clippy::useless_vec, unused)]
+#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::useless_vec, unused)]
 #![warn(clippy::single_range_in_vec_init)]
 #![feature(generic_arg_infer)]
 
diff --git a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.fixed b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.fixed
new file mode 100644
index 00000000000..1a07f119398
--- /dev/null
+++ b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.fixed
@@ -0,0 +1,180 @@
+//@normalize-stderr-test: "\(\d+ byte\)" -> "(N byte)"
+//@normalize-stderr-test: "\(limit: \d+ byte\)" -> "(limit: N byte)"
+#![deny(clippy::trivially_copy_pass_by_ref)]
+#![allow(
+    clippy::disallowed_names,
+    clippy::extra_unused_lifetimes,
+    clippy::needless_lifetimes,
+    clippy::needless_pass_by_ref_mut,
+    clippy::redundant_field_names,
+    clippy::uninlined_format_args
+)]
+
+#[derive(Copy, Clone)]
+struct Foo(u32);
+
+#[derive(Copy, Clone)]
+struct Bar([u8; 24]);
+
+#[derive(Copy, Clone)]
+pub struct Color {
+    pub r: u8,
+    pub g: u8,
+    pub b: u8,
+    pub a: u8,
+}
+
+struct FooRef<'a> {
+    foo: &'a Foo,
+}
+
+type Baz = u32;
+
+fn good(a: &mut u32, b: u32, c: &Bar) {}
+
+fn good_return_implicit_lt_ref(foo: &Foo) -> &u32 {
+    &foo.0
+}
+
+#[allow(clippy::needless_lifetimes)]
+fn good_return_explicit_lt_ref<'a>(foo: &'a Foo) -> &'a u32 {
+    &foo.0
+}
+
+#[allow(mismatched_lifetime_syntaxes)]
+fn good_return_implicit_lt_struct(foo: &Foo) -> FooRef {
+    FooRef { foo }
+}
+
+#[allow(clippy::needless_lifetimes)]
+fn good_return_explicit_lt_struct<'a>(foo: &'a Foo) -> FooRef<'a> {
+    FooRef { foo }
+}
+
+fn bad(x: u32, y: Foo, z: Baz) {}
+//~^ ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by
+//~| ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by
+//~| ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by
+
+impl Foo {
+    fn good(self, a: &mut u32, b: u32, c: &Bar) {}
+
+    fn good2(&mut self) {}
+
+    fn bad(self, x: u32, y: Foo, z: Baz) {}
+    //~^ ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by
+    //~| ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by
+    //~| ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by
+    //~| ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by
+
+    fn bad2(x: u32, y: Foo, z: Baz) {}
+    //~^ ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by
+    //~| ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by
+    //~| ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by
+
+    fn bad_issue7518(self, other: Self) {}
+    //~^ ERROR: this argument (4 byte) is passed by reference, but would be more efficient if
+}
+
+impl AsRef<u32> for Foo {
+    fn as_ref(&self) -> &u32 {
+        &self.0
+    }
+}
+
+impl Bar {
+    fn good(&self, a: &mut u32, b: u32, c: &Bar) {}
+
+    fn bad2(x: u32, y: Foo, z: Baz) {}
+    //~^ ERROR: this argument (4 byte) is passed by reference, but would be more efficient if
+    //~| ERROR: this argument (4 byte) is passed by reference, but would be more efficient if
+    //~| ERROR: this argument (4 byte) is passed by reference, but would be more efficient if
+}
+
+trait MyTrait {
+    fn trait_method(&self, foo: Foo);
+    //~^ ERROR: this argument (4 byte) is passed by reference, but would be more efficient if
+}
+
+pub trait MyTrait2 {
+    fn trait_method2(&self, color: &Color);
+}
+
+trait MyTrait3 {
+    #[expect(clippy::trivially_copy_pass_by_ref)]
+    fn trait_method(&self, foo: &Foo);
+}
+
+// Trait impls should not warn
+impl MyTrait3 for Foo {
+    fn trait_method(&self, foo: &Foo) {
+        unimplemented!()
+    }
+}
+
+mod issue3992 {
+    pub trait A {
+        #[allow(clippy::trivially_copy_pass_by_ref)]
+        fn a(b: &u16) {}
+    }
+
+    #[allow(clippy::trivially_copy_pass_by_ref)]
+    pub fn c(d: &u16) {}
+}
+
+mod issue5876 {
+    // Don't lint here as it is always inlined
+    #[inline(always)]
+    fn foo_always(x: &i32) {
+        println!("{}", x);
+    }
+
+    #[inline(never)]
+    fn foo_never(x: i32) {
+        //~^ ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by
+        println!("{}", x);
+    }
+
+    #[inline]
+    fn foo(x: i32) {
+        //~^ ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by
+        println!("{}", x);
+    }
+}
+
+fn ref_to_opt_ref_implicit(x: &u32) -> Option<&u32> {
+    Some(x)
+}
+
+fn ref_to_opt_ref_explicit<'a>(x: &'a u32) -> Option<&'a u32> {
+    Some(x)
+}
+
+fn with_constraint<'a, 'b: 'a>(x: &'b u32, y: &'a u32) -> &'a u32 {
+    if true { x } else { y }
+}
+
+async fn async_implicit(x: &u32) -> &u32 {
+    x
+}
+
+async fn async_explicit<'a>(x: &'a u32) -> &'a u32 {
+    x
+}
+
+fn unrelated_lifetimes<'a, 'b>(_x: u32, y: &'b u32) -> &'b u32 {
+    //~^ ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by
+    y
+}
+
+fn return_ptr(x: &u32) -> *const u32 {
+    x
+}
+
+fn return_field_ptr(x: &(u32, u32)) -> *const u32 {
+    &x.0
+}
+
+fn return_field_ptr_addr_of(x: &(u32, u32)) -> *const u32 {
+    core::ptr::addr_of!(x.0)
+}
diff --git a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs
index 37bc6f89a20..07b1842bbf8 100644
--- a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs
+++ b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs
@@ -1,14 +1,15 @@
 //@normalize-stderr-test: "\(\d+ byte\)" -> "(N byte)"
-//@normalize-stderr-test: "\(limit: \d+ byte\)" -> "(limit: 8 byte)"
+//@normalize-stderr-test: "\(limit: \d+ byte\)" -> "(limit: N byte)"
 #![deny(clippy::trivially_copy_pass_by_ref)]
 #![allow(
     clippy::disallowed_names,
+    clippy::extra_unused_lifetimes,
     clippy::needless_lifetimes,
+    clippy::needless_pass_by_ref_mut,
     clippy::redundant_field_names,
-    clippy::uninlined_format_args,
-    clippy::needless_pass_by_ref_mut
+    clippy::uninlined_format_args
 )]
-//@no-rustfix
+
 #[derive(Copy, Clone)]
 struct Foo(u32);
 
@@ -40,6 +41,7 @@ fn good_return_explicit_lt_ref<'a>(foo: &'a Foo) -> &'a u32 {
     &foo.0
 }
 
+#[allow(mismatched_lifetime_syntaxes)]
 fn good_return_implicit_lt_struct(foo: &Foo) -> FooRef {
     FooRef { foo }
 }
@@ -90,21 +92,26 @@ impl Bar {
 }
 
 trait MyTrait {
-    fn trait_method(&self, _foo: &Foo);
+    fn trait_method(&self, foo: &Foo);
     //~^ ERROR: this argument (4 byte) is passed by reference, but would be more efficient if
 }
 
 pub trait MyTrait2 {
-    fn trait_method2(&self, _color: &Color);
+    fn trait_method2(&self, color: &Color);
+}
+
+trait MyTrait3 {
+    #[expect(clippy::trivially_copy_pass_by_ref)]
+    fn trait_method(&self, foo: &Foo);
 }
 
-impl MyTrait for Foo {
-    fn trait_method(&self, _foo: &Foo) {
+// Trait impls should not warn
+impl MyTrait3 for Foo {
+    fn trait_method(&self, foo: &Foo) {
         unimplemented!()
     }
 }
 
-#[allow(unused_variables)]
 mod issue3992 {
     pub trait A {
         #[allow(clippy::trivially_copy_pass_by_ref)]
@@ -135,57 +142,39 @@ mod issue5876 {
     }
 }
 
-fn _ref_to_opt_ref_implicit(x: &u32) -> Option<&u32> {
+fn ref_to_opt_ref_implicit(x: &u32) -> Option<&u32> {
     Some(x)
 }
 
-#[allow(clippy::needless_lifetimes)]
-fn _ref_to_opt_ref_explicit<'a>(x: &'a u32) -> Option<&'a u32> {
+fn ref_to_opt_ref_explicit<'a>(x: &'a u32) -> Option<&'a u32> {
     Some(x)
 }
 
-fn _with_constraint<'a, 'b: 'a>(x: &'b u32, y: &'a u32) -> &'a u32 {
+fn with_constraint<'a, 'b: 'a>(x: &'b u32, y: &'a u32) -> &'a u32 {
     if true { x } else { y }
 }
 
-async fn _async_implicit(x: &u32) -> &u32 {
+async fn async_implicit(x: &u32) -> &u32 {
     x
 }
 
-#[allow(clippy::needless_lifetimes)]
-async fn _async_explicit<'a>(x: &'a u32) -> &'a u32 {
+async fn async_explicit<'a>(x: &'a u32) -> &'a u32 {
     x
 }
 
-fn _unrelated_lifetimes<'a, 'b>(_x: &'a u32, y: &'b u32) -> &'b u32 {
+fn unrelated_lifetimes<'a, 'b>(_x: &'a u32, y: &'b u32) -> &'b u32 {
     //~^ ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by
     y
 }
 
-fn _return_ptr(x: &u32) -> *const u32 {
+fn return_ptr(x: &u32) -> *const u32 {
     x
 }
 
-fn _return_field_ptr(x: &(u32, u32)) -> *const u32 {
+fn return_field_ptr(x: &(u32, u32)) -> *const u32 {
     &x.0
 }
 
-fn _return_field_ptr_addr_of(x: &(u32, u32)) -> *const u32 {
+fn return_field_ptr_addr_of(x: &(u32, u32)) -> *const u32 {
     core::ptr::addr_of!(x.0)
 }
-
-fn main() {
-    let (mut foo, bar) = (Foo(0), Bar([0; 24]));
-    let (mut a, b, c, x, y, z) = (0, 0, Bar([0; 24]), 0, Foo(0), 0);
-    good(&mut a, b, &c);
-    good_return_implicit_lt_ref(&y);
-    good_return_explicit_lt_ref(&y);
-    bad(&x, &y, &z);
-    foo.good(&mut a, b, &c);
-    foo.good2();
-    foo.bad(&x, &y, &z);
-    Foo::bad2(&x, &y, &z);
-    bar.good(&mut a, b, &c);
-    Bar::bad2(&x, &y, &z);
-    foo.as_ref();
-}
diff --git a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr
index e813fecf653..36247d3fe0b 100644
--- a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr
+++ b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr
@@ -1,5 +1,5 @@
-error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)
-  --> tests/ui/trivially_copy_pass_by_ref.rs:52:11
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> tests/ui/trivially_copy_pass_by_ref.rs:54:11
    |
 LL | fn bad(x: &u32, y: &Foo, z: &Baz) {}
    |           ^^^^ help: consider passing by value instead: `u32`
@@ -10,107 +10,107 @@ note: the lint level is defined here
 LL | #![deny(clippy::trivially_copy_pass_by_ref)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)
-  --> tests/ui/trivially_copy_pass_by_ref.rs:52:20
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> tests/ui/trivially_copy_pass_by_ref.rs:54:20
    |
 LL | fn bad(x: &u32, y: &Foo, z: &Baz) {}
    |                    ^^^^ help: consider passing by value instead: `Foo`
 
-error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)
-  --> tests/ui/trivially_copy_pass_by_ref.rs:52:29
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> tests/ui/trivially_copy_pass_by_ref.rs:54:29
    |
 LL | fn bad(x: &u32, y: &Foo, z: &Baz) {}
    |                             ^^^^ help: consider passing by value instead: `Baz`
 
-error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)
-  --> tests/ui/trivially_copy_pass_by_ref.rs:62:12
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> tests/ui/trivially_copy_pass_by_ref.rs:64:12
    |
 LL |     fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
    |            ^^^^^ help: consider passing by value instead: `self`
 
-error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)
-  --> tests/ui/trivially_copy_pass_by_ref.rs:62:22
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> tests/ui/trivially_copy_pass_by_ref.rs:64:22
    |
 LL |     fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
    |                      ^^^^ help: consider passing by value instead: `u32`
 
-error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)
-  --> tests/ui/trivially_copy_pass_by_ref.rs:62:31
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> tests/ui/trivially_copy_pass_by_ref.rs:64:31
    |
 LL |     fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
    |                               ^^^^ help: consider passing by value instead: `Foo`
 
-error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)
-  --> tests/ui/trivially_copy_pass_by_ref.rs:62:40
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> tests/ui/trivially_copy_pass_by_ref.rs:64:40
    |
 LL |     fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
    |                                        ^^^^ help: consider passing by value instead: `Baz`
 
-error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)
-  --> tests/ui/trivially_copy_pass_by_ref.rs:68:16
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> tests/ui/trivially_copy_pass_by_ref.rs:70:16
    |
 LL |     fn bad2(x: &u32, y: &Foo, z: &Baz) {}
    |                ^^^^ help: consider passing by value instead: `u32`
 
-error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)
-  --> tests/ui/trivially_copy_pass_by_ref.rs:68:25
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> tests/ui/trivially_copy_pass_by_ref.rs:70:25
    |
 LL |     fn bad2(x: &u32, y: &Foo, z: &Baz) {}
    |                         ^^^^ help: consider passing by value instead: `Foo`
 
-error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)
-  --> tests/ui/trivially_copy_pass_by_ref.rs:68:34
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> tests/ui/trivially_copy_pass_by_ref.rs:70:34
    |
 LL |     fn bad2(x: &u32, y: &Foo, z: &Baz) {}
    |                                  ^^^^ help: consider passing by value instead: `Baz`
 
-error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)
-  --> tests/ui/trivially_copy_pass_by_ref.rs:73:35
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> tests/ui/trivially_copy_pass_by_ref.rs:75:35
    |
 LL |     fn bad_issue7518(self, other: &Self) {}
    |                                   ^^^^^ help: consider passing by value instead: `Self`
 
-error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)
-  --> tests/ui/trivially_copy_pass_by_ref.rs:86:16
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> tests/ui/trivially_copy_pass_by_ref.rs:88:16
    |
 LL |     fn bad2(x: &u32, y: &Foo, z: &Baz) {}
    |                ^^^^ help: consider passing by value instead: `u32`
 
-error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)
-  --> tests/ui/trivially_copy_pass_by_ref.rs:86:25
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> tests/ui/trivially_copy_pass_by_ref.rs:88:25
    |
 LL |     fn bad2(x: &u32, y: &Foo, z: &Baz) {}
    |                         ^^^^ help: consider passing by value instead: `Foo`
 
-error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)
-  --> tests/ui/trivially_copy_pass_by_ref.rs:86:34
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> tests/ui/trivially_copy_pass_by_ref.rs:88:34
    |
 LL |     fn bad2(x: &u32, y: &Foo, z: &Baz) {}
    |                                  ^^^^ help: consider passing by value instead: `Baz`
 
-error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)
-  --> tests/ui/trivially_copy_pass_by_ref.rs:93:34
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> tests/ui/trivially_copy_pass_by_ref.rs:95:33
    |
-LL |     fn trait_method(&self, _foo: &Foo);
-   |                                  ^^^^ help: consider passing by value instead: `Foo`
+LL |     fn trait_method(&self, foo: &Foo);
+   |                                 ^^^^ help: consider passing by value instead: `Foo`
 
-error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)
-  --> tests/ui/trivially_copy_pass_by_ref.rs:126:21
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> tests/ui/trivially_copy_pass_by_ref.rs:133:21
    |
 LL |     fn foo_never(x: &i32) {
    |                     ^^^^ help: consider passing by value instead: `i32`
 
-error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)
-  --> tests/ui/trivially_copy_pass_by_ref.rs:132:15
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> tests/ui/trivially_copy_pass_by_ref.rs:139:15
    |
 LL |     fn foo(x: &i32) {
    |               ^^^^ help: consider passing by value instead: `i32`
 
-error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)
-  --> tests/ui/trivially_copy_pass_by_ref.rs:160:37
+error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
+  --> tests/ui/trivially_copy_pass_by_ref.rs:165:36
    |
-LL | fn _unrelated_lifetimes<'a, 'b>(_x: &'a u32, y: &'b u32) -> &'b u32 {
-   |                                     ^^^^^^^ help: consider passing by value instead: `u32`
+LL | fn unrelated_lifetimes<'a, 'b>(_x: &'a u32, y: &'b u32) -> &'b u32 {
+   |                                    ^^^^^^^ help: consider passing by value instead: `u32`
 
 error: aborting due to 18 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
index b064a8b8f46..316eac0b58b 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
@@ -675,3 +675,9 @@ mod issue_14242 {
         rc_slice_provider().to_vec().into_iter()
     }
 }
+
+fn issue14833() {
+    use std::collections::HashSet;
+    let mut s = HashSet::<&String>::new();
+    s.remove(&"hello".to_owned());
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
index 7954a4ad4ce..f2dbd1db3c9 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
@@ -675,3 +675,9 @@ mod issue_14242 {
         rc_slice_provider().to_vec().into_iter()
     }
 }
+
+fn issue14833() {
+    use std::collections::HashSet;
+    let mut s = HashSet::<&String>::new();
+    s.remove(&"hello".to_owned());
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_wraps.stderr b/src/tools/clippy/tests/ui/unnecessary_wraps.stderr
index ba562f5a50b..13d71271e21 100644
--- a/src/tools/clippy/tests/ui/unnecessary_wraps.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_wraps.stderr
@@ -1,13 +1,8 @@
 error: this function's return value is unnecessarily wrapped by `Option`
   --> tests/ui/unnecessary_wraps.rs:9:1
    |
-LL | / fn func1(a: bool, b: bool) -> Option<i32> {
-LL | |
-LL | |
-LL | |     if a && b {
-...  |
-LL | | }
-   | |_^
+LL | fn func1(a: bool, b: bool) -> Option<i32> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::unnecessary-wraps` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::unnecessary_wraps)]`
@@ -16,7 +11,7 @@ help: remove `Option` from the return type...
 LL - fn func1(a: bool, b: bool) -> Option<i32> {
 LL + fn func1(a: bool, b: bool) -> i32 {
    |
-help: ...and then change returning expressions
+help: ...and then remove the surrounding `Some()` from returning expressions
    |
 LL ~         return 42;
 LL |     }
@@ -30,21 +25,15 @@ LL ~         return 1337;
 error: this function's return value is unnecessarily wrapped by `Option`
   --> tests/ui/unnecessary_wraps.rs:24:1
    |
-LL | / fn func2(a: bool, b: bool) -> Option<i32> {
-LL | |
-LL | |
-LL | |     if a && b {
-...  |
-LL | |     if a { Some(20) } else { Some(30) }
-LL | | }
-   | |_^
+LL | fn func2(a: bool, b: bool) -> Option<i32> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove `Option` from the return type...
    |
 LL - fn func2(a: bool, b: bool) -> Option<i32> {
 LL + fn func2(a: bool, b: bool) -> i32 {
    |
-help: ...and then change returning expressions
+help: ...and then remove the surrounding `Some()` from returning expressions
    |
 LL ~         return 10;
 LL |     }
@@ -54,19 +43,15 @@ LL ~     if a { 20 } else { 30 }
 error: this function's return value is unnecessarily wrapped by `Option`
   --> tests/ui/unnecessary_wraps.rs:44:1
    |
-LL | / fn func5() -> Option<i32> {
-LL | |
-LL | |
-LL | |     Some(1)
-LL | | }
-   | |_^
+LL | fn func5() -> Option<i32> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove `Option` from the return type...
    |
 LL - fn func5() -> Option<i32> {
 LL + fn func5() -> i32 {
    |
-help: ...and then change returning expressions
+help: ...and then remove the surrounding `Some()` from returning expressions
    |
 LL -     Some(1)
 LL +     1
@@ -75,19 +60,15 @@ LL +     1
 error: this function's return value is unnecessarily wrapped by `Result`
   --> tests/ui/unnecessary_wraps.rs:56:1
    |
-LL | / fn func7() -> Result<i32, ()> {
-LL | |
-LL | |
-LL | |     Ok(1)
-LL | | }
-   | |_^
+LL | fn func7() -> Result<i32, ()> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove `Result` from the return type...
    |
 LL - fn func7() -> Result<i32, ()> {
 LL + fn func7() -> i32 {
    |
-help: ...and then change returning expressions
+help: ...and then remove the surrounding `Ok()` from returning expressions
    |
 LL -     Ok(1)
 LL +     1
@@ -96,19 +77,15 @@ LL +     1
 error: this function's return value is unnecessarily wrapped by `Option`
   --> tests/ui/unnecessary_wraps.rs:86:5
    |
-LL | /     fn func12() -> Option<i32> {
-LL | |
-LL | |
-LL | |         Some(1)
-LL | |     }
-   | |_____^
+LL |     fn func12() -> Option<i32> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove `Option` from the return type...
    |
 LL -     fn func12() -> Option<i32> {
 LL +     fn func12() -> i32 {
    |
-help: ...and then change returning expressions
+help: ...and then remove the surrounding `Some()` from returning expressions
    |
 LL -         Some(1)
 LL +         1
@@ -117,13 +94,8 @@ LL +         1
 error: this function's return value is unnecessary
   --> tests/ui/unnecessary_wraps.rs:115:1
    |
-LL | / fn issue_6640_1(a: bool, b: bool) -> Option<()> {
-LL | |
-LL | |
-LL | |     if a && b {
-...  |
-LL | | }
-   | |_^
+LL | fn issue_6640_1(a: bool, b: bool) -> Option<()> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the return type...
    |
@@ -144,13 +116,8 @@ LL ~         return ;
 error: this function's return value is unnecessary
   --> tests/ui/unnecessary_wraps.rs:130:1
    |
-LL | / fn issue_6640_2(a: bool, b: bool) -> Result<(), i32> {
-LL | |
-LL | |
-LL | |     if a && b {
-...  |
-LL | | }
-   | |_^
+LL | fn issue_6640_2(a: bool, b: bool) -> Result<(), i32> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the return type...
    |
diff --git a/src/tools/clippy/tests/ui/use_self.fixed b/src/tools/clippy/tests/ui/use_self.fixed
index f15e5e0a5bb..cccb6bffabb 100644
--- a/src/tools/clippy/tests/ui/use_self.fixed
+++ b/src/tools/clippy/tests/ui/use_self.fixed
@@ -69,7 +69,7 @@ mod lifetimes {
     impl<'a> Foo<'a> {
         // Cannot use `Self` as return type, because the function is actually `fn foo<'b>(s: &'b str) ->
         // Foo<'b>`
-        fn foo(s: &str) -> Foo {
+        fn foo(s: &str) -> Foo<'_> {
             Foo { foo_str: s }
         }
         // cannot replace with `Self`, because that's `Foo<'a>`
diff --git a/src/tools/clippy/tests/ui/use_self.rs b/src/tools/clippy/tests/ui/use_self.rs
index b6376938611..09288677aa7 100644
--- a/src/tools/clippy/tests/ui/use_self.rs
+++ b/src/tools/clippy/tests/ui/use_self.rs
@@ -69,7 +69,7 @@ mod lifetimes {
     impl<'a> Foo<'a> {
         // Cannot use `Self` as return type, because the function is actually `fn foo<'b>(s: &'b str) ->
         // Foo<'b>`
-        fn foo(s: &str) -> Foo {
+        fn foo(s: &str) -> Foo<'_> {
             Foo { foo_str: s }
         }
         // cannot replace with `Self`, because that's `Foo<'a>`
diff --git a/src/tools/clippy/tests/ui/useless_asref.fixed b/src/tools/clippy/tests/ui/useless_asref.fixed
index 8c1f948fb58..3c3ea5a736d 100644
--- a/src/tools/clippy/tests/ui/useless_asref.fixed
+++ b/src/tools/clippy/tests/ui/useless_asref.fixed
@@ -248,6 +248,16 @@ impl Issue12357 {
     }
 }
 
+fn issue_14828() {
+    pub trait T {
+        fn as_ref(&self) {}
+    }
+
+    impl T for () {}
+
+    ().as_ref();
+}
+
 fn main() {
     not_ok();
     ok();
diff --git a/src/tools/clippy/tests/ui/useless_asref.rs b/src/tools/clippy/tests/ui/useless_asref.rs
index d9db2d4f559..c173dd67715 100644
--- a/src/tools/clippy/tests/ui/useless_asref.rs
+++ b/src/tools/clippy/tests/ui/useless_asref.rs
@@ -248,6 +248,16 @@ impl Issue12357 {
     }
 }
 
+fn issue_14828() {
+    pub trait T {
+        fn as_ref(&self) {}
+    }
+
+    impl T for () {}
+
+    ().as_ref();
+}
+
 fn main() {
     not_ok();
     ok();
diff --git a/src/tools/clippy/tests/ui/useless_concat.fixed b/src/tools/clippy/tests/ui/useless_concat.fixed
new file mode 100644
index 00000000000..360b6f6ce82
--- /dev/null
+++ b/src/tools/clippy/tests/ui/useless_concat.fixed
@@ -0,0 +1,41 @@
+//@aux-build:proc_macros.rs
+
+#![warn(clippy::useless_concat)]
+#![allow(clippy::print_literal)]
+
+extern crate proc_macros;
+use proc_macros::{external, with_span};
+
+macro_rules! my_concat {
+    ($fmt:literal $(, $e:expr)*) => {
+        println!(concat!("ERROR: ", $fmt), $($e,)*);
+    }
+}
+
+fn main() {
+    let x = ""; //~ useless_concat
+    let x = "c"; //~ useless_concat
+    let x = "\""; //~ useless_concat
+    let x = "true"; //~ useless_concat
+    let x = "1"; //~ useless_concat
+    let x = "1.0000"; //~ useless_concat
+    let x = "1"; //~ useless_concat
+    let x = "1"; //~ useless_concat
+    let x = "1.0000"; //~ useless_concat
+    let x = "1.0000"; //~ useless_concat
+    let x = "a😀\n"; //~ useless_concat
+    let x = "a"; //~ useless_concat
+    let x = "1"; //~ useless_concat
+    println!("b: {}", "a"); //~ useless_concat
+    // Should not lint.
+    let x = concat!("a", "b");
+    let local_i32 = 1;
+    my_concat!("{}", local_i32);
+    let x = concat!(file!(), "#L", line!());
+
+    external! { concat!(); }
+    with_span! {
+        span
+        concat!();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/useless_concat.rs b/src/tools/clippy/tests/ui/useless_concat.rs
new file mode 100644
index 00000000000..338d20a48ae
--- /dev/null
+++ b/src/tools/clippy/tests/ui/useless_concat.rs
@@ -0,0 +1,41 @@
+//@aux-build:proc_macros.rs
+
+#![warn(clippy::useless_concat)]
+#![allow(clippy::print_literal)]
+
+extern crate proc_macros;
+use proc_macros::{external, with_span};
+
+macro_rules! my_concat {
+    ($fmt:literal $(, $e:expr)*) => {
+        println!(concat!("ERROR: ", $fmt), $($e,)*);
+    }
+}
+
+fn main() {
+    let x = concat!(); //~ useless_concat
+    let x = concat!('c'); //~ useless_concat
+    let x = concat!('"'); //~ useless_concat
+    let x = concat!(true); //~ useless_concat
+    let x = concat!(1f32); //~ useless_concat
+    let x = concat!(1.0000f32); //~ useless_concat
+    let x = concat!(1_f32); //~ useless_concat
+    let x = concat!(1_); //~ useless_concat
+    let x = concat!(1.0000_f32); //~ useless_concat
+    let x = concat!(1.0000_); //~ useless_concat
+    let x = concat!("a\u{1f600}\n"); //~ useless_concat
+    let x = concat!(r##"a"##); //~ useless_concat
+    let x = concat!(1); //~ useless_concat
+    println!("b: {}", concat!("a")); //~ useless_concat
+    // Should not lint.
+    let x = concat!("a", "b");
+    let local_i32 = 1;
+    my_concat!("{}", local_i32);
+    let x = concat!(file!(), "#L", line!());
+
+    external! { concat!(); }
+    with_span! {
+        span
+        concat!();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/useless_concat.stderr b/src/tools/clippy/tests/ui/useless_concat.stderr
new file mode 100644
index 00000000000..43d6d9ff579
--- /dev/null
+++ b/src/tools/clippy/tests/ui/useless_concat.stderr
@@ -0,0 +1,89 @@
+error: unneeded use of `concat!` macro
+  --> tests/ui/useless_concat.rs:16:13
+   |
+LL |     let x = concat!();
+   |             ^^^^^^^^^ help: replace with: `""`
+   |
+   = note: `-D clippy::useless-concat` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::useless_concat)]`
+
+error: unneeded use of `concat!` macro
+  --> tests/ui/useless_concat.rs:17:13
+   |
+LL |     let x = concat!('c');
+   |             ^^^^^^^^^^^^ help: replace with: `"c"`
+
+error: unneeded use of `concat!` macro
+  --> tests/ui/useless_concat.rs:18:13
+   |
+LL |     let x = concat!('"');
+   |             ^^^^^^^^^^^^ help: replace with: `"\""`
+
+error: unneeded use of `concat!` macro
+  --> tests/ui/useless_concat.rs:19:13
+   |
+LL |     let x = concat!(true);
+   |             ^^^^^^^^^^^^^ help: replace with: `"true"`
+
+error: unneeded use of `concat!` macro
+  --> tests/ui/useless_concat.rs:20:13
+   |
+LL |     let x = concat!(1f32);
+   |             ^^^^^^^^^^^^^ help: replace with: `"1"`
+
+error: unneeded use of `concat!` macro
+  --> tests/ui/useless_concat.rs:21:13
+   |
+LL |     let x = concat!(1.0000f32);
+   |             ^^^^^^^^^^^^^^^^^^ help: replace with: `"1.0000"`
+
+error: unneeded use of `concat!` macro
+  --> tests/ui/useless_concat.rs:22:13
+   |
+LL |     let x = concat!(1_f32);
+   |             ^^^^^^^^^^^^^^ help: replace with: `"1"`
+
+error: unneeded use of `concat!` macro
+  --> tests/ui/useless_concat.rs:23:13
+   |
+LL |     let x = concat!(1_);
+   |             ^^^^^^^^^^^ help: replace with: `"1"`
+
+error: unneeded use of `concat!` macro
+  --> tests/ui/useless_concat.rs:24:13
+   |
+LL |     let x = concat!(1.0000_f32);
+   |             ^^^^^^^^^^^^^^^^^^^ help: replace with: `"1.0000"`
+
+error: unneeded use of `concat!` macro
+  --> tests/ui/useless_concat.rs:25:13
+   |
+LL |     let x = concat!(1.0000_);
+   |             ^^^^^^^^^^^^^^^^ help: replace with: `"1.0000"`
+
+error: unneeded use of `concat!` macro
+  --> tests/ui/useless_concat.rs:26:13
+   |
+LL |     let x = concat!("a\u{1f600}\n");
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `"a😀\n"`
+
+error: unneeded use of `concat!` macro
+  --> tests/ui/useless_concat.rs:27:13
+   |
+LL |     let x = concat!(r##"a"##);
+   |             ^^^^^^^^^^^^^^^^^ help: replace with: `"a"`
+
+error: unneeded use of `concat!` macro
+  --> tests/ui/useless_concat.rs:28:13
+   |
+LL |     let x = concat!(1);
+   |             ^^^^^^^^^^ help: replace with: `"1"`
+
+error: unneeded use of `concat!` macro
+  --> tests/ui/useless_concat.rs:29:23
+   |
+LL |     println!("b: {}", concat!("a"));
+   |                       ^^^^^^^^^^^^ help: replace with: `"a"`
+
+error: aborting due to 14 previous errors
+
diff --git a/src/tools/clippy/tests/ui/useless_conversion.fixed b/src/tools/clippy/tests/ui/useless_conversion.fixed
index 489caacf212..ad30c94f347 100644
--- a/src/tools/clippy/tests/ui/useless_conversion.fixed
+++ b/src/tools/clippy/tests/ui/useless_conversion.fixed
@@ -427,3 +427,18 @@ mod issue11819 {
         }
     }
 }
+
+fn issue14739() {
+    use std::ops::Range;
+
+    const R: Range<u32> = 2..7;
+
+    R.into_iter().all(|_x| true); // no lint
+
+    R.into_iter().any(|_x| true); // no lint
+
+    R.for_each(|_x| {});
+    //~^ useless_conversion
+    let _ = R.map(|_x| 0);
+    //~^ useless_conversion
+}
diff --git a/src/tools/clippy/tests/ui/useless_conversion.rs b/src/tools/clippy/tests/ui/useless_conversion.rs
index 4f3a3b00ea2..505afb34000 100644
--- a/src/tools/clippy/tests/ui/useless_conversion.rs
+++ b/src/tools/clippy/tests/ui/useless_conversion.rs
@@ -427,3 +427,18 @@ mod issue11819 {
         }
     }
 }
+
+fn issue14739() {
+    use std::ops::Range;
+
+    const R: Range<u32> = 2..7;
+
+    R.into_iter().all(|_x| true); // no lint
+
+    R.into_iter().any(|_x| true); // no lint
+
+    R.into_iter().for_each(|_x| {});
+    //~^ useless_conversion
+    let _ = R.into_iter().map(|_x| 0);
+    //~^ useless_conversion
+}
diff --git a/src/tools/clippy/tests/ui/useless_conversion.stderr b/src/tools/clippy/tests/ui/useless_conversion.stderr
index 3cde2a786e4..3bfaf1411c2 100644
--- a/src/tools/clippy/tests/ui/useless_conversion.stderr
+++ b/src/tools/clippy/tests/ui/useless_conversion.stderr
@@ -377,5 +377,17 @@ LL -             takes_into_iter(self.my_field.into_iter());
 LL +             takes_into_iter(&mut *self.my_field);
    |
 
-error: aborting due to 41 previous errors
+error: useless conversion to the same type: `std::ops::Range<u32>`
+  --> tests/ui/useless_conversion.rs:440:5
+   |
+LL |     R.into_iter().for_each(|_x| {});
+   |     ^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `R`
+
+error: useless conversion to the same type: `std::ops::Range<u32>`
+  --> tests/ui/useless_conversion.rs:442:13
+   |
+LL |     let _ = R.into_iter().map(|_x| 0);
+   |             ^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `R`
+
+error: aborting due to 43 previous errors
 
diff --git a/src/tools/clippy/tests/ui/while_let_loop.rs b/src/tools/clippy/tests/ui/while_let_loop.rs
index d591ab984cf..95062c9f46c 100644
--- a/src/tools/clippy/tests/ui/while_let_loop.rs
+++ b/src/tools/clippy/tests/ui/while_let_loop.rs
@@ -154,3 +154,89 @@ fn issue_5715(mut m: core::cell::RefCell<Option<u32>>) {
         m = core::cell::RefCell::new(Some(x + 1));
     }
 }
+
+mod issue_362 {
+    pub fn merge_sorted<T>(xs: Vec<T>, ys: Vec<T>) -> Vec<T>
+    where
+        T: PartialOrd,
+    {
+        let total_len = xs.len() + ys.len();
+        let mut res = Vec::with_capacity(total_len);
+        let mut ix = xs.into_iter().peekable();
+        let mut iy = ys.into_iter().peekable();
+        loop {
+            //~^ while_let_loop
+            let lt = match (ix.peek(), iy.peek()) {
+                (Some(x), Some(y)) => x < y,
+                _ => break,
+            };
+            res.push(if lt { &mut ix } else { &mut iy }.next().unwrap());
+        }
+        res.extend(ix);
+        res.extend(iy);
+        res
+    }
+}
+
+fn let_assign() {
+    loop {
+        //~^ while_let_loop
+        let x = if let Some(y) = Some(3) {
+            y
+        } else {
+            break;
+        };
+        if x == 3 {
+            break;
+        }
+    }
+
+    loop {
+        //~^ while_let_loop
+        let x: u32 = if let Some(y) = Some(3) {
+            y
+        } else {
+            break;
+        };
+        if x == 3 {
+            break;
+        }
+    }
+
+    loop {
+        //~^ while_let_loop
+        let x = if let Some(x) = Some(3) {
+            x
+        } else {
+            break;
+        };
+        if x == 3 {
+            break;
+        }
+    }
+
+    loop {
+        //~^ while_let_loop
+        let x: u32 = if let Some(x) = Some(3) {
+            x
+        } else {
+            break;
+        };
+        if x == 3 {
+            break;
+        }
+    }
+
+    loop {
+        //~^ while_let_loop
+        let x = if let Some(x) = Some(2) {
+            let t = 1;
+            t + x
+        } else {
+            break;
+        };
+        if x == 3 {
+            break;
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/while_let_loop.stderr b/src/tools/clippy/tests/ui/while_let_loop.stderr
index bd482857e67..ed42628a53e 100644
--- a/src/tools/clippy/tests/ui/while_let_loop.stderr
+++ b/src/tools/clippy/tests/ui/while_let_loop.stderr
@@ -57,7 +57,125 @@ LL | |         let (e, l) = match "".split_whitespace().next() {
 ...  |
 LL | |         let _ = (e, l);
 LL | |     }
-   | |_____^ help: try: `while let Some(word) = "".split_whitespace().next() { .. }`
+   | |_____^
+   |
+help: try
+   |
+LL ~     while let Some(word) = "".split_whitespace().next() {
+LL +         let (e, l) = (word.is_empty(), word.len());
+LL +         ..
+LL +     }
+   |
+
+error: this loop could be written as a `while let` loop
+  --> tests/ui/while_let_loop.rs:167:9
+   |
+LL | /         loop {
+LL | |
+LL | |             let lt = match (ix.peek(), iy.peek()) {
+LL | |                 (Some(x), Some(y)) => x < y,
+...  |
+LL | |             res.push(if lt { &mut ix } else { &mut iy }.next().unwrap());
+LL | |         }
+   | |_________^
+   |
+help: try
+   |
+LL ~         while let (Some(x), Some(y)) = (ix.peek(), iy.peek()) {
+LL +             let lt = x < y;
+LL +             ..
+LL +         }
+   |
+
+error: this loop could be written as a `while let` loop
+  --> tests/ui/while_let_loop.rs:182:5
+   |
+LL | /     loop {
+LL | |
+LL | |         let x = if let Some(y) = Some(3) {
+LL | |             y
+...  |
+LL | |     }
+   | |_____^
+   |
+help: try
+   |
+LL ~     while let Some(y) = Some(3) {
+LL +         let x = y;
+LL +         ..
+LL +     }
+   |
+
+error: this loop could be written as a `while let` loop
+  --> tests/ui/while_let_loop.rs:194:5
+   |
+LL | /     loop {
+LL | |
+LL | |         let x: u32 = if let Some(y) = Some(3) {
+LL | |             y
+...  |
+LL | |     }
+   | |_____^
+   |
+help: try
+   |
+LL ~     while let Some(y) = Some(3) {
+LL +         let x: u32 = y;
+LL +         ..
+LL +     }
+   |
+
+error: this loop could be written as a `while let` loop
+  --> tests/ui/while_let_loop.rs:206:5
+   |
+LL | /     loop {
+LL | |
+LL | |         let x = if let Some(x) = Some(3) {
+LL | |             x
+...  |
+LL | |     }
+   | |_____^ help: try: `while let Some(x) = Some(3) { .. }`
+
+error: this loop could be written as a `while let` loop
+  --> tests/ui/while_let_loop.rs:218:5
+   |
+LL | /     loop {
+LL | |
+LL | |         let x: u32 = if let Some(x) = Some(3) {
+LL | |             x
+...  |
+LL | |     }
+   | |_____^
+   |
+help: try
+   |
+LL ~     while let Some(x) = Some(3) {
+LL +         let x: u32 = x;
+LL +         ..
+LL +     }
+   |
+
+error: this loop could be written as a `while let` loop
+  --> tests/ui/while_let_loop.rs:230:5
+   |
+LL | /     loop {
+LL | |
+LL | |         let x = if let Some(x) = Some(2) {
+LL | |             let t = 1;
+...  |
+LL | |     }
+   | |_____^
+   |
+help: try
+   |
+LL ~     while let Some(x) = Some(2) {
+LL +         let x = {
+LL +             let t = 1;
+LL +             t + x
+LL +         };
+LL +         ..
+LL +     }
+   |
 
-error: aborting due to 5 previous errors
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/zero_sized_hashmap_values.rs b/src/tools/clippy/tests/ui/zero_sized_hashmap_values.rs
index 4beeef421f3..dcbfd16843d 100644
--- a/src/tools/clippy/tests/ui/zero_sized_hashmap_values.rs
+++ b/src/tools/clippy/tests/ui/zero_sized_hashmap_values.rs
@@ -71,6 +71,27 @@ fn test2(map: HashMap<String, usize>, key: &str) -> HashMap<String, usize> {
     todo!();
 }
 
+fn issue14822() {
+    trait Trait {
+        type T;
+    }
+    struct S<T: Trait>(T::T);
+
+    // The `delay_bug` happens when evaluating the pointer metadata of `S<T>` which depends on
+    // whether `T::T` is `Sized`. Since the type alias doesn't have a trait bound of `T: Trait`
+    // evaluating `T::T: Sized` ultimately fails with `NoSolution`.
+    type A<T> = HashMap<u32, *const S<T>>;
+    type B<T> = HashMap<u32, S<T>>;
+
+    enum E {}
+    impl Trait for E {
+        type T = ();
+    }
+    type C = HashMap<u32, *const S<E>>;
+    type D = HashMap<u32, S<E>>;
+    //~^ zero_sized_map_values
+}
+
 fn main() {
     let _: HashMap<String, ()> = HashMap::new();
     //~^ zero_sized_map_values
diff --git a/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr b/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr
index ed8536acfe8..d29491fa05c 100644
--- a/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr
+++ b/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr
@@ -81,7 +81,15 @@ LL | fn test(map: HashMap<String, ()>, key: &str) -> HashMap<String, ()> {
    = help: consider using a set instead
 
 error: map with zero-sized value type
-  --> tests/ui/zero_sized_hashmap_values.rs:75:34
+  --> tests/ui/zero_sized_hashmap_values.rs:91:14
+   |
+LL |     type D = HashMap<u32, S<E>>;
+   |              ^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using a set instead
+
+error: map with zero-sized value type
+  --> tests/ui/zero_sized_hashmap_values.rs:96:34
    |
 LL |     let _: HashMap<String, ()> = HashMap::new();
    |                                  ^^^^^^^
@@ -89,7 +97,7 @@ LL |     let _: HashMap<String, ()> = HashMap::new();
    = help: consider using a set instead
 
 error: map with zero-sized value type
-  --> tests/ui/zero_sized_hashmap_values.rs:75:12
+  --> tests/ui/zero_sized_hashmap_values.rs:96:12
    |
 LL |     let _: HashMap<String, ()> = HashMap::new();
    |            ^^^^^^^^^^^^^^^^^^^
@@ -97,12 +105,12 @@ LL |     let _: HashMap<String, ()> = HashMap::new();
    = help: consider using a set instead
 
 error: map with zero-sized value type
-  --> tests/ui/zero_sized_hashmap_values.rs:81:12
+  --> tests/ui/zero_sized_hashmap_values.rs:102:12
    |
 LL |     let _: HashMap<_, _> = std::iter::empty::<(String, ())>().collect();
    |            ^^^^^^^^^^^^^
    |
    = help: consider using a set instead
 
-error: aborting due to 13 previous errors
+error: aborting due to 14 previous errors
 
diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml
index eb2f9f9dd61..16557a4bebb 100644
--- a/src/tools/clippy/triagebot.toml
+++ b/src/tools/clippy/triagebot.toml
@@ -1,7 +1,7 @@
 [relabel]
 allow-unauthenticated = [
     "A-*", "C-*", "E-*", "I-*", "L-*", "P-*", "S-*", "T-*",
-    "good-first-issue", "beta-nominated"
+    "good first issue", "beta-nominated"
 ]
 
 # Allows shortcuts like `@rustbot ready`
@@ -45,6 +45,7 @@ contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIB
 users_on_vacation = [
     "matthiaskrgr",
     "Manishearth",
+    "blyxyas",
 ]
 
 [assign.owners]
diff --git a/src/tools/clippy/util/gh-pages/index_template.html b/src/tools/clippy/util/gh-pages/index_template.html
index 19dc1ec0b0c..865b9523c39 100644
--- a/src/tools/clippy/util/gh-pages/index_template.html
+++ b/src/tools/clippy/util/gh-pages/index_template.html
@@ -50,7 +50,7 @@ Otherwise, have a great day =^.^=
 
     <div class="container"> {# #}
         <div class="page-header"> {# #}
-            <h1>Clippy Lints</h1> {# #}
+            <h1>Clippy Lints <span id="lint-count" class="badge"></span></h1> {# #}
         </div> {# #}
 
         <noscript> {# #}
diff --git a/src/tools/clippy/util/gh-pages/script.js b/src/tools/clippy/util/gh-pages/script.js
index c942a6a05a1..fec883938d6 100644
--- a/src/tools/clippy/util/gh-pages/script.js
+++ b/src/tools/clippy/util/gh-pages/script.js
@@ -71,6 +71,7 @@ window.searchState = {
         } else {
             window.location.hash = '';
         }
+        updateLintCount();
     },
 };
 
@@ -598,3 +599,14 @@ generateSearch();
 parseURLFilters();
 scrollToLintByURL();
 filters.filterLints();
+updateLintCount();
+
+function updateLintCount() {
+    const allLints = filters.getAllLints();
+    const totalLints = allLints.length;
+    
+    const countElement = document.getElementById("lint-count");
+    if (countElement) {
+        countElement.innerText = `Total number: ${totalLints}`;
+    }
+}
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index 4f93b498741..9b9d94bbead 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -495,6 +495,7 @@ impl Config {
             "arm64ec",
             "riscv32",
             "riscv64",
+            "loongarch32",
             "loongarch64",
             "s390x",
             // These targets require an additional asm_experimental_arch feature.
diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs
index 5757e422ae2..1406553c9ea 100644
--- a/src/tools/compiletest/src/directive-list.rs
+++ b/src/tools/compiletest/src/directive-list.rs
@@ -73,6 +73,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "ignore-linux",
     "ignore-lldb",
     "ignore-llvm-version",
+    "ignore-loongarch32",
     "ignore-loongarch64",
     "ignore-macabi",
     "ignore-macos",
@@ -196,6 +197,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "only-i686-unknown-linux-gnu",
     "only-ios",
     "only-linux",
+    "only-loongarch32",
     "only-loongarch64",
     "only-loongarch64-unknown-linux-gnu",
     "only-macos",
diff --git a/src/tools/generate-copyright/Cargo.toml b/src/tools/generate-copyright/Cargo.toml
index ab76d0fc01e..e420a450d42 100644
--- a/src/tools/generate-copyright/Cargo.toml
+++ b/src/tools/generate-copyright/Cargo.toml
@@ -8,7 +8,7 @@ description = "Produces a manifest of all the copyrighted materials in the Rust
 
 [dependencies]
 anyhow = "1.0.65"
-askama = "0.13.0"
+askama = "0.14.0"
 cargo_metadata = "0.18.1"
 serde = { version = "1.0.147", features = ["derive"] }
 serde_json = "1.0.85"
diff --git a/src/tools/generate-copyright/src/cargo_metadata.rs b/src/tools/generate-copyright/src/cargo_metadata.rs
index b717bd53eb1..3fae26bda47 100644
--- a/src/tools/generate-copyright/src/cargo_metadata.rs
+++ b/src/tools/generate-copyright/src/cargo_metadata.rs
@@ -46,11 +46,12 @@ pub struct PackageMetadata {
 /// covered it already.
 pub fn get_metadata_and_notices(
     cargo: &Path,
+    cargo_home_path: &Path,
     vendor_path: &Path,
     root_path: &Path,
     manifest_paths: &[PathBuf],
 ) -> Result<BTreeMap<Package, PackageMetadata>, Error> {
-    let mut output = get_metadata(cargo, root_path, manifest_paths)?;
+    let mut output = get_metadata(cargo, cargo_home_path, root_path, manifest_paths)?;
 
     // Now for each dependency we found, go and grab any important looking files
     for (package, metadata) in output.iter_mut() {
@@ -66,6 +67,7 @@ pub fn get_metadata_and_notices(
 /// assume `reuse` has covered it already.
 pub fn get_metadata(
     cargo: &Path,
+    cargo_home_path: &Path,
     root_path: &Path,
     manifest_paths: &[PathBuf],
 ) -> Result<BTreeMap<Package, PackageMetadata>, Error> {
@@ -81,8 +83,11 @@ pub fn get_metadata(
             .manifest_path(manifest_path)
             .exec()?;
         for package in metadata.packages {
-            let manifest_path = package.manifest_path.as_path();
-            if manifest_path.starts_with(root_path) {
+            let package_manifest_path = package.manifest_path.as_path();
+
+            if package_manifest_path.starts_with(root_path)
+                && !package_manifest_path.starts_with(cargo_home_path)
+            {
                 // it's an in-tree dependency and reuse covers it
                 continue;
             }
diff --git a/src/tools/generate-copyright/src/main.rs b/src/tools/generate-copyright/src/main.rs
index d6ed7261b7c..5497db1f5f3 100644
--- a/src/tools/generate-copyright/src/main.rs
+++ b/src/tools/generate-copyright/src/main.rs
@@ -15,6 +15,7 @@ mod cargo_metadata;
 ///
 /// Run `x.py run generate-copyright`
 fn main() -> Result<(), Error> {
+    let cargo_home = env_path("CARGO_HOME")?;
     let dest_file = env_path("DEST")?;
     let libstd_dest_file = env_path("DEST_LIBSTD")?;
     let src_dir = env_path("SRC_DIR")?;
@@ -39,11 +40,17 @@ fn main() -> Result<(), Error> {
         .collect::<Vec<_>>();
 
     // Scan Cargo dependencies
-    let mut collected_cargo_metadata =
-        cargo_metadata::get_metadata_and_notices(&cargo, &vendor_dir, &src_dir, &cargo_manifests)?;
+    let mut collected_cargo_metadata = cargo_metadata::get_metadata_and_notices(
+        &cargo,
+        &cargo_home,
+        &vendor_dir,
+        &src_dir,
+        &cargo_manifests,
+    )?;
 
     let library_collected_cargo_metadata = cargo_metadata::get_metadata_and_notices(
         &cargo,
+        &cargo_home,
         &vendor_dir,
         &src_dir,
         &library_manifests,
diff --git a/src/tools/jsondocck/src/config.rs b/src/tools/jsondocck/src/config.rs
index 9b3ba3f3fbe..6bef37c2259 100644
--- a/src/tools/jsondocck/src/config.rs
+++ b/src/tools/jsondocck/src/config.rs
@@ -4,7 +4,7 @@ use getopts::Options;
 pub struct Config {
     /// The directory documentation output was generated in
     pub doc_dir: String,
-    /// The file documentation was generated for, with docck commands to check
+    /// The file documentation was generated for, with docck directives to check
     pub template: String,
 }
 
diff --git a/src/tools/jsondocck/src/directive.rs b/src/tools/jsondocck/src/directive.rs
new file mode 100644
index 00000000000..fdb2fa6dbbe
--- /dev/null
+++ b/src/tools/jsondocck/src/directive.rs
@@ -0,0 +1,232 @@
+use std::borrow::Cow;
+
+use serde_json::Value;
+
+use crate::cache::Cache;
+
+#[derive(Debug)]
+pub struct Directive {
+    pub kind: DirectiveKind,
+    pub path: String,
+    pub lineno: usize,
+}
+
+#[derive(Debug)]
+pub enum DirectiveKind {
+    /// `//@ has <path>`
+    ///
+    /// Checks the path exists.
+    HasPath,
+
+    /// `//@ has <path> <value>`
+    ///
+    /// Check one thing at the path  is equal to the value.
+    HasValue { value: String },
+
+    /// `//@ !has <path>`
+    ///
+    /// 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.
+    Is { value: String },
+
+    /// `//@ is <path> <value> <value>...`
+    ///
+    /// Check that the path matches to exactly every given value.
+    IsMany { values: Vec<String> },
+
+    /// `//@ !is <path> <value>`
+    ///
+    /// Check the path isn't the given value.
+    IsNot { value: String },
+
+    /// `//@ count <path> <value>`
+    ///
+    /// Check the path has the expected number of matches.
+    CountIs { expected: usize },
+
+    /// `//@ set <name> = <path>`
+    Set { variable: String },
+}
+
+impl DirectiveKind {
+    /// Returns both the kind and the path.
+    ///
+    /// Returns `None` if the directive isn't from jsondocck (e.g. from compiletest).
+    pub fn parse<'a>(
+        directive_name: &str,
+        negated: bool,
+        args: &'a [String],
+    ) -> Option<(Self, &'a str)> {
+        let kind = match (directive_name, negated) {
+            ("count", false) => {
+                assert_eq!(args.len(), 2);
+                let expected = args[1].parse().expect("invalid number for `count`");
+                Self::CountIs { expected }
+            }
+
+            ("ismany", false) => {
+                // FIXME: Make this >= 3, and migrate len(values)==1 cases to @is
+                assert!(args.len() >= 2, "Not enough args to `ismany`");
+                let values = args[1..].to_owned();
+                Self::IsMany { values }
+            }
+
+            ("is", false) => {
+                assert_eq!(args.len(), 2);
+                Self::Is { value: args[1].clone() }
+            }
+            ("is", true) => {
+                assert_eq!(args.len(), 2);
+                Self::IsNot { value: args[1].clone() }
+            }
+
+            ("set", false) => {
+                assert_eq!(args.len(), 3);
+                assert_eq!(args[1], "=");
+                return Some((Self::Set { variable: args[0].clone() }, &args[2]));
+            }
+
+            ("has", false) => match args {
+                [_path] => Self::HasPath,
+                [_path, value] => Self::HasValue { value: value.clone() },
+                _ => panic!("`//@ has` must have 2 or 3 arguments, but got {args:?}"),
+            },
+            ("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:?}"),
+            },
+            // Ignore compiletest directives, like //@ edition
+            (_, false) if KNOWN_DIRECTIVE_NAMES.contains(&directive_name) => {
+                return None;
+            }
+            _ => {
+                panic!("Invalid directive `//@ {}{directive_name}`", if negated { "!" } else { "" })
+            }
+        };
+
+        Some((kind, &args[0]))
+    }
+}
+
+impl Directive {
+    /// Performs the actual work of ensuring a directive passes.
+    pub fn check(&self, cache: &mut Cache) -> Result<(), String> {
+        let matches = cache.select(&self.path);
+        match &self.kind {
+            DirectiveKind::HasPath => {
+                if matches.is_empty() {
+                    return Err("matched to no values".to_owned());
+                }
+            }
+            DirectiveKind::HasNotPath => {
+                if !matches.is_empty() {
+                    return Err(format!("matched to {matches:?}, but wanted no matches"));
+                }
+            }
+            DirectiveKind::HasValue { value } => {
+                let want_value = string_to_value(value, cache);
+                if !matches.contains(&want_value.as_ref()) {
+                    return Err(format!(
+                        "matched to {matches:?}, which didn't contain {want_value:?}"
+                    ));
+                }
+            }
+            DirectiveKind::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:?}"
+                    ));
+                }
+            }
+
+            DirectiveKind::Is { value } => {
+                let want_value = string_to_value(value, cache);
+                let matched = get_one(&matches)?;
+                if matched != want_value.as_ref() {
+                    return Err(format!("matched to {matched:?} but want {want_value:?}"));
+                }
+            }
+            DirectiveKind::IsNot { value } => {
+                let wantnt_value = string_to_value(value, cache);
+                let matched = get_one(&matches)?;
+                if matched == wantnt_value.as_ref() {
+                    return Err(format!("got value {wantnt_value:?}, but want anything else"));
+                }
+            }
+
+            DirectiveKind::IsMany { values } => {
+                // Serde json doesn't implement Ord or Hash for Value, so we must
+                // use a Vec here. While in theory that makes setwize equality
+                // O(n^2), in practice n will never be large enough to matter.
+                let expected_values =
+                    values.iter().map(|v| string_to_value(v, cache)).collect::<Vec<_>>();
+                if expected_values.len() != matches.len() {
+                    return Err(format!(
+                        "Expected {} values, but matched to {} values ({:?})",
+                        expected_values.len(),
+                        matches.len(),
+                        matches
+                    ));
+                };
+                for got_value in matches {
+                    if !expected_values.iter().any(|exp| &**exp == got_value) {
+                        return Err(format!("has match {got_value:?}, which was not expected",));
+                    }
+                }
+            }
+            DirectiveKind::CountIs { expected } => {
+                if *expected != matches.len() {
+                    return Err(format!(
+                        "matched to `{matches:?}` with length {}, but expected length {expected}",
+                        matches.len(),
+                    ));
+                }
+            }
+            DirectiveKind::Set { variable } => {
+                let value = get_one(&matches)?;
+                let r = cache.variables.insert(variable.to_owned(), value.clone());
+                assert!(r.is_none(), "name collision: {variable:?} is duplicated");
+            }
+        }
+
+        Ok(())
+    }
+}
+
+fn get_one<'a>(matches: &[&'a Value]) -> Result<&'a Value, String> {
+    match matches {
+        [] => Err("matched to no values".to_owned()),
+        [matched] => Ok(matched),
+        _ => Err(format!("matched to multiple values {matches:?}, but want exactly 1")),
+    }
+}
+
+// FIXME: This setup is temporary until we figure out how to improve this situation.
+//        See <https://github.com/rust-lang/rust/issues/125813#issuecomment-2141953780>.
+include!(concat!(env!("CARGO_MANIFEST_DIR"), "/../compiletest/src/directive-list.rs"));
+
+fn string_to_value<'a>(s: &str, cache: &'a Cache) -> Cow<'a, Value> {
+    if s.starts_with("$") {
+        Cow::Borrowed(&cache.variables.get(&s[1..]).unwrap_or_else(|| {
+            // FIXME(adotinthevoid): Show line number
+            panic!("No variable: `{}`. Current state: `{:?}`", &s[1..], cache.variables)
+        }))
+    } else {
+        Cow::Owned(serde_json::from_str(s).expect(&format!("Cannot convert `{}` to json", s)))
+    }
+}
diff --git a/src/tools/jsondocck/src/error.rs b/src/tools/jsondocck/src/error.rs
index 0a3e085b405..eb2932f7803 100644
--- a/src/tools/jsondocck/src/error.rs
+++ b/src/tools/jsondocck/src/error.rs
@@ -1,7 +1,7 @@
-use crate::Command;
+use crate::Directive;
 
 #[derive(Debug)]
 pub struct CkError {
     pub message: String,
-    pub command: Command,
+    pub directive: Directive,
 }
diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs
index 65ad38da98b..d84be4d3a3a 100644
--- a/src/tools/jsondocck/src/main.rs
+++ b/src/tools/jsondocck/src/main.rs
@@ -1,17 +1,17 @@
-use std::borrow::Cow;
 use std::process::ExitCode;
 use std::sync::LazyLock;
 use std::{env, fs};
 
 use regex::{Regex, RegexBuilder};
-use serde_json::Value;
 
 mod cache;
 mod config;
+mod directive;
 mod error;
 
 use cache::Cache;
 use config::parse_config;
+use directive::{Directive, DirectiveKind};
 use error::CkError;
 
 fn main() -> ExitCode {
@@ -19,14 +19,14 @@ fn main() -> ExitCode {
 
     let mut failed = Vec::new();
     let mut cache = Cache::new(&config);
-    let Ok(commands) = get_commands(&config.template) else {
+    let Ok(directives) = get_directives(&config.template) else {
         eprintln!("Jsondocck failed for {}", &config.template);
         return ExitCode::FAILURE;
     };
 
-    for command in commands {
-        if let Err(message) = check_command(&command, &mut cache) {
-            failed.push(CkError { command, message });
+    for directive in directives {
+        if let Err(message) = directive.check(&mut cache) {
+            failed.push(CkError { directive, message });
         }
     }
 
@@ -34,130 +34,20 @@ fn main() -> ExitCode {
         ExitCode::SUCCESS
     } else {
         for i in failed {
-            eprintln!("{}:{}, command failed", config.template, i.command.lineno);
+            eprintln!("{}:{}, directive failed", config.template, i.directive.lineno);
             eprintln!("{}", i.message)
         }
         ExitCode::FAILURE
     }
 }
 
-#[derive(Debug)]
-pub struct Command {
-    kind: CommandKind,
-    path: String,
-    lineno: usize,
-}
-
-#[derive(Debug)]
-enum CommandKind {
-    /// `//@ has <path>`
-    ///
-    /// Checks the path exists.
-    HasPath,
-
-    /// `//@ has <path> <value>`
-    ///
-    /// Check one thing at the path  is equal to the value.
-    HasValue { value: String },
-
-    /// `//@ !has <path>`
-    ///
-    /// 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.
-    Is { value: String },
-
-    /// `//@ is <path> <value> <value>...`
-    ///
-    /// Check that the path matches to exactly every given value.
-    IsMany { values: Vec<String> },
-
-    /// `//@ !is <path> <value>`
-    ///
-    /// Check the path isn't the given value.
-    IsNot { value: String },
-
-    /// `//@ count <path> <value>`
-    ///
-    /// Check the path has the expected number of matches.
-    CountIs { expected: usize },
-
-    /// `//@ set <name> = <path>`
-    Set { variable: String },
-}
-
-impl CommandKind {
-    /// Returns both the kind and the path.
-    ///
-    /// Returns `None` if the command isn't from jsondocck (e.g. from compiletest).
-    fn parse<'a>(command_name: &str, negated: bool, args: &'a [String]) -> Option<(Self, &'a str)> {
-        let kind = match (command_name, negated) {
-            ("count", false) => {
-                assert_eq!(args.len(), 2);
-                let expected = args[1].parse().expect("invalid number for `count`");
-                Self::CountIs { expected }
-            }
-
-            ("ismany", false) => {
-                // FIXME: Make this >= 3, and migrate len(values)==1 cases to @is
-                assert!(args.len() >= 2, "Not enough args to `ismany`");
-                let values = args[1..].to_owned();
-                Self::IsMany { values }
-            }
-
-            ("is", false) => {
-                assert_eq!(args.len(), 2);
-                Self::Is { value: args[1].clone() }
-            }
-            ("is", true) => {
-                assert_eq!(args.len(), 2);
-                Self::IsNot { value: args[1].clone() }
-            }
-
-            ("set", false) => {
-                assert_eq!(args.len(), 3);
-                assert_eq!(args[1], "=");
-                return Some((Self::Set { variable: args[0].clone() }, &args[2]));
-            }
-
-            ("has", false) => match args {
-                [_path] => Self::HasPath,
-                [_path, value] => Self::HasValue { value: value.clone() },
-                _ => panic!("`//@ has` must have 2 or 3 arguments, but got {args:?}"),
-            },
-            ("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;
-            }
-            _ => {
-                panic!("Invalid command `//@ {}{command_name}`", if negated { "!" } else { "" })
-            }
-        };
-
-        Some((kind, &args[0]))
-    }
-}
-
 static LINE_PATTERN: LazyLock<Regex> = LazyLock::new(|| {
     RegexBuilder::new(
         r#"
         ^\s*
         //@\s+
         (?P<negated>!?)
-        (?P<cmd>[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*)
+        (?P<directive>[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*)
         (?P<args>.*)$
     "#,
     )
@@ -180,16 +70,12 @@ static DEPRECATED_LINE_PATTERN: LazyLock<Regex> = LazyLock::new(|| {
 });
 
 fn print_err(msg: &str, lineno: usize) {
-    eprintln!("Invalid command: {} on line {}", msg, lineno)
+    eprintln!("Invalid directive: {} on line {}", msg, lineno)
 }
 
-// FIXME: This setup is temporary until we figure out how to improve this situation.
-//        See <https://github.com/rust-lang/rust/issues/125813#issuecomment-2141953780>.
-include!(concat!(env!("CARGO_MANIFEST_DIR"), "/../compiletest/src/directive-list.rs"));
-
-/// Get a list of commands from a file.
-fn get_commands(template: &str) -> Result<Vec<Command>, ()> {
-    let mut commands = Vec::new();
+/// Get a list of directives from a file.
+fn get_directives(template: &str) -> Result<Vec<Directive>, ()> {
+    let mut directives = Vec::new();
     let mut errors = false;
     let file = fs::read_to_string(template).unwrap();
 
@@ -197,7 +83,7 @@ fn get_commands(template: &str) -> Result<Vec<Command>, ()> {
         let lineno = lineno + 1;
 
         if DEPRECATED_LINE_PATTERN.is_match(line) {
-            print_err("Deprecated command syntax, replace `// @` with `//@ `", lineno);
+            print_err("Deprecated directive syntax, replace `// @` with `//@ `", lineno);
             errors = true;
             continue;
         }
@@ -215,115 +101,10 @@ fn get_commands(template: &str) -> Result<Vec<Command>, ()> {
             continue;
         };
 
-        if let Some((kind, path)) = CommandKind::parse(&cap["cmd"], negated, &args) {
-            commands.push(Command { kind, lineno, path: path.to_owned() })
+        if let Some((kind, path)) = DirectiveKind::parse(&cap["directive"], negated, &args) {
+            directives.push(Directive { kind, lineno, path: path.to_owned() })
         }
     }
 
-    if !errors { Ok(commands) } else { Err(()) }
-}
-
-/// Performs the actual work of ensuring a command passes.
-fn check_command(command: &Command, cache: &mut Cache) -> Result<(), String> {
-    let matches = cache.select(&command.path);
-    match &command.kind {
-        CommandKind::HasPath => {
-            if matches.is_empty() {
-                return Err("matched to no values".to_owned());
-            }
-        }
-        CommandKind::HasNotPath => {
-            if !matches.is_empty() {
-                return Err(format!("matched to {matches:?}, but wanted no matches"));
-            }
-        }
-        CommandKind::HasValue { value } => {
-            let want_value = string_to_value(value, cache);
-            if !matches.contains(&want_value.as_ref()) {
-                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)?;
-            if matched != want_value.as_ref() {
-                return Err(format!("matched to {matched:?} but want {want_value:?}"));
-            }
-        }
-        CommandKind::IsNot { value } => {
-            let wantnt_value = string_to_value(value, cache);
-            let matched = get_one(&matches)?;
-            if matched == wantnt_value.as_ref() {
-                return Err(format!("got value {wantnt_value:?}, but want anything else"));
-            }
-        }
-
-        CommandKind::IsMany { values } => {
-            // Serde json doesn't implement Ord or Hash for Value, so we must
-            // use a Vec here. While in theory that makes setwize equality
-            // O(n^2), in practice n will never be large enough to matter.
-            let expected_values =
-                values.iter().map(|v| string_to_value(v, cache)).collect::<Vec<_>>();
-            if expected_values.len() != matches.len() {
-                return Err(format!(
-                    "Expected {} values, but matched to {} values ({:?})",
-                    expected_values.len(),
-                    matches.len(),
-                    matches
-                ));
-            };
-            for got_value in matches {
-                if !expected_values.iter().any(|exp| &**exp == got_value) {
-                    return Err(format!("has match {got_value:?}, which was not expected",));
-                }
-            }
-        }
-        CommandKind::CountIs { expected } => {
-            if *expected != matches.len() {
-                return Err(format!(
-                    "matched to `{matches:?}` with length {}, but expected length {expected}",
-                    matches.len(),
-                ));
-            }
-        }
-        CommandKind::Set { variable } => {
-            let value = get_one(&matches)?;
-            let r = cache.variables.insert(variable.to_owned(), value.clone());
-            assert!(r.is_none(), "name collision: {variable:?} is duplicated");
-        }
-    }
-
-    Ok(())
-}
-
-fn get_one<'a>(matches: &[&'a Value]) -> Result<&'a Value, String> {
-    match matches {
-        [] => Err("matched to no values".to_owned()),
-        [matched] => Ok(matched),
-        _ => Err(format!("matched to multiple values {matches:?}, but want exactly 1")),
-    }
-}
-
-fn string_to_value<'a>(s: &str, cache: &'a Cache) -> Cow<'a, Value> {
-    if s.starts_with("$") {
-        Cow::Borrowed(&cache.variables.get(&s[1..]).unwrap_or_else(|| {
-            // FIXME(adotinthevoid): Show line number
-            panic!("No variable: `{}`. Current state: `{:?}`", &s[1..], cache.variables)
-        }))
-    } else {
-        Cow::Owned(serde_json::from_str(s).expect(&format!("Cannot convert `{}` to json", s)))
-    }
+    if !errors { Ok(directives) } else { Err(()) }
 }
diff --git a/src/tools/lint-docs/Cargo.toml b/src/tools/lint-docs/Cargo.toml
index 3578bda8276..f1ffda75ac0 100644
--- a/src/tools/lint-docs/Cargo.toml
+++ b/src/tools/lint-docs/Cargo.toml
@@ -7,6 +7,7 @@ description = "A script to extract the lint documentation for the rustc book."
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
+rustc-literal-escaper = "0.0.2"
 serde_json = "1.0.57"
 tempfile = "3.1.0"
 walkdir = "2.3.1"
diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs
index cacce01675f..6bb18c2bced 100644
--- a/src/tools/lint-docs/src/lib.rs
+++ b/src/tools/lint-docs/src/lib.rs
@@ -4,6 +4,7 @@ use std::fs;
 use std::path::{Path, PathBuf};
 use std::process::Command;
 
+use rustc_literal_escaper::{Mode, unescape_unicode};
 use walkdir::WalkDir;
 
 mod groups;
@@ -214,6 +215,16 @@ impl<'a> LintExtractor<'a> {
                         let line = line.trim();
                         if let Some(text) = line.strip_prefix("/// ") {
                             doc_lines.push(text.to_string());
+                        } else if let Some(text) = line.strip_prefix("#[doc = \"") {
+                            let escaped = text.strip_suffix("\"]").unwrap();
+                            let mut buf = String::new();
+                            unescape_unicode(escaped, Mode::Str, &mut |_, c| match c {
+                                Ok(c) => buf.push(c),
+                                Err(err) => {
+                                    assert!(!err.is_fatal(), "failed to unescape string literal")
+                                }
+                            });
+                            doc_lines.push(buf);
                         } else if line == "///" {
                             doc_lines.push("".to_string());
                         } else if line.starts_with("// ") {
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index 122438a2509..de521393cd0 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -218,7 +218,7 @@ degree documented below):
   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 the entire test suite.
-  - `freebsd`: maintained by @YohDeadfall. Supports `std::env` and parts of `std::{thread, fs}`, but not `std::sync`.
+  - `freebsd`: maintained by @YohDeadfall and @LorrensP-2158466. Supports the entire test suite.
   - `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/cargo-miri/Cargo.lock b/src/tools/miri/cargo-miri/Cargo.lock
index bd4ca2860f3..c1915ae617e 100644
--- a/src/tools/miri/cargo-miri/Cargo.lock
+++ b/src/tools/miri/cargo-miri/Cargo.lock
@@ -208,9 +208,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-build-sysroot"
-version = "0.5.4"
+version = "0.5.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6d984a9db43148467059309bd1e5ad577085162f695d9fe2cf3543aeb25cd38"
+checksum = "10edc2e4393515193bd766e2f6c050b0536a68e56f2b6d56c07ababfdc114ff0"
 dependencies = [
  "anyhow",
  "rustc_version",
diff --git a/src/tools/miri/cargo-miri/Cargo.toml b/src/tools/miri/cargo-miri/Cargo.toml
index 23048914af1..5c579b2a77d 100644
--- a/src/tools/miri/cargo-miri/Cargo.toml
+++ b/src/tools/miri/cargo-miri/Cargo.toml
@@ -18,7 +18,7 @@ directories = "6"
 rustc_version = "0.4"
 serde_json = "1.0.40"
 cargo_metadata = "0.19"
-rustc-build-sysroot = "0.5.4"
+rustc-build-sysroot = "0.5.7"
 
 # Enable some feature flags that dev-dependencies need but dependencies
 # do not.  This makes `./miri install` after `./miri build` faster.
diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs
index 4857f62cd3a..a5e019a8ea9 100644
--- a/src/tools/miri/cargo-miri/src/phases.rs
+++ b/src/tools/miri/cargo-miri/src/phases.rs
@@ -90,7 +90,7 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
                 "`cargo miri` supports the following subcommands: `run`, `test`, `nextest`, `clean`, and `setup`."
             ),
     };
-    let verbose = num_arg_flag("-v");
+    let verbose = num_arg_flag("-v") + num_arg_flag("--verbose");
     let quiet = has_arg_flag("-q") || has_arg_flag("--quiet");
 
     // Determine the involved architectures.
diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh
index 755e02d02ec..8941af681a4 100755
--- a/src/tools/miri/ci/ci.sh
+++ b/src/tools/miri/ci/ci.sh
@@ -142,12 +142,12 @@ case $HOST_TARGET in
     # Host
     GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests
     # Extra tier 1
-    # With reduced many-seed count to avoid spending too much time on that.
-    # (All OSes and ABIs are run with 64 seeds at least once though via the macOS runner.)
-    MANY_SEEDS=16 TEST_TARGET=i686-unknown-linux-gnu run_tests
-    MANY_SEEDS=16 TEST_TARGET=aarch64-unknown-linux-gnu run_tests
-    MANY_SEEDS=16 TEST_TARGET=x86_64-apple-darwin run_tests
-    MANY_SEEDS=16 TEST_TARGET=x86_64-pc-windows-gnu run_tests
+    MANY_SEEDS=64 TEST_TARGET=i686-unknown-linux-gnu run_tests
+    MANY_SEEDS=64 TEST_TARGET=aarch64-unknown-linux-gnu run_tests
+    MANY_SEEDS=64 TEST_TARGET=x86_64-apple-darwin run_tests
+    MANY_SEEDS=64 TEST_TARGET=x86_64-pc-windows-gnu run_tests
+    # Extra tier 1 candidate
+    MANY_SEEDS=64 TEST_TARGET=aarch64-pc-windows-msvc run_tests
     ;;
   aarch64-apple-darwin)
     # Host
@@ -156,16 +156,18 @@ case $HOST_TARGET in
     MANY_SEEDS=64 TEST_TARGET=i686-pc-windows-gnu run_tests
     MANY_SEEDS=64 TEST_TARGET=x86_64-pc-windows-msvc CARGO_MIRI_ENV=1 run_tests
     # Extra tier 2
-    TEST_TARGET=arm-unknown-linux-gnueabi run_tests
-    TEST_TARGET=s390x-unknown-linux-gnu run_tests # big-endian architecture of choice
+    MANY_SEEDS=16 TEST_TARGET=arm-unknown-linux-gnueabi run_tests # 32bit ARM
+    MANY_SEEDS=16 TEST_TARGET=aarch64-pc-windows-gnullvm run_tests # gnullvm ABI
+    MANY_SEEDS=16 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
+    MANY_SEEDS=16 TEST_TARGET=mips-unknown-linux-gnu run_tests # a 32bit big-endian target, and also a target without 64bit atomics
+    MANY_SEEDS=16 TEST_TARGET=x86_64-unknown-illumos run_tests
+    MANY_SEEDS=16 TEST_TARGET=x86_64-pc-solaris run_tests
+    MANY_SEEDS=16 TEST_TARGET=x86_64-unknown-freebsd run_tests
+    MANY_SEEDS=16 TEST_TARGET=i686-unknown-freebsd 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 thread sync concurrency fs libc-pipe
-    TEST_TARGET=i686-unknown-freebsd   run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency fs libc-pipe
     TEST_TARGET=aarch64-linux-android  run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency 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
@@ -177,7 +179,7 @@ case $HOST_TARGET in
     # Host
     # Without GC_STRESS and with reduced many-seeds count as this is the slowest runner.
     # (The macOS runner checks windows-msvc with full many-seeds count.)
-    MIR_OPT=1 MANY_SEEDS=16 TEST_BENCH=1 run_tests
+    MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 run_tests
     # Extra tier 1
     # We really want to ensure a Linux target works on a Windows host,
     # and a 64bit target works on a 32bit host.
diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs
index 3b7b159aeab..86362145d47 100644
--- a/src/tools/miri/miri-script/src/commands.rs
+++ b/src/tools/miri/miri-script/src/commands.rs
@@ -1,4 +1,4 @@
-use std::collections::HashMap;
+use std::collections::BTreeMap;
 use std::ffi::{OsStr, OsString};
 use std::fmt::Write as _;
 use std::fs::{self, File};
@@ -404,7 +404,28 @@ impl Command {
         // We want to forward the host stdin so apparently we cannot use `cmd!`.
         let mut cmd = process::Command::new("git");
         cmd.arg("rebase").arg(&base).arg("--interactive");
-        cmd.env("GIT_SEQUENCE_EDITOR", env::current_exe()?);
+        let current_exe = {
+            if cfg!(windows) {
+                // Apparently git-for-Windows gets confused by backslashes if we just use
+                // `current_exe()` here. So replace them by forward slashes if this is not a "magic"
+                // path starting with "\\". This is clearly a git bug but we work around it here.
+                // Also see <https://github.com/rust-lang/miri/issues/4340>.
+                let bin = env::current_exe()?;
+                match bin.into_os_string().into_string() {
+                    Err(not_utf8) => not_utf8.into(), // :shrug:
+                    Ok(str) => {
+                        if str.starts_with(r"\\") {
+                            str.into() // don't touch these magic paths, they must use backslashes
+                        } else {
+                            str.replace('\\', "/").into()
+                        }
+                    }
+                }
+            } else {
+                env::current_exe()?
+            }
+        };
+        cmd.env("GIT_SEQUENCE_EDITOR", current_exe);
         cmd.env("MIRI_SCRIPT_IS_GIT_SEQUENCE_EDITOR", "1");
         cmd.current_dir(sh.current_dir());
         let result = cmd.status()?;
@@ -489,7 +510,9 @@ impl Command {
             sh.read_dir(benches_dir)?
                 .into_iter()
                 .filter(|path| path.is_dir())
-                .map(|path| path.into_os_string().into_string().unwrap())
+                // Only keep the basename: that matches the usage with a manual bench list,
+                // and it ensure the path concatenations below work as intended.
+                .map(|path| path.file_name().unwrap().to_owned().into_string().unwrap())
                 .collect()
         } else {
             benches.into_iter().collect()
@@ -530,14 +553,16 @@ impl Command {
             stddev: f64,
         }
 
-        let gather_results = || -> Result<HashMap<&str, BenchResult>> {
+        let gather_results = || -> Result<BTreeMap<&str, BenchResult>> {
             let baseline_temp_dir = results_json_dir.unwrap();
-            let mut results = HashMap::new();
+            let mut results = BTreeMap::new();
             for bench in &benches {
-                let result = File::open(path!(baseline_temp_dir / format!("{bench}.bench.json")))?;
-                let mut result: serde_json::Value =
-                    serde_json::from_reader(BufReader::new(result))?;
-                let result: BenchResult = serde_json::from_value(result["results"][0].take())?;
+                let result = File::open(path!(baseline_temp_dir / format!("{bench}.bench.json")))
+                    .context("failed to read hyperfine JSON")?;
+                let mut result: serde_json::Value = serde_json::from_reader(BufReader::new(result))
+                    .context("failed to parse hyperfine JSON")?;
+                let result: BenchResult = serde_json::from_value(result["results"][0].take())
+                    .context("failed to interpret hyperfine JSON")?;
                 results.insert(bench as &str, result);
             }
             Ok(results)
@@ -549,15 +574,15 @@ impl Command {
             serde_json::to_writer_pretty(BufWriter::new(baseline), &results)?;
         } else if let Some(baseline_file) = load_baseline {
             let new_results = gather_results()?;
-            let baseline_results: HashMap<String, BenchResult> = {
+            let baseline_results: BTreeMap<String, BenchResult> = {
                 let f = File::open(baseline_file)?;
                 serde_json::from_reader(BufReader::new(f))?
             };
             println!(
                 "Comparison with baseline (relative speed, lower is better for the new results):"
             );
-            for (bench, new_result) in new_results.iter() {
-                let Some(baseline_result) = baseline_results.get(*bench) else { continue };
+            for (bench, new_result) in new_results {
+                let Some(baseline_result) = baseline_results.get(bench) else { continue };
 
                 // Compare results (inspired by hyperfine)
                 let ratio = new_result.mean / baseline_result.mean;
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 8b98fe3c4fc..553d410b2bc 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-ac17c3486c6fdfbb0c3c18b99f3d8dfbff625d29
+337c11e5932275e7d450c1f2e26f289f0ddfa717
diff --git a/src/tools/miri/src/alloc_bytes.rs b/src/tools/miri/src/alloc/alloc_bytes.rs
index 69ede279aa9..2a253952b27 100644
--- a/src/tools/miri/src/alloc_bytes.rs
+++ b/src/tools/miri/src/alloc/alloc_bytes.rs
@@ -1,10 +1,23 @@
 use std::alloc::Layout;
 use std::borrow::Cow;
 use std::{alloc, slice};
+#[cfg(target_os = "linux")]
+use std::{cell::RefCell, rc::Rc};
 
 use rustc_abi::{Align, Size};
 use rustc_middle::mir::interpret::AllocBytes;
 
+#[cfg(target_os = "linux")]
+use crate::alloc::isolated_alloc::IsolatedAlloc;
+use crate::helpers::ToU64 as _;
+
+#[derive(Clone, Debug)]
+pub enum MiriAllocParams {
+    Global,
+    #[cfg(target_os = "linux")]
+    Isolated(Rc<RefCell<IsolatedAlloc>>),
+}
+
 /// Allocation bytes that explicitly handle the layout of the data they're storing.
 /// This is necessary to interface with native code that accesses the program store in Miri.
 #[derive(Debug)]
@@ -16,13 +29,16 @@ pub struct MiriAllocBytes {
     /// * If `self.layout.size() == 0`, then `self.ptr` was allocated with the equivalent layout with size 1.
     /// * Otherwise, `self.ptr` points to memory allocated with `self.layout`.
     ptr: *mut u8,
+    /// Whether this instance of `MiriAllocBytes` had its allocation created by calling `alloc::alloc()`
+    /// (`Global`) or the discrete allocator (`Isolated`)
+    params: MiriAllocParams,
 }
 
 impl Clone for MiriAllocBytes {
     fn clone(&self) -> Self {
         let bytes: Cow<'_, [u8]> = Cow::Borrowed(self);
-        let align = Align::from_bytes(self.layout.align().try_into().unwrap()).unwrap();
-        MiriAllocBytes::from_bytes(bytes, align)
+        let align = Align::from_bytes(self.layout.align().to_u64()).unwrap();
+        MiriAllocBytes::from_bytes(bytes, align, self.params.clone())
     }
 }
 
@@ -35,8 +51,16 @@ impl Drop for MiriAllocBytes {
         } else {
             self.layout
         };
+
         // SAFETY: Invariant, `self.ptr` points to memory allocated with `self.layout`.
-        unsafe { alloc::dealloc(self.ptr, alloc_layout) }
+        unsafe {
+            match self.params.clone() {
+                MiriAllocParams::Global => alloc::dealloc(self.ptr, alloc_layout),
+                #[cfg(target_os = "linux")]
+                MiriAllocParams::Isolated(alloc) =>
+                    alloc.borrow_mut().dealloc(self.ptr, alloc_layout),
+            }
+        }
     }
 }
 
@@ -65,7 +89,8 @@ impl MiriAllocBytes {
     fn alloc_with(
         size: u64,
         align: u64,
-        alloc_fn: impl FnOnce(Layout) -> *mut u8,
+        params: MiriAllocParams,
+        alloc_fn: impl FnOnce(Layout, &MiriAllocParams) -> *mut u8,
     ) -> Result<MiriAllocBytes, ()> {
         let size = usize::try_from(size).map_err(|_| ())?;
         let align = usize::try_from(align).map_err(|_| ())?;
@@ -73,24 +98,36 @@ impl MiriAllocBytes {
         // When size is 0 we allocate 1 byte anyway, to ensure each allocation has a unique address.
         let alloc_layout =
             if size == 0 { Layout::from_size_align(1, align).unwrap() } else { layout };
-        let ptr = alloc_fn(alloc_layout);
+        let ptr = alloc_fn(alloc_layout, &params);
         if ptr.is_null() {
             Err(())
         } else {
             // SAFETY: All `MiriAllocBytes` invariants are fulfilled.
-            Ok(Self { ptr, layout })
+            Ok(Self { ptr, layout, params })
         }
     }
 }
 
 impl AllocBytes for MiriAllocBytes {
-    fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, align: Align) -> Self {
+    type AllocParams = MiriAllocParams;
+
+    fn from_bytes<'a>(
+        slice: impl Into<Cow<'a, [u8]>>,
+        align: Align,
+        params: MiriAllocParams,
+    ) -> Self {
         let slice = slice.into();
         let size = slice.len();
         let align = align.bytes();
         // SAFETY: `alloc_fn` will only be used with `size != 0`.
-        let alloc_fn = |layout| unsafe { alloc::alloc(layout) };
-        let alloc_bytes = MiriAllocBytes::alloc_with(size.try_into().unwrap(), align, alloc_fn)
+        let alloc_fn = |layout, params: &MiriAllocParams| unsafe {
+            match params {
+                MiriAllocParams::Global => alloc::alloc(layout),
+                #[cfg(target_os = "linux")]
+                MiriAllocParams::Isolated(alloc) => alloc.borrow_mut().alloc(layout),
+            }
+        };
+        let alloc_bytes = MiriAllocBytes::alloc_with(size.to_u64(), align, params, alloc_fn)
             .unwrap_or_else(|()| {
                 panic!("Miri ran out of memory: cannot create allocation of {size} bytes")
             });
@@ -100,12 +137,18 @@ impl AllocBytes for MiriAllocBytes {
         alloc_bytes
     }
 
-    fn zeroed(size: Size, align: Align) -> Option<Self> {
+    fn zeroed(size: Size, align: Align, params: MiriAllocParams) -> Option<Self> {
         let size = size.bytes();
         let align = align.bytes();
         // SAFETY: `alloc_fn` will only be used with `size != 0`.
-        let alloc_fn = |layout| unsafe { alloc::alloc_zeroed(layout) };
-        MiriAllocBytes::alloc_with(size, align, alloc_fn).ok()
+        let alloc_fn = |layout, params: &MiriAllocParams| unsafe {
+            match params {
+                MiriAllocParams::Global => alloc::alloc_zeroed(layout),
+                #[cfg(target_os = "linux")]
+                MiriAllocParams::Isolated(alloc) => alloc.borrow_mut().alloc_zeroed(layout),
+            }
+        };
+        MiriAllocBytes::alloc_with(size, align, params, alloc_fn).ok()
     }
 
     fn as_mut_ptr(&mut self) -> *mut u8 {
diff --git a/src/tools/miri/src/alloc/isolated_alloc.rs b/src/tools/miri/src/alloc/isolated_alloc.rs
new file mode 100644
index 00000000000..3a7879f372a
--- /dev/null
+++ b/src/tools/miri/src/alloc/isolated_alloc.rs
@@ -0,0 +1,386 @@
+use std::alloc::{self, Layout};
+
+use rustc_index::bit_set::DenseBitSet;
+
+/// How many bytes of memory each bit in the bitset represents.
+const COMPRESSION_FACTOR: usize = 4;
+
+/// A dedicated allocator for interpreter memory contents, ensuring they are stored on dedicated
+/// pages (not mixed with Miri's own memory). This is used in native-lib mode.
+#[derive(Debug)]
+pub struct IsolatedAlloc {
+    /// Pointers to page-aligned memory that has been claimed by the allocator.
+    /// Every pointer here must point to a page-sized allocation claimed via
+    /// the global allocator. These pointers are used for "small" allocations.
+    page_ptrs: Vec<*mut u8>,
+    /// Metadata about which bytes have been allocated on each page. The length
+    /// of this vector must be the same as that of `page_ptrs`, and the domain
+    /// size of the bitset must be exactly `page_size / COMPRESSION_FACTOR`.
+    ///
+    /// Conceptually, each bit of the bitset represents the allocation status of
+    /// one n-byte chunk on the corresponding element of `page_ptrs`. Thus,
+    /// indexing into it should be done with a value one-nth of the corresponding
+    /// offset on the matching `page_ptrs` element (n = `COMPRESSION_FACTOR`).
+    page_infos: Vec<DenseBitSet<usize>>,
+    /// Pointers to multiple-page-sized allocations. These must also be page-aligned,
+    /// with their size stored as the second element of the vector.
+    huge_ptrs: Vec<(*mut u8, usize)>,
+    /// The host (not emulated) page size.
+    page_size: usize,
+}
+
+impl IsolatedAlloc {
+    /// Creates an empty allocator.
+    pub fn new() -> Self {
+        Self {
+            page_ptrs: Vec::new(),
+            huge_ptrs: Vec::new(),
+            page_infos: Vec::new(),
+            // SAFETY: `sysconf(_SC_PAGESIZE)` is always safe to call at runtime
+            // See https://www.man7.org/linux/man-pages/man3/sysconf.3.html
+            page_size: unsafe { libc::sysconf(libc::_SC_PAGESIZE).try_into().unwrap() },
+        }
+    }
+
+    /// For simplicity, we serve small allocations in multiples of COMPRESSION_FACTOR
+    /// bytes with at least that alignment.
+    #[inline]
+    fn normalized_layout(layout: Layout) -> Layout {
+        let align =
+            if layout.align() < COMPRESSION_FACTOR { COMPRESSION_FACTOR } else { layout.align() };
+        let size = layout.size().next_multiple_of(COMPRESSION_FACTOR);
+        Layout::from_size_align(size, align).unwrap()
+    }
+
+    /// Returns the layout used to allocate the pages that hold small allocations.
+    #[inline]
+    fn page_layout(&self) -> Layout {
+        Layout::from_size_align(self.page_size, self.page_size).unwrap()
+    }
+
+    /// If the allocation is greater than a page, then round to the nearest page #.
+    #[inline]
+    fn huge_normalized_layout(layout: Layout, page_size: usize) -> Layout {
+        // Allocate in page-sized chunks
+        let size = layout.size().next_multiple_of(page_size);
+        // And make sure the align is at least one page
+        let align = std::cmp::max(layout.align(), page_size);
+        Layout::from_size_align(size, align).unwrap()
+    }
+
+    /// Determined whether a given normalized (size, align) should be sent to
+    /// `alloc_huge` / `dealloc_huge`.
+    #[inline]
+    fn is_huge_alloc(&self, layout: &Layout) -> bool {
+        layout.align() > self.page_size / 2 || layout.size() >= self.page_size / 2
+    }
+
+    /// Allocates memory as described in `Layout`. This memory should be deallocated
+    /// by calling `dealloc` on this same allocator.
+    ///
+    /// SAFETY: See `alloc::alloc()`
+    pub unsafe fn alloc(&mut self, layout: Layout) -> *mut u8 {
+        // SAFETY: Upheld by caller
+        unsafe { self.allocate(layout, false) }
+    }
+
+    /// Same as `alloc`, but zeroes out the memory.
+    ///
+    /// SAFETY: See `alloc::alloc_zeroed()`
+    pub unsafe fn alloc_zeroed(&mut self, layout: Layout) -> *mut u8 {
+        // SAFETY: Upheld by caller
+        unsafe { self.allocate(layout, true) }
+    }
+
+    /// Abstracts over the logic of `alloc_zeroed` vs `alloc`, as determined by
+    /// the `zeroed` argument.
+    ///
+    /// SAFETY: See `alloc::alloc()`, with the added restriction that `page_size`
+    /// corresponds to the host pagesize.
+    unsafe fn allocate(&mut self, layout: Layout, zeroed: bool) -> *mut u8 {
+        let layout = IsolatedAlloc::normalized_layout(layout);
+        if self.is_huge_alloc(&layout) {
+            // SAFETY: Validity of `layout` upheld by caller; we checked that
+            // the size and alignment are appropriate for being a huge alloc
+            unsafe { self.alloc_huge(layout, zeroed) }
+        } else {
+            for (&mut page, pinfo) in std::iter::zip(&mut self.page_ptrs, &mut self.page_infos) {
+                // SAFETY: The value in `self.page_size` is used to allocate
+                // `page`, with page alignment
+                if let Some(ptr) =
+                    unsafe { Self::alloc_small(self.page_size, layout, page, pinfo, zeroed) }
+                {
+                    return ptr;
+                }
+            }
+
+            // We get here only if there's no space in our existing pages
+            let page_size = self.page_size;
+            // Add another page and allocate from it; this cannot fail since the
+            // new page is empty and we already asserted it fits into a page
+            let (page, pinfo) = self.add_page();
+
+            // SAFETY: See comment on `alloc_from_page` above
+            unsafe { Self::alloc_small(page_size, layout, page, pinfo, zeroed).unwrap() }
+        }
+    }
+
+    /// Used internally by `allocate` to abstract over some logic.
+    ///
+    /// SAFETY: `page` must be a page-aligned pointer to an allocated page,
+    /// where the allocation is (at least) `page_size` bytes.
+    unsafe fn alloc_small(
+        page_size: usize,
+        layout: Layout,
+        page: *mut u8,
+        pinfo: &mut DenseBitSet<usize>,
+        zeroed: bool,
+    ) -> Option<*mut u8> {
+        // Check every alignment-sized block and see if there exists a `size`
+        // chunk of empty space i.e. forall idx . !pinfo.contains(idx / n)
+        for offset in (0..page_size).step_by(layout.align()) {
+            let offset_pinfo = offset / COMPRESSION_FACTOR;
+            let size_pinfo = layout.size() / COMPRESSION_FACTOR;
+            // DenseBitSet::contains() panics if the index is out of bounds
+            if pinfo.domain_size() < offset_pinfo + size_pinfo {
+                break;
+            }
+            if !pinfo.contains_any(offset_pinfo..offset_pinfo + size_pinfo) {
+                pinfo.insert_range(offset_pinfo..offset_pinfo + size_pinfo);
+                // SAFETY: We checked the available bytes after `idx` in the call
+                // to `domain_size` above and asserted there are at least `idx +
+                // layout.size()` bytes available and unallocated after it.
+                // `page` must point to the start of the page, so adding `idx`
+                // is safe per the above.
+                unsafe {
+                    let ptr = page.add(offset);
+                    if zeroed {
+                        // Only write the bytes we were specifically asked to
+                        // zero out, even if we allocated more
+                        ptr.write_bytes(0, layout.size());
+                    }
+                    return Some(ptr);
+                }
+            }
+        }
+        None
+    }
+
+    /// Expands the available memory pool by adding one page.
+    fn add_page(&mut self) -> (*mut u8, &mut DenseBitSet<usize>) {
+        // SAFETY: The system page size, which is the layout size, cannot be 0
+        let page_ptr = unsafe { alloc::alloc(self.page_layout()) };
+        // `page_infos` has to have one bit for each `COMPRESSION_FACTOR`-sized chunk of bytes in the page.
+        assert!(self.page_size % COMPRESSION_FACTOR == 0);
+        self.page_infos.push(DenseBitSet::new_empty(self.page_size / COMPRESSION_FACTOR));
+        self.page_ptrs.push(page_ptr);
+        (page_ptr, self.page_infos.last_mut().unwrap())
+    }
+
+    /// Allocates in multiples of one page on the host system.
+    ///
+    /// SAFETY: Same as `alloc()`.
+    unsafe fn alloc_huge(&mut self, layout: Layout, zeroed: bool) -> *mut u8 {
+        let layout = IsolatedAlloc::huge_normalized_layout(layout, self.page_size);
+        // SAFETY: Upheld by caller
+        let ret =
+            unsafe { if zeroed { alloc::alloc_zeroed(layout) } else { alloc::alloc(layout) } };
+        self.huge_ptrs.push((ret, layout.size()));
+        ret
+    }
+
+    /// Deallocates a pointer from this allocator.
+    ///
+    /// SAFETY: This pointer must have been allocated by calling `alloc()` (or
+    /// `alloc_zeroed()`) with the same layout as the one passed on this same
+    /// `IsolatedAlloc`.
+    pub unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
+        let layout = IsolatedAlloc::normalized_layout(layout);
+
+        if self.is_huge_alloc(&layout) {
+            // SAFETY: Partly upheld by caller, and we checked that the size
+            // and align, meaning this must have been allocated via `alloc_huge`
+            unsafe {
+                self.dealloc_huge(ptr, layout);
+            }
+        } else {
+            // SAFETY: It's not a huge allocation, therefore it is a small one.
+            let idx = unsafe { self.dealloc_small(ptr, layout) };
+
+            // This may have been the last allocation on this page. If so, free the entire page.
+            // FIXME: this can lead to threshold effects, we should probably add some form
+            // of hysteresis.
+            if self.page_infos[idx].is_empty() {
+                self.page_infos.remove(idx);
+                let page_ptr = self.page_ptrs.remove(idx);
+                // SAFETY: We checked that there are no outstanding allocations
+                // from us pointing to this page, and we know it was allocated
+                // with this layout
+                unsafe {
+                    alloc::dealloc(page_ptr, self.page_layout());
+                }
+            }
+        }
+    }
+
+    /// Returns the index of the page that this was deallocated from
+    ///
+    /// SAFETY: the pointer must have been allocated with `alloc_small`.
+    unsafe fn dealloc_small(&mut self, ptr: *mut u8, layout: Layout) -> usize {
+        // Offset of the pointer in the current page
+        let offset = ptr.addr() % self.page_size;
+        // And then the page's base address
+        let page_addr = ptr.addr() - offset;
+
+        // Find the page this allocation belongs to.
+        // This could be made faster if the list was sorted -- the allocator isn't fully optimized at the moment.
+        let pinfo = std::iter::zip(&mut self.page_ptrs, &mut self.page_infos)
+            .enumerate()
+            .find(|(_, (page, _))| page.addr() == page_addr);
+        let Some((idx_of_pinfo, (_, pinfo))) = pinfo else {
+            panic!("Freeing in an unallocated page: {ptr:?}\nHolding pages {:?}", self.page_ptrs)
+        };
+        // Mark this range as available in the page.
+        let ptr_idx_pinfo = offset / COMPRESSION_FACTOR;
+        let size_pinfo = layout.size() / COMPRESSION_FACTOR;
+        for idx in ptr_idx_pinfo..ptr_idx_pinfo + size_pinfo {
+            pinfo.remove(idx);
+        }
+        idx_of_pinfo
+    }
+
+    /// SAFETY: Same as `dealloc()` with the added requirement that `layout`
+    /// must ask for a size larger than the host pagesize.
+    unsafe fn dealloc_huge(&mut self, ptr: *mut u8, layout: Layout) {
+        let layout = IsolatedAlloc::huge_normalized_layout(layout, self.page_size);
+        // Find the pointer matching in address with the one we got
+        let idx = self
+            .huge_ptrs
+            .iter()
+            .position(|pg| ptr.addr() == pg.0.addr())
+            .expect("Freeing unallocated pages");
+        // And kick it from the list
+        self.huge_ptrs.remove(idx);
+        // SAFETY: Caller ensures validity of the layout
+        unsafe {
+            alloc::dealloc(ptr, layout);
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    /// Helper function to assert that all bytes from `ptr` to `ptr.add(layout.size())`
+    /// are zeroes.
+    ///
+    /// SAFETY: `ptr` must have been allocated with `layout`.
+    unsafe fn assert_zeroes(ptr: *mut u8, layout: Layout) {
+        // SAFETY: Caller ensures this is valid
+        unsafe {
+            for ofs in 0..layout.size() {
+                assert_eq!(0, ptr.add(ofs).read());
+            }
+        }
+    }
+
+    /// Check that small (sub-pagesize) allocations are properly zeroed out.
+    #[test]
+    fn small_zeroes() {
+        let mut alloc = IsolatedAlloc::new();
+        // 256 should be less than the pagesize on *any* system
+        let layout = Layout::from_size_align(256, 32).unwrap();
+        // SAFETY: layout size is the constant above, not 0
+        let ptr = unsafe { alloc.alloc_zeroed(layout) };
+        // SAFETY: `ptr` was just allocated with `layout`
+        unsafe {
+            assert_zeroes(ptr, layout);
+            alloc.dealloc(ptr, layout);
+        }
+    }
+
+    /// Check that huge (> 1 page) allocations are properly zeroed out also.
+    #[test]
+    fn huge_zeroes() {
+        let mut alloc = IsolatedAlloc::new();
+        // 16k is about as big as pages get e.g. on macos aarch64
+        let layout = Layout::from_size_align(16 * 1024, 128).unwrap();
+        // SAFETY: layout size is the constant above, not 0
+        let ptr = unsafe { alloc.alloc_zeroed(layout) };
+        // SAFETY: `ptr` was just allocated with `layout`
+        unsafe {
+            assert_zeroes(ptr, layout);
+            alloc.dealloc(ptr, layout);
+        }
+    }
+
+    /// Check that repeatedly reallocating the same memory will still zero out
+    /// everything properly
+    #[test]
+    fn repeated_allocs() {
+        let mut alloc = IsolatedAlloc::new();
+        // Try both sub-pagesize allocs and those larger than / equal to a page
+        for sz in (1..=(16 * 1024)).step_by(128) {
+            let layout = Layout::from_size_align(sz, 1).unwrap();
+            // SAFETY: all sizes in the range above are nonzero as we start from 1
+            let ptr = unsafe { alloc.alloc_zeroed(layout) };
+            // SAFETY: `ptr` was just allocated with `layout`, which was used
+            // to bound the access size
+            unsafe {
+                assert_zeroes(ptr, layout);
+                ptr.write_bytes(255, sz);
+                alloc.dealloc(ptr, layout);
+            }
+        }
+    }
+
+    /// Checks that allocations of different sizes do not overlap, then for memory
+    /// leaks that might have occurred.
+    #[test]
+    fn check_leaks_and_overlaps() {
+        let mut alloc = IsolatedAlloc::new();
+
+        // Some random sizes and aligns
+        let mut sizes = vec![32; 10];
+        sizes.append(&mut vec![15; 4]);
+        sizes.append(&mut vec![256; 12]);
+        // Give it some multi-page ones too
+        sizes.append(&mut vec![32 * 1024; 4]);
+
+        // Matching aligns for the sizes
+        let mut aligns = vec![16; 12];
+        aligns.append(&mut vec![256; 2]);
+        aligns.append(&mut vec![64; 12]);
+        aligns.append(&mut vec![4096; 4]);
+
+        // Make sure we didn't mess up in the test itself!
+        assert_eq!(sizes.len(), aligns.len());
+
+        // Aggregate the sizes and aligns into a vec of layouts, then allocate them
+        let layouts: Vec<_> = std::iter::zip(sizes, aligns)
+            .map(|(sz, al)| Layout::from_size_align(sz, al).unwrap())
+            .collect();
+        // SAFETY: all sizes specified in `sizes` are nonzero
+        let ptrs: Vec<_> =
+            layouts.iter().map(|layout| unsafe { alloc.alloc_zeroed(*layout) }).collect();
+
+        for (&ptr, &layout) in std::iter::zip(&ptrs, &layouts) {
+            // We requested zeroed allocations, so check that that's true
+            // Then write to the end of the current size, so if the allocs
+            // overlap (or the zeroing is wrong) then `assert_zeroes` will panic.
+            // Also check that the alignment we asked for was respected
+            assert_eq!(ptr.addr().strict_rem(layout.align()), 0);
+            // SAFETY: each `ptr` was allocated with its corresponding `layout`,
+            // which is used to bound the access size
+            unsafe {
+                assert_zeroes(ptr, layout);
+                ptr.write_bytes(255, layout.size());
+                alloc.dealloc(ptr, layout);
+            }
+        }
+
+        // And then verify that no memory was leaked after all that
+        assert!(alloc.page_ptrs.is_empty() && alloc.huge_ptrs.is_empty());
+    }
+}
diff --git a/src/tools/miri/src/alloc/mod.rs b/src/tools/miri/src/alloc/mod.rs
new file mode 100644
index 00000000000..3be885920d2
--- /dev/null
+++ b/src/tools/miri/src/alloc/mod.rs
@@ -0,0 +1,5 @@
+mod alloc_bytes;
+#[cfg(target_os = "linux")]
+pub mod isolated_alloc;
+
+pub use self::alloc_bytes::{MiriAllocBytes, MiriAllocParams};
diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs
index dd389d97cdc..12a320b9676 100644
--- a/src/tools/miri/src/alloc_addresses/mod.rs
+++ b/src/tools/miri/src/alloc_addresses/mod.rs
@@ -135,11 +135,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if this.machine.native_lib.is_some() {
             // In native lib mode, we use the "real" address of the bytes for this allocation.
             // This ensures the interpreted program and native code have the same view of memory.
+            let params = this.machine.get_default_alloc_params();
             let base_ptr = match info.kind {
                 AllocKind::LiveData => {
                     if memory_kind == MiriMemoryKind::Global.into() {
                         // For new global allocations, we always pre-allocate the memory to be able use the machine address directly.
-                        let prepared_bytes = MiriAllocBytes::zeroed(info.size, info.align)
+                        let prepared_bytes = MiriAllocBytes::zeroed(info.size, info.align, params)
                             .unwrap_or_else(|| {
                                 panic!("Miri ran out of memory: cannot create allocation of {size:?} bytes", size = info.size)
                             });
@@ -158,8 +159,11 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 }
                 AllocKind::Function | AllocKind::VTable => {
                     // Allocate some dummy memory to get a unique address for this function/vtable.
-                    let alloc_bytes =
-                        MiriAllocBytes::from_bytes(&[0u8; 1], Align::from_bytes(1).unwrap());
+                    let alloc_bytes = MiriAllocBytes::from_bytes(
+                        &[0u8; 1],
+                        Align::from_bytes(1).unwrap(),
+                        params,
+                    );
                     let ptr = alloc_bytes.as_ptr();
                     // Leak the underlying memory to ensure it remains unique.
                     std::mem::forget(alloc_bytes);
@@ -168,7 +172,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 AllocKind::Dead => unreachable!(),
             };
             // We don't have to expose this pointer yet, we do that in `prepare_for_native_call`.
-            return interp_ok(base_ptr.addr().try_into().unwrap());
+            return interp_ok(base_ptr.addr().to_u64());
         }
         // We are not in native lib mode, so we control the addresses ourselves.
         if let Some((reuse_addr, clock)) = global_state.reuse.take_addr(
@@ -429,7 +433,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             prepared_alloc_bytes.copy_from_slice(bytes);
             interp_ok(prepared_alloc_bytes)
         } else {
-            interp_ok(MiriAllocBytes::from_bytes(std::borrow::Cow::Borrowed(bytes), align))
+            let params = this.machine.get_default_alloc_params();
+            interp_ok(MiriAllocBytes::from_bytes(std::borrow::Cow::Borrowed(bytes), align, params))
         }
     }
 
diff --git a/src/tools/miri/src/alloc_addresses/reuse_pool.rs b/src/tools/miri/src/alloc_addresses/reuse_pool.rs
index 29d4f2bb7b0..ab6aaed5e3e 100644
--- a/src/tools/miri/src/alloc_addresses/reuse_pool.rs
+++ b/src/tools/miri/src/alloc_addresses/reuse_pool.rs
@@ -4,6 +4,7 @@ use rand::Rng;
 use rustc_abi::{Align, Size};
 
 use crate::concurrency::VClock;
+use crate::helpers::ToUsize as _;
 use crate::{MemoryKind, MiriConfig, ThreadId};
 
 const MAX_POOL_SIZE: usize = 64;
@@ -46,7 +47,7 @@ impl ReusePool {
     }
 
     fn subpool(&mut self, align: Align) -> &mut Vec<(u64, Size, ThreadId, VClock)> {
-        let pool_idx: usize = align.bytes().trailing_zeros().try_into().unwrap();
+        let pool_idx: usize = align.bytes().trailing_zeros().to_usize();
         if self.pool.len() <= pool_idx {
             self.pool.resize(pool_idx + 1, Vec::new());
         }
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 469fc264970..0121472d330 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -281,7 +281,9 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls {
                             }
                             let codegen_fn_attrs = tcx.codegen_fn_attrs(local_def_id);
                             if codegen_fn_attrs.contains_extern_indicator()
-                                || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::USED)
+                                || codegen_fn_attrs
+                                    .flags
+                                    .contains(CodegenFnAttrFlags::USED_COMPILER)
                                 || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
                             {
                                 Some((
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
index f5a0013047a..7b4c533cfae 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
@@ -504,7 +504,7 @@ impl DisplayFmt {
         if let Some(perm) = perm {
             format!(
                 "{ac}{st}",
-                ac = if perm.is_initialized() { self.accessed.yes } else { self.accessed.no },
+                ac = if perm.is_accessed() { self.accessed.yes } else { self.accessed.no },
                 st = perm.permission().short_name(),
             )
         } else {
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
index f3e32e75f2f..411ae89da90 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
@@ -3,6 +3,8 @@ use rustc_middle::mir::{Mutability, RetagKind};
 use rustc_middle::ty::layout::HasTypingEnv;
 use rustc_middle::ty::{self, Ty};
 
+use self::foreign_access_skipping::IdempotentForeignAccess;
+use self::tree::LocationState;
 use crate::borrow_tracker::{GlobalState, GlobalStateInner, ProtectorKind};
 use crate::concurrency::data_race::NaReadType;
 use crate::*;
@@ -95,7 +97,7 @@ impl<'tcx> Tree {
     /// A tag just lost its protector.
     ///
     /// This emits a special kind of access that is only applied
-    /// to initialized locations, as a protection against other
+    /// to accessed locations, as a protection against other
     /// tags not having been made aware of the existence of this
     /// protector.
     pub fn release_protector(
@@ -113,16 +115,19 @@ impl<'tcx> Tree {
 
 /// Policy for a new borrow.
 #[derive(Debug, Clone, Copy)]
-struct NewPermission {
-    /// Which permission should the pointer start with.
-    initial_state: Permission,
+pub struct NewPermission {
+    /// Permission for the frozen part of the range.
+    freeze_perm: Permission,
+    /// Whether a read access should be performed on the frozen part on a retag.
+    freeze_access: bool,
+    /// Permission for the non-frozen part of the range.
+    nonfreeze_perm: Permission,
+    /// Whether a read access should be performed on the non-frozen
+    /// part on a retag.
+    nonfreeze_access: bool,
     /// Whether this pointer is part of the arguments of a function call.
     /// `protector` is `Some(_)` for all pointers marked `noalias`.
     protector: Option<ProtectorKind>,
-    /// Whether a read should be performed on a retag.  This should be `false`
-    /// for `Cell` because this could cause data races when using thread-safe
-    /// data types like `Mutex<T>`.
-    initial_read: bool,
 }
 
 impl<'tcx> NewPermission {
@@ -133,27 +138,42 @@ impl<'tcx> NewPermission {
         kind: RetagKind,
         cx: &crate::MiriInterpCx<'tcx>,
     ) -> Option<Self> {
-        let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.typing_env());
         let ty_is_unpin = pointee.is_unpin(*cx.tcx, cx.typing_env());
         let is_protected = kind == RetagKind::FnEntry;
-        // As demonstrated by `tests/fail/tree_borrows/reservedim_spurious_write.rs`,
-        // interior mutability and protectors interact poorly.
-        // To eliminate the case of Protected Reserved IM we override interior mutability
-        // in the case of a protected reference: protected references are always considered
-        // "freeze" in their reservation phase.
-        let (initial_state, initial_read) = match mutability {
+        let protector = is_protected.then_some(ProtectorKind::StrongProtector);
+
+        Some(match mutability {
             Mutability::Mut if ty_is_unpin =>
-                (Permission::new_reserved(ty_is_freeze, is_protected), true),
-            Mutability::Not if ty_is_freeze => (Permission::new_frozen(), true),
-            Mutability::Not if !ty_is_freeze => (Permission::new_cell(), false),
-            // Raw pointers never enter this function so they are not handled.
-            // However raw pointers are not the only pointers that take the parent
-            // tag, this also happens for `!Unpin` `&mut`s, which are excluded above.
+                NewPermission {
+                    freeze_perm: Permission::new_reserved(
+                        /* ty_is_freeze */ true,
+                        is_protected,
+                    ),
+                    freeze_access: true,
+                    nonfreeze_perm: Permission::new_reserved(
+                        /* ty_is_freeze */ false,
+                        is_protected,
+                    ),
+                    // If we have a mutable reference, then the non-frozen part will
+                    // have state `ReservedIM` or `Reserved`, which can have an initial read access
+                    // performed on it because you cannot have multiple mutable borrows.
+                    nonfreeze_access: true,
+                    protector,
+                },
+            Mutability::Not =>
+                NewPermission {
+                    freeze_perm: Permission::new_frozen(),
+                    freeze_access: true,
+                    nonfreeze_perm: Permission::new_cell(),
+                    // If it is a shared reference, then the non-frozen
+                    // part will have state `Cell`, which should not have an initial access,
+                    // as this can cause data races when using thread-safe data types like
+                    // `Mutex<T>`.
+                    nonfreeze_access: false,
+                    protector,
+                },
             _ => return None,
-        };
-
-        let protector = is_protected.then_some(ProtectorKind::StrongProtector);
-        Some(Self { initial_state, protector, initial_read })
+        })
     }
 
     /// Compute permission for `Box`-like type (`Box` always, and also `Unique` if enabled).
@@ -168,13 +188,17 @@ impl<'tcx> NewPermission {
         pointee.is_unpin(*cx.tcx, cx.typing_env()).then_some(()).map(|()| {
             // Regular `Unpin` box, give it `noalias` but only a weak protector
             // because it is valid to deallocate it within the function.
-            let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.typing_env());
-            let protected = kind == RetagKind::FnEntry;
-            let initial_state = Permission::new_reserved(ty_is_freeze, protected);
-            Self {
-                initial_state,
-                protector: protected.then_some(ProtectorKind::WeakProtector),
-                initial_read: true,
+            let is_protected = kind == RetagKind::FnEntry;
+            let protector = is_protected.then_some(ProtectorKind::WeakProtector);
+            NewPermission {
+                freeze_perm: Permission::new_reserved(/* ty_is_freeze */ true, is_protected),
+                freeze_access: true,
+                nonfreeze_perm: Permission::new_reserved(
+                    /* ty_is_freeze */ false,
+                    is_protected,
+                ),
+                nonfreeze_access: true,
+                protector,
             }
         })
     }
@@ -194,8 +218,6 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         new_tag: BorTag,
     ) -> InterpResult<'tcx, Option<Provenance>> {
         let this = self.eval_context_mut();
-        // Make sure the new permission makes sense as the initial permission of a fresh tag.
-        assert!(new_perm.initial_state.is_initial());
         // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050).
         this.check_ptr_access(place.ptr(), ptr_size, CheckInAllocMsg::Dereferenceable)?;
 
@@ -206,7 +228,13 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             let global = this.machine.borrow_tracker.as_ref().unwrap().borrow();
             let ty = place.layout.ty;
             if global.tracked_pointer_tags.contains(&new_tag) {
-                let kind_str = format!("initial state {} (pointee type {ty})", new_perm.initial_state);
+                 let ty_is_freeze = ty.is_freeze(*this.tcx, this.typing_env());
+                 let kind_str =
+                     if ty_is_freeze {
+                         format!("initial state {} (pointee type {ty})", new_perm.freeze_perm)
+                     } else {
+                         format!("initial state {}/{} outside/inside UnsafeCell (pointee type {ty})", new_perm.freeze_perm, new_perm.nonfreeze_perm)
+                     };
                 this.emit_diagnostic(NonHaltingDiagnostic::CreatedPointerTag(
                     new_tag.inner(),
                     Some(kind_str),
@@ -285,43 +313,103 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let span = this.machine.current_span();
         let alloc_extra = this.get_alloc_extra(alloc_id)?;
-        let range = alloc_range(base_offset, ptr_size);
         let mut tree_borrows = alloc_extra.borrow_tracker_tb().borrow_mut();
 
-        // All reborrows incur a (possibly zero-sized) read access to the parent
-        if new_perm.initial_read {
-            tree_borrows.perform_access(
-                orig_tag,
-                Some((range, AccessKind::Read, diagnostics::AccessCause::Reborrow)),
-                this.machine.borrow_tracker.as_ref().unwrap(),
-                alloc_id,
-                this.machine.current_span(),
-            )?;
-        }
+        // Store initial permissions and their corresponding range.
+        let mut perms_map: RangeMap<LocationState> = RangeMap::new(
+            ptr_size,
+            LocationState::new_accessed(Permission::new_disabled(), IdempotentForeignAccess::None), // this will be overwritten
+        );
+        // Keep track of whether the node has any part that allows for interior mutability.
+        // FIXME: This misses `PhantomData<UnsafeCell<T>>` which could be considered a marker
+        // for requesting interior mutability.
+        let mut has_unsafe_cell = false;
+
+        // When adding a new node, the SIFA of its parents needs to be updated, potentially across
+        // the entire memory range. For the parts that are being accessed below, the access itself
+        // trivially takes care of that. However, we have to do some more work to also deal with
+        // the parts that are not being accessed. Specifically what we do is that we
+        // call `update_last_accessed_after_retag` on the SIFA of the permission set for the part of
+        // memory outside `perm_map` -- so that part is definitely taken care of. The remaining concern
+        // is the part of memory that is in the range of `perms_map`, but not accessed below.
+        // There we have two cases:
+        // * If we do have an `UnsafeCell` (`has_unsafe_cell` becomes true), then the non-accessed part
+        //   uses `nonfreeze_perm`, so the `nonfreeze_perm` initialized parts are also fine. We enforce
+        //   the `freeze_perm` parts to be accessed, and thus everything is taken care of.
+        // * If there is no `UnsafeCell`, then `freeze_perm` is used everywhere (both inside and outside the initial range),
+        //   and we update everything to have the `freeze_perm`'s SIFA, so there are no issues. (And this assert below is not
+        //   actually needed in this case).
+        assert!(new_perm.freeze_access);
+
+        let protected = new_perm.protector.is_some();
+        this.visit_freeze_sensitive(place, ptr_size, |range, frozen| {
+            has_unsafe_cell = has_unsafe_cell || !frozen;
+
+            // We are only ever `Frozen` inside the frozen bits.
+            let (perm, access) = if frozen {
+                (new_perm.freeze_perm, new_perm.freeze_access)
+            } else {
+                (new_perm.nonfreeze_perm, new_perm.nonfreeze_access)
+            };
+
+            // Store initial permissions.
+            for (_loc_range, loc) in perms_map.iter_mut(range.start, range.size) {
+                let sifa = perm.strongest_idempotent_foreign_access(protected);
+                // NOTE: Currently, `access` is false if and only if `perm` is Cell, so this `if`
+                // doesn't not change whether any code is UB or not. We could just always use
+                // `new_accessed` and everything would stay the same. But that seems conceptually
+                // odd, so we keep the initial "accessed" bit of the `LocationState` in sync with whether
+                // a read access is performed below.
+                if access {
+                    *loc = LocationState::new_accessed(perm, sifa);
+                } else {
+                    *loc = LocationState::new_non_accessed(perm, sifa);
+                }
+            }
+
+            // Some reborrows incur a read access to the parent.
+            if access {
+                // Adjust range to be relative to allocation start (rather than to `place`).
+                let mut range_in_alloc = range;
+                range_in_alloc.start += base_offset;
+
+                tree_borrows.perform_access(
+                    orig_tag,
+                    Some((range_in_alloc, AccessKind::Read, diagnostics::AccessCause::Reborrow)),
+                    this.machine.borrow_tracker.as_ref().unwrap(),
+                    alloc_id,
+                    this.machine.current_span(),
+                )?;
+
+                // Also inform the data race model (but only if any bytes are actually affected).
+                if range.size.bytes() > 0 {
+                    if let Some(data_race) = alloc_extra.data_race.as_vclocks_ref() {
+                        data_race.read(
+                            alloc_id,
+                            range_in_alloc,
+                            NaReadType::Retag,
+                            Some(place.layout.ty),
+                            &this.machine,
+                        )?
+                    }
+                }
+            }
+            interp_ok(())
+        })?;
+
         // Record the parent-child pair in the tree.
         tree_borrows.new_child(
+            base_offset,
             orig_tag,
             new_tag,
-            new_perm.initial_state,
-            range,
+            perms_map,
+            // Allow lazily writing to surrounding data if we found an `UnsafeCell`.
+            if has_unsafe_cell { new_perm.nonfreeze_perm } else { new_perm.freeze_perm },
+            protected,
             span,
-            new_perm.protector.is_some(),
         )?;
         drop(tree_borrows);
 
-        // Also inform the data race model (but only if any bytes are actually affected).
-        if range.size.bytes() > 0 && new_perm.initial_read {
-            if let Some(data_race) = alloc_extra.data_race.as_vclocks_ref() {
-                data_race.read(
-                    alloc_id,
-                    range,
-                    NaReadType::Retag,
-                    Some(place.layout.ty),
-                    &this.machine,
-                )?;
-            }
-        }
-
         interp_ok(Some(Provenance::Concrete { alloc_id, tag: new_tag }))
     }
 
@@ -508,15 +596,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn tb_protect_place(&mut self, place: &MPlaceTy<'tcx>) -> InterpResult<'tcx, MPlaceTy<'tcx>> {
         let this = self.eval_context_mut();
 
-        // Note: if we were to inline `new_reserved` below we would find out that
-        // `ty_is_freeze` is eventually unused because it appears in a `ty_is_freeze || true`.
-        // We are nevertheless including it here for clarity.
-        let ty_is_freeze = place.layout.ty.is_freeze(*this.tcx, this.typing_env());
         // Retag it. With protection! That is the entire point.
         let new_perm = NewPermission {
-            initial_state: Permission::new_reserved(ty_is_freeze, /* protected */ true),
+            // Note: If we are creating a protected Reserved, which can
+            // never be ReservedIM, the value of the `ty_is_freeze`
+            // argument doesn't matter
+            // (`ty_is_freeze || true` in `new_reserved` will always be `true`).
+            freeze_perm: Permission::new_reserved(
+                /* ty_is_freeze */ true, /* protected */ true,
+            ),
+            freeze_access: true,
+            nonfreeze_perm: Permission::new_reserved(
+                /* ty_is_freeze */ false, /* protected */ true,
+            ),
+            nonfreeze_access: true,
             protector: Some(ProtectorKind::StrongProtector),
-            initial_read: true,
         };
         this.tb_retag_place(place, new_perm)
     }
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
index 087f6fc3f24..38863ca0734 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
@@ -94,6 +94,7 @@ impl PermissionPriv {
     }
 
     /// Reject `ReservedIM` that cannot exist in the presence of a protector.
+    #[cfg(test)]
     fn compatible_with_protector(&self) -> bool {
         // FIXME(TB-Cell): It is unclear what to do here.
         // `Cell` will occur with a protector but won't provide the guarantees
@@ -253,10 +254,6 @@ impl Permission {
     pub fn is_disabled(&self) -> bool {
         self.inner == Disabled
     }
-    /// Check if `self` is the post-child-write state of a pointer (is `Active`).
-    pub fn is_active(&self) -> bool {
-        self.inner == Active
-    }
     /// Check if `self` is the never-allow-writes-again state of a pointer (is `Frozen`).
     pub fn is_frozen(&self) -> bool {
         self.inner == Frozen
@@ -289,6 +286,11 @@ impl Permission {
     /// is a protector is relevant because being protected takes priority over being
     /// interior mutable)
     pub fn new_reserved(ty_is_freeze: bool, protected: bool) -> Self {
+        // As demonstrated by `tests/fail/tree_borrows/reservedim_spurious_write.rs`,
+        // interior mutability and protectors interact poorly.
+        // To eliminate the case of Protected Reserved IM we override interior mutability
+        // in the case of a protected reference: protected references are always considered
+        // "freeze" in their reservation phase.
         if ty_is_freeze || protected { Self::new_reserved_frz() } else { Self::new_reserved_im() }
     }
 
@@ -309,6 +311,7 @@ impl Permission {
     }
 
     /// Reject `ReservedIM` that cannot exist in the presence of a protector.
+    #[cfg(test)]
     pub fn compatible_with_protector(&self) -> bool {
         self.inner.compatible_with_protector()
     }
@@ -393,11 +396,6 @@ impl PermTransition {
         self.from <= self.to
     }
 
-    pub fn from(from: Permission, to: Permission) -> Option<Self> {
-        let t = Self { from: from.inner, to: to.inner };
-        t.is_possible().then_some(t)
-    }
-
     pub fn is_noop(self) -> bool {
         self.from == self.to
     }
@@ -407,11 +405,6 @@ impl PermTransition {
         (starting_point.inner == self.from).then_some(Permission { inner: self.to })
     }
 
-    /// Extract starting point of a transition
-    pub fn started(self) -> Permission {
-        Permission { inner: self.from }
-    }
-
     /// Determines if this transition would disable the permission.
     pub fn produces_disabled(self) -> bool {
         self.to == Disabled
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
index 47ccaadbb9e..48e4a19e263 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs
@@ -10,6 +10,7 @@
 //!   and the relative position of the access;
 //! - idempotency properties asserted in `perms.rs` (for optimizations)
 
+use std::ops::Range;
 use std::{fmt, mem};
 
 use rustc_abi::Size;
@@ -32,18 +33,18 @@ mod tests;
 /// Data for a single *location*.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub(super) struct LocationState {
-    /// A location is initialized when it is child-accessed for the first time (and the initial
+    /// A location is "accessed" when it is child-accessed for the first time (and the initial
     /// retag initializes the location for the range covered by the type), and it then stays
-    /// initialized forever.
-    /// For initialized locations, "permission" is the current permission. However, for
-    /// uninitialized locations, we still need to track the "future initial permission": this will
+    /// accessed forever.
+    /// For accessed locations, "permission" is the current permission. However, for
+    /// non-accessed locations, we still need to track the "future initial permission": this will
     /// start out to be `default_initial_perm`, but foreign accesses need to be taken into account.
     /// Crucially however, while transitions to `Disabled` would usually be UB if this location is
-    /// protected, that is *not* the case for uninitialized locations. Instead we just have a latent
+    /// protected, that is *not* the case for non-accessed locations. Instead we just have a latent
     /// "future initial permission" of `Disabled`, causing UB only if an access is ever actually
     /// performed.
-    /// Note that the tree root is also always initialized, as if the allocation was a write access.
-    initialized: bool,
+    /// Note that the tree root is also always accessed, as if the allocation was a write access.
+    accessed: bool,
     /// This pointer's current permission / future initial permission.
     permission: Permission,
     /// See `foreign_access_skipping.rs`.
@@ -58,30 +59,30 @@ impl LocationState {
     /// to any foreign access yet.
     /// The permission is not allowed to be `Active`.
     /// `sifa` is the (strongest) idempotent foreign access, see `foreign_access_skipping.rs`
-    fn new_uninit(permission: Permission, sifa: IdempotentForeignAccess) -> Self {
+    pub fn new_non_accessed(permission: Permission, sifa: IdempotentForeignAccess) -> Self {
         assert!(permission.is_initial() || permission.is_disabled());
-        Self { permission, initialized: false, idempotent_foreign_access: sifa }
+        Self { permission, accessed: false, idempotent_foreign_access: sifa }
     }
 
     /// Constructs a new initial state. It has not yet been subjected
     /// to any foreign access. However, it is already marked as having been accessed.
     /// `sifa` is the (strongest) idempotent foreign access, see `foreign_access_skipping.rs`
-    fn new_init(permission: Permission, sifa: IdempotentForeignAccess) -> Self {
-        Self { permission, initialized: true, idempotent_foreign_access: sifa }
+    pub fn new_accessed(permission: Permission, sifa: IdempotentForeignAccess) -> Self {
+        Self { permission, accessed: true, idempotent_foreign_access: sifa }
     }
 
-    /// Check if the location has been initialized, i.e. if it has
+    /// Check if the location has been accessed, i.e. if it has
     /// ever been accessed through a child pointer.
-    pub fn is_initialized(&self) -> bool {
-        self.initialized
+    pub fn is_accessed(&self) -> bool {
+        self.accessed
     }
 
     /// Check if the state can exist as the initial permission of a pointer.
     ///
-    /// Do not confuse with `is_initialized`, the two are almost orthogonal
-    /// as apart from `Active` which is not initial and must be initialized,
+    /// Do not confuse with `is_accessed`, the two are almost orthogonal
+    /// as apart from `Active` which is not initial and must be accessed,
     /// any other permission can have an arbitrary combination of being
-    /// initial/initialized.
+    /// initial/accessed.
     /// FIXME: when the corresponding `assert` in `tree_borrows/mod.rs` finally
     /// passes and can be uncommented, remove this `#[allow(dead_code)]`.
     #[cfg_attr(not(test), allow(dead_code))]
@@ -95,8 +96,8 @@ impl LocationState {
 
     /// Apply the effect of an access to one location, including
     /// - applying `Permission::perform_access` to the inner `Permission`,
-    /// - emitting protector UB if the location is initialized,
-    /// - updating the initialized status (child accesses produce initialized locations).
+    /// - emitting protector UB if the location is accessed,
+    /// - updating the accessed status (child accesses produce accessed locations).
     fn perform_access(
         &mut self,
         access_kind: AccessKind,
@@ -106,14 +107,14 @@ impl LocationState {
         let old_perm = self.permission;
         let transition = Permission::perform_access(access_kind, rel_pos, old_perm, protected)
             .ok_or(TransitionError::ChildAccessForbidden(old_perm))?;
-        self.initialized |= !rel_pos.is_foreign();
+        self.accessed |= !rel_pos.is_foreign();
         self.permission = transition.applied(old_perm).unwrap();
-        // Why do only initialized locations cause protector errors?
+        // Why do only accessed locations cause protector errors?
         // Consider two mutable references `x`, `y` into disjoint parts of
         // the same allocation. A priori, these may actually both be used to
         // access the entire allocation, as long as only reads occur. However,
         // a write to `y` needs to somehow record that `x` can no longer be used
-        // on that location at all. For these uninitialized locations (i.e., locations
+        // on that location at all. For these non-accessed locations (i.e., locations
         // that haven't been accessed with `x` yet), we track the "future initial state":
         // it defaults to whatever the initial state of the tag is,
         // but the access to `y` moves that "future initial state" of `x` to `Disabled`.
@@ -121,8 +122,8 @@ impl LocationState {
         // So clearly protectors shouldn't fire for such "future initial state" transitions.
         //
         // See the test `two_mut_protected_same_alloc` in `tests/pass/tree_borrows/tree-borrows.rs`
-        // for an example of safe code that would be UB if we forgot to check `self.initialized`.
-        if protected && self.initialized && transition.produces_disabled() {
+        // for an example of safe code that would be UB if we forgot to check `self.accessed`.
+        if protected && self.accessed && transition.produces_disabled() {
             return Err(TransitionError::ProtectedDisabled(old_perm));
         }
         Ok(transition)
@@ -157,11 +158,11 @@ impl LocationState {
                 self.idempotent_foreign_access.can_skip_foreign_access(happening_now);
             if self.permission.is_disabled() {
                 // A foreign access to a `Disabled` tag will have almost no observable effect.
-                // It's a theorem that `Disabled` node have no protected initialized children,
+                // It's a theorem that `Disabled` node have no protected accessed children,
                 // and so this foreign access will never trigger any protector.
-                // (Intuition: You're either protected initialized, and thus can't become Disabled
-                // or you're already Disabled protected, but not initialized, and then can't
-                // become initialized since that requires a child access, which Disabled blocks.)
+                // (Intuition: You're either protected accessed, and thus can't become Disabled
+                // or you're already Disabled protected, but not accessed, and then can't
+                // become accessed since that requires a child access, which Disabled blocks.)
                 // Further, the children will never be able to read or write again, since they
                 // have a `Disabled` parent. So this only affects diagnostics, such that the
                 // blocking write will still be identified directly, just at a different tag.
@@ -217,7 +218,7 @@ impl LocationState {
 impl fmt::Display for LocationState {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "{}", self.permission)?;
-        if !self.initialized {
+        if !self.accessed {
             write!(f, "?")?;
         }
         Ok(())
@@ -598,12 +599,15 @@ impl Tree {
         let rperms = {
             let mut perms = UniValMap::default();
             // We manually set it to `Active` on all in-bounds positions.
-            // We also ensure that it is initialized, so that no `Active` but
-            // not yet initialized nodes exist. Essentially, we pretend there
+            // We also ensure that it is accessed, so that no `Active` but
+            // not yet accessed nodes exist. Essentially, we pretend there
             // was a write that initialized these to `Active`.
             perms.insert(
                 root_idx,
-                LocationState::new_init(Permission::new_active(), IdempotentForeignAccess::None),
+                LocationState::new_accessed(
+                    Permission::new_active(),
+                    IdempotentForeignAccess::None,
+                ),
             );
             RangeMap::new(size, perms)
         };
@@ -612,20 +616,32 @@ impl Tree {
 }
 
 impl<'tcx> Tree {
-    /// Insert a new tag in the tree
-    pub fn new_child(
+    /// Insert a new tag in the tree.
+    ///
+    /// `initial_perms` defines the initial permissions for the part of memory
+    /// that is already considered "initialized" immediately. The ranges in this
+    /// map are relative to `base_offset`.
+    /// `default_perm` defines the initial permission for the rest of the allocation.
+    ///
+    /// For all non-accessed locations in the RangeMap (those that haven't had an
+    /// implicit read), their SIFA must be weaker than or as weak as the SIFA of
+    /// `default_perm`.
+    pub(super) fn new_child(
         &mut self,
+        base_offset: Size,
         parent_tag: BorTag,
         new_tag: BorTag,
-        default_initial_perm: Permission,
-        reborrow_range: AllocRange,
+        initial_perms: RangeMap<LocationState>,
+        default_perm: Permission,
+        protected: bool,
         span: Span,
-        prot: bool,
     ) -> InterpResult<'tcx> {
-        assert!(!self.tag_mapping.contains_key(&new_tag));
         let idx = self.tag_mapping.insert(new_tag);
         let parent_idx = self.tag_mapping.get(&parent_tag).unwrap();
-        let strongest_idempotent = default_initial_perm.strongest_idempotent_foreign_access(prot);
+        assert!(default_perm.is_initial());
+
+        let default_strongest_idempotent =
+            default_perm.strongest_idempotent_foreign_access(protected);
         // Create the node
         self.nodes.insert(
             idx,
@@ -633,25 +649,36 @@ impl<'tcx> Tree {
                 tag: new_tag,
                 parent: Some(parent_idx),
                 children: SmallVec::default(),
-                default_initial_perm,
-                default_initial_idempotent_foreign_access: strongest_idempotent,
-                debug_info: NodeDebugInfo::new(new_tag, default_initial_perm, span),
+                default_initial_perm: default_perm,
+                default_initial_idempotent_foreign_access: default_strongest_idempotent,
+                debug_info: NodeDebugInfo::new(new_tag, default_perm, span),
             },
         );
         // Register new_tag as a child of parent_tag
         self.nodes.get_mut(parent_idx).unwrap().children.push(idx);
-        // Initialize perms
-        let perm = LocationState::new_init(default_initial_perm, strongest_idempotent);
-        for (_perms_range, perms) in self.rperms.iter_mut(reborrow_range.start, reborrow_range.size)
+
+        for (Range { start, end }, &perm) in
+            initial_perms.iter(Size::from_bytes(0), initial_perms.size())
         {
-            perms.insert(idx, perm);
+            assert!(perm.is_initial());
+            for (_perms_range, perms) in self
+                .rperms
+                .iter_mut(Size::from_bytes(start) + base_offset, Size::from_bytes(end - start))
+            {
+                assert!(
+                    default_strongest_idempotent
+                        >= perm.permission.strongest_idempotent_foreign_access(protected)
+                );
+                perms.insert(idx, perm);
+            }
         }
 
         // Inserting the new perms might have broken the SIFA invariant (see `foreign_access_skipping.rs`).
         // We now weaken the recorded SIFA for our parents, until the invariant is restored.
         // We could weaken them all to `LocalAccess`, but it is more efficient to compute the SIFA
         // for the new permission statically, and use that.
-        self.update_last_accessed_after_retag(parent_idx, strongest_idempotent);
+        // See the comment in `tb_reborrow` for why it is correct to use the SIFA of `default_uninit_perm`.
+        self.update_last_accessed_after_retag(parent_idx, default_strongest_idempotent);
 
         interp_ok(())
     }
@@ -758,14 +785,14 @@ impl<'tcx> Tree {
     ///
     /// If `access_range_and_kind` is `None`, this is interpreted as the special
     /// access that is applied on protector release:
-    /// - the access will be applied only to initialized locations of the allocation,
+    /// - the access will be applied only to accessed locations of the allocation,
     /// - it will not be visible to children,
     /// - it will be recorded as a `FnExit` diagnostic access
     /// - and it will be a read except if the location is `Active`, i.e. has been written to,
     ///   in which case it will be a write.
     ///
     /// `LocationState::perform_access` will take care of raising transition
-    /// errors and updating the `initialized` status of each location,
+    /// errors and updating the `accessed` status of each location,
     /// this traversal adds to that:
     /// - inserting into the map locations that do not exist yet,
     /// - trimming the traversal,
@@ -858,7 +885,7 @@ impl<'tcx> Tree {
             }
         } else {
             // This is a special access through the entire allocation.
-            // It actually only affects `initialized` locations, so we need
+            // It actually only affects `accessed` locations, so we need
             // to filter on those before initiating the traversal.
             //
             // In addition this implicit access should not be visible to children,
@@ -868,10 +895,10 @@ impl<'tcx> Tree {
             // why this is important.
             for (perms_range, perms) in self.rperms.iter_mut_all() {
                 let idx = self.tag_mapping.get(&tag).unwrap();
-                // Only visit initialized permissions
+                // Only visit accessed permissions
                 if let Some(p) = perms.get(idx)
                     && let Some(access_kind) = p.permission.protector_end_access()
-                    && p.initialized
+                    && p.accessed
                 {
                     let access_cause = diagnostics::AccessCause::FnExit(access_kind);
                     TreeVisitor { nodes: &mut self.nodes, tag_mapping: &self.tag_mapping, perms }
@@ -1035,7 +1062,7 @@ impl Tree {
 
 impl Node {
     pub fn default_location_state(&self) -> LocationState {
-        LocationState::new_uninit(
+        LocationState::new_non_accessed(
             self.default_initial_perm,
             self.default_initial_idempotent_foreign_access,
         )
@@ -1073,15 +1100,4 @@ impl AccessRelatedness {
     pub fn is_foreign(self) -> bool {
         matches!(self, AccessRelatedness::AncestorAccess | AccessRelatedness::CousinAccess)
     }
-
-    /// Given the AccessRelatedness for the parent node, compute the AccessRelatedness
-    /// for the child node. This function assumes that we propagate away from the initial
-    /// access.
-    pub fn for_child(self) -> Self {
-        use AccessRelatedness::*;
-        match self {
-            AncestorAccess | This => AncestorAccess,
-            StrictChildAccess | CousinAccess => CousinAccess,
-        }
-    }
 }
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs
index dbfa9807e3b..bb3fc2d80b3 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs
@@ -9,10 +9,10 @@ use crate::borrow_tracker::tree_borrows::exhaustive::{Exhaustive, precondition};
 impl Exhaustive for LocationState {
     fn exhaustive() -> Box<dyn Iterator<Item = Self>> {
         // We keep `latest_foreign_access` at `None` as that's just a cache.
-        Box::new(<(Permission, bool)>::exhaustive().map(|(permission, initialized)| {
+        Box::new(<(Permission, bool)>::exhaustive().map(|(permission, accessed)| {
             Self {
                 permission,
-                initialized,
+                accessed,
                 idempotent_foreign_access: IdempotentForeignAccess::default(),
             }
         }))
@@ -76,8 +76,8 @@ fn as_protected(b: bool) -> &'static str {
     if b { " (protected)" } else { "" }
 }
 
-fn as_lazy_or_init(b: bool) -> &'static str {
-    if b { "initialized" } else { "lazy" }
+fn as_lazy_or_accessed(b: bool) -> &'static str {
+    if b { "accessed" } else { "lazy" }
 }
 
 /// Test that tree compacting (as performed by the GC) is sound.
@@ -106,7 +106,7 @@ fn tree_compacting_is_sound() {
                         as_foreign_or_child(rel),
                         kind,
                         parent.permission(),
-                        as_lazy_or_init(child.is_initialized()),
+                        as_lazy_or_accessed(child.is_accessed()),
                         child.permission(),
                         as_protected(child_protected),
                         np.permission(),
@@ -122,7 +122,7 @@ fn tree_compacting_is_sound() {
                         as_foreign_or_child(rel),
                         kind,
                         parent.permission(),
-                        as_lazy_or_init(child.is_initialized()),
+                        as_lazy_or_accessed(child.is_accessed()),
                         child.permission(),
                         as_protected(child_protected),
                         nc.permission()
@@ -435,19 +435,19 @@ mod spurious_read {
             Ok(Self { x, y, ..self })
         }
 
-        /// Perform a read on the given pointer if its state is `initialized`.
+        /// Perform a read on the given pointer if its state is `accessed`.
         /// Must be called just after reborrowing a pointer, and just after
         /// removing a protector.
-        fn read_if_initialized(self, ptr: PtrSelector) -> Result<Self, ()> {
-            let initialized = match ptr {
-                PtrSelector::X => self.x.state.initialized,
-                PtrSelector::Y => self.y.state.initialized,
+        fn read_if_accessed(self, ptr: PtrSelector) -> Result<Self, ()> {
+            let accessed = match ptr {
+                PtrSelector::X => self.x.state.accessed,
+                PtrSelector::Y => self.y.state.accessed,
                 PtrSelector::Other =>
                     panic!(
-                        "the `initialized` status of `PtrSelector::Other` is unknown, do not pass it to `read_if_initialized`"
+                        "the `accessed` status of `PtrSelector::Other` is unknown, do not pass it to `read_if_accessed`"
                     ),
             };
-            if initialized {
+            if accessed {
                 self.perform_test_access(&TestAccess { ptr, kind: AccessKind::Read })
             } else {
                 Ok(self)
@@ -457,13 +457,13 @@ mod spurious_read {
         /// Remove the protector of `x`, including the implicit read on function exit.
         fn end_protector_x(self) -> Result<Self, ()> {
             let x = self.x.end_protector();
-            Self { x, ..self }.read_if_initialized(PtrSelector::X)
+            Self { x, ..self }.read_if_accessed(PtrSelector::X)
         }
 
         /// Remove the protector of `y`, including the implicit read on function exit.
         fn end_protector_y(self) -> Result<Self, ()> {
             let y = self.y.end_protector();
-            Self { y, ..self }.read_if_initialized(PtrSelector::Y)
+            Self { y, ..self }.read_if_accessed(PtrSelector::Y)
         }
 
         fn retag_y(self, new_y: LocStateProt) -> Result<Self, ()> {
@@ -473,7 +473,7 @@ mod spurious_read {
             }
             // `xy_rel` changes to "mutually foreign" now: `y` can no longer be a parent of `x`.
             Self { y: new_y, xy_rel: RelPosXY::MutuallyForeign, ..self }
-                .read_if_initialized(PtrSelector::Y)
+                .read_if_accessed(PtrSelector::Y)
         }
 
         fn perform_test_event<RetX, RetY>(self, evt: &TestEvent<RetX, RetY>) -> Result<Self, ()> {
@@ -602,14 +602,14 @@ mod spurious_read {
             xy_rel: RelPosXY::MutuallyForeign,
             x: LocStateProt {
                 // For the tests, the strongest idempotent foreign access does not matter, so we use `Default::default`
-                state: LocationState::new_init(
+                state: LocationState::new_accessed(
                     Permission::new_frozen(),
                     IdempotentForeignAccess::default(),
                 ),
                 prot: true,
             },
             y: LocStateProt {
-                state: LocationState::new_uninit(
+                state: LocationState::new_non_accessed(
                     Permission::new_reserved(/* freeze */ true, /* protected */ true),
                     IdempotentForeignAccess::default(),
                 ),
@@ -650,8 +650,8 @@ mod spurious_read {
             for xy_rel in RelPosXY::exhaustive() {
                 for (x_retag_perm, y_current_perm) in <(LocationState, LocationState)>::exhaustive()
                 {
-                    // We can only do spurious reads for initialized locations anyway.
-                    precondition!(x_retag_perm.initialized);
+                    // We can only do spurious reads for accessed locations anyway.
+                    precondition!(x_retag_perm.accessed);
                     // And `x` just got retagged, so it must be initial.
                     precondition!(x_retag_perm.permission.is_initial());
                     // As stated earlier, `x` is always protected in the patterns we consider here.
@@ -696,7 +696,7 @@ mod spurious_read {
         fn initial_state(&self) -> Result<LocStateProtPair, ()> {
             let (x, y) = self.retag_permissions();
             let state = LocStateProtPair { xy_rel: self.xy_rel, x, y };
-            state.read_if_initialized(PtrSelector::X)
+            state.read_if_accessed(PtrSelector::X)
         }
     }
 
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs
index 7874721c0ac..dcd5a6cb023 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/unimap.rs
@@ -17,6 +17,8 @@ use std::mem;
 
 use rustc_data_structures::fx::FxHashMap;
 
+use crate::helpers::ToUsize;
+
 /// Intermediate key between a UniKeyMap and a UniValMap.
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
 pub struct UniIndex {
@@ -158,7 +160,7 @@ where
 impl<V> UniValMap<V> {
     /// Whether this index has an associated value.
     pub fn contains_idx(&self, idx: UniIndex) -> bool {
-        self.data.get(idx.idx as usize).and_then(Option::as_ref).is_some()
+        self.data.get(idx.idx.to_usize()).and_then(Option::as_ref).is_some()
     }
 
     /// Reserve enough space to insert the value at the right index.
@@ -174,29 +176,29 @@ impl<V> UniValMap<V> {
 
     /// Assign a value to the index. Permanently overwrites any previous value.
     pub fn insert(&mut self, idx: UniIndex, val: V) {
-        self.extend_to_length(idx.idx as usize + 1);
-        self.data[idx.idx as usize] = Some(val)
+        self.extend_to_length(idx.idx.to_usize() + 1);
+        self.data[idx.idx.to_usize()] = Some(val)
     }
 
     /// Get the value at this index, if it exists.
     pub fn get(&self, idx: UniIndex) -> Option<&V> {
-        self.data.get(idx.idx as usize).and_then(Option::as_ref)
+        self.data.get(idx.idx.to_usize()).and_then(Option::as_ref)
     }
 
     /// Get the value at this index mutably, if it exists.
     pub fn get_mut(&mut self, idx: UniIndex) -> Option<&mut V> {
-        self.data.get_mut(idx.idx as usize).and_then(Option::as_mut)
+        self.data.get_mut(idx.idx.to_usize()).and_then(Option::as_mut)
     }
 
     /// Delete any value associated with this index.
     /// Returns None if the value was not present, otherwise
     /// returns the previously stored value.
     pub fn remove(&mut self, idx: UniIndex) -> Option<V> {
-        if idx.idx as usize >= self.data.len() {
+        if idx.idx.to_usize() >= self.data.len() {
             return None;
         }
         let mut res = None;
-        mem::swap(&mut res, &mut self.data[idx.idx as usize]);
+        mem::swap(&mut res, &mut self.data[idx.idx.to_usize()]);
         res
     }
 }
@@ -209,8 +211,8 @@ pub struct UniEntry<'a, V> {
 impl<'a, V> UniValMap<V> {
     /// Get a wrapper around a mutable access to the value corresponding to `idx`.
     pub fn entry(&'a mut self, idx: UniIndex) -> UniEntry<'a, V> {
-        self.extend_to_length(idx.idx as usize + 1);
-        UniEntry { inner: &mut self.data[idx.idx as usize] }
+        self.extend_to_length(idx.idx.to_usize() + 1);
+        UniEntry { inner: &mut self.data[idx.idx.to_usize()] }
     }
 }
 
diff --git a/src/tools/miri/src/concurrency/cpu_affinity.rs b/src/tools/miri/src/concurrency/cpu_affinity.rs
index b47b614cf5f..9583de5a483 100644
--- a/src/tools/miri/src/concurrency/cpu_affinity.rs
+++ b/src/tools/miri/src/concurrency/cpu_affinity.rs
@@ -25,7 +25,7 @@ impl CpuAffinityMask {
         let mut this = Self([0; Self::CPU_MASK_BYTES]);
 
         // the default affinity mask includes only the available CPUs
-        for i in 0..cpu_count as usize {
+        for i in 0..cpu_count.to_usize() {
             this.set(cx, i);
         }
 
diff --git a/src/tools/miri/src/concurrency/mod.rs b/src/tools/miri/src/concurrency/mod.rs
index dd33f90f153..aaa3fc85a6c 100644
--- a/src/tools/miri/src/concurrency/mod.rs
+++ b/src/tools/miri/src/concurrency/mod.rs
@@ -8,8 +8,19 @@ pub mod thread;
 mod vector_clock;
 pub mod weak_memory;
 
+// cfg(bootstrap)
+macro_rules! cfg_select_dispatch {
+    ($($tokens:tt)*) => {
+        #[cfg(bootstrap)]
+        cfg_match! { $($tokens)* }
+
+        #[cfg(not(bootstrap))]
+        cfg_select! { $($tokens)* }
+    };
+}
+
 // Import either the real genmc adapter or a dummy module.
-cfg_match! {
+cfg_select_dispatch! {
     feature = "genmc" => {
         mod genmc;
         pub use self::genmc::{GenmcCtx, GenmcConfig};
diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs
index 8aa65e6cb61..ba1436b77b8 100644
--- a/src/tools/miri/src/concurrency/thread.rs
+++ b/src/tools/miri/src/concurrency/thread.rs
@@ -218,34 +218,37 @@ impl<'tcx> Thread<'tcx> {
         }
     }
 
-    /// Return the top user-relevant frame, if there is one.
+    /// Return the top user-relevant frame, if there is one. `skip` indicates how many top frames
+    /// should be skipped.
     /// Note that the choice to return `None` here when there is no user-relevant frame is part of
     /// justifying the optimization that only pushes of user-relevant frames require updating the
     /// `top_user_relevant_frame` field.
-    fn compute_top_user_relevant_frame(&self) -> Option<usize> {
+    fn compute_top_user_relevant_frame(&self, skip: usize) -> Option<usize> {
         self.stack
             .iter()
             .enumerate()
             .rev()
+            .skip(skip)
             .find_map(|(idx, frame)| if frame.extra.is_user_relevant { Some(idx) } else { None })
     }
 
-    /// Re-compute the top user-relevant frame from scratch.
-    pub fn recompute_top_user_relevant_frame(&mut self) {
-        self.top_user_relevant_frame = self.compute_top_user_relevant_frame();
+    /// Re-compute the top user-relevant frame from scratch. `skip` indicates how many top frames
+    /// should be skipped.
+    pub fn recompute_top_user_relevant_frame(&mut self, skip: usize) {
+        self.top_user_relevant_frame = self.compute_top_user_relevant_frame(skip);
     }
 
     /// Set the top user-relevant frame to the given value. Must be equal to what
     /// `get_top_user_relevant_frame` would return!
     pub fn set_top_user_relevant_frame(&mut self, frame_idx: usize) {
-        debug_assert_eq!(Some(frame_idx), self.compute_top_user_relevant_frame());
+        debug_assert_eq!(Some(frame_idx), self.compute_top_user_relevant_frame(0));
         self.top_user_relevant_frame = Some(frame_idx);
     }
 
     /// Returns the topmost frame that is considered user-relevant, or the
     /// top of the stack if there is no such frame, or `None` if the stack is empty.
     pub fn top_user_relevant_frame(&self) -> Option<usize> {
-        debug_assert_eq!(self.top_user_relevant_frame, self.compute_top_user_relevant_frame());
+        debug_assert_eq!(self.top_user_relevant_frame, self.compute_top_user_relevant_frame(0));
         // This can be called upon creation of an allocation. We create allocations while setting up
         // parts of the Rust runtime when we do not have any stack frames yet, so we need to handle
         // empty stacks.
@@ -894,12 +897,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             if tcx.is_foreign_item(def_id) {
                 throw_unsup_format!("foreign thread-local statics are not supported");
             }
+            let params = this.machine.get_default_alloc_params();
             let alloc = this.ctfe_query(|tcx| tcx.eval_static_initializer(def_id))?;
             // We make a full copy of this allocation.
             let mut alloc = alloc.inner().adjust_from_tcx(
                 &this.tcx,
                 |bytes, align| {
-                    interp_ok(MiriAllocBytes::from_bytes(std::borrow::Cow::Borrowed(bytes), align))
+                    interp_ok(MiriAllocBytes::from_bytes(
+                        std::borrow::Cow::Borrowed(bytes),
+                        align,
+                        params,
+                    ))
                 },
                 |ptr| this.global_root_pointer(ptr),
             )?;
diff --git a/src/tools/miri/src/concurrency/vector_clock.rs b/src/tools/miri/src/concurrency/vector_clock.rs
index 78858fcedae..494e7922d2b 100644
--- a/src/tools/miri/src/concurrency/vector_clock.rs
+++ b/src/tools/miri/src/concurrency/vector_clock.rs
@@ -7,6 +7,7 @@ use rustc_span::{DUMMY_SP, Span, SpanData};
 use smallvec::SmallVec;
 
 use super::data_race::NaReadType;
+use crate::helpers::ToUsize;
 
 /// A vector clock index, this is associated with a thread id
 /// but in some cases one vector index may be shared with
@@ -157,7 +158,7 @@ impl VClock {
 
     #[inline]
     pub(super) fn index_mut(&mut self, index: VectorIdx) -> &mut VTimestamp {
-        self.0.as_mut_slice().get_mut(index.to_u32() as usize).unwrap()
+        self.0.as_mut_slice().get_mut(index.to_u32().to_usize()).unwrap()
     }
 
     /// Get a mutable slice to the internal vector with minimum `min_len`
@@ -420,7 +421,7 @@ impl Index<VectorIdx> for VClock {
 
     #[inline]
     fn index(&self, index: VectorIdx) -> &VTimestamp {
-        self.as_slice().get(index.to_u32() as usize).unwrap_or(&VTimestamp::ZERO)
+        self.as_slice().get(index.to_u32().to_usize()).unwrap_or(&VTimestamp::ZERO)
     }
 }
 
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index 10570a37e5d..1728a9cfd6d 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -255,8 +255,7 @@ pub fn report_error<'tcx>(
                 ],
             UnsupportedForeignItem(_) => {
                 vec![
-                    note!("if this is a basic API commonly used on this target, please report an issue with Miri"),
-                    note!("however, note that Miri does not aim to support every FFI function out there; for instance, we will not support APIs for things such as GUIs, scripting languages, or databases"),
+                    note!("this means the program tried to do something Miri does not support; it does not indicate a bug in the program"),
                 ]
             }
             StackedBorrowsUb { help, history, .. } => {
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index a90c6ab9d40..5880e5fbc37 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -354,14 +354,13 @@ pub fn create_ecx<'tcx>(
             argvs.push(arg_place.to_ref(&ecx));
         }
         // Make an array with all these pointers, in the Miri memory.
-        let argvs_layout = ecx.layout_of(Ty::new_array(
-            tcx,
-            Ty::new_imm_ptr(tcx, tcx.types.u8),
-            u64::try_from(argvs.len()).unwrap(),
-        ))?;
+        let u8_ptr_type = Ty::new_imm_ptr(tcx, tcx.types.u8);
+        let u8_ptr_ptr_type = Ty::new_imm_ptr(tcx, u8_ptr_type);
+        let argvs_layout =
+            ecx.layout_of(Ty::new_array(tcx, u8_ptr_type, u64::try_from(argvs.len()).unwrap()))?;
         let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into())?;
-        for (idx, arg) in argvs.into_iter().enumerate() {
-            let place = ecx.project_field(&argvs_place, idx)?;
+        for (arg, idx) in argvs.into_iter().zip(0..) {
+            let place = ecx.project_index(&argvs_place, idx)?;
             ecx.write_immediate(arg, &place)?;
         }
         ecx.mark_immutable(&argvs_place);
@@ -373,10 +372,8 @@ pub fn create_ecx<'tcx>(
             ecx.mark_immutable(&argc_place);
             ecx.machine.argc = Some(argc_place.ptr());
 
-            let argv_place = ecx.allocate(
-                ecx.layout_of(Ty::new_imm_ptr(tcx, tcx.types.unit))?,
-                MiriMemoryKind::Machine.into(),
-            )?;
+            let argv_place =
+                ecx.allocate(ecx.layout_of(u8_ptr_ptr_type)?, MiriMemoryKind::Machine.into())?;
             ecx.write_pointer(argvs_place.ptr(), &argv_place)?;
             ecx.mark_immutable(&argv_place);
             ecx.machine.argv = Some(argv_place.ptr());
@@ -392,13 +389,15 @@ pub fn create_ecx<'tcx>(
                 ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Machine.into())?;
             ecx.machine.cmd_line = Some(cmd_place.ptr());
             // Store the UTF-16 string. We just allocated so we know the bounds are fine.
-            for (idx, &c) in cmd_utf16.iter().enumerate() {
-                let place = ecx.project_field(&cmd_place, idx)?;
+            for (&c, idx) in cmd_utf16.iter().zip(0..) {
+                let place = ecx.project_index(&cmd_place, idx)?;
                 ecx.write_scalar(Scalar::from_u16(c), &place)?;
             }
             ecx.mark_immutable(&cmd_place);
         }
-        ecx.mplace_to_ref(&argvs_place)?
+        let imm = argvs_place.to_ref(&ecx);
+        let layout = ecx.layout_of(u8_ptr_ptr_type)?;
+        ImmTy::from_immediate(imm, layout)
     };
 
     // Return place (in static memory so that it does not count as leak).
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index 8e7c9edfcc0..4edecc864dd 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -3,7 +3,7 @@ use std::time::Duration;
 use std::{cmp, iter};
 
 use rand::RngCore;
-use rustc_abi::{Align, ExternAbi, FieldIdx, FieldsShape, Size, Variants};
+use rustc_abi::{Align, CanonAbi, ExternAbi, FieldIdx, FieldsShape, Size, Variants};
 use rustc_apfloat::Float;
 use rustc_apfloat::ieee::{Double, Half, Quad, Single};
 use rustc_hir::Safety;
@@ -18,7 +18,7 @@ use rustc_middle::ty::{self, Binder, FloatTy, FnSig, IntTy, Ty, TyCtxt, UintTy};
 use rustc_session::config::CrateType;
 use rustc_span::{Span, Symbol};
 use rustc_symbol_mangling::mangle_internal_symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use crate::*;
 
@@ -135,7 +135,7 @@ pub fn iter_exported_symbols<'tcx>(
             let codegen_attrs = tcx.codegen_fn_attrs(def_id);
             codegen_attrs.contains_extern_indicator()
                 || codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
-                || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED)
+                || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER)
                 || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
         };
         if exported {
@@ -326,7 +326,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx, Option<P>> {
         let this = self.eval_context_ref();
         let adt = base.layout().ty.ty_adt_def().unwrap();
-        for (idx, field) in adt.non_enum_variant().fields.iter().enumerate() {
+        for (idx, field) in adt.non_enum_variant().fields.iter_enumerated() {
             if field.name.as_str() == name {
                 return interp_ok(Some(this.project_field(base, idx)?));
             }
@@ -376,6 +376,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
         for (idx, &val) in values.iter().enumerate() {
+            let idx = FieldIdx::from_usize(idx);
             let field = this.project_field(dest, idx)?;
             this.write_int(val, &field)?;
         }
@@ -470,7 +471,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             caller_fn_abi,
             &args.iter().map(|a| FnArg::Copy(a.clone().into())).collect::<Vec<_>>(),
             /*with_caller_location*/ false,
-            &dest,
+            &dest.into(),
             stack_pop,
         )
     }
@@ -763,10 +764,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     /// `EINVAL` in this case.
     fn read_timespec(&mut self, tp: &MPlaceTy<'tcx>) -> InterpResult<'tcx, Option<Duration>> {
         let this = self.eval_context_mut();
-        let seconds_place = this.project_field(tp, 0)?;
+        let seconds_place = this.project_field(tp, FieldIdx::ZERO)?;
         let seconds_scalar = this.read_scalar(&seconds_place)?;
         let seconds = seconds_scalar.to_target_isize(this)?;
-        let nanoseconds_place = this.project_field(tp, 1)?;
+        let nanoseconds_place = this.project_field(tp, FieldIdx::ONE)?;
         let nanoseconds_scalar = this.read_scalar(&nanoseconds_place)?;
         let nanoseconds = nanoseconds_scalar.to_target_isize(this)?;
 
@@ -936,11 +937,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn check_callconv<'a>(
         &self,
         fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
-        exp_abi: Conv,
+        exp_abi: CanonAbi,
     ) -> InterpResult<'a, ()> {
         if fn_abi.conv != exp_abi {
             throw_ub_format!(
-                "calling a function with calling convention {exp_abi} using caller calling convention {}",
+                r#"calling a function with calling convention "{exp_abi}" using caller calling convention "{}""#,
                 fn_abi.conv
             );
         }
@@ -973,7 +974,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn check_abi_and_shim_symbol_clash(
         &mut self,
         abi: &FnAbi<'tcx, Ty<'tcx>>,
-        exp_abi: Conv,
+        exp_abi: CanonAbi,
         link_name: Symbol,
     ) -> InterpResult<'tcx, ()> {
         self.check_callconv(abi, exp_abi)?;
@@ -998,7 +999,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn check_shim<'a, const N: usize>(
         &mut self,
         abi: &FnAbi<'tcx, Ty<'tcx>>,
-        exp_abi: Conv,
+        exp_abi: CanonAbi,
         link_name: Symbol,
         args: &'a [OpTy<'tcx>],
     ) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]> {
@@ -1098,7 +1099,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn check_shim_variadic<'a, const N: usize>(
         &mut self,
         abi: &FnAbi<'tcx, Ty<'tcx>>,
-        exp_abi: Conv,
+        exp_abi: CanonAbi,
         link_name: Symbol,
         args: &'a [OpTy<'tcx>],
     ) -> InterpResult<'tcx, (&'a [OpTy<'tcx>; N], &'a [OpTy<'tcx>])>
@@ -1412,3 +1413,26 @@ pub(crate) fn windows_check_buffer_size((success, len): (bool, u64)) -> u32 {
         u32::try_from(len).unwrap()
     }
 }
+
+/// We don't support 16-bit systems, so let's have ergonomic conversion from `u32` to `usize`.
+pub trait ToUsize {
+    fn to_usize(self) -> usize;
+}
+
+impl ToUsize for u32 {
+    fn to_usize(self) -> usize {
+        self.try_into().unwrap()
+    }
+}
+
+/// Similarly, a maximum address size of `u64` is assumed widely here, so let's have ergonomic
+/// converion from `usize` to `u64`.
+pub trait ToU64 {
+    fn to_u64(self) -> u64;
+}
+
+impl ToU64 for usize {
+    fn to_u64(self) -> u64 {
+        self.try_into().unwrap()
+    }
+}
diff --git a/src/tools/miri/src/intrinsics/atomic.rs b/src/tools/miri/src/intrinsics/atomic.rs
index 2eb8086f578..0a59a707a10 100644
--- a/src/tools/miri/src/intrinsics/atomic.rs
+++ b/src/tools/miri/src/intrinsics/atomic.rs
@@ -1,4 +1,5 @@
 use rustc_middle::mir::BinOp;
+use rustc_middle::ty::AtomicOrdering;
 use rustc_middle::{mir, ty};
 
 use self::helpers::check_intrinsic_arg_count;
@@ -19,96 +20,137 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn emulate_atomic_intrinsic(
         &mut self,
         intrinsic_name: &str,
+        generic_args: ty::GenericArgsRef<'tcx>,
         args: &[OpTy<'tcx>],
         dest: &MPlaceTy<'tcx>,
     ) -> InterpResult<'tcx, EmulateItemResult> {
         let this = self.eval_context_mut();
 
-        let intrinsic_structure: Vec<_> = intrinsic_name.split('_').collect();
+        let get_ord_at = |i: usize| {
+            let ordering = generic_args.const_at(i).to_value();
+            ordering.valtree.unwrap_branch()[0].unwrap_leaf().to_atomic_ordering()
+        };
 
-        fn read_ord(ord: &str) -> AtomicReadOrd {
+        fn read_ord(ord: AtomicOrdering) -> AtomicReadOrd {
             match ord {
-                "seqcst" => AtomicReadOrd::SeqCst,
-                "acquire" => AtomicReadOrd::Acquire,
-                "relaxed" => AtomicReadOrd::Relaxed,
-                _ => panic!("invalid read ordering `{ord}`"),
+                AtomicOrdering::SeqCst => AtomicReadOrd::SeqCst,
+                AtomicOrdering::Acquire => AtomicReadOrd::Acquire,
+                AtomicOrdering::Relaxed => AtomicReadOrd::Relaxed,
+                _ => panic!("invalid read ordering `{ord:?}`"),
             }
         }
 
-        fn write_ord(ord: &str) -> AtomicWriteOrd {
+        fn write_ord(ord: AtomicOrdering) -> AtomicWriteOrd {
             match ord {
-                "seqcst" => AtomicWriteOrd::SeqCst,
-                "release" => AtomicWriteOrd::Release,
-                "relaxed" => AtomicWriteOrd::Relaxed,
-                _ => panic!("invalid write ordering `{ord}`"),
+                AtomicOrdering::SeqCst => AtomicWriteOrd::SeqCst,
+                AtomicOrdering::Release => AtomicWriteOrd::Release,
+                AtomicOrdering::Relaxed => AtomicWriteOrd::Relaxed,
+                _ => panic!("invalid write ordering `{ord:?}`"),
             }
         }
 
-        fn rw_ord(ord: &str) -> AtomicRwOrd {
+        fn rw_ord(ord: AtomicOrdering) -> AtomicRwOrd {
             match ord {
-                "seqcst" => AtomicRwOrd::SeqCst,
-                "acqrel" => AtomicRwOrd::AcqRel,
-                "acquire" => AtomicRwOrd::Acquire,
-                "release" => AtomicRwOrd::Release,
-                "relaxed" => AtomicRwOrd::Relaxed,
-                _ => panic!("invalid read-write ordering `{ord}`"),
+                AtomicOrdering::SeqCst => AtomicRwOrd::SeqCst,
+                AtomicOrdering::AcqRel => AtomicRwOrd::AcqRel,
+                AtomicOrdering::Acquire => AtomicRwOrd::Acquire,
+                AtomicOrdering::Release => AtomicRwOrd::Release,
+                AtomicOrdering::Relaxed => AtomicRwOrd::Relaxed,
             }
         }
 
-        fn fence_ord(ord: &str) -> AtomicFenceOrd {
+        fn fence_ord(ord: AtomicOrdering) -> AtomicFenceOrd {
             match ord {
-                "seqcst" => AtomicFenceOrd::SeqCst,
-                "acqrel" => AtomicFenceOrd::AcqRel,
-                "acquire" => AtomicFenceOrd::Acquire,
-                "release" => AtomicFenceOrd::Release,
-                _ => panic!("invalid fence ordering `{ord}`"),
+                AtomicOrdering::SeqCst => AtomicFenceOrd::SeqCst,
+                AtomicOrdering::AcqRel => AtomicFenceOrd::AcqRel,
+                AtomicOrdering::Acquire => AtomicFenceOrd::Acquire,
+                AtomicOrdering::Release => AtomicFenceOrd::Release,
+                _ => panic!("invalid fence ordering `{ord:?}`"),
             }
         }
 
-        match &*intrinsic_structure {
-            ["load", ord] => this.atomic_load(args, dest, read_ord(ord))?,
-            ["store", ord] => this.atomic_store(args, write_ord(ord))?,
-
-            ["fence", ord] => this.atomic_fence_intrinsic(args, fence_ord(ord))?,
-            ["singlethreadfence", ord] => this.compiler_fence_intrinsic(args, fence_ord(ord))?,
-
-            ["xchg", ord] => this.atomic_exchange(args, dest, rw_ord(ord))?,
-            ["cxchg", ord1, ord2] =>
-                this.atomic_compare_exchange(args, dest, rw_ord(ord1), read_ord(ord2))?,
-            ["cxchgweak", ord1, ord2] =>
-                this.atomic_compare_exchange_weak(args, dest, rw_ord(ord1), read_ord(ord2))?,
-
-            ["or", ord] =>
-                this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), rw_ord(ord))?,
-            ["xor", ord] =>
-                this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), rw_ord(ord))?,
-            ["and", ord] =>
-                this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), rw_ord(ord))?,
-            ["nand", ord] =>
-                this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), rw_ord(ord))?,
-            ["xadd", ord] =>
-                this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), rw_ord(ord))?,
-            ["xsub", ord] =>
-                this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), rw_ord(ord))?,
-            ["min", ord] => {
+        match intrinsic_name {
+            "load" => {
+                let ord = get_ord_at(1);
+                this.atomic_load(args, dest, read_ord(ord))?;
+            }
+
+            "store" => {
+                let ord = get_ord_at(1);
+                this.atomic_store(args, write_ord(ord))?
+            }
+
+            "fence" => {
+                let ord = get_ord_at(0);
+                this.atomic_fence_intrinsic(args, fence_ord(ord))?
+            }
+            "singlethreadfence" => {
+                let ord = get_ord_at(0);
+                this.compiler_fence_intrinsic(args, fence_ord(ord))?;
+            }
+
+            "xchg" => {
+                let ord = get_ord_at(1);
+                this.atomic_exchange(args, dest, rw_ord(ord))?;
+            }
+            "cxchg" => {
+                let ord1 = get_ord_at(1);
+                let ord2 = get_ord_at(2);
+                this.atomic_compare_exchange(args, dest, rw_ord(ord1), read_ord(ord2))?;
+            }
+            "cxchgweak" => {
+                let ord1 = get_ord_at(1);
+                let ord2 = get_ord_at(2);
+                this.atomic_compare_exchange_weak(args, dest, rw_ord(ord1), read_ord(ord2))?;
+            }
+
+            "or" => {
+                let ord = get_ord_at(1);
+                this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), rw_ord(ord))?;
+            }
+            "xor" => {
+                let ord = get_ord_at(1);
+                this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), rw_ord(ord))?;
+            }
+            "and" => {
+                let ord = get_ord_at(1);
+                this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), rw_ord(ord))?;
+            }
+            "nand" => {
+                let ord = get_ord_at(1);
+                this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), rw_ord(ord))?;
+            }
+            "xadd" => {
+                let ord = get_ord_at(1);
+                this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), rw_ord(ord))?;
+            }
+            "xsub" => {
+                let ord = get_ord_at(1);
+                this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), rw_ord(ord))?;
+            }
+            "min" => {
+                let ord = get_ord_at(1);
                 // Later we will use the type to indicate signed vs unsigned,
                 // so make sure it matches the intrinsic name.
                 assert!(matches!(args[1].layout.ty.kind(), ty::Int(_)));
                 this.atomic_rmw_op(args, dest, AtomicOp::Min, rw_ord(ord))?;
             }
-            ["umin", ord] => {
+            "umin" => {
+                let ord = get_ord_at(1);
                 // Later we will use the type to indicate signed vs unsigned,
                 // so make sure it matches the intrinsic name.
                 assert!(matches!(args[1].layout.ty.kind(), ty::Uint(_)));
                 this.atomic_rmw_op(args, dest, AtomicOp::Min, rw_ord(ord))?;
             }
-            ["max", ord] => {
+            "max" => {
+                let ord = get_ord_at(1);
                 // Later we will use the type to indicate signed vs unsigned,
                 // so make sure it matches the intrinsic name.
                 assert!(matches!(args[1].layout.ty.kind(), ty::Int(_)));
                 this.atomic_rmw_op(args, dest, AtomicOp::Max, rw_ord(ord))?;
             }
-            ["umax", ord] => {
+            "umax" => {
+                let ord = get_ord_at(1);
                 // Later we will use the type to indicate signed vs unsigned,
                 // so make sure it matches the intrinsic name.
                 assert!(matches!(args[1].layout.ty.kind(), ty::Uint(_)));
diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs
index 982fbc31811..a4882a20148 100644
--- a/src/tools/miri/src/intrinsics/mod.rs
+++ b/src/tools/miri/src/intrinsics/mod.rs
@@ -22,7 +22,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         &mut self,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx>],
-        dest: &MPlaceTy<'tcx>,
+        dest: &PlaceTy<'tcx>,
         ret: Option<mir::BasicBlock>,
         unwind: mir::UnwindAction,
     ) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
@@ -45,7 +45,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let intrinsic_name = this.tcx.item_name(instance.def_id());
         let intrinsic_name = intrinsic_name.as_str();
 
-        match this.emulate_intrinsic_by_name(intrinsic_name, instance.args, args, dest, ret)? {
+        // FIXME: avoid allocating memory
+        let dest = this.force_allocation(dest)?;
+
+        match this.emulate_intrinsic_by_name(intrinsic_name, instance.args, args, &dest, ret)? {
             EmulateItemResult::NotSupported => {
                 // We haven't handled the intrinsic, let's see if we can use a fallback body.
                 if this.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden {
@@ -94,7 +97,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
 
         if let Some(name) = intrinsic_name.strip_prefix("atomic_") {
-            return this.emulate_atomic_intrinsic(name, args, dest);
+            return this.emulate_atomic_intrinsic(name, generic_args, args, dest);
         }
         if let Some(name) = intrinsic_name.strip_prefix("simd_") {
             return this.emulate_simd_intrinsic(name, generic_args, args, dest);
@@ -156,67 +159,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(Scalar::from_bool(branch), dest)?;
             }
 
-            "floorf16" | "ceilf16" | "truncf16" | "roundf16" | "round_ties_even_f16" => {
-                let [f] = check_intrinsic_arg_count(args)?;
-                let f = this.read_scalar(f)?.to_f16()?;
-                let mode = match intrinsic_name {
-                    "floorf16" => Round::TowardNegative,
-                    "ceilf16" => Round::TowardPositive,
-                    "truncf16" => Round::TowardZero,
-                    "roundf16" => Round::NearestTiesToAway,
-                    "round_ties_even_f16" => Round::NearestTiesToEven,
-                    _ => bug!(),
-                };
-                let res = f.round_to_integral(mode).value;
-                let res = this.adjust_nan(res, &[f]);
-                this.write_scalar(res, dest)?;
-            }
-            "floorf32" | "ceilf32" | "truncf32" | "roundf32" | "round_ties_even_f32" => {
-                let [f] = check_intrinsic_arg_count(args)?;
-                let f = this.read_scalar(f)?.to_f32()?;
-                let mode = match intrinsic_name {
-                    "floorf32" => Round::TowardNegative,
-                    "ceilf32" => Round::TowardPositive,
-                    "truncf32" => Round::TowardZero,
-                    "roundf32" => Round::NearestTiesToAway,
-                    "round_ties_even_f32" => Round::NearestTiesToEven,
-                    _ => bug!(),
-                };
-                let res = f.round_to_integral(mode).value;
-                let res = this.adjust_nan(res, &[f]);
-                this.write_scalar(res, dest)?;
-            }
-            "floorf64" | "ceilf64" | "truncf64" | "roundf64" | "round_ties_even_f64" => {
-                let [f] = check_intrinsic_arg_count(args)?;
-                let f = this.read_scalar(f)?.to_f64()?;
-                let mode = match intrinsic_name {
-                    "floorf64" => Round::TowardNegative,
-                    "ceilf64" => Round::TowardPositive,
-                    "truncf64" => Round::TowardZero,
-                    "roundf64" => Round::NearestTiesToAway,
-                    "round_ties_even_f64" => Round::NearestTiesToEven,
-                    _ => bug!(),
-                };
-                let res = f.round_to_integral(mode).value;
-                let res = this.adjust_nan(res, &[f]);
-                this.write_scalar(res, dest)?;
-            }
-            "floorf128" | "ceilf128" | "truncf128" | "roundf128" | "round_ties_even_f128" => {
-                let [f] = check_intrinsic_arg_count(args)?;
-                let f = this.read_scalar(f)?.to_f128()?;
-                let mode = match intrinsic_name {
-                    "floorf128" => Round::TowardNegative,
-                    "ceilf128" => Round::TowardPositive,
-                    "truncf128" => Round::TowardZero,
-                    "roundf128" => Round::NearestTiesToAway,
-                    "round_ties_even_f128" => Round::NearestTiesToEven,
-                    _ => bug!(),
-                };
-                let res = f.round_to_integral(mode).value;
-                let res = this.adjust_nan(res, &[f]);
-                this.write_scalar(res, dest)?;
-            }
-
             "sqrtf32" => {
                 let [f] = check_intrinsic_arg_count(args)?;
                 let f = this.read_scalar(f)?.to_f32()?;
diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs
index c9250ba1b81..b17fd4fb7f9 100644
--- a/src/tools/miri/src/intrinsics/simd.rs
+++ b/src/tools/miri/src/intrinsics/simd.rs
@@ -634,7 +634,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let index_len = index.len();
 
                 assert_eq!(left_len, right_len);
-                assert_eq!(index_len as u64, dest_len);
+                assert_eq!(u64::try_from(index_len).unwrap(), dest_len);
 
                 for i in 0..dest_len {
                     let src_index: u64 =
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 329a7e56bc0..51ec19af52a 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -1,5 +1,6 @@
+#![cfg_attr(bootstrap, feature(cfg_match))]
+#![cfg_attr(not(bootstrap), feature(cfg_select))]
 #![feature(rustc_private)]
-#![feature(cfg_match)]
 #![feature(float_gamma)]
 #![feature(float_erf)]
 #![feature(map_try_insert)]
@@ -11,6 +12,7 @@
 #![feature(nonzero_ops)]
 #![feature(strict_overflow_ops)]
 #![feature(pointer_is_aligned_to)]
+#![feature(ptr_metadata)]
 #![feature(unqualified_local_imports)]
 #![feature(derive_coerce_pointee)]
 #![feature(arbitrary_self_types)]
@@ -41,14 +43,7 @@
     rustc::potential_query_instability,
     rustc::untranslatable_diagnostic,
 )]
-#![warn(
-    rust_2018_idioms,
-    unqualified_local_imports,
-    clippy::cast_possible_wrap, // unsigned -> signed
-    clippy::cast_sign_loss, // signed -> unsigned
-    clippy::cast_lossless,
-    clippy::cast_possible_truncation,
-)]
+#![warn(rust_2018_idioms, unqualified_local_imports, clippy::as_conversions)]
 // Needed for rustdoc from bootstrap (with `-Znormalize-docs`).
 #![recursion_limit = "256"]
 
@@ -76,8 +71,8 @@ extern crate rustc_target;
 #[allow(unused_extern_crates)]
 extern crate rustc_driver;
 
+mod alloc;
 mod alloc_addresses;
-mod alloc_bytes;
 mod borrow_tracker;
 mod clock;
 mod concurrency;
@@ -112,8 +107,8 @@ pub type OpTy<'tcx> = interpret::OpTy<'tcx, machine::Provenance>;
 pub type PlaceTy<'tcx> = interpret::PlaceTy<'tcx, machine::Provenance>;
 pub type MPlaceTy<'tcx> = interpret::MPlaceTy<'tcx, machine::Provenance>;
 
+pub use crate::alloc::MiriAllocBytes;
 pub use crate::alloc_addresses::{EvalContextExt as _, ProvenanceMode};
-pub use crate::alloc_bytes::MiriAllocBytes;
 pub use crate::borrow_tracker::stacked_borrows::{
     EvalContextExt as _, Item, Permission, Stack, Stacks,
 };
@@ -140,7 +135,7 @@ pub use crate::eval::{
     AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, MiriEntryFnType, RejectOpWith,
     ValidationMode, create_ecx, eval_entry,
 };
-pub use crate::helpers::{AccessKind, EvalContextExt as _};
+pub use crate::helpers::{AccessKind, EvalContextExt as _, ToU64 as _, ToUsize as _};
 pub use crate::intrinsics::EvalContextExt as _;
 pub use crate::machine::{
     AllocExtra, DynMachineCallback, FrameExtra, MachineCallback, MemoryKind, MiriInterpCx,
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 1c6c7894cb4..15b3653d7ae 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -532,6 +532,10 @@ pub struct MiriMachine<'tcx> {
     /// Needs to be queried by ptr_to_int, hence needs interior mutability.
     pub(crate) rng: RefCell<StdRng>,
 
+    /// The allocator used for the machine's `AllocBytes` in native-libs mode.
+    #[cfg(target_os = "linux")]
+    pub(crate) allocator: Option<Rc<RefCell<crate::alloc::isolated_alloc::IsolatedAlloc>>>,
+
     /// The allocation IDs to report when they are being allocated
     /// (helps for debugging memory leaks and use after free bugs).
     tracked_alloc_ids: FxHashSet<AllocId>,
@@ -544,9 +548,6 @@ pub struct MiriMachine<'tcx> {
     /// Failure rate of compare_exchange_weak, between 0.0 and 1.0
     pub(crate) cmpxchg_weak_failure_rate: f64,
 
-    /// Corresponds to -Zmiri-mute-stdout-stderr and doesn't write the output but acts as if it succeeded.
-    pub(crate) mute_stdout_stderr: bool,
-
     /// The probability of the active thread being preempted at the end of each basic block.
     pub(crate) preemption_rate: f64,
 
@@ -718,11 +719,14 @@ impl<'tcx> MiriMachine<'tcx> {
             local_crates,
             extern_statics: FxHashMap::default(),
             rng: RefCell::new(rng),
+            #[cfg(target_os = "linux")]
+            allocator: if config.native_lib.is_some() {
+                Some(Rc::new(RefCell::new(crate::alloc::isolated_alloc::IsolatedAlloc::new())))
+            } else { None },
             tracked_alloc_ids: config.tracked_alloc_ids.clone(),
             track_alloc_accesses: config.track_alloc_accesses,
             check_alignment: config.check_alignment,
             cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate,
-            mute_stdout_stderr: config.mute_stdout_stderr,
             preemption_rate: config.preemption_rate,
             report_progress: config.report_progress,
             basic_block_count: 0,
@@ -921,11 +925,12 @@ impl VisitProvenance for MiriMachine<'_> {
             backtrace_style: _,
             local_crates: _,
             rng: _,
+            #[cfg(target_os = "linux")]
+            allocator: _,
             tracked_alloc_ids: _,
             track_alloc_accesses: _,
             check_alignment: _,
             cmpxchg_weak_failure_rate: _,
-            mute_stdout_stderr: _,
             preemption_rate: _,
             report_progress: _,
             basic_block_count: _,
@@ -1120,7 +1125,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         instance: ty::Instance<'tcx>,
         abi: &FnAbi<'tcx, Ty<'tcx>>,
         args: &[FnArg<'tcx, Provenance>],
-        dest: &MPlaceTy<'tcx>,
+        dest: &PlaceTy<'tcx>,
         ret: Option<mir::BasicBlock>,
         unwind: mir::UnwindAction,
     ) -> InterpResult<'tcx, Option<(&'tcx mir::Body<'tcx>, ty::Instance<'tcx>)>> {
@@ -1147,7 +1152,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         fn_val: DynSym,
         abi: &FnAbi<'tcx, Ty<'tcx>>,
         args: &[FnArg<'tcx, Provenance>],
-        dest: &MPlaceTy<'tcx>,
+        dest: &PlaceTy<'tcx>,
         ret: Option<mir::BasicBlock>,
         unwind: mir::UnwindAction,
     ) -> InterpResult<'tcx> {
@@ -1160,7 +1165,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         ecx: &mut MiriInterpCx<'tcx>,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx>],
-        dest: &MPlaceTy<'tcx>,
+        dest: &PlaceTy<'tcx>,
         ret: Option<mir::BasicBlock>,
         unwind: mir::UnwindAction,
     ) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
@@ -1639,15 +1644,21 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         interp_ok(())
     }
 
-    fn before_stack_pop(
-        ecx: &InterpCx<'tcx, Self>,
-        frame: &Frame<'tcx, Self::Provenance, Self::FrameExtra>,
-    ) -> InterpResult<'tcx> {
+    fn before_stack_pop(ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> {
+        let frame = ecx.frame();
         // We want this *before* the return value copy, because the return place itself is protected
-        // until we do `end_call` here.
+        // until we do `on_stack_pop` here, and we need to un-protect it to copy the return value.
         if ecx.machine.borrow_tracker.is_some() {
             ecx.on_stack_pop(frame)?;
         }
+        if frame.extra.is_user_relevant {
+            // All that we store is whether or not the frame we just removed is local, so now we
+            // have no idea where the next topmost local frame is. So we recompute it.
+            // (If this ever becomes a bottleneck, we could have `push` store the previous
+            // user-relevant frame and restore that here.)
+            // We have to skip the frame that is just being popped.
+            ecx.active_thread_mut().recompute_top_user_relevant_frame(/* skip */ 1);
+        }
         // tracing-tree can autoamtically annotate scope changes, but it gets very confused by our
         // concurrency and what it prints is just plain wrong. So we print our own information
         // instead. (Cc https://github.com/rust-lang/miri/issues/2266)
@@ -1661,15 +1672,8 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
         frame: Frame<'tcx, Provenance, FrameExtra<'tcx>>,
         unwinding: bool,
     ) -> InterpResult<'tcx, ReturnAction> {
-        if frame.extra.is_user_relevant {
-            // All that we store is whether or not the frame we just removed is local, so now we
-            // have no idea where the next topmost local frame is. So we recompute it.
-            // (If this ever becomes a bottleneck, we could have `push` store the previous
-            // user-relevant frame and restore that here.)
-            ecx.active_thread_mut().recompute_top_user_relevant_frame();
-        }
         let res = {
-            // Move `frame`` into a sub-scope so we control when it will be dropped.
+            // Move `frame` into a sub-scope so we control when it will be dropped.
             let mut frame = frame;
             let timing = frame.extra.timing.take();
             let res = ecx.handle_stack_pop_unwind(frame.extra, unwinding);
@@ -1781,7 +1785,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
             let is_generic = instance
                 .args
                 .into_iter()
-                .any(|kind| !matches!(kind.unpack(), ty::GenericArgKind::Lifetime(_)));
+                .any(|arg| !matches!(arg.kind(), ty::GenericArgKind::Lifetime(_)));
             let can_be_inlined = matches!(
                 ecx.tcx.sess.opts.unstable_opts.cross_crate_inline_threshold,
                 InliningThreshold::Always
@@ -1809,6 +1813,18 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
     ) -> Cow<'e, RangeSet> {
         Cow::Borrowed(ecx.machine.union_data_ranges.entry(ty).or_insert_with(compute_range))
     }
+
+    fn get_default_alloc_params(&self) -> <Self::Bytes as AllocBytes>::AllocParams {
+        use crate::alloc::MiriAllocParams;
+
+        #[cfg(target_os = "linux")]
+        match &self.allocator {
+            Some(alloc) => MiriAllocParams::Isolated(alloc.clone()),
+            None => MiriAllocParams::Global,
+        }
+        #[cfg(not(target_os = "linux"))]
+        MiriAllocParams::Global
+    }
 }
 
 /// Trait for callbacks handling asynchronous machine operations.
diff --git a/src/tools/miri/src/range_map.rs b/src/tools/miri/src/range_map.rs
index 2c2484cd0bc..29a5a8537a4 100644
--- a/src/tools/miri/src/range_map.rs
+++ b/src/tools/miri/src/range_map.rs
@@ -31,6 +31,11 @@ impl<T> RangeMap<T> {
         RangeMap { v }
     }
 
+    pub fn size(&self) -> Size {
+        let size = self.v.last().map(|x| x.range.end).unwrap_or(0);
+        Size::from_bytes(size)
+    }
+
     /// Finds the index containing the given offset.
     fn find_offset(&self, offset: u64) -> usize {
         self.v
@@ -71,10 +76,7 @@ impl<T> RangeMap<T> {
         };
         // The first offset that is not included any more.
         let end = offset + len;
-        assert!(
-            end <= self.v.last().unwrap().range.end,
-            "iterating beyond the bounds of this RangeMap"
-        );
+        assert!(end <= self.size().bytes(), "iterating beyond the bounds of this RangeMap");
         slice
             .iter()
             .take_while(move |elem| elem.range.start < end)
@@ -327,4 +329,16 @@ mod tests {
         let map = RangeMap::<i32>::new(Size::from_bytes(20), -1);
         let _ = map.iter(Size::from_bytes(11), Size::from_bytes(11));
     }
+
+    #[test]
+    fn empty_map_iter() {
+        let map = RangeMap::<i32>::new(Size::from_bytes(0), -1);
+        let _ = map.iter(Size::from_bytes(0), Size::from_bytes(0));
+    }
+
+    #[test]
+    fn empty_map_iter_mut() {
+        let mut map = RangeMap::<i32>::new(Size::from_bytes(0), -1);
+        let _ = map.iter_mut(Size::from_bytes(0), Size::from_bytes(0));
+    }
 }
diff --git a/src/tools/miri/src/shims/aarch64.rs b/src/tools/miri/src/shims/aarch64.rs
index 7cccc9e51d8..44ad5081ad5 100644
--- a/src/tools/miri/src/shims/aarch64.rs
+++ b/src/tools/miri/src/shims/aarch64.rs
@@ -1,7 +1,8 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::mir::BinOp;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use crate::*;
 
@@ -19,7 +20,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let unprefixed_name = link_name.as_str().strip_prefix("llvm.aarch64.").unwrap();
         match unprefixed_name {
             "isb" => {
-                let [arg] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [arg] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let arg = this.read_scalar(arg)?.to_i32()?;
                 match arg {
                     // SY ("full system scope")
@@ -37,7 +38,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // `left` input, the second half of the output from the `right` input.
             // https://developer.arm.com/architectures/instruction-sets/intrinsics/vpmaxq_u8
             "neon.umaxp.v16i8" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
diff --git a/src/tools/miri/src/shims/alloc.rs b/src/tools/miri/src/shims/alloc.rs
index 323b95d5f5f..d7bb16f0858 100644
--- a/src/tools/miri/src/shims/alloc.rs
+++ b/src/tools/miri/src/shims/alloc.rs
@@ -13,10 +13,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // alignment requirement and size less than or equal to the size requested."
         // So first we need to figure out what the limits are for "fundamental alignment".
         // This is given by `alignof(max_align_t)`. The following list is taken from
-        // `library/std/src/sys/pal/common/alloc.rs` (where this is called `MIN_ALIGN`) and should
+        // `library/std/src/sys/alloc/mod.rs` (where this is called `MIN_ALIGN`) and should
         // be kept in sync.
         let max_fundamental_align = match this.tcx.sess.target.arch.as_ref() {
-            "x86" | "arm" | "mips" | "mips32r6" | "powerpc" | "powerpc64" | "wasm32" => 8,
+            "x86" | "arm" | "loongarch32" | "mips" | "mips32r6" | "powerpc" | "powerpc64"
+            | "wasm32" => 8,
             "x86_64" | "aarch64" | "mips64" | "mips64r6" | "s390x" | "sparc64" | "loongarch64" =>
                 16,
             arch => bug!("unsupported target architecture for malloc: `{}`", arch),
diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs
index 7e667e70a17..8606735c913 100644
--- a/src/tools/miri/src/shims/backtrace.rs
+++ b/src/tools/miri/src/shims/backtrace.rs
@@ -1,8 +1,8 @@
-use rustc_abi::Size;
+use rustc_abi::{CanonAbi, FieldIdx, Size};
 use rustc_middle::ty::layout::LayoutOf as _;
 use rustc_middle::ty::{self, Instance, Ty};
 use rustc_span::{BytePos, Loc, Symbol, hygiene};
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use crate::*;
 
@@ -16,7 +16,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         dest: &MPlaceTy<'tcx>,
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
-        let [flags] = this.check_shim(abi, Conv::Rust, link_name, args)?;
+        let [flags] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
 
         let flags = this.read_scalar(flags)?.to_u64()?;
         if flags != 0 {
@@ -25,7 +25,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let frame_count = this.active_thread_stack().len();
 
-        this.write_scalar(Scalar::from_target_usize(frame_count.try_into().unwrap(), this), dest)
+        this.write_scalar(Scalar::from_target_usize(frame_count.to_u64(), this), dest)
     }
 
     fn handle_miri_get_backtrace(
@@ -38,7 +38,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let ptr_ty = this.machine.layouts.mut_raw_ptr.ty;
         let ptr_layout = this.layout_of(ptr_ty)?;
 
-        let [flags, buf] = this.check_shim(abi, Conv::Rust, link_name, args)?;
+        let [flags, buf] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
 
         let flags = this.read_scalar(flags)?.to_u64()?;
         let buf_place = this.deref_pointer_as(buf, ptr_layout)?;
@@ -70,7 +70,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             1 =>
                 for (i, ptr) in ptrs.into_iter().enumerate() {
-                    let offset = ptr_layout.size.checked_mul(i.try_into().unwrap(), this).unwrap();
+                    let offset = ptr_layout.size.checked_mul(i.to_u64(), this).unwrap();
 
                     let op_place = buf_place.offset(offset, ptr_layout, this)?;
 
@@ -118,7 +118,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         dest: &MPlaceTy<'tcx>,
     ) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
-        let [ptr, flags] = this.check_shim(abi, Conv::Rust, link_name, args)?;
+        let [ptr, flags] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
 
         let flags = this.read_scalar(flags)?.to_u64()?;
 
@@ -158,24 +158,24 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             1 => {
                 this.write_scalar(
-                    Scalar::from_target_usize(name.len().try_into().unwrap(), this),
-                    &this.project_field(dest, 0)?,
+                    Scalar::from_target_usize(name.len().to_u64(), this),
+                    &this.project_field(dest, FieldIdx::from_u32(0))?,
                 )?;
                 this.write_scalar(
-                    Scalar::from_target_usize(filename.len().try_into().unwrap(), this),
-                    &this.project_field(dest, 1)?,
+                    Scalar::from_target_usize(filename.len().to_u64(), this),
+                    &this.project_field(dest, FieldIdx::from_u32(1))?,
                 )?;
             }
             _ => throw_unsup_format!("unknown `miri_resolve_frame` flags {}", flags),
         }
 
-        this.write_scalar(Scalar::from_u32(lineno), &this.project_field(dest, 2)?)?;
-        this.write_scalar(Scalar::from_u32(colno), &this.project_field(dest, 3)?)?;
+        this.write_scalar(Scalar::from_u32(lineno), &this.project_field(dest, FieldIdx::from_u32(2))?)?;
+        this.write_scalar(Scalar::from_u32(colno), &this.project_field(dest, FieldIdx::from_u32(3))?)?;
 
         // Support a 4-field struct for now - this is deprecated
         // and slated for removal.
         if num_fields == 5 {
-            this.write_pointer(fn_ptr, &this.project_field(dest, 4)?)?;
+            this.write_pointer(fn_ptr, &this.project_field(dest, FieldIdx::from_u32(4))?)?;
         }
 
         interp_ok(())
@@ -190,7 +190,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
 
         let [ptr, flags, name_ptr, filename_ptr] =
-            this.check_shim(abi, Conv::Rust, link_name, args)?;
+            this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
 
         let flags = this.read_scalar(flags)?.to_u64()?;
         if flags != 0 {
diff --git a/src/tools/miri/src/shims/files.rs b/src/tools/miri/src/shims/files.rs
index 42603e784bb..606d1ffbea6 100644
--- a/src/tools/miri/src/shims/files.rs
+++ b/src/tools/miri/src/shims/files.rs
@@ -135,7 +135,10 @@ pub trait FileDescription: std::fmt::Debug + FileDescriptionExt {
 
     /// 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.
+    ///
+    /// When the read is done, `finish` will be called. Note that `read` itself may return before
+    /// that happens! Everything that should happen "after" the `read` needs to happen inside
+    /// `finish`.
     fn read<'tcx>(
         self: FileDescriptionRef<Self>,
         _communicate_allowed: bool,
@@ -149,7 +152,10 @@ pub trait FileDescription: std::fmt::Debug + FileDescriptionExt {
 
     /// Writes as much as possible from the given buffer `ptr`.
     /// `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.
+    ///
+    /// When the write is done, `finish` will be called. Note that `write` itself may return before
+    /// that happens! Everything that should happen "after" the `write` needs to happen inside
+    /// `finish`.
     fn write<'tcx>(
         self: FileDescriptionRef<Self>,
         _communicate_allowed: bool,
@@ -196,6 +202,20 @@ pub trait FileDescription: std::fmt::Debug + FileDescriptionExt {
     fn as_unix<'tcx>(&self, _ecx: &MiriInterpCx<'tcx>) -> &dyn UnixFileDescription {
         panic!("Not a unix file descriptor: {}", self.name());
     }
+
+    /// Implementation of fcntl(F_GETFL) for this FD.
+    fn get_flags<'tcx>(&self, _ecx: &mut MiriInterpCx<'tcx>) -> InterpResult<'tcx, Scalar> {
+        throw_unsup_format!("fcntl: {} is not supported for F_GETFL", self.name());
+    }
+
+    /// Implementation of fcntl(F_SETFL) for this FD.
+    fn set_flags<'tcx>(
+        &self,
+        _flag: i32,
+        _ecx: &mut MiriInterpCx<'tcx>,
+    ) -> InterpResult<'tcx, Scalar> {
+        throw_unsup_format!("fcntl: {} is not supported for F_SETFL", self.name());
+    }
 }
 
 impl FileDescription for io::Stdin {
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index 52c16a0c2e2..ae04ca018ab 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -2,7 +2,7 @@ use std::collections::hash_map::Entry;
 use std::io::Write;
 use std::path::Path;
 
-use rustc_abi::{Align, AlignFromBytesError, Size};
+use rustc_abi::{Align, AlignFromBytesError, CanonAbi, Size};
 use rustc_apfloat::Float;
 use rustc_ast::expand::allocator::alloc_error_handler_name;
 use rustc_hir::def::DefKind;
@@ -12,7 +12,7 @@ use rustc_middle::mir::interpret::AllocInit;
 use rustc_middle::ty::{Instance, Ty};
 use rustc_middle::{mir, ty};
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use self::helpers::{ToHost, ToSoft};
 use super::alloc::EvalContextExt as _;
@@ -43,7 +43,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         link_name: Symbol,
         abi: &FnAbi<'tcx, Ty<'tcx>>,
         args: &[OpTy<'tcx>],
-        dest: &MPlaceTy<'tcx>,
+        dest: &PlaceTy<'tcx>,
         ret: Option<mir::BasicBlock>,
         unwind: mir::UnwindAction,
     ) -> InterpResult<'tcx, Option<(&'tcx mir::Body<'tcx>, ty::Instance<'tcx>)>> {
@@ -69,8 +69,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             _ => {}
         }
 
+        // FIXME: avoid allocating memory
+        let dest = this.force_allocation(dest)?;
+
         // The rest either implements the logic, or falls back to `lookup_exported_symbol`.
-        match this.emulate_foreign_item_inner(link_name, abi, args, dest)? {
+        match this.emulate_foreign_item_inner(link_name, abi, args, &dest)? {
             EmulateItemResult::NeedsReturn => {
                 trace!("{:?}", this.dump_place(&dest.clone().into()));
                 this.return_to_block(ret)?;
@@ -111,7 +114,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         sym: DynSym,
         abi: &FnAbi<'tcx, Ty<'tcx>>,
         args: &[OpTy<'tcx>],
-        dest: &MPlaceTy<'tcx>,
+        dest: &PlaceTy<'tcx>,
         ret: Option<mir::BasicBlock>,
         unwind: mir::UnwindAction,
     ) -> InterpResult<'tcx> {
@@ -247,7 +250,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // When adding a new shim, you should follow the following pattern:
         // ```
         // "shim_name" => {
-        //     let [arg1, arg2, arg3] = this.check_shim(abi, Conv::::C , link_name, args)?;
+        //     let [arg1, arg2, arg3] = this.check_shim(abi, CanonAbi::C , link_name, args)?;
         //     let result = this.shim_name(arg1, arg2, arg3)?;
         //     this.write_scalar(result, dest)?;
         // }
@@ -285,16 +288,16 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
         match link_name.as_str() {
             // Miri-specific extern functions
             "miri_start_unwind" => {
-                let [payload] = this.check_shim(abi, Conv::Rust, link_name, args)?;
+                let [payload] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
                 this.handle_miri_start_unwind(payload)?;
                 return interp_ok(EmulateItemResult::NeedsUnwind);
             }
             "miri_run_provenance_gc" => {
-                let [] = this.check_shim(abi, Conv::Rust, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
                 this.run_provenance_gc();
             }
             "miri_get_alloc_id" => {
-                let [ptr] = this.check_shim(abi, Conv::Rust, link_name, args)?;
+                let [ptr] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let (alloc_id, _, _) = this.ptr_get_alloc_id(ptr, 0).map_err_kind(|_e| {
                     err_machine_stop!(TerminationInfo::Abort(format!(
@@ -304,7 +307,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(Scalar::from_u64(alloc_id.0.get()), dest)?;
             }
             "miri_print_borrow_state" => {
-                let [id, show_unnamed] = this.check_shim(abi, Conv::Rust, link_name, args)?;
+                let [id, show_unnamed] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
                 let id = this.read_scalar(id)?.to_u64()?;
                 let show_unnamed = this.read_scalar(show_unnamed)?.to_bool()?;
                 if let Some(id) = std::num::NonZero::new(id).map(AllocId)
@@ -318,7 +321,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "miri_pointer_name" => {
                 // This associates a name to a tag. Very useful for debugging, and also makes
                 // tests more strict.
-                let [ptr, nth_parent, name] = this.check_shim(abi, Conv::Rust, link_name, args)?;
+                let [ptr, nth_parent, name] =
+                    this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let nth_parent = this.read_scalar(nth_parent)?.to_u8()?;
                 let name = this.read_immediate(name)?;
@@ -331,7 +335,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.give_pointer_debug_name(ptr, nth_parent, &name)?;
             }
             "miri_static_root" => {
-                let [ptr] = this.check_shim(abi, Conv::Rust, link_name, args)?;
+                let [ptr] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let (alloc_id, offset, _) = this.ptr_get_alloc_id(ptr, 0)?;
                 if offset != Size::ZERO {
@@ -342,7 +346,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.machine.static_roots.push(alloc_id);
             }
             "miri_host_to_target_path" => {
-                let [ptr, out, out_size] = this.check_shim(abi, Conv::Rust, link_name, args)?;
+                let [ptr, out, out_size] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let out = this.read_pointer(out)?;
                 let out_size = this.read_scalar(out_size)?.to_target_usize(this)?;
@@ -378,7 +382,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Writes some bytes to the interpreter's stdout/stderr. See the
             // README for details.
             "miri_write_to_stdout" | "miri_write_to_stderr" => {
-                let [msg] = this.check_shim(abi, Conv::Rust, link_name, args)?;
+                let [msg] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
                 let msg = this.read_immediate(msg)?;
                 let msg = this.read_byte_slice(&msg)?;
                 // Note: we're ignoring errors writing to host stdout/stderr.
@@ -392,7 +396,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "miri_promise_symbolic_alignment" => {
                 use rustc_abi::AlignFromBytesError;
 
-                let [ptr, align] = this.check_shim(abi, Conv::Rust, link_name, args)?;
+                let [ptr, align] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let align = this.read_target_usize(align)?;
                 if !align.is_power_of_two() {
@@ -433,12 +437,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // Aborting the process.
             "exit" => {
-                let [code] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [code] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let code = this.read_scalar(code)?.to_i32()?;
                 throw_machine_stop!(TerminationInfo::Exit { code, leak_check: false });
             }
             "abort" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 throw_machine_stop!(TerminationInfo::Abort(
                     "the program aborted execution".to_owned()
                 ))
@@ -446,7 +450,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // Standard C allocation
             "malloc" => {
-                let [size] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [size] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let size = this.read_target_usize(size)?;
                 if size <= this.max_size_of_val().bytes() {
                     let res = this.malloc(size, AllocInit::Uninit)?;
@@ -460,7 +464,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 }
             }
             "calloc" => {
-                let [items, elem_size] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [items, elem_size] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let items = this.read_target_usize(items)?;
                 let elem_size = this.read_target_usize(elem_size)?;
                 if let Some(size) = this.compute_size_in_bytes(Size::from_bytes(elem_size), items) {
@@ -475,12 +479,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 }
             }
             "free" => {
-                let [ptr] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [ptr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 this.free(ptr)?;
             }
             "realloc" => {
-                let [old_ptr, new_size] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [old_ptr, new_size] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let old_ptr = this.read_pointer(old_ptr)?;
                 let new_size = this.read_target_usize(new_size)?;
                 if new_size <= this.max_size_of_val().bytes() {
@@ -500,7 +504,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let default = |ecx: &mut MiriInterpCx<'tcx>| {
                     // Only call `check_shim` when `#[global_allocator]` isn't used. When that
                     // macro is used, we act like no shim exists, so that the exported function can run.
-                    let [size, align] = ecx.check_shim(abi, Conv::Rust, link_name, args)?;
+                    let [size, align] = ecx.check_shim(abi, CanonAbi::Rust, link_name, args)?;
                     let size = ecx.read_target_usize(size)?;
                     let align = ecx.read_target_usize(align)?;
 
@@ -533,7 +537,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 return this.emulate_allocator(|this| {
                     // See the comment for `__rust_alloc` why `check_shim` is only called in the
                     // default case.
-                    let [size, align] = this.check_shim(abi, Conv::Rust, link_name, args)?;
+                    let [size, align] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
                     let size = this.read_target_usize(size)?;
                     let align = this.read_target_usize(align)?;
 
@@ -555,7 +559,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     // See the comment for `__rust_alloc` why `check_shim` is only called in the
                     // default case.
                     let [ptr, old_size, align] =
-                        ecx.check_shim(abi, Conv::Rust, link_name, args)?;
+                        ecx.check_shim(abi, CanonAbi::Rust, link_name, args)?;
                     let ptr = ecx.read_pointer(ptr)?;
                     let old_size = ecx.read_target_usize(old_size)?;
                     let align = ecx.read_target_usize(align)?;
@@ -586,7 +590,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     // See the comment for `__rust_alloc` why `check_shim` is only called in the
                     // default case.
                     let [ptr, old_size, align, new_size] =
-                        this.check_shim(abi, Conv::Rust, link_name, args)?;
+                        this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
                     let ptr = this.read_pointer(ptr)?;
                     let old_size = this.read_target_usize(old_size)?;
                     let align = this.read_target_usize(align)?;
@@ -610,7 +614,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // C memory handling functions
             "memcmp" => {
-                let [left, right, n] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, n] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let left = this.read_pointer(left)?;
                 let right = this.read_pointer(right)?;
                 let n = Size::from_bytes(this.read_target_usize(n)?);
@@ -634,12 +638,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(Scalar::from_i32(result), dest)?;
             }
             "memrchr" => {
-                let [ptr, val, num] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [ptr, val, num] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let val = this.read_scalar(val)?.to_i32()?;
                 let num = this.read_target_usize(num)?;
                 // The docs say val is "interpreted as unsigned char".
-                #[expect(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
+                #[expect(clippy::as_conversions)]
                 let val = val as u8;
 
                 // C requires that this must always be a valid pointer (C18 §7.1.4).
@@ -660,12 +664,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 }
             }
             "memchr" => {
-                let [ptr, val, num] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [ptr, val, num] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let val = this.read_scalar(val)?.to_i32()?;
                 let num = this.read_target_usize(num)?;
                 // The docs say val is "interpreted as unsigned char".
-                #[expect(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
+                #[expect(clippy::as_conversions)]
                 let val = val as u8;
 
                 // C requires that this must always be a valid pointer (C18 §7.1.4).
@@ -676,14 +680,14 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     .iter()
                     .position(|&c| c == val);
                 if let Some(idx) = idx {
-                    let new_ptr = ptr.wrapping_offset(Size::from_bytes(idx as u64), this);
+                    let new_ptr = ptr.wrapping_offset(Size::from_bytes(idx), this);
                     this.write_pointer(new_ptr, dest)?;
                 } else {
                     this.write_null(dest)?;
                 }
             }
             "strlen" => {
-                let [ptr] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [ptr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 // This reads at least 1 byte, so we are already enforcing that this is a valid pointer.
                 let n = this.read_c_str(ptr)?.len();
@@ -693,7 +697,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 )?;
             }
             "wcslen" => {
-                let [ptr] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [ptr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 // This reads at least 1 byte, so we are already enforcing that this is a valid pointer.
                 let n = this.read_wchar_t_str(ptr)?.len();
@@ -703,7 +707,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 )?;
             }
             "memcpy" => {
-                let [ptr_dest, ptr_src, n] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [ptr_dest, ptr_src, n] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let ptr_dest = this.read_pointer(ptr_dest)?;
                 let ptr_src = this.read_pointer(ptr_src)?;
                 let n = this.read_target_usize(n)?;
@@ -717,7 +721,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_pointer(ptr_dest, dest)?;
             }
             "strcpy" => {
-                let [ptr_dest, ptr_src] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [ptr_dest, ptr_src] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let ptr_dest = this.read_pointer(ptr_dest)?;
                 let ptr_src = this.read_pointer(ptr_src)?;
 
@@ -748,7 +752,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             | "erff"
             | "erfcf"
             => {
-                let [f] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [f] = this.check_shim(abi, CanonAbi::C , link_name, args)?;
                 let f = this.read_scalar(f)?.to_f32()?;
                 // Using host floats (but it's fine, these operations do not have guaranteed precision).
                 let f_host = f.to_host();
@@ -786,7 +790,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             | "atan2f"
             | "fdimf"
             => {
-                let [f1, f2] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [f1, f2] = this.check_shim(abi, CanonAbi::C , link_name, args)?;
                 let f1 = this.read_scalar(f1)?.to_f32()?;
                 let f2 = this.read_scalar(f2)?.to_f32()?;
                 // underscore case for windows, here and below
@@ -825,7 +829,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             | "erf"
             | "erfc"
             => {
-                let [f] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [f] = this.check_shim(abi, CanonAbi::C , link_name, args)?;
                 let f = this.read_scalar(f)?.to_f64()?;
                 // Using host floats (but it's fine, these operations do not have guaranteed precision).
                 let f_host = f.to_host();
@@ -863,7 +867,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             | "atan2"
             | "fdim"
             => {
-                let [f1, f2] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [f1, f2] = this.check_shim(abi, CanonAbi::C , link_name, args)?;
                 let f1 = this.read_scalar(f1)?.to_f64()?;
                 let f2 = this.read_scalar(f2)?.to_f64()?;
                 // underscore case for windows, here and below
@@ -892,7 +896,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             | "ldexp"
             | "scalbn"
             => {
-                let [x, exp] = this.check_shim(abi, Conv::C , link_name, args)?;
+                let [x, exp] = this.check_shim(abi, CanonAbi::C , link_name, args)?;
                 // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same.
                 let x = this.read_scalar(x)?.to_f64()?;
                 let exp = this.read_scalar(exp)?.to_i32()?;
@@ -902,7 +906,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(res, dest)?;
             }
             "lgammaf_r" => {
-                let [x, signp] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [x, signp] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let x = this.read_scalar(x)?.to_f32()?;
                 let signp = this.deref_pointer_as(signp, this.machine.layouts.i32)?;
 
@@ -918,7 +922,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(res, dest)?;
             }
             "lgamma_r" => {
-                let [x, signp] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [x, signp] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let x = this.read_scalar(x)?.to_f64()?;
                 let signp = this.deref_pointer_as(signp, this.machine.layouts.i32)?;
 
@@ -936,7 +940,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // LLVM intrinsics
             "llvm.prefetch" => {
-                let [p, rw, loc, ty] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [p, rw, loc, ty] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let _ = this.read_pointer(p)?;
                 let rw = this.read_scalar(rw)?.to_i32()?;
@@ -963,7 +967,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Used to implement the x86 `_mm{,256,512}_popcnt_epi{8,16,32,64}` and wasm
             // `{i,u}8x16_popcnt` functions.
             name if name.starts_with("llvm.ctpop.v") => {
-                let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (op, op_len) = this.project_to_simd(op)?;
                 let (dest, dest_len) = this.project_to_simd(dest)?;
@@ -999,7 +1003,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             // FIXME: Move this to an `arm` submodule.
             "llvm.arm.hint" if this.tcx.sess.target.arch == "arm" => {
-                let [arg] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [arg] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let arg = this.read_scalar(arg)?.to_i32()?;
                 // Note that different arguments might have different target feature requirements.
                 match arg {
diff --git a/src/tools/miri/src/shims/io_error.rs b/src/tools/miri/src/shims/io_error.rs
index acf3f74a93d..e597b527cb7 100644
--- a/src/tools/miri/src/shims/io_error.rs
+++ b/src/tools/miri/src/shims/io_error.rs
@@ -1,4 +1,5 @@
 use std::io;
+use std::io::ErrorKind;
 
 use crate::*;
 
@@ -13,6 +14,29 @@ pub enum IoError {
 }
 pub use self::IoError::*;
 
+impl IoError {
+    pub(crate) fn into_ntstatus(self) -> i32 {
+        let raw = match self {
+            HostError(e) =>
+                match e.kind() {
+                    // STATUS_MEDIA_WRITE_PROTECTED
+                    ErrorKind::ReadOnlyFilesystem => 0xC00000A2u32,
+                    // STATUS_FILE_INVALID
+                    ErrorKind::InvalidInput => 0xC0000098,
+                    // STATUS_DISK_FULL
+                    ErrorKind::QuotaExceeded => 0xC000007F,
+                    // STATUS_ACCESS_DENIED
+                    ErrorKind::PermissionDenied => 0xC0000022,
+                    // For the default error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR.
+                    _ => 0xC0000185,
+                },
+            // For the default error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR.
+            _ => 0xC0000185,
+        };
+        raw.cast_signed()
+    }
+}
+
 impl From<io::Error> for IoError {
     fn from(value: io::Error) -> Self {
         IoError::HostError(value)
diff --git a/src/tools/miri/src/shims/native_lib.rs b/src/tools/miri/src/shims/native_lib.rs
index 1a43e229725..1e6c93333c1 100644
--- a/src/tools/miri/src/shims/native_lib.rs
+++ b/src/tools/miri/src/shims/native_lib.rs
@@ -93,14 +93,10 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
         // Try getting the function from the shared library.
         let (lib, lib_path) = this.machine.native_lib.as_ref().unwrap();
-        let func: libloading::Symbol<'_, unsafe extern "C" fn()> = unsafe {
-            match lib.get(link_name.as_str().as_bytes()) {
-                Ok(x) => x,
-                Err(_) => {
-                    return None;
-                }
-            }
-        };
+        let func: libloading::Symbol<'_, unsafe extern "C" fn()> =
+            unsafe { lib.get(link_name.as_str().as_bytes()).ok()? };
+        #[expect(clippy::as_conversions)] // fn-ptr to raw-ptr cast needs `as`.
+        let fn_ptr = *func.deref() as *mut std::ffi::c_void;
 
         // FIXME: this is a hack!
         // The `libloading` crate will automatically load system libraries like `libc`.
@@ -115,7 +111,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // using the `libc` crate where this interface is public.
         let mut info = std::mem::MaybeUninit::<libc::Dl_info>::zeroed();
         unsafe {
-            if libc::dladdr(*func.deref() as *const _, info.as_mut_ptr()) != 0 {
+            if libc::dladdr(fn_ptr, info.as_mut_ptr()) != 0 {
                 let info = info.assume_init();
                 #[cfg(target_os = "cygwin")]
                 let fname_ptr = info.dli_fname.as_ptr();
@@ -129,8 +125,9 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 }
             }
         }
+
         // Return a pointer to the function.
-        Some(CodePtr(*func.deref() as *mut _))
+        Some(CodePtr(fn_ptr))
     }
 }
 
diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs
index b5ed5ea837b..a6bce830149 100644
--- a/src/tools/miri/src/shims/panic.rs
+++ b/src/tools/miri/src/shims/panic.rs
@@ -56,7 +56,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         interp_ok(())
     }
 
-    /// Handles the `try` intrinsic, the underlying implementation of `std::panicking::try`.
+    /// Handles the `catch_unwind` intrinsic.
     fn handle_catch_unwind(
         &mut self,
         args: &[OpTy<'tcx>],
@@ -66,7 +66,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
 
         // Signature:
-        //   fn r#try(try_fn: fn(*mut u8), data: *mut u8, catch_fn: fn(*mut u8, *mut u8)) -> i32
+        //   fn catch_unwind(try_fn: fn(*mut u8), data: *mut u8, catch_fn: fn(*mut u8, *mut u8)) -> i32
         // Calls `try_fn` with `data` as argument. If that executes normally, returns 0.
         // If that unwinds, calls `catch_fn` with the first argument being `data` and
         // then second argument being a target-dependent `payload` (i.e. it is up to us to define
@@ -120,14 +120,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // We only care about `catch_panic` if we're unwinding - if we're doing a normal
         // return, then we don't need to do anything special.
         if let (true, Some(catch_unwind)) = (unwinding, extra.catch_unwind.take()) {
-            // We've just popped a frame that was pushed by `try`,
+            // We've just popped a frame that was pushed by `catch_unwind`,
             // and we are unwinding, so we should catch that.
             trace!(
                 "unwinding: found catch_panic frame during unwinding: {:?}",
                 this.frame().instance()
             );
 
-            // We set the return value of `try` to 1, since there was a panic.
+            // We set the return value of `catch_unwind` to 1, since there was a panic.
             this.write_scalar(Scalar::from_i32(1), &catch_unwind.dest)?;
 
             // The Thread's `panic_payload` holds what was passed to `miri_start_unwind`.
@@ -142,7 +142,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 ExternAbi::Rust,
                 &[catch_unwind.data, payload],
                 None,
-                // Directly return to caller of `try`.
+                // Directly return to caller of `catch_unwind`.
                 StackPopCleanup::Goto {
                     ret: catch_unwind.ret,
                     // `catch_fn` must not unwind.
@@ -247,7 +247,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             _ => {
                 // Call the lang item associated with this message.
-                let fn_item = this.tcx.require_lang_item(msg.panic_function(), None);
+                let fn_item = this.tcx.require_lang_item(msg.panic_function(), this.tcx.span);
                 let instance = ty::Instance::mono(this.tcx.tcx, fn_item);
                 this.call_function(
                     instance,
diff --git a/src/tools/miri/src/shims/unix/android/foreign_items.rs b/src/tools/miri/src/shims/unix/android/foreign_items.rs
index 0e7cf7153f5..690b5295681 100644
--- a/src/tools/miri/src/shims/unix/android/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/android/foreign_items.rs
@@ -1,6 +1,7 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use crate::shims::unix::android::thread::prctl;
 use crate::shims::unix::linux_like::epoll::EvalContextExt as _;
@@ -25,29 +26,29 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         match link_name.as_str() {
             // epoll, eventfd
             "epoll_create1" => {
-                let [flag] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [flag] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.epoll_create1(flag)?;
                 this.write_scalar(result, dest)?;
             }
             "epoll_ctl" => {
-                let [epfd, op, fd, event] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [epfd, op, fd, event] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.epoll_ctl(epfd, op, fd, event)?;
                 this.write_scalar(result, dest)?;
             }
             "epoll_wait" => {
                 let [epfd, events, maxevents, timeout] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.epoll_wait(epfd, events, maxevents, timeout, dest)?;
             }
             "eventfd" => {
-                let [val, flag] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [val, flag] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.eventfd(val, flag)?;
                 this.write_scalar(result, dest)?;
             }
 
             // Miscellaneous
             "__errno" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let errno_place = this.last_error_place()?;
                 this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
             }
diff --git a/src/tools/miri/src/shims/unix/android/thread.rs b/src/tools/miri/src/shims/unix/android/thread.rs
index 30ec0aefcbf..5d17d6c8517 100644
--- a/src/tools/miri/src/shims/unix/android/thread.rs
+++ b/src/tools/miri/src/shims/unix/android/thread.rs
@@ -1,13 +1,13 @@
-use rustc_abi::Size;
+use rustc_abi::{CanonAbi, Size};
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use crate::helpers::check_min_vararg_count;
 use crate::shims::unix::thread::{EvalContextExt as _, ThreadNameResult};
 use crate::*;
 
-const TASK_COMM_LEN: usize = 16;
+const TASK_COMM_LEN: u64 = 16;
 
 pub fn prctl<'tcx>(
     ecx: &mut MiriInterpCx<'tcx>,
@@ -16,7 +16,7 @@ pub fn prctl<'tcx>(
     args: &[OpTy<'tcx>],
     dest: &MPlaceTy<'tcx>,
 ) -> InterpResult<'tcx> {
-    let ([op], varargs) = ecx.check_shim_variadic(abi, Conv::C, link_name, args)?;
+    let ([op], varargs) = ecx.check_shim_variadic(abi, CanonAbi::C, link_name, args)?;
 
     // FIXME: Use constants once https://github.com/rust-lang/libc/pull/3941 backported to the 0.2 branch.
     let pr_set_name = 15;
@@ -38,7 +38,7 @@ pub fn prctl<'tcx>(
             let [name] = check_min_vararg_count("prctl(PR_GET_NAME, ...)", varargs)?;
             let name = ecx.read_scalar(name)?;
             let thread = ecx.pthread_self()?;
-            let len = Scalar::from_target_usize(TASK_COMM_LEN as u64, ecx);
+            let len = Scalar::from_target_usize(TASK_COMM_LEN, ecx);
             ecx.check_ptr_access(
                 name.to_pointer(ecx)?,
                 Size::from_bytes(TASK_COMM_LEN),
diff --git a/src/tools/miri/src/shims/unix/env.rs b/src/tools/miri/src/shims/unix/env.rs
index aebb5757aec..62ac7ee3806 100644
--- a/src/tools/miri/src/shims/unix/env.rs
+++ b/src/tools/miri/src/shims/unix/env.rs
@@ -2,8 +2,9 @@ use std::ffi::{OsStr, OsString};
 use std::io::ErrorKind;
 use std::{env, mem};
 
-use rustc_abi::Size;
+use rustc_abi::{FieldIdx, Size};
 use rustc_data_structures::fx::FxHashMap;
+use rustc_index::IndexVec;
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::LayoutOf;
 
@@ -118,7 +119,7 @@ fn alloc_env_var<'tcx>(
 /// Allocates an `environ` block with the given list of pointers.
 fn alloc_environ_block<'tcx>(
     ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>,
-    mut vars: Vec<Pointer>,
+    mut vars: IndexVec<FieldIdx, Pointer>,
 ) -> InterpResult<'tcx, Pointer> {
     // Add trailing null.
     vars.push(Pointer::null());
@@ -129,7 +130,7 @@ fn alloc_environ_block<'tcx>(
         u64::try_from(vars.len()).unwrap(),
     ))?;
     let vars_place = ecx.allocate(vars_layout, MiriMemoryKind::Runtime.into())?;
-    for (idx, var) in vars.into_iter().enumerate() {
+    for (idx, var) in vars.into_iter_enumerated() {
         let place = ecx.project_field(&vars_place, idx)?;
         ecx.write_pointer(var, &place)?;
     }
diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs
index 156814a26fa..71102d9f2f3 100644
--- a/src/tools/miri/src/shims/unix/fd.rs
+++ b/src/tools/miri/src/shims/unix/fd.rs
@@ -141,6 +141,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let f_getfd = this.eval_libc_i32("F_GETFD");
         let f_dupfd = this.eval_libc_i32("F_DUPFD");
         let f_dupfd_cloexec = this.eval_libc_i32("F_DUPFD_CLOEXEC");
+        let f_getfl = this.eval_libc_i32("F_GETFL");
+        let f_setfl = this.eval_libc_i32("F_SETFL");
 
         // We only support getting the flags for a descriptor.
         match cmd {
@@ -175,6 +177,25 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     this.set_last_error_and_return_i32(LibcError("EBADF"))
                 }
             }
+            cmd if cmd == f_getfl => {
+                // Check if this is a valid open file descriptor.
+                let Some(fd) = this.machine.fds.get(fd_num) else {
+                    return this.set_last_error_and_return_i32(LibcError("EBADF"));
+                };
+
+                fd.get_flags(this)
+            }
+            cmd if cmd == f_setfl => {
+                // Check if this is a valid open file descriptor.
+                let Some(fd) = this.machine.fds.get(fd_num) else {
+                    return this.set_last_error_and_return_i32(LibcError("EBADF"));
+                };
+
+                let [flag] = check_min_vararg_count("fcntl(fd, F_SETFL, ...)", varargs)?;
+                let flag = this.read_scalar(flag)?.to_i32()?;
+
+                fd.set_flags(flag, this)
+            }
             cmd if this.tcx.sess.target.os == "macos"
                 && cmd == this.eval_libc_i32("F_FULLFSYNC") =>
             {
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index 026aa1f9503..9106ef94c43 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -1,11 +1,11 @@
 use std::ffi::OsStr;
 use std::str;
 
-use rustc_abi::{ExternAbi, Size};
+use rustc_abi::{CanonAbi, ExternAbi, Size};
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use self::shims::unix::android::foreign_items as android;
 use self::shims::unix::freebsd::foreign_items as freebsd;
@@ -334,7 +334,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             "fcntl" => {
                 let ([fd_num, cmd], varargs) =
-                    this.check_shim_variadic(abi, Conv::C, link_name, args)?;
+                    this.check_shim_variadic(abi, CanonAbi::C, link_name, args)?;
                 let result = this.fcntl(fd_num, cmd, varargs)?;
                 this.write_scalar(result, dest)?;
             }
@@ -387,7 +387,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // `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
                 let ([path_raw, flag], varargs) =
-                    this.check_shim_variadic(abi, Conv::C, link_name, args)?;
+                    this.check_shim_variadic(abi, CanonAbi::C, link_name, args)?;
                 let result = this.open(path_raw, flag, varargs)?;
                 this.write_scalar(result, dest)?;
             }
@@ -701,20 +701,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // Allocation
             "posix_memalign" => {
-                let [memptr, align, size] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [memptr, align, size] = this.check_shim(abi, CanonAbi::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)?;
+                    this.check_shim(abi, CanonAbi::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, CanonAbi::C, link_name, args)?;
                 let result = this.munmap(addr, length)?;
                 this.write_scalar(result, dest)?;
             }
@@ -722,7 +722,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "reallocarray" => {
                 // Currently this function does not exist on all Unixes, e.g. on macOS.
                 this.check_target_os(&["linux", "freebsd", "android"], link_name)?;
-                let [ptr, nmemb, size] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [ptr, nmemb, size] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let nmemb = this.read_target_usize(nmemb)?;
                 let size = this.read_target_usize(size)?;
@@ -745,14 +745,14 @@ 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, CanonAbi::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, CanonAbi::C, link_name, args)?;
                 this.read_target_usize(handle)?;
                 let symbol = this.read_pointer(symbol)?;
                 let name = this.read_c_str(symbol)?;
@@ -768,7 +768,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, CanonAbi::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)?;
 
@@ -796,21 +796,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, CanonAbi::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, CanonAbi::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, CanonAbi::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)?;
@@ -822,156 +822,157 @@ 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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::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, CanonAbi::C, link_name, args)?;
                 let result = this.nanosleep(req, rem)?;
                 this.write_scalar(result, dest)?;
             }
             "sched_getaffinity" => {
                 // Currently this function does not exist on all Unixes, e.g. on macOS.
                 this.check_target_os(&["linux", "freebsd", "android"], link_name)?;
-                let [pid, cpusetsize, mask] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [pid, cpusetsize, mask] = this.check_shim(abi, CanonAbi::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)?;
@@ -1008,7 +1009,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "sched_setaffinity" => {
                 // Currently this function does not exist on all Unixes, e.g. on macOS.
                 this.check_target_os(&["linux", "freebsd", "android"], link_name)?;
-                let [pid, cpusetsize, mask] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [pid, cpusetsize, mask] = this.check_shim(abi, CanonAbi::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)?;
@@ -1048,12 +1049,13 @@ 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, CanonAbi::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, CanonAbi::C, link_name, args)?;
                 this.read_pointer(prepare)?;
                 this.read_pointer(parent)?;
                 this.read_pointer(child)?;
@@ -1067,7 +1069,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     &["linux", "macos", "freebsd", "illumos", "solaris", "android"],
                     link_name,
                 )?;
-                let [buf, bufsize] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [buf, bufsize] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let buf = this.read_pointer(buf)?;
                 let bufsize = this.read_target_usize(bufsize)?;
 
@@ -1085,7 +1087,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, CanonAbi::C, link_name, args)?;
                 let result = this.strerror_r(errnum, buf, buflen)?;
                 this.write_scalar(result, dest)?;
             }
@@ -1097,7 +1099,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     &["linux", "freebsd", "illumos", "solaris", "android"],
                     link_name,
                 )?;
-                let [ptr, len, flags] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [ptr, len, flags] = this.check_shim(abi, CanonAbi::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()?;
@@ -1109,7 +1111,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // This function is non-standard but exists with the same signature and
                 // same behavior (eg never fails) on FreeBSD and Solaris/Illumos.
                 this.check_target_os(&["freebsd", "illumos", "solaris"], link_name)?;
-                let [ptr, len] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [ptr, len] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let len = this.read_target_usize(len)?;
                 this.gen_random(ptr, len)?;
@@ -1133,12 +1135,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     link_name,
                 )?;
                 // This function looks and behaves excatly like miri_start_unwind.
-                let [payload] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [payload] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.handle_miri_start_unwind(payload)?;
                 return interp_ok(EmulateItemResult::NeedsUnwind);
             }
             "getuid" | "geteuid" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 // For now, just pretend we always have this fixed UID.
                 this.write_int(UID, dest)?;
             }
@@ -1146,7 +1148,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // 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)?;
+                let [_attr, guard_size] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let guard_size_layout = this.machine.layouts.usize;
                 let guard_size = this.deref_pointer_as(guard_size, guard_size_layout)?;
                 this.write_scalar(
@@ -1159,11 +1161,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
 
             "pthread_attr_init" | "pthread_attr_destroy" if this.frame_in_std() => {
-                let [_] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [_] = this.check_shim(abi, CanonAbi::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)?;
+                let [_, _] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.write_null(dest)?;
             }
 
@@ -1171,7 +1173,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // 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)?;
+                    this.check_shim(abi, CanonAbi::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_as(addr_place, this.machine.layouts.usize)?;
@@ -1191,18 +1193,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
 
             "signal" | "sigaltstack" if this.frame_in_std() => {
-                let [_, _] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [_, _] = this.check_shim(abi, CanonAbi::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)?;
+                let [_, _, _] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.write_null(dest)?;
             }
 
             "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, CanonAbi::C, link_name, args)?;
                 this.check_no_isolation("`getpwuid_r`")?;
 
                 let uid = this.read_scalar(uid)?.to_u32()?;
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 21a386b2927..42502d5bf09 100644
--- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
@@ -1,6 +1,7 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use super::sync::EvalContextExt as _;
 use crate::shims::unix::*;
@@ -23,8 +24,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         match link_name.as_str() {
             // Threading
             "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.
+                let [thread, name] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
+                let max_len = u64::MAX; // FreeBSD does not seem to have a limit.
                 let res = match this.pthread_setname_np(
                     this.read_scalar(thread)?,
                     this.read_scalar(name)?,
@@ -38,7 +39,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(res, dest)?;
             }
             "pthread_getname_np" => {
-                let [thread, name, len] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [thread, name, len] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 // 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
@@ -56,10 +57,74 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(res, dest)?;
             }
 
+            "cpuset_getaffinity" => {
+                // The "same" kind of api as `sched_getaffinity` but more fine grained control for FreeBSD specifically.
+                let [level, which, id, set_size, mask] =
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
+
+                let level = this.read_scalar(level)?.to_i32()?;
+                let which = this.read_scalar(which)?.to_i32()?;
+                let id = this.read_scalar(id)?.to_i64()?;
+                let set_size = this.read_target_usize(set_size)?; // measured in bytes
+                let mask = this.read_pointer(mask)?;
+
+                let _level_root = this.eval_libc_i32("CPU_LEVEL_ROOT");
+                let _level_cpuset = this.eval_libc_i32("CPU_LEVEL_CPUSET");
+                let level_which = this.eval_libc_i32("CPU_LEVEL_WHICH");
+
+                let _which_tid = this.eval_libc_i32("CPU_WHICH_TID");
+                let which_pid = this.eval_libc_i32("CPU_WHICH_PID");
+                let _which_jail = this.eval_libc_i32("CPU_WHICH_JAIL");
+                let _which_cpuset = this.eval_libc_i32("CPU_WHICH_CPUSET");
+                let _which_irq = this.eval_libc_i32("CPU_WHICH_IRQ");
+
+                // For sched_getaffinity, the current process is identified by -1.
+                // TODO: Use gettid? I'm (LorrensP-2158466) not that familiar with this api .
+                let id = match id {
+                    -1 => this.active_thread(),
+                    _ =>
+                        throw_unsup_format!(
+                            "`cpuset_getaffinity` is only supported with a pid of -1 (indicating the current thread)"
+                        ),
+                };
+
+                if this.ptr_is_null(mask)? {
+                    this.set_last_error_and_return(LibcError("EFAULT"), dest)?;
+                }
+                // We only support CPU_LEVEL_WHICH and CPU_WHICH_PID for now.
+                // This is the bare minimum to make the tests pass.
+                else if level != level_which || which != which_pid {
+                    throw_unsup_format!(
+                        "`cpuset_getaffinity` is only supported with `level` set to CPU_LEVEL_WHICH and `which` set to CPU_WHICH_PID."
+                    );
+                } else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&id) {
+                    // `cpusetsize` must be large enough to contain the entire CPU mask.
+                    // FreeBSD only uses `cpusetsize` to verify that it's sufficient for the kernel's CPU mask.
+                    // If it's too small, the syscall returns ERANGE.
+                    // If it's large enough, copying the kernel mask to user space is safe, regardless of the actual size.
+                    // See https://github.com/freebsd/freebsd-src/blob/909aa6781340f8c0b4ae01c6366bf1556ee2d1be/sys/kern/kern_cpuset.c#L1985
+                    if set_size < u64::from(this.machine.num_cpus).div_ceil(8) {
+                        this.set_last_error_and_return(LibcError("ERANGE"), dest)?;
+                    } else {
+                        let cpuset = cpuset.clone();
+                        let byte_count =
+                            Ord::min(cpuset.as_slice().len(), set_size.try_into().unwrap());
+                        this.write_bytes_ptr(
+                            mask,
+                            cpuset.as_slice()[..byte_count].iter().copied(),
+                        )?;
+                        this.write_null(dest)?;
+                    }
+                } else {
+                    // `id` is always that of the active thread, so this is currently unreachable.
+                    unreachable!();
+                }
+            }
+
             // Synchronization primitives
             "_umtx_op" => {
                 let [obj, op, val, uaddr, uaddr2] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this._umtx_op(obj, op, val, uaddr, uaddr2, dest)?;
             }
 
@@ -67,29 +132,29 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // For those, we both intercept `func` and `call@FBSD_1.0` symbols cases
             // since freebsd 12 the former form can be expected.
             "stat" | "stat@FBSD_1.0" => {
-                let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [path, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.macos_fbsd_solarish_stat(path, buf)?;
                 this.write_scalar(result, dest)?;
             }
             "lstat" | "lstat@FBSD_1.0" => {
-                let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [path, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.macos_fbsd_solarish_lstat(path, buf)?;
                 this.write_scalar(result, dest)?;
             }
             "fstat" | "fstat@FBSD_1.0" => {
-                let [fd, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [fd, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.macos_fbsd_solarish_fstat(fd, buf)?;
                 this.write_scalar(result, dest)?;
             }
             "readdir_r" | "readdir_r@FBSD_1.0" => {
-                let [dirp, entry, result] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [dirp, entry, result] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.macos_fbsd_readdir_r(dirp, entry, result)?;
                 this.write_scalar(result, dest)?;
             }
 
             // Miscellaneous
             "__error" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let errno_place = this.last_error_place()?;
                 this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
             }
@@ -97,7 +162,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // 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_get_np" if this.frame_in_std() => {
-                let [_thread, _attr] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [_thread, _attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.write_null(dest)?;
             }
 
diff --git a/src/tools/miri/src/shims/unix/freebsd/sync.rs b/src/tools/miri/src/shims/unix/freebsd/sync.rs
index 54650f35b2c..f4e7d9e58f9 100644
--- a/src/tools/miri/src/shims/unix/freebsd/sync.rs
+++ b/src/tools/miri/src/shims/unix/freebsd/sync.rs
@@ -2,6 +2,8 @@
 
 use core::time::Duration;
 
+use rustc_abi::FieldIdx;
+
 use crate::concurrency::sync::FutexRef;
 use crate::*;
 
@@ -214,18 +216,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Only flag allowed is UMTX_ABSTIME.
         let abs_time = this.eval_libc_u32("UMTX_ABSTIME");
 
-        let timespec_place = this.project_field(ut, 0)?;
+        let timespec_place = this.project_field(ut, FieldIdx::from_u32(0))?;
         // Inner `timespec` must still be valid.
         let duration = match this.read_timespec(&timespec_place)? {
             Some(dur) => dur,
             None => return interp_ok(None),
         };
 
-        let flags_place = this.project_field(ut, 1)?;
+        let flags_place = this.project_field(ut, FieldIdx::from_u32(1))?;
         let flags = this.read_scalar(&flags_place)?.to_u32()?;
         let abs_time_flag = flags == abs_time;
 
-        let clock_id_place = this.project_field(ut, 2)?;
+        let clock_id_place = this.project_field(ut, FieldIdx::from_u32(2))?;
         let clock_id = this.read_scalar(&clock_id_place)?.to_i32()?;
         let timeout_clock = this.translate_umtx_time_clock_id(clock_id)?;
 
diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs
index 1f6acff0787..31cb269059c 100644
--- a/src/tools/miri/src/shims/unix/fs.rs
+++ b/src/tools/miri/src/shims/unix/fs.rs
@@ -89,8 +89,19 @@ impl UnixFileDescription for FileHandle {
         communicate_allowed: bool,
         op: FlockOp,
     ) -> InterpResult<'tcx, io::Result<()>> {
+        // cfg(bootstrap)
+        macro_rules! cfg_select_dispatch {
+            ($($tokens:tt)*) => {
+                #[cfg(bootstrap)]
+                cfg_match! { $($tokens)* }
+
+                #[cfg(not(bootstrap))]
+                cfg_select! { $($tokens)* }
+            };
+        }
+
         assert!(communicate_allowed, "isolation should have prevented even opening a file");
-        cfg_match! {
+        cfg_select_dispatch! {
             all(target_family = "unix", not(target_os = "solaris")) => {
                 use std::os::fd::AsRawFd;
 
@@ -121,13 +132,13 @@ impl UnixFileDescription for FileHandle {
                 use std::os::windows::io::AsRawHandle;
 
                 use windows_sys::Win32::Foundation::{
-                    ERROR_IO_PENDING, ERROR_LOCK_VIOLATION, FALSE, HANDLE, TRUE,
+                    ERROR_IO_PENDING, ERROR_LOCK_VIOLATION, FALSE, TRUE,
                 };
                 use windows_sys::Win32::Storage::FileSystem::{
                     LOCKFILE_EXCLUSIVE_LOCK, LOCKFILE_FAIL_IMMEDIATELY, LockFileEx, UnlockFile,
                 };
 
-                let fh = self.file.as_raw_handle() as HANDLE;
+                let fh = self.file.as_raw_handle();
 
                 use FlockOp::*;
                 let (ret, lock_nb) = match op {
diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
index f5da7b0170b..aeaff1cb13a 100644
--- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
@@ -1,6 +1,7 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use self::shims::unix::linux::mem::EvalContextExt as _;
 use self::shims::unix::linux_like::epoll::EvalContextExt as _;
@@ -14,7 +15,7 @@ use crate::*;
 // The documentation of glibc complains that the kernel never exposes
 // TASK_COMM_LEN through the headers, so it's assumed to always be 16 bytes
 // long including a null terminator.
-const TASK_COMM_LEN: usize = 16;
+const TASK_COMM_LEN: u64 = 16;
 
 pub fn is_dyn_sym(name: &str) -> bool {
     matches!(name, "statx")
@@ -36,47 +37,48 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         match link_name.as_str() {
             // File related shims
             "readdir64" => {
-                let [dirp] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [dirp] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.linux_solarish_readdir64("dirent64", dirp)?;
                 this.write_scalar(result, dest)?;
             }
             "sync_file_range" => {
-                let [fd, offset, nbytes, flags] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [fd, offset, nbytes, flags] =
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.sync_file_range(fd, offset, nbytes, flags)?;
                 this.write_scalar(result, dest)?;
             }
             "statx" => {
                 let [dirfd, pathname, flags, mask, statxbuf] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.linux_statx(dirfd, pathname, flags, mask, statxbuf)?;
                 this.write_scalar(result, dest)?;
             }
 
             // epoll, eventfd
             "epoll_create1" => {
-                let [flag] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [flag] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.epoll_create1(flag)?;
                 this.write_scalar(result, dest)?;
             }
             "epoll_ctl" => {
-                let [epfd, op, fd, event] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [epfd, op, fd, event] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.epoll_ctl(epfd, op, fd, event)?;
                 this.write_scalar(result, dest)?;
             }
             "epoll_wait" => {
                 let [epfd, events, maxevents, timeout] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.epoll_wait(epfd, events, maxevents, timeout, dest)?;
             }
             "eventfd" => {
-                let [val, flag] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [val, flag] = this.check_shim(abi, CanonAbi::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)?;
+                let [thread, name] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let res = match this.pthread_setname_np(
                     this.read_scalar(thread)?,
                     this.read_scalar(name)?,
@@ -91,12 +93,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(res, dest)?;
             }
             "pthread_getname_np" => {
-                let [thread, name, len] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [thread, name, len] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 // The function's behavior isn't portable between platforms.
                 // In case of glibc, the length of the output buffer must
                 // be not shorter than TASK_COMM_LEN.
                 let len = this.read_scalar(len)?;
-                let res = if len.to_target_usize(this)? >= TASK_COMM_LEN as u64 {
+                let res = if len.to_target_usize(this)? >= TASK_COMM_LEN {
                     match this.pthread_getname_np(
                         this.read_scalar(thread)?,
                         this.read_scalar(name)?,
@@ -114,7 +116,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(res, dest)?;
             }
             "gettid" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.linux_gettid()?;
                 this.write_scalar(result, dest)?;
             }
@@ -127,34 +129,34 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Miscellaneous
             "mmap64" => {
                 let [addr, length, prot, flags, fd, offset] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let offset = this.read_scalar(offset)?.to_i64()?;
                 let ptr = this.mmap(addr, length, prot, flags, fd, offset.into())?;
                 this.write_scalar(ptr, dest)?;
             }
             "mremap" => {
                 let ([old_address, old_size, new_size, flags], _) =
-                    this.check_shim_variadic(abi, Conv::C, link_name, args)?;
+                    this.check_shim_variadic(abi, CanonAbi::C, link_name, args)?;
                 let ptr = this.mremap(old_address, old_size, new_size, flags)?;
                 this.write_scalar(ptr, dest)?;
             }
             "__xpg_strerror_r" => {
-                let [errnum, buf, buflen] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [errnum, buf, buflen] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.strerror_r(errnum, buf, buflen)?;
                 this.write_scalar(result, dest)?;
             }
             "__errno_location" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let errno_place = this.last_error_place()?;
                 this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
             }
             "__libc_current_sigrtmin" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 this.write_int(SIGRTMIN, dest)?;
             }
             "__libc_current_sigrtmax" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 this.write_int(SIGRTMAX, dest)?;
             }
@@ -162,7 +164,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // 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_getattr_np" if this.frame_in_std() => {
-                let [_thread, _attr] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [_thread, _attr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.write_null(dest)?;
             }
 
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 b489595b4cd..f971fb10b19 100644
--- a/src/tools/miri/src/shims/unix/linux_like/epoll.rs
+++ b/src/tools/miri/src/shims/unix/linux_like/epoll.rs
@@ -4,6 +4,8 @@ use std::io;
 use std::rc::{Rc, Weak};
 use std::time::Duration;
 
+use rustc_abi::FieldIdx;
+
 use crate::concurrency::VClock;
 use crate::shims::files::{
     DynFileDescriptionRef, FdId, FileDescription, FileDescriptionRef, WeakFileDescriptionRef,
@@ -284,8 +286,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         if op == epoll_ctl_add || op == epoll_ctl_mod {
             // Read event bitmask and data from epoll_event passed by caller.
-            let mut events = this.read_scalar(&this.project_field(&event, 0)?)?.to_u32()?;
-            let data = this.read_scalar(&this.project_field(&event, 1)?)?.to_u64()?;
+            let mut events = this.read_scalar(&this.project_field(&event, FieldIdx::ZERO)?)?.to_u32()?;
+            let data = this.read_scalar(&this.project_field(&event, FieldIdx::ONE)?)?.to_u64()?;
 
             // Unset the flag we support to discover if any unsupported flags are used.
             let mut flags = events;
diff --git a/src/tools/miri/src/shims/unix/linux_like/syscall.rs b/src/tools/miri/src/shims/unix/linux_like/syscall.rs
index 22c6dc97507..d42d6b9073e 100644
--- a/src/tools/miri/src/shims/unix/linux_like/syscall.rs
+++ b/src/tools/miri/src/shims/unix/linux_like/syscall.rs
@@ -1,6 +1,7 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use crate::helpers::check_min_vararg_count;
 use crate::shims::unix::linux_like::eventfd::EvalContextExt as _;
@@ -14,7 +15,7 @@ pub fn syscall<'tcx>(
     args: &[OpTy<'tcx>],
     dest: &MPlaceTy<'tcx>,
 ) -> InterpResult<'tcx> {
-    let ([op], varargs) = ecx.check_shim_variadic(abi, Conv::C, link_name, args)?;
+    let ([op], varargs) = ecx.check_shim_variadic(abi, CanonAbi::C, link_name, args)?;
     // The syscall variadic function is legal to call with more arguments than needed,
     // extra arguments are simply ignored. The important check is that when we use an
     // argument, we have to also check all arguments *before* it to ensure that they
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 5046e965082..ae921a013a4 100644
--- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
@@ -1,6 +1,7 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use super::sync::{EvalContextExt as _, MacOsFutexTimeout};
 use crate::shims::unix::*;
@@ -34,64 +35,64 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         match link_name.as_str() {
             // errno
             "__error" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let errno_place = this.last_error_place()?;
                 this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
             }
 
             // File related shims
             "close$NOCANCEL" => {
-                let [result] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [result] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.close(result)?;
                 this.write_scalar(result, dest)?;
             }
             "stat" | "stat64" | "stat$INODE64" => {
-                let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [path, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.macos_fbsd_solarish_stat(path, buf)?;
                 this.write_scalar(result, dest)?;
             }
             "lstat" | "lstat64" | "lstat$INODE64" => {
-                let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [path, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.macos_fbsd_solarish_lstat(path, buf)?;
                 this.write_scalar(result, dest)?;
             }
             "fstat" | "fstat64" | "fstat$INODE64" => {
-                let [fd, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [fd, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.macos_fbsd_solarish_fstat(fd, buf)?;
                 this.write_scalar(result, dest)?;
             }
             "opendir$INODE64" => {
-                let [name] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [name] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.opendir(name)?;
                 this.write_scalar(result, dest)?;
             }
             "readdir_r" | "readdir_r$INODE64" => {
-                let [dirp, entry, result] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [dirp, entry, result] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.macos_fbsd_readdir_r(dirp, entry, result)?;
                 this.write_scalar(result, dest)?;
             }
             "realpath$DARWIN_EXTSN" => {
-                let [path, resolved_path] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [path, resolved_path] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.realpath(path, resolved_path)?;
                 this.write_scalar(result, dest)?;
             }
             "ioctl" => {
                 let ([fd_num, cmd], varargs) =
-                    this.check_shim_variadic(abi, Conv::C, link_name, args)?;
+                    this.check_shim_variadic(abi, CanonAbi::C, link_name, args)?;
                 let result = this.ioctl(fd_num, cmd, varargs)?;
                 this.write_scalar(result, dest)?;
             }
 
             // Environment related shims
             "_NSGetEnviron" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let environ = this.machine.env_vars.unix().environ();
                 this.write_pointer(environ, dest)?;
             }
 
             // Random data generation
             "CCRandomGenerateBytes" => {
-                let [bytes, count] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [bytes, count] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let bytes = this.read_pointer(bytes)?;
                 let count = this.read_target_usize(count)?;
                 let success = this.eval_libc_i32("kCCSuccess");
@@ -101,28 +102,28 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // Time related shims
             "mach_absolute_time" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.mach_absolute_time()?;
                 this.write_scalar(result, dest)?;
             }
 
             "mach_timebase_info" => {
-                let [info] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [info] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.mach_timebase_info(info)?;
                 this.write_scalar(result, dest)?;
             }
 
             // Access to command-line arguments
             "_NSGetArgc" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.write_pointer(this.machine.argc.expect("machine must be initialized"), dest)?;
             }
             "_NSGetArgv" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.write_pointer(this.machine.argv.expect("machine must be initialized"), dest)?;
             }
             "_NSGetExecutablePath" => {
-                let [buf, bufsize] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [buf, bufsize] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.check_no_isolation("`_NSGetExecutablePath`")?;
 
                 let buf_ptr = this.read_pointer(buf)?;
@@ -147,7 +148,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // Thread-local storage
             "_tlv_atexit" => {
-                let [dtor, data] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [dtor, data] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let dtor = this.read_pointer(dtor)?;
                 let dtor = this.get_ptr_fn(dtor)?.as_instance()?;
                 let data = this.read_scalar(data)?;
@@ -157,13 +158,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // Querying system information
             "pthread_get_stackaddr_np" => {
-                let [thread] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [thread] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.read_target_usize(thread)?;
                 let stack_addr = Scalar::from_uint(this.machine.stack_addr, this.pointer_size());
                 this.write_scalar(stack_addr, dest)?;
             }
             "pthread_get_stacksize_np" => {
-                let [thread] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [thread] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.read_target_usize(thread)?;
                 let stack_size = Scalar::from_uint(this.machine.stack_size, this.pointer_size());
                 this.write_scalar(stack_size, dest)?;
@@ -171,7 +172,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // Threading
             "pthread_setname_np" => {
-                let [name] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [name] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 // The real implementation has logic in two places:
                 // * in userland at https://github.com/apple-oss-distributions/libpthread/blob/c032e0b076700a0a47db75528a282b8d3a06531a/src/pthread.c#L1178-L1200,
@@ -186,7 +187,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let res = match this.pthread_setname_np(
                     thread,
                     this.read_scalar(name)?,
-                    this.eval_libc("MAXTHREADNAMESIZE").to_target_usize(this)?.try_into().unwrap(),
+                    this.eval_libc("MAXTHREADNAMESIZE").to_target_usize(this)?,
                     /* truncate */ false,
                 )? {
                     ThreadNameResult::Ok => Scalar::from_u32(0),
@@ -198,7 +199,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(res, dest)?;
             }
             "pthread_getname_np" => {
-                let [thread, name, len] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [thread, name, len] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 // The function's behavior isn't portable between platforms.
                 // In case of macOS, a truncated name (due to a too small buffer)
@@ -225,7 +226,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Synchronization primitives
             "os_sync_wait_on_address" => {
                 let [addr_op, value_op, size_op, flags_op] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.os_sync_wait_on_address(
                     addr_op,
                     value_op,
@@ -237,7 +238,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             "os_sync_wait_on_address_with_deadline" => {
                 let [addr_op, value_op, size_op, flags_op, clock_op, timeout_op] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.os_sync_wait_on_address(
                     addr_op,
                     value_op,
@@ -249,7 +250,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             "os_sync_wait_on_address_with_timeout" => {
                 let [addr_op, value_op, size_op, flags_op, clock_op, timeout_op] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.os_sync_wait_on_address(
                     addr_op,
                     value_op,
@@ -261,36 +262,36 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             "os_sync_wake_by_address_any" => {
                 let [addr_op, size_op, flags_op] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.os_sync_wake_by_address(
                     addr_op, size_op, flags_op, /* all */ false, dest,
                 )?;
             }
             "os_sync_wake_by_address_all" => {
                 let [addr_op, size_op, flags_op] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.os_sync_wake_by_address(
                     addr_op, size_op, flags_op, /* all */ true, dest,
                 )?;
             }
             "os_unfair_lock_lock" => {
-                let [lock_op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [lock_op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.os_unfair_lock_lock(lock_op)?;
             }
             "os_unfair_lock_trylock" => {
-                let [lock_op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [lock_op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.os_unfair_lock_trylock(lock_op, dest)?;
             }
             "os_unfair_lock_unlock" => {
-                let [lock_op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [lock_op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.os_unfair_lock_unlock(lock_op)?;
             }
             "os_unfair_lock_assert_owner" => {
-                let [lock_op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [lock_op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.os_unfair_lock_assert_owner(lock_op)?;
             }
             "os_unfair_lock_assert_not_owner" => {
-                let [lock_op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [lock_op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.os_unfair_lock_assert_not_owner(lock_op)?;
             }
 
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 21d4f41f485..e3d15b89be6 100644
--- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
@@ -1,6 +1,7 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use crate::shims::unix::foreign_items::EvalContextExt as _;
 use crate::shims::unix::linux_like::epoll::EvalContextExt as _;
@@ -26,32 +27,32 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // 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 [flag] = this.check_shim(abi, CanonAbi::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 [epfd, op, fd, event] = this.check_shim(abi, CanonAbi::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.check_shim(abi, CanonAbi::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 [val, flag] = this.check_shim(abi, CanonAbi::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)?;
+                let [thread, name] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 // THREAD_NAME_MAX allows a thread name of 31+1 length
                 // https://github.com/illumos/illumos-gate/blob/7671517e13b8123748eda4ef1ee165c6d9dba7fe/usr/src/uts/common/sys/thread.h#L613
                 let max_len = 32;
@@ -69,7 +70,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(res, dest)?;
             }
             "pthread_getname_np" => {
-                let [thread, name, len] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [thread, name, len] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 // See https://illumos.org/man/3C/pthread_getname_np for the error codes.
                 let res = match this.pthread_getname_np(
                     this.read_scalar(thread)?,
@@ -86,22 +87,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // File related shims
             "stat" | "stat64" => {
-                let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [path, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.macos_fbsd_solarish_stat(path, buf)?;
                 this.write_scalar(result, dest)?;
             }
             "lstat" | "lstat64" => {
-                let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [path, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.macos_fbsd_solarish_lstat(path, buf)?;
                 this.write_scalar(result, dest)?;
             }
             "fstat" | "fstat64" => {
-                let [fd, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [fd, buf] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.macos_fbsd_solarish_fstat(fd, buf)?;
                 this.write_scalar(result, dest)?;
             }
             "readdir" => {
-                let [dirp] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [dirp] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.linux_solarish_readdir64("dirent", dirp)?;
                 this.write_scalar(result, dest)?;
             }
@@ -109,20 +110,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Sockets and pipes
             "__xnet_socketpair" => {
                 let [domain, type_, protocol, sv] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                    this.check_shim(abi, CanonAbi::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)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let errno_place = this.last_error_place()?;
                 this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
             }
 
             "stack_getbounds" => {
-                let [stack] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [stack] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let stack = this.deref_pointer_as(stack, this.libc_ty_layout("stack_t"))?;
 
                 this.write_int_fields_named(
@@ -140,7 +141,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
 
             "pset_info" => {
-                let [pset, tpe, cpus, list] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [pset, tpe, cpus, list] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 // We do not need to handle the current process cpu mask, available_parallelism
                 // implementation pass null anyway. We only care for the number of
                 // cpus.
@@ -169,7 +170,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
 
             "__sysconf_xpg7" => {
-                let [val] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [val] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.sysconf(val)?;
                 this.write_scalar(result, dest)?;
             }
diff --git a/src/tools/miri/src/shims/unix/thread.rs b/src/tools/miri/src/shims/unix/thread.rs
index 3d990a1a042..4b6615b3ea8 100644
--- a/src/tools/miri/src/shims/unix/thread.rs
+++ b/src/tools/miri/src/shims/unix/thread.rs
@@ -86,7 +86,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         &mut self,
         thread: Scalar,
         name: Scalar,
-        name_max_len: usize,
+        name_max_len: u64,
         truncate: bool,
     ) -> InterpResult<'tcx, ThreadNameResult> {
         let this = self.eval_context_mut();
@@ -99,9 +99,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let mut name = this.read_c_str(name)?.to_owned();
 
         // Comparing with `>=` to account for null terminator.
-        if name.len() >= name_max_len {
+        if name.len().to_u64() >= name_max_len {
             if truncate {
-                name.truncate(name_max_len.saturating_sub(1));
+                name.truncate(name_max_len.saturating_sub(1).try_into().unwrap());
             } else {
                 return interp_ok(ThreadNameResult::NameTooLong);
             }
diff --git a/src/tools/miri/src/shims/unix/unnamed_socket.rs b/src/tools/miri/src/shims/unix/unnamed_socket.rs
index 135d8f6bee7..817ddd7954d 100644
--- a/src/tools/miri/src/shims/unix/unnamed_socket.rs
+++ b/src/tools/miri/src/shims/unix/unnamed_socket.rs
@@ -20,6 +20,16 @@ use crate::*;
 /// be configured in the real system.
 const MAX_SOCKETPAIR_BUFFER_CAPACITY: usize = 212992;
 
+#[derive(Debug, PartialEq)]
+enum AnonSocketType {
+    // Either end of the socketpair fd.
+    Socketpair,
+    // Read end of the pipe.
+    PipeRead,
+    // Write end of the pipe.
+    PipeWrite,
+}
+
 /// One end of a pair of connected unnamed sockets.
 #[derive(Debug)]
 struct AnonSocket {
@@ -40,7 +50,10 @@ struct AnonSocket {
     /// A list of thread ids blocked because the buffer was full.
     /// Once another thread reads some bytes, these threads will be unblocked.
     blocked_write_tid: RefCell<Vec<ThreadId>>,
-    is_nonblock: bool,
+    /// Whether this fd is non-blocking or not.
+    is_nonblock: Cell<bool>,
+    // Differentiate between different AnonSocket fd types.
+    fd_type: AnonSocketType,
 }
 
 #[derive(Debug)]
@@ -63,7 +76,10 @@ impl AnonSocket {
 
 impl FileDescription for AnonSocket {
     fn name(&self) -> &'static str {
-        "socketpair"
+        match self.fd_type {
+            AnonSocketType::Socketpair => "socketpair",
+            AnonSocketType::PipeRead | AnonSocketType::PipeWrite => "pipe",
+        }
     }
 
     fn close<'tcx>(
@@ -110,6 +126,66 @@ impl FileDescription for AnonSocket {
     fn as_unix<'tcx>(&self, _ecx: &MiriInterpCx<'tcx>) -> &dyn UnixFileDescription {
         self
     }
+
+    fn get_flags<'tcx>(&self, ecx: &mut MiriInterpCx<'tcx>) -> InterpResult<'tcx, Scalar> {
+        let mut flags = 0;
+
+        // Get flag for file access mode.
+        // The flag for both socketpair and pipe will remain the same even when the peer
+        // fd is closed, so we need to look at the original type of this socket, not at whether
+        // the peer socket still exists.
+        match self.fd_type {
+            AnonSocketType::Socketpair => {
+                flags |= ecx.eval_libc_i32("O_RDWR");
+            }
+            AnonSocketType::PipeRead => {
+                flags |= ecx.eval_libc_i32("O_RDONLY");
+            }
+            AnonSocketType::PipeWrite => {
+                flags |= ecx.eval_libc_i32("O_WRONLY");
+            }
+        }
+
+        // Get flag for blocking status.
+        if self.is_nonblock.get() {
+            flags |= ecx.eval_libc_i32("O_NONBLOCK");
+        }
+
+        interp_ok(Scalar::from_i32(flags))
+    }
+
+    fn set_flags<'tcx>(
+        &self,
+        mut flag: i32,
+        ecx: &mut MiriInterpCx<'tcx>,
+    ) -> InterpResult<'tcx, Scalar> {
+        // FIXME: File creation flags should be ignored.
+
+        let o_nonblock = ecx.eval_libc_i32("O_NONBLOCK");
+        let o_rdonly = ecx.eval_libc_i32("O_RDONLY");
+        let o_wronly = ecx.eval_libc_i32("O_WRONLY");
+        let o_rdwr = ecx.eval_libc_i32("O_RDWR");
+
+        // O_NONBLOCK flag can be set / unset by user.
+        if flag & o_nonblock == o_nonblock {
+            self.is_nonblock.set(true);
+            flag &= !o_nonblock;
+        } else {
+            self.is_nonblock.set(false);
+        }
+
+        // Ignore all file access mode flags.
+        flag &= !(o_rdonly | o_wronly | o_rdwr);
+
+        // Throw error if there is any unsupported flag.
+        if flag != 0 {
+            throw_unsup_format!(
+                "fcntl: only O_NONBLOCK is supported for F_SETFL on socketpairs and pipes"
+            )
+        }
+
+        interp_ok(Scalar::from_i32(0))
+    }
 }
 
 /// Write to AnonSocket based on the space available and return the written byte size.
@@ -141,7 +217,7 @@ fn anonsocket_write<'tcx>(
     // Let's see if we can write.
     let available_space = MAX_SOCKETPAIR_BUFFER_CAPACITY.strict_sub(writebuf.borrow().buf.len());
     if available_space == 0 {
-        if self_ref.is_nonblock {
+        if self_ref.is_nonblock.get() {
             // Non-blocking socketpair with a full buffer.
             return finish.call(ecx, Err(ErrorKind::WouldBlock.into()));
         } else {
@@ -223,7 +299,7 @@ fn anonsocket_read<'tcx>(
             // Socketpair with no peer and empty buffer.
             // 0 bytes successfully read indicates end-of-file.
             return finish.call(ecx, Ok(0));
-        } else if self_ref.is_nonblock {
+        } else if self_ref.is_nonblock.get() {
             // Non-blocking socketpair with writer and empty buffer.
             // https://linux.die.net/man/2/read
             // EAGAIN or EWOULDBLOCK can be returned for socket,
@@ -407,7 +483,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             peer_lost_data: Cell::new(false),
             blocked_read_tid: RefCell::new(Vec::new()),
             blocked_write_tid: RefCell::new(Vec::new()),
-            is_nonblock: is_sock_nonblock,
+            is_nonblock: Cell::new(is_sock_nonblock),
+            fd_type: AnonSocketType::Socketpair,
         });
         let fd1 = fds.new_ref(AnonSocket {
             readbuf: Some(RefCell::new(Buffer::new())),
@@ -415,7 +492,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             peer_lost_data: Cell::new(false),
             blocked_read_tid: RefCell::new(Vec::new()),
             blocked_write_tid: RefCell::new(Vec::new()),
-            is_nonblock: is_sock_nonblock,
+            is_nonblock: Cell::new(is_sock_nonblock),
+            fd_type: AnonSocketType::Socketpair,
         });
 
         // Make the file descriptions point to each other.
@@ -475,7 +553,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             peer_lost_data: Cell::new(false),
             blocked_read_tid: RefCell::new(Vec::new()),
             blocked_write_tid: RefCell::new(Vec::new()),
-            is_nonblock,
+            is_nonblock: Cell::new(is_nonblock),
+            fd_type: AnonSocketType::PipeRead,
         });
         let fd1 = fds.new_ref(AnonSocket {
             readbuf: None,
@@ -483,7 +562,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             peer_lost_data: Cell::new(false),
             blocked_read_tid: RefCell::new(Vec::new()),
             blocked_write_tid: RefCell::new(Vec::new()),
-            is_nonblock,
+            is_nonblock: Cell::new(is_nonblock),
+            fd_type: AnonSocketType::PipeWrite,
         });
 
         // Make the file descriptions point to each other.
diff --git a/src/tools/miri/src/shims/wasi/foreign_items.rs b/src/tools/miri/src/shims/wasi/foreign_items.rs
index 90de62b9e57..8d92d0f3381 100644
--- a/src/tools/miri/src/shims/wasi/foreign_items.rs
+++ b/src/tools/miri/src/shims/wasi/foreign_items.rs
@@ -1,6 +1,7 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use crate::shims::alloc::EvalContextExt as _;
 use crate::*;
@@ -22,12 +23,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         match link_name.as_str() {
             // Allocation
             "posix_memalign" => {
-                let [memptr, align, size] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [memptr, align, size] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let result = this.posix_memalign(memptr, align, size)?;
                 this.write_scalar(result, dest)?;
             }
             "aligned_alloc" => {
-                let [align, size] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [align, size] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let res = this.aligned_alloc(align, size)?;
                 this.write_pointer(res, dest)?;
             }
diff --git a/src/tools/miri/src/shims/windows/env.rs b/src/tools/miri/src/shims/windows/env.rs
index 1b2ccd99ef9..a7c26d601e5 100644
--- a/src/tools/miri/src/shims/windows/env.rs
+++ b/src/tools/miri/src/shims/windows/env.rs
@@ -230,7 +230,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         interp_ok(match directories::UserDirs::new() {
             Some(dirs) => {
                 let home = dirs.home_dir();
-                let size_avail = if this.ptr_is_null(size.ptr())? {
+                let size_avail = if this.ptr_is_null(buf)? {
                     0 // if the buf pointer is null, we can't write to it; `size` will be updated to the required length
                 } else {
                     this.read_scalar(&size)?.to_u32()?
@@ -238,8 +238,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // Of course we cannot use `windows_check_buffer_size` here since this uses
                 // a different method for dealing with a too-small buffer than the other functions...
                 let (success, len) = this.write_path_to_wide_str(home, buf, size_avail.into())?;
-                // The Windows docs just say that this is written on failure. But std
-                // seems to rely on it always being written.
+                // As per <https://github.com/MicrosoftDocs/sdk-api/pull/1810>, the size is always
+                // written, not just on failure.
                 this.write_scalar(Scalar::from_u32(len.try_into().unwrap()), &size)?;
                 if success {
                     Scalar::from_i32(1) // return TRUE
diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs
index c80858c6363..10f6df67ad4 100644
--- a/src/tools/miri/src/shims/windows/foreign_items.rs
+++ b/src/tools/miri/src/shims/windows/foreign_items.rs
@@ -2,10 +2,10 @@ use std::ffi::OsStr;
 use std::path::{self, Path, PathBuf};
 use std::{io, iter, str};
 
-use rustc_abi::{Align, Size};
+use rustc_abi::{Align, CanonAbi, Size, X86Call};
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use self::shims::windows::handle::{Handle, PseudoHandle};
 use crate::shims::os_str::bytes_to_os_str;
@@ -140,7 +140,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // https://github.com/rust-lang/rust/blob/fb00adbdb69266f10df95a4527b767b0ad35ea48/compiler/rustc_target/src/spec/mod.rs#L2766-L2768,
         // x86-32 Windows uses a different calling convention than other Windows targets
         // for the "system" ABI.
-        let sys_conv = if this.tcx.sess.target.arch == "x86" { Conv::X86Stdcall } else { Conv::C };
+        let sys_conv = if this.tcx.sess.target.arch == "x86" {
+            CanonAbi::X86(X86Call::Stdcall)
+        } else {
+            CanonAbi::C
+        };
 
         // See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern.
 
@@ -195,69 +199,52 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
             // File related shims
             "NtWriteFile" => {
-                if !this.frame_in_std() {
-                    throw_unsup_format!(
-                        "`NtWriteFile` support is crude and just enough for stdout to work"
-                    );
-                }
-
                 let [
                     handle,
-                    _event,
-                    _apc_routine,
-                    _apc_context,
+                    event,
+                    apc_routine,
+                    apc_context,
                     io_status_block,
                     buf,
                     n,
                     byte_offset,
-                    _key,
+                    key,
                 ] = this.check_shim(abi, sys_conv, link_name, args)?;
-                let handle = this.read_target_isize(handle)?;
-                let buf = this.read_pointer(buf)?;
-                let n = this.read_scalar(n)?.to_u32()?;
-                let byte_offset = this.read_target_usize(byte_offset)?; // is actually a pointer
-                let io_status_block = this
-                    .deref_pointer_as(io_status_block, this.windows_ty_layout("IO_STATUS_BLOCK"))?;
-
-                if byte_offset != 0 {
-                    throw_unsup_format!(
-                        "`NtWriteFile` `ByteOffset` parameter is non-null, which is unsupported"
-                    );
-                }
-
-                let written = if handle == -11 || handle == -12 {
-                    // stdout/stderr
-                    use io::Write;
-
-                    let buf_cont =
-                        this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(u64::from(n)))?;
-                    let res = if this.machine.mute_stdout_stderr {
-                        Ok(buf_cont.len())
-                    } else if handle == -11 {
-                        io::stdout().write(buf_cont)
-                    } else {
-                        io::stderr().write(buf_cont)
-                    };
-                    // We write at most `n` bytes, which is a `u32`, so we cannot have written more than that.
-                    res.ok().map(|n| u32::try_from(n).unwrap())
-                } else {
-                    throw_unsup_format!(
-                        "on Windows, writing to anything except stdout/stderr is not supported"
-                    )
-                };
-                // We have to put the result into io_status_block.
-                if let Some(n) = written {
-                    let io_status_information =
-                        this.project_field_named(&io_status_block, "Information")?;
-                    this.write_scalar(
-                        Scalar::from_target_usize(n.into(), this),
-                        &io_status_information,
-                    )?;
-                }
-                // Return whether this was a success. >= 0 is success.
-                // For the error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR.
-                this.write_scalar(
-                    Scalar::from_u32(if written.is_some() { 0 } else { 0xC0000185u32 }),
+                this.NtWriteFile(
+                    handle,
+                    event,
+                    apc_routine,
+                    apc_context,
+                    io_status_block,
+                    buf,
+                    n,
+                    byte_offset,
+                    key,
+                    dest,
+                )?;
+            }
+            "NtReadFile" => {
+                let [
+                    handle,
+                    event,
+                    apc_routine,
+                    apc_context,
+                    io_status_block,
+                    buf,
+                    n,
+                    byte_offset,
+                    key,
+                ] = this.check_shim(abi, sys_conv, link_name, args)?;
+                this.NtReadFile(
+                    handle,
+                    event,
+                    apc_routine,
+                    apc_context,
+                    io_status_block,
+                    buf,
+                    n,
+                    byte_offset,
+                    key,
                     dest,
                 )?;
             }
@@ -322,6 +309,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let res = this.DeleteFileW(file_name)?;
                 this.write_scalar(res, dest)?;
             }
+            "SetFilePointerEx" => {
+                let [file, distance_to_move, new_file_pointer, move_method] =
+                    this.check_shim(abi, sys_conv, link_name, args)?;
+                let res =
+                    this.SetFilePointerEx(file, distance_to_move, new_file_pointer, move_method)?;
+                this.write_scalar(res, dest)?;
+            }
 
             // Allocation
             "HeapAlloc" => {
@@ -582,6 +576,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let ret = this.WaitForSingleObject(handle, timeout)?;
                 this.write_scalar(ret, dest)?;
             }
+            "GetCurrentProcess" => {
+                let [] = this.check_shim(abi, sys_conv, link_name, args)?;
+
+                this.write_scalar(
+                    Handle::Pseudo(PseudoHandle::CurrentProcess).to_scalar(this),
+                    dest,
+                )?;
+            }
             "GetCurrentThread" => {
                 let [] = this.check_shim(abi, sys_conv, link_name, args)?;
 
@@ -700,12 +702,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             "GetStdHandle" => {
                 let [which] = this.check_shim(abi, sys_conv, link_name, args)?;
-                let which = this.read_scalar(which)?.to_i32()?;
-                // We just make this the identity function, so we know later in `NtWriteFile` which
-                // one it is. This is very fake, but libtest needs it so we cannot make it a
-                // std-only shim.
-                // FIXME: this should return real HANDLEs when io support is added
-                this.write_scalar(Scalar::from_target_isize(which.into(), this), dest)?;
+                let res = this.GetStdHandle(which)?;
+                this.write_scalar(res, dest)?;
+            }
+            "DuplicateHandle" => {
+                let [src_proc, src_handle, target_proc, target_handle, access, inherit, options] =
+                    this.check_shim(abi, sys_conv, link_name, args)?;
+                let res = this.DuplicateHandle(
+                    src_proc,
+                    src_handle,
+                    target_proc,
+                    target_handle,
+                    access,
+                    inherit,
+                    options,
+                )?;
+                this.write_scalar(res, dest)?;
             }
             "CloseHandle" => {
                 let [handle] = this.check_shim(abi, sys_conv, link_name, args)?;
@@ -848,7 +860,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     );
                 }
                 // This function looks and behaves excatly like miri_start_unwind.
-                let [payload] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [payload] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 this.handle_miri_start_unwind(payload)?;
                 return interp_ok(EmulateItemResult::NeedsUnwind);
             }
diff --git a/src/tools/miri/src/shims/windows/fs.rs b/src/tools/miri/src/shims/windows/fs.rs
index 7561bf45219..72e016c12e9 100644
--- a/src/tools/miri/src/shims/windows/fs.rs
+++ b/src/tools/miri/src/shims/windows/fs.rs
@@ -1,5 +1,6 @@
 use std::fs::{Metadata, OpenOptions};
 use std::io;
+use std::io::SeekFrom;
 use std::path::PathBuf;
 use std::time::SystemTime;
 
@@ -390,6 +391,267 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
         }
     }
+
+    fn NtWriteFile(
+        &mut self,
+        handle: &OpTy<'tcx>,          // HANDLE
+        event: &OpTy<'tcx>,           // HANDLE
+        apc_routine: &OpTy<'tcx>,     // PIO_APC_ROUTINE
+        apc_ctx: &OpTy<'tcx>,         // PVOID
+        io_status_block: &OpTy<'tcx>, // PIO_STATUS_BLOCK
+        buf: &OpTy<'tcx>,             // PVOID
+        n: &OpTy<'tcx>,               // ULONG
+        byte_offset: &OpTy<'tcx>,     // PLARGE_INTEGER
+        key: &OpTy<'tcx>,             // PULONG
+        dest: &MPlaceTy<'tcx>,        // return type: NTSTATUS
+    ) -> InterpResult<'tcx, ()> {
+        let this = self.eval_context_mut();
+        let handle = this.read_handle(handle, "NtWriteFile")?;
+        let event = this.read_handle(event, "NtWriteFile")?;
+        let apc_routine = this.read_pointer(apc_routine)?;
+        let apc_ctx = this.read_pointer(apc_ctx)?;
+        let buf = this.read_pointer(buf)?;
+        let count = this.read_scalar(n)?.to_u32()?;
+        let byte_offset = this.read_target_usize(byte_offset)?; // is actually a pointer, but we only support null
+        let key = this.read_pointer(key)?;
+        let io_status_block =
+            this.deref_pointer_as(io_status_block, this.windows_ty_layout("IO_STATUS_BLOCK"))?;
+
+        if event != Handle::Null {
+            throw_unsup_format!(
+                "`NtWriteFile` `Event` parameter is non-null, which is unsupported"
+            );
+        }
+
+        if !this.ptr_is_null(apc_routine)? {
+            throw_unsup_format!(
+                "`NtWriteFile` `ApcRoutine` parameter is non-null, which is unsupported"
+            );
+        }
+
+        if !this.ptr_is_null(apc_ctx)? {
+            throw_unsup_format!(
+                "`NtWriteFile` `ApcContext` parameter is non-null, which is unsupported"
+            );
+        }
+
+        if byte_offset != 0 {
+            throw_unsup_format!(
+                "`NtWriteFile` `ByteOffset` parameter is non-null, which is unsupported"
+            );
+        }
+
+        if !this.ptr_is_null(key)? {
+            throw_unsup_format!("`NtWriteFile` `Key` parameter is non-null, which is unsupported");
+        }
+
+        let fd = match handle {
+            Handle::File(fd) => fd,
+            _ => this.invalid_handle("NtWriteFile")?,
+        };
+
+        let Some(desc) = this.machine.fds.get(fd) else { this.invalid_handle("NtWriteFile")? };
+
+        // Windows writes the output code to IO_STATUS_BLOCK.Status, and number of bytes written
+        // to IO_STATUS_BLOCK.Information.
+        // The status block value and the returned value don't need to match - but
+        // for the cases implemented by miri so far, we can choose to decide that they do.
+        let io_status = {
+            let anon = this.project_field_named(&io_status_block, "Anonymous")?;
+            this.project_field_named(&anon, "Status")?
+        };
+        let io_status_info = this.project_field_named(&io_status_block, "Information")?;
+
+        let finish = {
+            let io_status = io_status.clone();
+            let io_status_info = io_status_info.clone();
+            let dest = dest.clone();
+            callback!(
+                @capture<'tcx> {
+                    count: u32,
+                    io_status: MPlaceTy<'tcx>,
+                    io_status_info: MPlaceTy<'tcx>,
+                    dest: MPlaceTy<'tcx>,
+                }
+                |this, result: Result<usize, IoError>| {
+                    match result {
+                        Ok(read_size) => {
+                            assert!(read_size <= count.try_into().unwrap());
+                            // This must fit since `count` fits.
+                            this.write_int(u64::try_from(read_size).unwrap(), &io_status_info)?;
+                            this.write_int(0, &io_status)?;
+                            this.write_int(0, &dest)
+                        }
+                        Err(e) => {
+                            this.write_int(0, &io_status_info)?;
+                            let status = e.into_ntstatus();
+                            this.write_int(status, &io_status)?;
+                            this.write_int(status, &dest)
+                        }
+                }}
+            )
+        };
+
+        desc.write(this.machine.communicate(), buf, count.try_into().unwrap(), this, finish)?;
+
+        // Return status is written to `dest` and `io_status_block` on callback completion.
+        interp_ok(())
+    }
+
+    fn NtReadFile(
+        &mut self,
+        handle: &OpTy<'tcx>,          // HANDLE
+        event: &OpTy<'tcx>,           // HANDLE
+        apc_routine: &OpTy<'tcx>,     // PIO_APC_ROUTINE
+        apc_ctx: &OpTy<'tcx>,         // PVOID
+        io_status_block: &OpTy<'tcx>, // PIO_STATUS_BLOCK
+        buf: &OpTy<'tcx>,             // PVOID
+        n: &OpTy<'tcx>,               // ULONG
+        byte_offset: &OpTy<'tcx>,     // PLARGE_INTEGER
+        key: &OpTy<'tcx>,             // PULONG
+        dest: &MPlaceTy<'tcx>,        // return type: NTSTATUS
+    ) -> InterpResult<'tcx, ()> {
+        let this = self.eval_context_mut();
+        let handle = this.read_handle(handle, "NtReadFile")?;
+        let event = this.read_handle(event, "NtReadFile")?;
+        let apc_routine = this.read_pointer(apc_routine)?;
+        let apc_ctx = this.read_pointer(apc_ctx)?;
+        let buf = this.read_pointer(buf)?;
+        let count = this.read_scalar(n)?.to_u32()?;
+        let byte_offset = this.read_target_usize(byte_offset)?; // is actually a pointer, but we only support null
+        let key = this.read_pointer(key)?;
+        let io_status_block =
+            this.deref_pointer_as(io_status_block, this.windows_ty_layout("IO_STATUS_BLOCK"))?;
+
+        if event != Handle::Null {
+            throw_unsup_format!("`NtReadFile` `Event` parameter is non-null, which is unsupported");
+        }
+
+        if !this.ptr_is_null(apc_routine)? {
+            throw_unsup_format!(
+                "`NtReadFile` `ApcRoutine` parameter is non-null, which is unsupported"
+            );
+        }
+
+        if !this.ptr_is_null(apc_ctx)? {
+            throw_unsup_format!(
+                "`NtReadFile` `ApcContext` parameter is non-null, which is unsupported"
+            );
+        }
+
+        if byte_offset != 0 {
+            throw_unsup_format!(
+                "`NtReadFile` `ByteOffset` parameter is non-null, which is unsupported"
+            );
+        }
+
+        if !this.ptr_is_null(key)? {
+            throw_unsup_format!("`NtReadFile` `Key` parameter is non-null, which is unsupported");
+        }
+
+        // See NtWriteFile above for commentary on this
+        let io_status = {
+            let anon = this.project_field_named(&io_status_block, "Anonymous")?;
+            this.project_field_named(&anon, "Status")?
+        };
+        let io_status_info = this.project_field_named(&io_status_block, "Information")?;
+
+        let finish = {
+            let io_status = io_status.clone();
+            let io_status_info = io_status_info.clone();
+            let dest = dest.clone();
+            callback!(
+                @capture<'tcx> {
+                    count: u32,
+                    io_status: MPlaceTy<'tcx>,
+                    io_status_info: MPlaceTy<'tcx>,
+                    dest: MPlaceTy<'tcx>,
+                }
+                |this, result: Result<usize, IoError>| {
+                    match result {
+                        Ok(read_size) => {
+                            assert!(read_size <= count.try_into().unwrap());
+                            // This must fit since `count` fits.
+                            this.write_int(u64::try_from(read_size).unwrap(), &io_status_info)?;
+                            this.write_int(0, &io_status)?;
+                            this.write_int(0, &dest)
+                        }
+                        Err(e) => {
+                            this.write_int(0, &io_status_info)?;
+                            let status = e.into_ntstatus();
+                            this.write_int(status, &io_status)?;
+                            this.write_int(status, &dest)
+                        }
+                }}
+            )
+        };
+
+        let fd = match handle {
+            Handle::File(fd) => fd,
+            _ => this.invalid_handle("NtWriteFile")?,
+        };
+
+        let Some(desc) = this.machine.fds.get(fd) else { this.invalid_handle("NtReadFile")? };
+
+        desc.read(this.machine.communicate(), buf, count.try_into().unwrap(), this, finish)?;
+
+        // See NtWriteFile for commentary on this
+        interp_ok(())
+    }
+
+    fn SetFilePointerEx(
+        &mut self,
+        file: &OpTy<'tcx>,         // HANDLE
+        dist_to_move: &OpTy<'tcx>, // LARGE_INTEGER
+        new_fp: &OpTy<'tcx>,       // PLARGE_INTEGER
+        move_method: &OpTy<'tcx>,  // DWORD
+    ) -> InterpResult<'tcx, Scalar> {
+        // ^ Returns BOOL (i32 on Windows)
+        let this = self.eval_context_mut();
+        let file = this.read_handle(file, "SetFilePointerEx")?;
+        let dist_to_move = this.read_scalar(dist_to_move)?.to_i64()?;
+        let new_fp_ptr = this.read_pointer(new_fp)?;
+        let move_method = this.read_scalar(move_method)?.to_u32()?;
+
+        let fd = match file {
+            Handle::File(fd) => fd,
+            _ => this.invalid_handle("SetFilePointerEx")?,
+        };
+
+        let Some(desc) = this.machine.fds.get(fd) else {
+            throw_unsup_format!("`SetFilePointerEx` is only supported on file backed handles");
+        };
+
+        let file_begin = this.eval_windows_u32("c", "FILE_BEGIN");
+        let file_current = this.eval_windows_u32("c", "FILE_CURRENT");
+        let file_end = this.eval_windows_u32("c", "FILE_END");
+
+        let seek = if move_method == file_begin {
+            SeekFrom::Start(dist_to_move.try_into().unwrap())
+        } else if move_method == file_current {
+            SeekFrom::Current(dist_to_move)
+        } else if move_method == file_end {
+            SeekFrom::End(dist_to_move)
+        } else {
+            throw_unsup_format!("Invalid move method: {move_method}")
+        };
+
+        match desc.seek(this.machine.communicate(), seek)? {
+            Ok(n) => {
+                if !this.ptr_is_null(new_fp_ptr)? {
+                    this.write_scalar(
+                        Scalar::from_i64(n.try_into().unwrap()),
+                        &this.deref_pointer_as(new_fp, this.machine.layouts.i64)?,
+                    )?;
+                }
+                interp_ok(this.eval_windows("c", "TRUE"))
+            }
+            Err(e) => {
+                this.set_last_error(e)?;
+                interp_ok(this.eval_windows("c", "FALSE"))
+            }
+        }
+    }
 }
 
 /// Windows FILETIME is measured in 100-nanosecs since 1601
@@ -401,7 +663,7 @@ fn extract_windows_epoch<'tcx>(
         Some(time) => {
             let duration = ecx.system_time_since_windows_epoch(&time)?;
             let duration_ticks = ecx.windows_ticks_for(duration)?;
-            #[allow(clippy::cast_possible_truncation)]
+            #[expect(clippy::as_conversions)]
             interp_ok(Some((duration_ticks as u32, (duration_ticks >> 32) as u32)))
         }
         None => interp_ok(None),
diff --git a/src/tools/miri/src/shims/windows/handle.rs b/src/tools/miri/src/shims/windows/handle.rs
index eec6c62bebc..1e30bf25ed9 100644
--- a/src/tools/miri/src/shims/windows/handle.rs
+++ b/src/tools/miri/src/shims/windows/handle.rs
@@ -9,6 +9,7 @@ use crate::*;
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 pub enum PseudoHandle {
     CurrentThread,
+    CurrentProcess,
 }
 
 /// Miri representation of a Windows `HANDLE`
@@ -23,16 +24,19 @@ pub enum Handle {
 
 impl PseudoHandle {
     const CURRENT_THREAD_VALUE: u32 = 0;
+    const CURRENT_PROCESS_VALUE: u32 = 1;
 
     fn value(self) -> u32 {
         match self {
             Self::CurrentThread => Self::CURRENT_THREAD_VALUE,
+            Self::CurrentProcess => Self::CURRENT_PROCESS_VALUE,
         }
     }
 
     fn from_value(value: u32) -> Option<Self> {
         match value {
             Self::CURRENT_THREAD_VALUE => Some(Self::CurrentThread),
+            Self::CURRENT_PROCESS_VALUE => Some(Self::CurrentProcess),
             _ => None,
         }
     }
@@ -70,8 +74,7 @@ impl Handle {
             Self::Null => 0,
             Self::Pseudo(pseudo_handle) => pseudo_handle.value(),
             Self::Thread(thread) => thread.to_u32(),
-            #[expect(clippy::cast_sign_loss)]
-            Self::File(fd) => fd as u32,
+            Self::File(fd) => fd.cast_unsigned(),
             // INVALID_HANDLE_VALUE is -1. This fact is explicitly declared or implied in several
             // pages of Windows documentation.
             // 1: https://learn.microsoft.com/en-us/dotnet/api/microsoft.win32.safehandles.safefilehandle?view=net-9.0
@@ -124,11 +127,10 @@ impl Handle {
             Self::NULL_DISCRIMINANT if data == 0 => Some(Self::Null),
             Self::PSEUDO_DISCRIMINANT => Some(Self::Pseudo(PseudoHandle::from_value(data)?)),
             Self::THREAD_DISCRIMINANT => Some(Self::Thread(ThreadId::new_unchecked(data))),
-            #[expect(clippy::cast_possible_wrap)]
             Self::FILE_DISCRIMINANT => {
                 // This cast preserves all bits.
                 assert_eq!(size_of_val(&data), size_of::<FdNum>());
-                Some(Self::File(data as FdNum))
+                Some(Self::File(data.cast_signed()))
             }
             Self::INVALID_DISCRIMINANT => Some(Self::Invalid),
             _ => None,
@@ -156,8 +158,7 @@ impl Handle {
     pub fn to_scalar(self, cx: &impl HasDataLayout) -> Scalar {
         // 64-bit handles are sign extended 32-bit handles
         // see https://docs.microsoft.com/en-us/windows/win32/winprog64/interprocess-communication
-        #[expect(clippy::cast_possible_wrap)] // we want it to wrap
-        let signed_handle = self.to_packed() as i32;
+        let signed_handle = self.to_packed().cast_signed();
         Scalar::from_target_isize(signed_handle.into(), cx)
     }
 
@@ -171,9 +172,8 @@ impl Handle {
     ) -> InterpResult<'tcx, Result<Self, HandleError>> {
         let sign_extended_handle = handle.to_target_isize(cx)?;
 
-        #[expect(clippy::cast_sign_loss)] // we want to lose the sign
         let handle = if let Ok(signed_handle) = i32::try_from(sign_extended_handle) {
-            signed_handle as u32
+            signed_handle.cast_unsigned()
         } else {
             // if a handle doesn't fit in an i32, it isn't valid.
             return interp_ok(Err(HandleError::InvalidHandle));
@@ -224,6 +224,100 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         )))
     }
 
+    fn GetStdHandle(&mut self, which: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
+        let this = self.eval_context_mut();
+        let which = this.read_scalar(which)?.to_i32()?;
+
+        let stdin = this.eval_windows("c", "STD_INPUT_HANDLE").to_i32()?;
+        let stdout = this.eval_windows("c", "STD_OUTPUT_HANDLE").to_i32()?;
+        let stderr = this.eval_windows("c", "STD_ERROR_HANDLE").to_i32()?;
+
+        // These values don't mean anything on Windows, but Miri unconditionally sets them up to the
+        // unix in/out/err descriptors. So we take advantage of that.
+        // Due to the `Handle` encoding, these values will not be directly exposed to the user.
+        let fd_num = if which == stdin {
+            0
+        } else if which == stdout {
+            1
+        } else if which == stderr {
+            2
+        } else {
+            throw_unsup_format!("Invalid argument to `GetStdHandle`: {which}")
+        };
+        let handle = Handle::File(fd_num);
+        interp_ok(handle.to_scalar(this))
+    }
+
+    fn DuplicateHandle(
+        &mut self,
+        src_proc: &OpTy<'tcx>,       // HANDLE
+        src_handle: &OpTy<'tcx>,     // HANDLE
+        target_proc: &OpTy<'tcx>,    // HANDLE
+        target_handle: &OpTy<'tcx>,  // LPHANDLE
+        desired_access: &OpTy<'tcx>, // DWORD
+        inherit: &OpTy<'tcx>,        // BOOL
+        options: &OpTy<'tcx>,        // DWORD
+    ) -> InterpResult<'tcx, Scalar> {
+        // ^ Returns BOOL (i32 on Windows)
+        let this = self.eval_context_mut();
+
+        let src_proc = this.read_handle(src_proc, "DuplicateHandle")?;
+        let src_handle = this.read_handle(src_handle, "DuplicateHandle")?;
+        let target_proc = this.read_handle(target_proc, "DuplicateHandle")?;
+        let target_handle_ptr = this.read_pointer(target_handle)?;
+        // Since we only support DUPLICATE_SAME_ACCESS, this value is ignored, but should be valid
+        let _ = this.read_scalar(desired_access)?.to_u32()?;
+        // We don't support the CreateProcess API, so inheritable or not means nothing.
+        // If we ever add CreateProcess support, this will need to be implemented.
+        let _ = this.read_scalar(inherit)?;
+        let options = this.read_scalar(options)?;
+
+        if src_proc != Handle::Pseudo(PseudoHandle::CurrentProcess) {
+            throw_unsup_format!(
+                "`DuplicateHandle` `hSourceProcessHandle` parameter is not the current process, which is unsupported"
+            );
+        }
+
+        if target_proc != Handle::Pseudo(PseudoHandle::CurrentProcess) {
+            throw_unsup_format!(
+                "`DuplicateHandle` `hSourceProcessHandle` parameter is not the current process, which is unsupported"
+            );
+        }
+
+        if this.ptr_is_null(target_handle_ptr)? {
+            throw_unsup_format!(
+                "`DuplicateHandle` `lpTargetHandle` parameter is null, which is unsupported"
+            );
+        }
+
+        if options != this.eval_windows("c", "DUPLICATE_SAME_ACCESS") {
+            throw_unsup_format!(
+                "`DuplicateHandle` `dwOptions` parameter is not `DUPLICATE_SAME_ACCESS`, which is unsupported"
+            );
+        }
+
+        let new_handle = match src_handle {
+            Handle::File(old_fd_num) => {
+                let Some(fd) = this.machine.fds.get(old_fd_num) else {
+                    this.invalid_handle("DuplicateHandle")?
+                };
+                Handle::File(this.machine.fds.insert(fd))
+            }
+            Handle::Thread(_) => {
+                throw_unsup_format!(
+                    "`DuplicateHandle` called on a thread handle, which is unsupported"
+                );
+            }
+            Handle::Pseudo(pseudo) => Handle::Pseudo(pseudo),
+            Handle::Null | Handle::Invalid => this.invalid_handle("DuplicateHandle")?,
+        };
+
+        let target_place = this.deref_pointer_as(target_handle, this.machine.layouts.usize)?;
+        this.write_scalar(new_handle.to_scalar(this), &target_place)?;
+
+        interp_ok(this.eval_windows("c", "TRUE"))
+    }
+
     fn CloseHandle(&mut self, handle_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
 
diff --git a/src/tools/miri/src/shims/x86/aesni.rs b/src/tools/miri/src/shims/x86/aesni.rs
index c6784db67fb..7191284b5a3 100644
--- a/src/tools/miri/src/shims/x86/aesni.rs
+++ b/src/tools/miri/src/shims/x86/aesni.rs
@@ -1,7 +1,8 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::LayoutOf as _;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use crate::*;
 
@@ -26,7 +27,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // `state` with the corresponding 128-bit key of `key`.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesdec_si128
             "aesdec" | "aesdec.256" | "aesdec.512" => {
-                let [state, key] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [state, key] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 aes_round(this, state, key, dest, |state, key| {
                     let key = aes::Block::from(key.to_le_bytes());
                     let mut state = aes::Block::from(state.to_le_bytes());
@@ -42,7 +43,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // `state` with the corresponding 128-bit key of `key`.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesdeclast_si128
             "aesdeclast" | "aesdeclast.256" | "aesdeclast.512" => {
-                let [state, key] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [state, key] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 aes_round(this, state, key, dest, |state, key| {
                     let mut state = aes::Block::from(state.to_le_bytes());
@@ -66,7 +67,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // `state` with the corresponding 128-bit key of `key`.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesenc_si128
             "aesenc" | "aesenc.256" | "aesenc.512" => {
-                let [state, key] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [state, key] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 aes_round(this, state, key, dest, |state, key| {
                     let key = aes::Block::from(key.to_le_bytes());
                     let mut state = aes::Block::from(state.to_le_bytes());
@@ -82,7 +83,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // `state` with the corresponding 128-bit key of `key`.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesenclast_si128
             "aesenclast" | "aesenclast.256" | "aesenclast.512" => {
-                let [state, key] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [state, key] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 aes_round(this, state, key, dest, |state, key| {
                     let mut state = aes::Block::from(state.to_le_bytes());
                     // `aes::hazmat::cipher_round` does the following operations:
@@ -102,7 +103,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Used to implement the _mm_aesimc_si128 function.
             // Performs the AES InvMixColumns operation on `op`
             "aesimc" => {
-                let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 // Transmute to `u128`
                 let op = op.transmute(this.machine.layouts.u128, this)?;
                 let dest = dest.transmute(this.machine.layouts.u128, this)?;
diff --git a/src/tools/miri/src/shims/x86/avx.rs b/src/tools/miri/src/shims/x86/avx.rs
index 3aeb2b429da..37539fec748 100644
--- a/src/tools/miri/src/shims/x86/avx.rs
+++ b/src/tools/miri/src/shims/x86/avx.rs
@@ -1,9 +1,10 @@
+use rustc_abi::CanonAbi;
 use rustc_apfloat::ieee::{Double, Single};
 use rustc_middle::mir;
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::LayoutOf as _;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use super::{
     FloatBinOp, FloatUnaryOp, bin_op_simd_float_all, conditional_dot_product, convert_float_to_int,
@@ -33,7 +34,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // matches the IEEE min/max operations, while x86 has different
             // semantics.
             "min.ps.256" | "max.ps.256" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which = match unprefixed_name {
                     "min.ps.256" => FloatBinOp::Min,
@@ -45,7 +46,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             // Used to implement _mm256_min_pd and _mm256_max_pd functions.
             "min.pd.256" | "max.pd.256" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which = match unprefixed_name {
                     "min.pd.256" => FloatBinOp::Min,
@@ -58,21 +59,21 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Used to implement the _mm256_round_ps function.
             // Rounds the elements of `op` according to `rounding`.
             "round.ps.256" => {
-                let [op, rounding] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op, rounding] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 round_all::<rustc_apfloat::ieee::Single>(this, op, rounding, dest)?;
             }
             // Used to implement the _mm256_round_pd function.
             // Rounds the elements of `op` according to `rounding`.
             "round.pd.256" => {
-                let [op, rounding] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op, rounding] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 round_all::<rustc_apfloat::ieee::Double>(this, op, rounding, dest)?;
             }
             // Used to implement _mm256_{rcp,rsqrt}_ps functions.
             // Performs the operations on all components of `op`.
             "rcp.ps.256" | "rsqrt.ps.256" => {
-                let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which = match unprefixed_name {
                     "rcp.ps.256" => FloatUnaryOp::Rcp,
@@ -84,7 +85,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             // Used to implement the _mm256_dp_ps function.
             "dp.ps.256" => {
-                let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 conditional_dot_product(this, left, right, imm, dest)?;
             }
@@ -92,7 +93,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Horizontally add/subtract adjacent floating point values
             // in `left` and `right`.
             "hadd.ps.256" | "hadd.pd.256" | "hsub.ps.256" | "hsub.pd.256" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which = match unprefixed_name {
                     "hadd.ps.256" | "hadd.pd.256" => mir::BinOp::Add,
@@ -107,7 +108,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // and `right`. For each component, returns 0 if false or u32::MAX
             // if true.
             "cmp.ps.256" => {
-                let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which =
                     FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
@@ -119,7 +120,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // and `right`. For each component, returns 0 if false or u64::MAX
             // if true.
             "cmp.pd.256" => {
-                let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which =
                     FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
@@ -130,7 +131,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // and _mm256_cvttpd_epi32 functions.
             // Converts packed f32/f64 to packed i32.
             "cvt.ps2dq.256" | "cvtt.ps2dq.256" | "cvt.pd2dq.256" | "cvtt.pd2dq.256" => {
-                let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let rnd = match unprefixed_name {
                     // "current SSE rounding mode", assume nearest
@@ -148,7 +149,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // sequence of 4-element arrays, and we shuffle each of these arrays, where
             // `control` determines which element of the current `data` array is written.
             "vpermilvar.ps" | "vpermilvar.ps.256" => {
-                let [data, control] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [data, control] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (data, data_len) = this.project_to_simd(data)?;
                 let (control, control_len) = this.project_to_simd(control)?;
@@ -181,7 +182,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // where `right` determines which element of the current `left` array is
             // written.
             "vpermilvar.pd" | "vpermilvar.pd.256" => {
-                let [data, control] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [data, control] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (data, data_len) = this.project_to_simd(data)?;
                 let (control, control_len) = this.project_to_simd(control)?;
@@ -213,7 +214,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // For each 128-bit element of `dest`, copies one from `left`, `right` or
             // zero, according to `imm`.
             "vperm2f128.ps.256" | "vperm2f128.pd.256" | "vperm2f128.si.256" => {
-                let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 assert_eq!(dest.layout, left.layout);
                 assert_eq!(dest.layout, right.layout);
@@ -256,7 +257,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // is one, it is loaded from `ptr.wrapping_add(i)`, otherwise zero is
             // loaded.
             "maskload.ps" | "maskload.pd" | "maskload.ps.256" | "maskload.pd.256" => {
-                let [ptr, mask] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [ptr, mask] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 mask_load(this, ptr, mask, dest)?;
             }
@@ -266,7 +267,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // is one, it is stored into `ptr.wapping_add(i)`.
             // Unlike SSE2's _mm_maskmoveu_si128, these are not non-temporal stores.
             "maskstore.ps" | "maskstore.pd" | "maskstore.ps.256" | "maskstore.pd.256" => {
-                let [ptr, mask, value] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [ptr, mask, value] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 mask_store(this, ptr, mask, value)?;
             }
@@ -276,7 +277,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // the data crosses a cache line, but for Miri this is just a regular
             // unaligned read.
             "ldu.dq.256" => {
-                let [src_ptr] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [src_ptr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let src_ptr = this.read_pointer(src_ptr)?;
                 let dest = dest.force_mplace(this)?;
 
@@ -288,7 +289,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Tests `op & mask == 0`, `op & mask == mask` or
             // `op & mask != 0 && op & mask != mask`
             "ptestz.256" | "ptestc.256" | "ptestnzc.256" => {
-                let [op, mask] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op, mask] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (all_zero, masked_set) = test_bits_masked(this, op, mask)?;
                 let res = match unprefixed_name {
@@ -311,7 +312,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "vtestz.pd.256" | "vtestc.pd.256" | "vtestnzc.pd.256" | "vtestz.pd" | "vtestc.pd"
             | "vtestnzc.pd" | "vtestz.ps.256" | "vtestc.ps.256" | "vtestnzc.ps.256"
             | "vtestz.ps" | "vtestc.ps" | "vtestnzc.ps" => {
-                let [op, mask] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op, mask] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (direct, negated) = test_high_bits_masked(this, op, mask)?;
                 let res = match unprefixed_name {
@@ -333,7 +334,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // compiler, making these functions no-ops.
 
                 // The only thing that needs to be ensured is the correct calling convention.
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
             }
             _ => return interp_ok(EmulateItemResult::NotSupported),
         }
diff --git a/src/tools/miri/src/shims/x86/avx2.rs b/src/tools/miri/src/shims/x86/avx2.rs
index c79899285cd..5dfe5cc2c54 100644
--- a/src/tools/miri/src/shims/x86/avx2.rs
+++ b/src/tools/miri/src/shims/x86/avx2.rs
@@ -1,8 +1,9 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::mir;
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::LayoutOf as _;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use super::{
     ShiftOp, horizontal_bin_op, int_abs, mask_load, mask_store, mpsadbw, packssdw, packsswb,
@@ -28,7 +29,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Used to implement the _mm256_abs_epi{8,16,32} functions.
             // Calculates the absolute value of packed 8/16/32-bit integers.
             "pabs.b" | "pabs.w" | "pabs.d" => {
-                let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 int_abs(this, op, dest)?;
             }
@@ -36,7 +37,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Horizontally add / add with saturation / subtract adjacent 16/32-bit
             // integer values in `left` and `right`.
             "phadd.w" | "phadd.sw" | "phadd.d" | "phsub.w" | "phsub.sw" | "phsub.d" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (which, saturating) = match unprefixed_name {
                     "phadd.w" | "phadd.d" => (mir::BinOp::Add, false),
@@ -57,7 +58,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             | "gather.d.pd.256" | "gather.q.pd" | "gather.q.pd.256" | "gather.d.ps"
             | "gather.d.ps.256" | "gather.q.ps" | "gather.q.ps.256" => {
                 let [src, slice, offsets, mask, scale] =
-                    this.check_shim(abi, Conv::C, link_name, args)?;
+                    this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 assert_eq!(dest.layout, src.layout);
 
@@ -114,7 +115,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // intermediate signed 32-bit integers. Horizontally add adjacent pairs of
             // intermediate 32-bit integers, and pack the results in `dest`.
             "pmadd.wd" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
@@ -150,7 +151,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // the saturating sum of the products with indices `2*i` and `2*i+1`
             // produces the output at index `i`.
             "pmadd.ub.sw" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
@@ -184,7 +185,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // is one, it is loaded from `ptr.wrapping_add(i)`, otherwise zero is
             // loaded.
             "maskload.d" | "maskload.q" | "maskload.d.256" | "maskload.q.256" => {
-                let [ptr, mask] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [ptr, mask] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 mask_load(this, ptr, mask, dest)?;
             }
@@ -194,7 +195,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // is one, it is stored into `ptr.wapping_add(i)`.
             // Unlike SSE2's _mm_maskmoveu_si128, these are not non-temporal stores.
             "maskstore.d" | "maskstore.q" | "maskstore.d.256" | "maskstore.q.256" => {
-                let [ptr, mask, value] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [ptr, mask, value] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 mask_store(this, ptr, mask, value)?;
             }
@@ -205,7 +206,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // offsets specified in `imm`.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mpsadbw_epu8
             "mpsadbw" => {
-                let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 mpsadbw(this, left, right, imm, dest)?;
             }
@@ -216,7 +217,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // 1 and then taking the bits `1..=16`.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mulhrs_epi16
             "pmul.hr.sw" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 pmulhrsw(this, left, right, dest)?;
             }
@@ -224,7 +225,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Converts two 16-bit integer vectors to a single 8-bit integer
             // vector with signed saturation.
             "packsswb" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 packsswb(this, left, right, dest)?;
             }
@@ -232,7 +233,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Converts two 32-bit integer vectors to a single 16-bit integer
             // vector with signed saturation.
             "packssdw" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 packssdw(this, left, right, dest)?;
             }
@@ -240,7 +241,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Converts two 16-bit signed integer vectors to a single 8-bit
             // unsigned integer vector with saturation.
             "packuswb" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 packuswb(this, left, right, dest)?;
             }
@@ -248,7 +249,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Concatenates two 32-bit signed integer vectors and converts
             // the result to a 16-bit unsigned integer vector with saturation.
             "packusdw" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 packusdw(this, left, right, dest)?;
             }
@@ -257,7 +258,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Shuffles `left` using the three low bits of each element of `right`
             // as indices.
             "permd" | "permps" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
@@ -277,7 +278,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Used to implement the _mm256_permute2x128_si256 function.
             // Shuffles 128-bit blocks of `a` and `b` using `imm` as pattern.
             "vperm2i128" => {
-                let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 assert_eq!(left.layout.size.bits(), 256);
                 assert_eq!(right.layout.size.bits(), 256);
@@ -314,7 +315,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // in `dest`.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_sad_epu8
             "psad.bw" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
@@ -346,7 +347,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Shuffles bytes from `left` using `right` as pattern.
             // Each 128-bit block is shuffled independently.
             "pshuf.b" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
@@ -377,7 +378,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // is writen to the corresponding output element.
             // Basically, we multiply `left` with `right.signum()`.
             "psign.b" | "psign.w" | "psign.d" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 psign(this, left, right, dest)?;
             }
@@ -391,7 +392,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // is copied to remaining bits.
             "psll.w" | "psrl.w" | "psra.w" | "psll.d" | "psrl.d" | "psra.d" | "psll.q"
             | "psrl.q" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which = match unprefixed_name {
                     "psll.w" | "psll.d" | "psll.q" => ShiftOp::Left,
@@ -406,7 +407,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // (except _mm{,256}_srav_epi64, which are not available in AVX2).
             "psllv.d" | "psllv.d.256" | "psllv.q" | "psllv.q.256" | "psrlv.d" | "psrlv.d.256"
             | "psrlv.q" | "psrlv.q.256" | "psrav.d" | "psrav.d.256" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which = match unprefixed_name {
                     "psllv.d" | "psllv.d.256" | "psllv.q" | "psllv.q.256" => ShiftOp::Left,
diff --git a/src/tools/miri/src/shims/x86/bmi.rs b/src/tools/miri/src/shims/x86/bmi.rs
index 8af59df0a68..80b1b2e16e6 100644
--- a/src/tools/miri/src/shims/x86/bmi.rs
+++ b/src/tools/miri/src/shims/x86/bmi.rs
@@ -1,6 +1,7 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use crate::*;
 
@@ -34,7 +35,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             return interp_ok(EmulateItemResult::NotSupported);
         }
 
-        let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+        let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
         let left = this.read_scalar(left)?;
         let right = this.read_scalar(right)?;
 
diff --git a/src/tools/miri/src/shims/x86/gfni.rs b/src/tools/miri/src/shims/x86/gfni.rs
index 4774ec9f9d8..f83ce560c84 100644
--- a/src/tools/miri/src/shims/x86/gfni.rs
+++ b/src/tools/miri/src/shims/x86/gfni.rs
@@ -1,6 +1,7 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use crate::*;
 
@@ -30,14 +31,14 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // See `affine_transform` for details.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8affine_
             "vgf2p8affineqb.128" | "vgf2p8affineqb.256" | "vgf2p8affineqb.512" => {
-                let [left, right, imm8] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm8] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 affine_transform(this, left, right, imm8, dest, /* inverse */ false)?;
             }
             // Used to implement the `_mm{, 256, 512}_gf2p8affineinv_epi64_epi8` functions.
             // See `affine_transform` for details.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8affineinv
             "vgf2p8affineinvqb.128" | "vgf2p8affineinvqb.256" | "vgf2p8affineinvqb.512" => {
-                let [left, right, imm8] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm8] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 affine_transform(this, left, right, imm8, dest, /* inverse */ true)?;
             }
             // Used to implement the `_mm{, 256, 512}_gf2p8mul_epi8` functions.
@@ -46,7 +47,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // polynomial representation with the reduction polynomial x^8 + x^4 + x^3 + x + 1.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8mul
             "vgf2p8mulb.128" | "vgf2p8mulb.256" | "vgf2p8mulb.512" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
                 let (dest, dest_len) = this.project_to_simd(dest)?;
@@ -133,12 +134,12 @@ fn affine_transform<'tcx>(
 // This is a evaluated at compile time. Trait based conversion is not available.
 /// See <https://www.corsix.org/content/galois-field-instructions-2021-cpus> for the
 /// definition of `gf_inv` which was used for the creation of this table.
-#[expect(clippy::cast_possible_truncation)]
 static TABLE: [u8; 256] = {
     let mut array = [0; 256];
 
     let mut i = 1;
     while i < 256 {
+        #[expect(clippy::as_conversions)] // no `try_from` in const...
         let mut x = i as u8;
         let mut y = gf2p8_mul(x, x);
         x = y;
@@ -160,7 +161,7 @@ static TABLE: [u8; 256] = {
 /// polynomial representation with the reduction polynomial x^8 + x^4 + x^3 + x + 1.
 /// See <https://www.corsix.org/content/galois-field-instructions-2021-cpus> for details.
 // This is a const function. Trait based conversion is not available.
-#[expect(clippy::cast_possible_truncation)]
+#[expect(clippy::as_conversions)]
 const fn gf2p8_mul(left: u8, right: u8) -> u8 {
     // This implementation is based on the `gf2p8mul_byte` definition found inside the Intel intrinsics guide.
     // See https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8mul
diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs
index e57217dc6f2..1e82f521249 100644
--- a/src/tools/miri/src/shims/x86/mod.rs
+++ b/src/tools/miri/src/shims/x86/mod.rs
@@ -1,11 +1,11 @@
-use rustc_abi::Size;
+use rustc_abi::{CanonAbi, FieldIdx, Size};
 use rustc_apfloat::Float;
 use rustc_apfloat::ieee::Single;
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::LayoutOf as _;
 use rustc_middle::{mir, ty};
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use self::helpers::bool_to_simd_element;
 use crate::*;
@@ -46,7 +46,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     return interp_ok(EmulateItemResult::NotSupported);
                 }
 
-                let [cb_in, a, b] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [cb_in, a, b] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let op = if unprefixed_name.starts_with("add") {
                     mir::BinOp::AddWithOverflow
                 } else {
@@ -54,8 +54,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 };
 
                 let (sum, cb_out) = carrying_add(this, cb_in, a, b, op)?;
-                this.write_scalar(cb_out, &this.project_field(dest, 0)?)?;
-                this.write_immediate(*sum, &this.project_field(dest, 1)?)?;
+                this.write_scalar(cb_out, &this.project_field(dest, FieldIdx::ZERO)?)?;
+                this.write_immediate(*sum, &this.project_field(dest, FieldIdx::ONE)?)?;
             }
 
             // Used to implement the `_addcarryx_u{32, 64}` functions. They are semantically identical with the `_addcarry_u{32, 64}` functions,
@@ -68,7 +68,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 if is_u64 && this.tcx.sess.target.arch != "x86_64" {
                     return interp_ok(EmulateItemResult::NotSupported);
                 }
-                let [c_in, a, b, out] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [c_in, a, b, out] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let out = this.deref_pointer_as(
                     out,
                     if is_u64 { this.machine.layouts.u64 } else { this.machine.layouts.u32 },
@@ -85,7 +85,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // the instruction behaves like a no-op, so it is always safe to call the
             // intrinsic.
             "sse2.pause" => {
-                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 // Only exhibit the spin-loop hint behavior when SSE2 is enabled.
                 if this.tcx.sess.unstable_target_features.contains(&Symbol::intern("sse2")) {
                     this.yield_active_thread();
@@ -104,7 +104,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     len = 8;
                 }
 
-                let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 pclmulqdq(this, left, right, imm, dest, len)?;
             }
@@ -1110,7 +1110,7 @@ fn pmulhrsw<'tcx>(
 
         // The result of this operation can overflow a signed 16-bit integer.
         // When `left` and `right` are -0x8000, the result is 0x8000.
-        #[expect(clippy::cast_possible_truncation)]
+        #[expect(clippy::as_conversions)]
         let res = res as i16;
 
         ecx.write_scalar(Scalar::from_i16(res), &dest)?;
diff --git a/src/tools/miri/src/shims/x86/sha.rs b/src/tools/miri/src/shims/x86/sha.rs
index 6d2c151243c..d37fad3e6c7 100644
--- a/src/tools/miri/src/shims/x86/sha.rs
+++ b/src/tools/miri/src/shims/x86/sha.rs
@@ -4,9 +4,10 @@
 //!
 //! [RustCrypto's sha256 module]: https://github.com/RustCrypto/hashes/blob/6be8466247e936c415d8aafb848697f39894a386/sha2/src/sha256/soft.rs
 
+use rustc_abi::CanonAbi;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use crate::*;
 
@@ -43,7 +44,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // We reverse the order because x86 is little endian but the copied implementation uses
             // big endian.
             for (i, part) in val.into_iter().rev().enumerate() {
-                let projected = &ecx.project_index(dest, i.try_into().unwrap())?;
+                let projected = &ecx.project_index(dest, i.to_u64())?;
                 ecx.write_scalar(Scalar::from_u32(part), projected)?;
             }
             interp_ok(())
@@ -52,7 +53,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         match unprefixed_name {
             // Used to implement the _mm_sha256rnds2_epu32 function.
             "256rnds2" => {
-                let [a, b, k] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [a, b, k] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (a_reg, a_len) = this.project_to_simd(a)?;
                 let (b_reg, b_len) = this.project_to_simd(b)?;
@@ -73,7 +74,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             // Used to implement the _mm_sha256msg1_epu32 function.
             "256msg1" => {
-                let [a, b] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [a, b] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (a_reg, a_len) = this.project_to_simd(a)?;
                 let (b_reg, b_len) = this.project_to_simd(b)?;
@@ -91,7 +92,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             // Used to implement the _mm_sha256msg2_epu32 function.
             "256msg2" => {
-                let [a, b] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [a, b] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (a_reg, a_len) = this.project_to_simd(a)?;
                 let (b_reg, b_len) = this.project_to_simd(b)?;
diff --git a/src/tools/miri/src/shims/x86/sse.rs b/src/tools/miri/src/shims/x86/sse.rs
index fd7aba2437a..1ec15d609c6 100644
--- a/src/tools/miri/src/shims/x86/sse.rs
+++ b/src/tools/miri/src/shims/x86/sse.rs
@@ -1,7 +1,8 @@
+use rustc_abi::CanonAbi;
 use rustc_apfloat::ieee::Single;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use super::{
     FloatBinOp, FloatUnaryOp, bin_op_simd_float_all, bin_op_simd_float_first, unary_op_ps,
@@ -33,7 +34,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Performs the operations on the first component of `left` and
             // `right` and copies the remaining components from `left`.
             "min.ss" | "max.ss" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which = match unprefixed_name {
                     "min.ss" => FloatBinOp::Min,
@@ -49,7 +50,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // matches the IEEE min/max operations, while x86 has different
             // semantics.
             "min.ps" | "max.ps" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which = match unprefixed_name {
                     "min.ps" => FloatBinOp::Min,
@@ -63,7 +64,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Performs the operations on the first component of `op` and
             // copies the remaining components from `op`.
             "rcp.ss" | "rsqrt.ss" => {
-                let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which = match unprefixed_name {
                     "rcp.ss" => FloatUnaryOp::Rcp,
@@ -76,7 +77,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Used to implement _mm_{sqrt,rcp,rsqrt}_ps functions.
             // Performs the operations on all components of `op`.
             "rcp.ps" | "rsqrt.ps" => {
-                let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which = match unprefixed_name {
                     "rcp.ps" => FloatUnaryOp::Rcp,
@@ -95,7 +96,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_ss are SSE functions
             // with hard-coded operations.
             "cmp.ss" => {
-                let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which =
                     FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
@@ -111,7 +112,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_ps are SSE functions
             // with hard-coded operations.
             "cmp.ps" => {
-                let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which =
                     FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
@@ -124,7 +125,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "comieq.ss" | "comilt.ss" | "comile.ss" | "comigt.ss" | "comige.ss" | "comineq.ss"
             | "ucomieq.ss" | "ucomilt.ss" | "ucomile.ss" | "ucomigt.ss" | "ucomige.ss"
             | "ucomineq.ss" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
@@ -152,7 +153,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // _mm_cvtss_si64 and _mm_cvttss_si64 functions.
             // Converts the first component of `op` from f32 to i32/i64.
             "cvtss2si" | "cvttss2si" | "cvtss2si64" | "cvttss2si64" => {
-                let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let (op, _) = this.project_to_simd(op)?;
 
                 let op = this.read_immediate(&this.project_index(&op, 0)?)?;
@@ -180,7 +181,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // are copied from `left`.
             // https://www.felixcloutier.com/x86/cvtsi2ss
             "cvtsi2ss" | "cvtsi642ss" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (dest, dest_len) = this.project_to_simd(dest)?;
diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs
index e0695b7cb7b..d6052f83077 100644
--- a/src/tools/miri/src/shims/x86/sse2.rs
+++ b/src/tools/miri/src/shims/x86/sse2.rs
@@ -1,7 +1,8 @@
+use rustc_abi::CanonAbi;
 use rustc_apfloat::ieee::Double;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use super::{
     FloatBinOp, ShiftOp, bin_op_simd_float_all, bin_op_simd_float_first, convert_float_to_int,
@@ -40,7 +41,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // intermediate signed 32-bit integers. Horizontally add adjacent pairs of
             // intermediate 32-bit integers, and pack the results in `dest`.
             "pmadd.wd" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
@@ -78,7 +79,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             //
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sad_epu8
             "psad.bw" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
@@ -116,7 +117,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // is copied to remaining bits.
             "psll.w" | "psrl.w" | "psra.w" | "psll.d" | "psrl.d" | "psra.d" | "psll.q"
             | "psrl.q" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which = match unprefixed_name {
                     "psll.w" | "psll.d" | "psll.q" => ShiftOp::Left,
@@ -131,7 +132,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // and _mm_cvttpd_epi32 functions.
             // Converts packed f32/f64 to packed i32.
             "cvtps2dq" | "cvttps2dq" | "cvtpd2dq" | "cvttpd2dq" => {
-                let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (op_len, _) = op.layout.ty.simd_size_and_type(*this.tcx);
                 let (dest_len, _) = dest.layout.ty.simd_size_and_type(*this.tcx);
@@ -168,7 +169,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Converts two 16-bit integer vectors to a single 8-bit integer
             // vector with signed saturation.
             "packsswb.128" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 packsswb(this, left, right, dest)?;
             }
@@ -176,7 +177,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Converts two 16-bit signed integer vectors to a single 8-bit
             // unsigned integer vector with saturation.
             "packuswb.128" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 packuswb(this, left, right, dest)?;
             }
@@ -184,7 +185,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Converts two 32-bit integer vectors to a single 16-bit integer
             // vector with signed saturation.
             "packssdw.128" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 packssdw(this, left, right, dest)?;
             }
@@ -194,7 +195,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // matches the IEEE min/max operations, while x86 has different
             // semantics.
             "min.sd" | "max.sd" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which = match unprefixed_name {
                     "min.sd" => FloatBinOp::Min,
@@ -210,7 +211,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // matches the IEEE min/max operations, while x86 has different
             // semantics.
             "min.pd" | "max.pd" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which = match unprefixed_name {
                     "min.pd" => FloatBinOp::Min,
@@ -229,7 +230,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_sd are SSE2 functions
             // with hard-coded operations.
             "cmp.sd" => {
-                let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which =
                     FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
@@ -245,7 +246,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_pd are SSE2 functions
             // with hard-coded operations.
             "cmp.pd" => {
-                let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which =
                     FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
@@ -258,7 +259,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             "comieq.sd" | "comilt.sd" | "comile.sd" | "comigt.sd" | "comige.sd" | "comineq.sd"
             | "ucomieq.sd" | "ucomilt.sd" | "ucomile.sd" | "ucomigt.sd" | "ucomige.sd"
             | "ucomineq.sd" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
@@ -286,7 +287,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // _mm_cvtsd_si64 and _mm_cvttsd_si64 functions.
             // Converts the first component of `op` from f64 to i32/i64.
             "cvtsd2si" | "cvttsd2si" | "cvtsd2si64" | "cvttsd2si64" => {
-                let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let (op, _) = this.project_to_simd(op)?;
 
                 let op = this.read_immediate(&this.project_index(&op, 0)?)?;
@@ -312,7 +313,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Converts the first f64/f32 from `right` to f32/f64 and copies
             // the remaining elements from `left`
             "cvtsd2ss" | "cvtss2sd" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, _) = this.project_to_simd(right)?;
diff --git a/src/tools/miri/src/shims/x86/sse3.rs b/src/tools/miri/src/shims/x86/sse3.rs
index 60b7764a01e..ebf3cb5c3ee 100644
--- a/src/tools/miri/src/shims/x86/sse3.rs
+++ b/src/tools/miri/src/shims/x86/sse3.rs
@@ -1,7 +1,8 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::mir;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use super::horizontal_bin_op;
 use crate::*;
@@ -25,7 +26,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Horizontally add/subtract adjacent floating point values
             // in `left` and `right`.
             "hadd.ps" | "hadd.pd" | "hsub.ps" | "hsub.pd" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let which = match unprefixed_name {
                     "hadd.ps" | "hadd.pd" => mir::BinOp::Add,
@@ -41,7 +42,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // the data crosses a cache line, but for Miri this is just a regular
             // unaligned read.
             "ldu.dq" => {
-                let [src_ptr] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [src_ptr] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let src_ptr = this.read_pointer(src_ptr)?;
                 let dest = dest.force_mplace(this)?;
 
diff --git a/src/tools/miri/src/shims/x86/sse41.rs b/src/tools/miri/src/shims/x86/sse41.rs
index 93d689a3044..6797039cf56 100644
--- a/src/tools/miri/src/shims/x86/sse41.rs
+++ b/src/tools/miri/src/shims/x86/sse41.rs
@@ -1,6 +1,7 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use super::{conditional_dot_product, mpsadbw, packusdw, round_all, round_first, test_bits_masked};
 use crate::*;
@@ -27,7 +28,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // bits `4..=5` if `imm`, and `i`th bit specifies whether element
             // `i` is zeroed.
             "insertps" => {
-                let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
@@ -62,7 +63,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Concatenates two 32-bit signed integer vectors and converts
             // the result to a 16-bit unsigned integer vector with saturation.
             "packusdw" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 packusdw(this, left, right, dest)?;
             }
@@ -72,7 +73,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // products, and conditionally stores the sum in `dest` using the low
             // 4 bits of `imm`.
             "dpps" | "dppd" => {
-                let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 conditional_dot_product(this, left, right, imm, dest)?;
             }
@@ -80,14 +81,14 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // functions. Rounds the first element of `right` according to `rounding`
             // and copies the remaining elements from `left`.
             "round.ss" => {
-                let [left, right, rounding] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, rounding] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 round_first::<rustc_apfloat::ieee::Single>(this, left, right, rounding, dest)?;
             }
             // Used to implement the _mm_floor_ps, _mm_ceil_ps and _mm_round_ps
             // functions. Rounds the elements of `op` according to `rounding`.
             "round.ps" => {
-                let [op, rounding] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op, rounding] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 round_all::<rustc_apfloat::ieee::Single>(this, op, rounding, dest)?;
             }
@@ -95,14 +96,14 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // functions. Rounds the first element of `right` according to `rounding`
             // and copies the remaining elements from `left`.
             "round.sd" => {
-                let [left, right, rounding] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, rounding] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 round_first::<rustc_apfloat::ieee::Double>(this, left, right, rounding, dest)?;
             }
             // Used to implement the _mm_floor_pd, _mm_ceil_pd and _mm_round_pd
             // functions. Rounds the elements of `op` according to `rounding`.
             "round.pd" => {
-                let [op, rounding] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op, rounding] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 round_all::<rustc_apfloat::ieee::Double>(this, op, rounding, dest)?;
             }
@@ -110,7 +111,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Find the minimum unsinged 16-bit integer in `op` and
             // returns its value and position.
             "phminposuw" => {
-                let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (op, op_len) = this.project_to_simd(op)?;
                 let (dest, dest_len) = this.project_to_simd(dest)?;
@@ -144,7 +145,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // offsets specified in `imm`.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_mpsadbw_epu8
             "mpsadbw" => {
-                let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 mpsadbw(this, left, right, imm, dest)?;
             }
@@ -153,7 +154,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Tests `(op & mask) == 0`, `(op & mask) == mask` or
             // `(op & mask) != 0 && (op & mask) != mask`
             "ptestz" | "ptestc" | "ptestnzc" => {
-                let [op, mask] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op, mask] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (all_zero, masked_set) = test_bits_masked(this, op, mask)?;
                 let res = match unprefixed_name {
diff --git a/src/tools/miri/src/shims/x86/sse42.rs b/src/tools/miri/src/shims/x86/sse42.rs
index 02336a722f7..830513f0291 100644
--- a/src/tools/miri/src/shims/x86/sse42.rs
+++ b/src/tools/miri/src/shims/x86/sse42.rs
@@ -1,9 +1,9 @@
-use rustc_abi::Size;
+use rustc_abi::{CanonAbi, Size};
 use rustc_middle::mir;
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::LayoutOf as _;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use crate::*;
 
@@ -223,7 +223,7 @@ fn deconstruct_args<'tcx>(
     };
 
     if is_explicit {
-        let [str1, len1, str2, len2, imm] = ecx.check_shim(abi, Conv::C, link_name, args)?;
+        let [str1, len1, str2, len2, imm] = ecx.check_shim(abi, CanonAbi::C, link_name, args)?;
         let imm = ecx.read_scalar(imm)?.to_u8()?;
 
         let default_len = default_len::<u32>(imm);
@@ -236,7 +236,7 @@ fn deconstruct_args<'tcx>(
 
         interp_ok((str1, str2, Some((len1, len2)), imm))
     } else {
-        let [str1, str2, imm] = ecx.check_shim(abi, Conv::C, link_name, args)?;
+        let [str1, str2, imm] = ecx.check_shim(abi, CanonAbi::C, link_name, args)?;
         let imm = ecx.read_scalar(imm)?.to_u8()?;
 
         let array_layout = array_layout_fn(ecx, imm)?;
@@ -386,7 +386,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // search for a null terminator (see `deconstruct_args` for more details).
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ig_expand=924,925
             "pcmpistriz128" | "pcmpistris128" => {
-                let [str1, str2, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [str1, str2, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let imm = this.read_scalar(imm)?.to_u8()?;
 
                 let str = if unprefixed_name == "pcmpistris128" { str1 } else { str2 };
@@ -406,7 +406,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // than 16 for byte-sized operands or 8 for word-sized operands.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ig_expand=1046,1047
             "pcmpestriz128" | "pcmpestris128" => {
-                let [_, len1, _, len2, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [_, len1, _, len2, imm] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let len = if unprefixed_name == "pcmpestris128" { len1 } else { len2 };
                 let len = this.read_scalar(len)?.to_i32()?;
                 let imm = this.read_scalar(imm)?.to_u8()?;
@@ -433,14 +433,14 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     return interp_ok(EmulateItemResult::NotSupported);
                 }
 
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
                 let left = this.read_scalar(left)?;
                 let right = this.read_scalar(right)?;
 
                 let crc = if bit_size == 64 {
                     // The 64-bit version will only consider the lower 32 bits,
                     // while the upper 32 bits get discarded.
-                    #[expect(clippy::cast_possible_truncation)]
+                    #[expect(clippy::as_conversions)]
                     u128::from((left.to_u64()? as u32).reverse_bits())
                 } else {
                     u128::from(left.to_u32()?.reverse_bits())
diff --git a/src/tools/miri/src/shims/x86/ssse3.rs b/src/tools/miri/src/shims/x86/ssse3.rs
index f3e9ac0e5dc..310d6b8f765 100644
--- a/src/tools/miri/src/shims/x86/ssse3.rs
+++ b/src/tools/miri/src/shims/x86/ssse3.rs
@@ -1,7 +1,8 @@
+use rustc_abi::CanonAbi;
 use rustc_middle::mir;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
-use rustc_target::callconv::{Conv, FnAbi};
+use rustc_target::callconv::FnAbi;
 
 use super::{horizontal_bin_op, int_abs, pmulhrsw, psign};
 use crate::*;
@@ -24,7 +25,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Used to implement the _mm_abs_epi{8,16,32} functions.
             // Calculates the absolute value of packed 8/16/32-bit integers.
             "pabs.b.128" | "pabs.w.128" | "pabs.d.128" => {
-                let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [op] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 int_abs(this, op, dest)?;
             }
@@ -32,7 +33,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Shuffles bytes from `left` using `right` as pattern.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_shuffle_epi8
             "pshuf.b.128" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
@@ -61,7 +62,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // integer values in `left` and `right`.
             "phadd.w.128" | "phadd.sw.128" | "phadd.d.128" | "phsub.w.128" | "phsub.sw.128"
             | "phsub.d.128" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (which, saturating) = match unprefixed_name {
                     "phadd.w.128" | "phadd.d.128" => (mir::BinOp::Add, false),
@@ -80,7 +81,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // produces the output at index `i`.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_maddubs_epi16
             "pmadd.ub.sw.128" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
@@ -115,7 +116,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // 1 and then taking the bits `1..=16`.
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_mulhrs_epi16
             "pmul.hr.sw.128" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 pmulhrsw(this, left, right, dest)?;
             }
@@ -125,7 +126,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // is writen to the corresponding output element.
             // Basically, we multiply `left` with `right.signum()`.
             "psign.b.128" | "psign.w.128" | "psign.d.128" => {
-                let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
+                let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
 
                 psign(this, left, right, dest)?;
             }
diff --git a/src/tools/miri/test_dependencies/Cargo.toml b/src/tools/miri/test_dependencies/Cargo.toml
index 653228a5e3d..fa833b51fa3 100644
--- a/src/tools/miri/test_dependencies/Cargo.toml
+++ b/src/tools/miri/test_dependencies/Cargo.toml
@@ -25,6 +25,13 @@ page_size = "0.6"
 tokio = { version = "1", features = ["macros", "rt-multi-thread", "time", "net", "fs", "sync", "signal", "io-util"] }
 
 [target.'cfg(windows)'.dependencies]
-windows-sys = { version = "0.59", features = ["Win32_Foundation", "Win32_System_Threading", "Win32_Storage_FileSystem", "Win32_Security"] }
+windows-sys = { version = "0.59", features = [
+    "Win32_Foundation",
+    "Win32_System_Threading",
+    "Win32_Storage_FileSystem",
+    "Win32_Security",
+    "Win32_System_IO",
+    "Wdk_Storage_FileSystem",
+] }
 
 [workspace]
diff --git a/src/tools/miri/tests/fail-dep/libc/fcntl_fsetfl_while_blocking.rs b/src/tools/miri/tests/fail-dep/libc/fcntl_fsetfl_while_blocking.rs
new file mode 100644
index 00000000000..eef32136a0a
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/fcntl_fsetfl_while_blocking.rs
@@ -0,0 +1,20 @@
+//@ignore-target: windows # Sockets/pipes are not implemented yet
+//~^ ERROR: deadlock: the evaluated program deadlocked
+//@compile-flags: -Zmiri-deterministic-concurrency
+use std::thread;
+
+/// If an O_NONBLOCK flag is set while the fd is blocking, that fd will not be woken up.
+fn main() {
+    let mut fds = [-1, -1];
+    let res = unsafe { libc::pipe(fds.as_mut_ptr()) };
+    assert_eq!(res, 0);
+    let mut buf: [u8; 5] = [0; 5];
+    let _thread1 = thread::spawn(move || {
+        // Add O_NONBLOCK flag while pipe is still block on read.
+        let res = unsafe { libc::fcntl(fds[0], libc::F_SETFL, libc::O_NONBLOCK) };
+        assert_eq!(res, 0);
+    });
+    // Main thread will block on read.
+    let _res = unsafe { libc::read(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
+    //~^ ERROR: deadlock: the evaluated program deadlocked
+}
diff --git a/src/tools/miri/tests/fail-dep/libc/fcntl_fsetfl_while_blocking.stderr b/src/tools/miri/tests/fail-dep/libc/fcntl_fsetfl_while_blocking.stderr
new file mode 100644
index 00000000000..9ca5598abae
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/fcntl_fsetfl_while_blocking.stderr
@@ -0,0 +1,19 @@
+error: deadlock: the evaluated program deadlocked
+   |
+   = note: the evaluated program deadlocked
+   = note: (no span available)
+   = note: BACKTRACE on thread `unnamed-ID`:
+
+error: deadlock: the evaluated program deadlocked
+  --> tests/fail-dep/libc/fcntl_fsetfl_while_blocking.rs:LL:CC
+   |
+LL |     let _res = unsafe { libc::read(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
+   |                                                                                              ^ the evaluated program deadlocked
+   |
+   = note: BACKTRACE:
+   = note: inside `main` at tests/fail-dep/libc/fcntl_fsetfl_while_blocking.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.rs b/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.rs
deleted file mode 100644
index 3ef194c5c71..00000000000
--- a/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@ignore-target: windows # No libc IO on Windows
-
-fn main() -> std::io::Result<()> {
-    let mut bytes = [0u8; 512];
-    unsafe {
-        libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512); //~ ERROR: `read` from stdin not available when isolation is enabled
-    }
-    Ok(())
-}
diff --git a/src/tools/miri/tests/fail-dep/libc/unsupported_incomplete_function.stderr b/src/tools/miri/tests/fail-dep/libc/unsupported_incomplete_function.stderr
index a92a97cef3b..52a93ab263d 100644
--- a/src/tools/miri/tests/fail-dep/libc/unsupported_incomplete_function.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/unsupported_incomplete_function.stderr
@@ -4,8 +4,7 @@ error: unsupported operation: can't call foreign function `signal` on $OS
 LL |         libc::signal(libc::SIGPIPE, libc::SIG_IGN);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't call foreign function `signal` on $OS
    |
-   = help: if this is a basic API commonly used on this target, please report an issue with Miri
-   = help: however, note that Miri does not aim to support every FFI function out there; for instance, we will not support APIs for things such as GUIs, scripting languages, or databases
+   = help: this means the program tried to do something Miri does not support; it does not indicate a bug in the program
    = note: BACKTRACE:
    = note: inside `main` at tests/fail-dep/libc/unsupported_incomplete_function.rs:LL:CC
 
diff --git a/src/tools/miri/tests/fail/alloc/no_global_allocator.stderr b/src/tools/miri/tests/fail/alloc/no_global_allocator.stderr
index 541af64b894..e80a3646714 100644
--- a/src/tools/miri/tests/fail/alloc/no_global_allocator.stderr
+++ b/src/tools/miri/tests/fail/alloc/no_global_allocator.stderr
@@ -4,8 +4,7 @@ error: unsupported operation: can't call foreign function `__rust_alloc` on $OS
 LL |         __rust_alloc(1, 1);
    |         ^^^^^^^^^^^^^^^^^^ can't call foreign function `__rust_alloc` on $OS
    |
-   = help: if this is a basic API commonly used on this target, please report an issue with Miri
-   = help: however, note that Miri does not aim to support every FFI function out there; for instance, we will not support APIs for things such as GUIs, scripting languages, or databases
+   = help: this means the program tried to do something Miri does not support; it does not indicate a bug in the program
    = note: BACKTRACE:
    = note: inside `miri_start` at tests/fail/alloc/no_global_allocator.rs:LL:CC
 
diff --git a/src/tools/miri/tests/fail/async-shared-mutable.rs b/src/tools/miri/tests/fail/async-shared-mutable.rs
new file mode 100644
index 00000000000..62780e7a11c
--- /dev/null
+++ b/src/tools/miri/tests/fail/async-shared-mutable.rs
@@ -0,0 +1,25 @@
+//! FIXME: This test should pass! However, `async fn` does not yet use `UnsafePinned`.
+//! This is a regression test for <https://github.com/rust-lang/rust/issues/137750>:
+//! `UnsafePinned` must include the effects of `UnsafeCell`.
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
+//@normalize-stderr-test: "\[0x[a-fx\d.]+\]" -> "[OFFSET]"
+
+use core::future::Future;
+use core::pin::{Pin, pin};
+use core::task::{Context, Poll, Waker};
+
+fn main() {
+    let mut f = pin!(async move {
+        let x = &mut 0u8;
+        core::future::poll_fn(move |_| {
+            *x = 1; //~ERROR: write access
+            Poll::<()>::Pending
+        })
+        .await
+    });
+    let mut cx = Context::from_waker(&Waker::noop());
+    assert_eq!(f.as_mut().poll(&mut cx), Poll::Pending);
+    let _: Pin<&_> = f.as_ref(); // Or: `f.as_mut().into_ref()`.
+    assert_eq!(f.as_mut().poll(&mut cx), Poll::Pending);
+}
diff --git a/src/tools/miri/tests/fail/async-shared-mutable.stack.stderr b/src/tools/miri/tests/fail/async-shared-mutable.stack.stderr
new file mode 100644
index 00000000000..8f53a55cc3e
--- /dev/null
+++ b/src/tools/miri/tests/fail/async-shared-mutable.stack.stderr
@@ -0,0 +1,43 @@
+error: Undefined Behavior: attempting a write access using <TAG> at ALLOC[OFFSET], but that tag does not exist in the borrow stack for this location
+  --> tests/fail/async-shared-mutable.rs:LL:CC
+   |
+LL |             *x = 1;
+   |             ^^^^^^
+   |             |
+   |             attempting a write access using <TAG> at ALLOC[OFFSET], but that tag does not exist in the borrow stack for this location
+   |             this error occurs as part of an access at ALLOC[OFFSET]
+   |
+   = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
+   = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
+help: <TAG> was created by a Unique retag at offsets [OFFSET]
+  --> tests/fail/async-shared-mutable.rs:LL:CC
+   |
+LL | /         core::future::poll_fn(move |_| {
+LL | |             *x = 1;
+LL | |             Poll::<()>::Pending
+LL | |         })
+LL | |         .await
+   | |______________^
+help: <TAG> was later invalidated at offsets [OFFSET] by a SharedReadOnly retag
+  --> tests/fail/async-shared-mutable.rs:LL:CC
+   |
+LL |     let _: Pin<&_> = f.as_ref(); // Or: `f.as_mut().into_ref()`.
+   |                      ^^^^^^^^^^
+   = note: BACKTRACE (of the first span):
+   = note: inside closure at tests/fail/async-shared-mutable.rs:LL:CC
+   = note: inside `<std::future::PollFn<{closure@tests/fail/async-shared-mutable.rs:LL:CC}> as std::future::Future>::poll` at RUSTLIB/core/src/future/poll_fn.rs:LL:CC
+note: inside closure
+  --> tests/fail/async-shared-mutable.rs:LL:CC
+   |
+LL |         .await
+   |          ^^^^^
+note: inside `main`
+  --> tests/fail/async-shared-mutable.rs:LL:CC
+   |
+LL |     assert_eq!(f.as_mut().poll(&mut cx), Poll::Pending);
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr b/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr
new file mode 100644
index 00000000000..d1e66a0d043
--- /dev/null
+++ b/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr
@@ -0,0 +1,47 @@
+error: Undefined Behavior: write access through <TAG> at ALLOC[OFFSET] is forbidden
+  --> tests/fail/async-shared-mutable.rs:LL:CC
+   |
+LL |             *x = 1;
+   |             ^^^^^^ write access through <TAG> at ALLOC[OFFSET] is forbidden
+   |
+   = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
+   = help: the accessed tag <TAG> has state Frozen which forbids this child write access
+help: the accessed tag <TAG> was created here, in the initial state Reserved
+  --> tests/fail/async-shared-mutable.rs:LL:CC
+   |
+LL | /         core::future::poll_fn(move |_| {
+LL | |             *x = 1;
+LL | |             Poll::<()>::Pending
+LL | |         })
+LL | |         .await
+   | |______________^
+help: the accessed tag <TAG> later transitioned to Active due to a child write access at offsets [OFFSET]
+  --> tests/fail/async-shared-mutable.rs:LL:CC
+   |
+LL |             *x = 1;
+   |             ^^^^^^
+   = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference
+help: the accessed tag <TAG> later transitioned to Frozen due to a reborrow (acting as a foreign read access) at offsets [OFFSET]
+  --> tests/fail/async-shared-mutable.rs:LL:CC
+   |
+LL |     let _: Pin<&_> = f.as_ref(); // Or: `f.as_mut().into_ref()`.
+   |                      ^^^^^^^^^^
+   = help: this transition corresponds to a loss of write permissions
+   = note: BACKTRACE (of the first span):
+   = note: inside closure at tests/fail/async-shared-mutable.rs:LL:CC
+   = note: inside `<std::future::PollFn<{closure@tests/fail/async-shared-mutable.rs:LL:CC}> as std::future::Future>::poll` at RUSTLIB/core/src/future/poll_fn.rs:LL:CC
+note: inside closure
+  --> tests/fail/async-shared-mutable.rs:LL:CC
+   |
+LL |         .await
+   |          ^^^^^
+note: inside `main`
+  --> tests/fail/async-shared-mutable.rs:LL:CC
+   |
+LL |     assert_eq!(f.as_mut().poll(&mut cx), Poll::Pending);
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/concurrency/read_only_atomic_load_large.rs b/src/tools/miri/tests/fail/concurrency/read_only_atomic_load_large.rs
index 42c3a9619d4..2c01b0132b8 100644
--- a/src/tools/miri/tests/fail/concurrency/read_only_atomic_load_large.rs
+++ b/src/tools/miri/tests/fail/concurrency/read_only_atomic_load_large.rs
@@ -2,6 +2,7 @@
 //@compile-flags: -Zmiri-disable-stacked-borrows
 // Needs atomic accesses larger than the pointer size
 //@ignore-bitwidth: 64
+//@ignore-target: mips-
 
 use std::sync::atomic::{AtomicI64, Ordering};
 
diff --git a/src/tools/miri/tests/fail/const-ub-checks.rs b/src/tools/miri/tests/fail/const-ub-checks.rs
index 9cc8b91ff50..004bbe9f5ea 100644
--- a/src/tools/miri/tests/fail/const-ub-checks.rs
+++ b/src/tools/miri/tests/fail/const-ub-checks.rs
@@ -1,7 +1,7 @@
 const UNALIGNED_READ: () = unsafe {
     let x = &[0u8; 4];
     let ptr = x.as_ptr().cast::<u32>();
-    ptr.read(); //~ERROR: evaluation of constant value failed
+    ptr.read(); //~ERROR: accessing memory based on pointer with alignment 1, but alignment 4 is required
 };
 
 fn main() {
diff --git a/src/tools/miri/tests/fail/const-ub-checks.stderr b/src/tools/miri/tests/fail/const-ub-checks.stderr
index e6b302dd28c..df2d5653d2d 100644
--- a/src/tools/miri/tests/fail/const-ub-checks.stderr
+++ b/src/tools/miri/tests/fail/const-ub-checks.stderr
@@ -1,8 +1,8 @@
-error[E0080]: evaluation of constant value failed
+error[E0080]: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required
   --> tests/fail/const-ub-checks.rs:LL:CC
    |
 LL |     ptr.read();
-   |     ^^^^^^^^^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required
+   |     ^^^^^^^^^^ evaluation of `UNALIGNED_READ` failed here
 
 note: erroneous constant encountered
   --> tests/fail/const-ub-checks.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/data_race/stack_pop_race.rs b/src/tools/miri/tests/fail/data_race/stack_pop_race.rs
index 5138bcbf8f7..e7632d43126 100644
--- a/src/tools/miri/tests/fail/data_race/stack_pop_race.rs
+++ b/src/tools/miri/tests/fail/data_race/stack_pop_race.rs
@@ -8,7 +8,7 @@ struct MakeSend(*const i32);
 unsafe impl Send for MakeSend {}
 
 fn main() {
-    race(0);
+    race(0); //~ERROR: Data race detected between (1) non-atomic read on thread `unnamed-1` and (2) deallocation on thread `main`
 }
 
 // Using an argument for the ptr to point to, since those do not get StorageDead.
@@ -22,5 +22,4 @@ fn race(local: i32) {
     thread::yield_now();
     // Deallocating the local (when `main` returns)
     // races with the read in the other thread.
-    // Make sure the error points at this function's end, not just the call site.
-} //~ERROR: Data race detected between (1) non-atomic read on thread `unnamed-1` and (2) deallocation on thread `main`
+}
diff --git a/src/tools/miri/tests/fail/data_race/stack_pop_race.stderr b/src/tools/miri/tests/fail/data_race/stack_pop_race.stderr
index 643426aba99..721b7563044 100644
--- a/src/tools/miri/tests/fail/data_race/stack_pop_race.stderr
+++ b/src/tools/miri/tests/fail/data_race/stack_pop_race.stderr
@@ -1,8 +1,8 @@
 error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) deallocation on thread `main` at ALLOC. (2) just happened here
   --> tests/fail/data_race/stack_pop_race.rs:LL:CC
    |
-LL | }
-   |  ^ Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) deallocation on thread `main` at ALLOC. (2) just happened here
+LL |     race(0);
+   |     ^^^^^^^ Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) deallocation on thread `main` at ALLOC. (2) just happened here
    |
 help: and (1) occurred earlier here
   --> tests/fail/data_race/stack_pop_race.rs:LL:CC
@@ -12,12 +12,7 @@ LL |         let _val = unsafe { *ptr.0 };
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE (of the first span):
-   = note: inside `race` at tests/fail/data_race/stack_pop_race.rs:LL:CC
-note: inside `main`
-  --> tests/fail/data_race/stack_pop_race.rs:LL:CC
-   |
-LL |     race(0);
-   |     ^^^^^^^
+   = note: inside `main` at tests/fail/data_race/stack_pop_race.rs:LL:CC
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
diff --git a/src/tools/miri/tests/fail/erroneous_const.rs b/src/tools/miri/tests/fail/erroneous_const.rs
index 65f7aafc3cc..6e126ed701f 100644
--- a/src/tools/miri/tests/fail/erroneous_const.rs
+++ b/src/tools/miri/tests/fail/erroneous_const.rs
@@ -4,7 +4,7 @@
 
 struct PrintName<T>(T);
 impl<T> PrintName<T> {
-    const VOID: ! = panic!(); //~ERROR: evaluation of `PrintName::<i32>::VOID` failed
+    const VOID: ! = panic!(); //~ERROR: explicit panic
 }
 
 fn no_codegen<T>() {
diff --git a/src/tools/miri/tests/fail/erroneous_const.stderr b/src/tools/miri/tests/fail/erroneous_const.stderr
index 6f1e3529ccc..1aa87dd7188 100644
--- a/src/tools/miri/tests/fail/erroneous_const.stderr
+++ b/src/tools/miri/tests/fail/erroneous_const.stderr
@@ -1,8 +1,8 @@
-error[E0080]: evaluation of `PrintName::<i32>::VOID` failed
+error[E0080]: evaluation panicked: explicit panic
   --> tests/fail/erroneous_const.rs:LL:CC
    |
 LL |     const VOID: ! = panic!();
-   |                     ^^^^^^^^ evaluation panicked: explicit panic
+   |                     ^^^^^^^^ evaluation of `PrintName::<i32>::VOID` failed here
 
 note: erroneous constant encountered
   --> tests/fail/erroneous_const.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/erroneous_const2.rs b/src/tools/miri/tests/fail/erroneous_const2.rs
index 9a1a970778f..ea98b64ad81 100644
--- a/src/tools/miri/tests/fail/erroneous_const2.rs
+++ b/src/tools/miri/tests/fail/erroneous_const2.rs
@@ -1,7 +1,7 @@
 const X: u32 = 5;
 const Y: u32 = 6;
 const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
-//~^ERROR: evaluation of constant value failed
+//~^ERROR: overflow
 
 #[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/5391
 fn main() {
diff --git a/src/tools/miri/tests/fail/erroneous_const2.stderr b/src/tools/miri/tests/fail/erroneous_const2.stderr
index 76f8cbcd289..08d2cc124f1 100644
--- a/src/tools/miri/tests/fail/erroneous_const2.stderr
+++ b/src/tools/miri/tests/fail/erroneous_const2.stderr
@@ -1,8 +1,8 @@
-error[E0080]: evaluation of constant value failed
+error[E0080]: attempt to compute `5_u32 - 6_u32`, which would overflow
   --> tests/fail/erroneous_const2.rs:LL:CC
    |
 LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
-   |                   ^^^^^ attempt to compute `5_u32 - 6_u32`, which would overflow
+   |                   ^^^^^ evaluation of `FOO` failed here
 
 note: erroneous constant encountered
   --> tests/fail/erroneous_const2.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/intrinsics/copy_overlapping.rs b/src/tools/miri/tests/fail/intrinsics/copy_overlapping.rs
index e6282613df7..ff16ac61d8b 100644
--- a/src/tools/miri/tests/fail/intrinsics/copy_overlapping.rs
+++ b/src/tools/miri/tests/fail/intrinsics/copy_overlapping.rs
@@ -1,14 +1,11 @@
-#![feature(intrinsics)]
-
-// Directly call intrinsic to avoid debug assertions in libstd
-#[rustc_intrinsic]
-unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
+#![feature(core_intrinsics)]
 
 fn main() {
     let mut data = [0u8; 16];
     unsafe {
         let a = data.as_mut_ptr();
         let b = a.wrapping_offset(1) as *mut _;
-        copy_nonoverlapping(a, b, 2); //~ ERROR: `copy_nonoverlapping` called on overlapping ranges
+        // Directly call intrinsic to avoid debug assertions in the `std::ptr` version.
+        std::intrinsics::copy_nonoverlapping(a, b, 2); //~ ERROR: `copy_nonoverlapping` called on overlapping ranges
     }
 }
diff --git a/src/tools/miri/tests/fail/intrinsics/copy_overlapping.stderr b/src/tools/miri/tests/fail/intrinsics/copy_overlapping.stderr
index fef5a0a82a0..9b60a48703b 100644
--- a/src/tools/miri/tests/fail/intrinsics/copy_overlapping.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/copy_overlapping.stderr
@@ -1,8 +1,8 @@
 error: Undefined Behavior: `copy_nonoverlapping` called on overlapping ranges
   --> tests/fail/intrinsics/copy_overlapping.rs:LL:CC
    |
-LL |         copy_nonoverlapping(a, b, 2);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `copy_nonoverlapping` called on overlapping ranges
+LL |         std::intrinsics::copy_nonoverlapping(a, b, 2);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `copy_nonoverlapping` called on overlapping ranges
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/copy_unaligned.rs b/src/tools/miri/tests/fail/intrinsics/copy_unaligned.rs
index ded9d0b669e..311789cdc4b 100644
--- a/src/tools/miri/tests/fail/intrinsics/copy_unaligned.rs
+++ b/src/tools/miri/tests/fail/intrinsics/copy_unaligned.rs
@@ -1,14 +1,11 @@
-#![feature(intrinsics)]
-
-// Directly call intrinsic to avoid debug assertions in libstd
-#[rustc_intrinsic]
-unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
+#![feature(core_intrinsics)]
 
 fn main() {
     let mut data = [0u16; 8];
     let ptr = (&mut data[0] as *mut u16 as *mut u8).wrapping_add(1) as *mut u16;
     // Even copying 0 elements to something unaligned should error
     unsafe {
-        copy_nonoverlapping(&data[5], ptr, 0); //~ ERROR: accessing memory with alignment 1, but alignment 2 is required
+        // Directly call intrinsic to avoid debug assertions in the `std::ptr` version.
+        std::intrinsics::copy_nonoverlapping(&data[5], ptr, 0); //~ ERROR: accessing memory with alignment 1, but alignment 2 is required
     }
 }
diff --git a/src/tools/miri/tests/fail/intrinsics/copy_unaligned.stderr b/src/tools/miri/tests/fail/intrinsics/copy_unaligned.stderr
index 2d0edd4e6cb..65dbdb3bbb6 100644
--- a/src/tools/miri/tests/fail/intrinsics/copy_unaligned.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/copy_unaligned.stderr
@@ -1,8 +1,8 @@
 error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required
   --> tests/fail/intrinsics/copy_unaligned.rs:LL:CC
    |
-LL |         copy_nonoverlapping(&data[5], ptr, 0);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required
+LL |         std::intrinsics::copy_nonoverlapping(&data[5], ptr, 0);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/panic/bad_unwind.stderr b/src/tools/miri/tests/fail/panic/bad_unwind.stderr
index 6ba39e8f7e2..8c269eae62a 100644
--- a/src/tools/miri/tests/fail/panic/bad_unwind.stderr
+++ b/src/tools/miri/tests/fail/panic/bad_unwind.stderr
@@ -13,8 +13,8 @@ LL |     std::panic::catch_unwind(|| unwind()).unwrap_err();
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE:
    = note: inside closure at tests/fail/panic/bad_unwind.rs:LL:CC
-   = note: inside `std::panicking::r#try::do_call::<{closure@tests/fail/panic/bad_unwind.rs:LL:CC}, ()>` at RUSTLIB/std/src/panicking.rs:LL:CC
-   = note: inside `std::panicking::r#try::<(), {closure@tests/fail/panic/bad_unwind.rs:LL:CC}>` at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside `std::panicking::catch_unwind::do_call::<{closure@tests/fail/panic/bad_unwind.rs:LL:CC}, ()>` at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside `std::panicking::catch_unwind::<(), {closure@tests/fail/panic/bad_unwind.rs:LL:CC}>` at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside `std::panic::catch_unwind::<{closure@tests/fail/panic/bad_unwind.rs:LL:CC}, ()>` at RUSTLIB/std/src/panic.rs:LL:CC
 note: inside `main`
   --> tests/fail/panic/bad_unwind.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr
index f57487e3ffe..b4dadeecaa8 100644
--- a/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr
+++ b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr
@@ -1,5 +1,5 @@
 
-thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC:
+thread 'main' panicked at tests/fail/ptr_swap_nonoverlapping.rs:LL:CC:
 unsafe precondition(s) violated: ptr::swap_nonoverlapping requires that both pointer arguments are aligned and non-null and the specified memory ranges do not overlap
 
 This indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety.
@@ -18,9 +18,6 @@ LL | ABORT()
    = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC
    = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
    = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC
-   = note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC
-   = note: inside `std::ptr::swap_nonoverlapping::precondition_check` at RUSTLIB/core/src/ub_checks.rs:LL:CC
-   = note: inside `std::ptr::swap_nonoverlapping::<usize>` at RUSTLIB/core/src/ub_checks.rs:LL:CC
 note: inside `main`
   --> tests/fail/ptr_swap_nonoverlapping.rs:LL:CC
    |
diff --git a/src/tools/miri/tests/fail/shims/isolated_stdin.rs b/src/tools/miri/tests/fail/shims/isolated_stdin.rs
new file mode 100644
index 00000000000..9f809039ada
--- /dev/null
+++ b/src/tools/miri/tests/fail/shims/isolated_stdin.rs
@@ -0,0 +1,12 @@
+//@error-in-other-file: `read` from stdin not available when isolation is enabled
+//@normalize-stderr-test: "src/sys/.*\.rs" -> "$$FILE"
+//@normalize-stderr-test: "\nLL \| .*" -> ""
+//@normalize-stderr-test: "\n... .*" -> ""
+//@normalize-stderr-test: "\| +[|_^]+" -> "| ^"
+//@normalize-stderr-test: "\n *= note:.*" -> ""
+use std::io::{self, Read};
+
+fn main() {
+    let mut bytes = [0u8; 512];
+    io::stdin().read(&mut bytes).unwrap();
+}
diff --git a/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.stderr b/src/tools/miri/tests/fail/shims/isolated_stdin.stderr
index bb7e8cef5dc..1a4d7e96329 100644
--- a/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.stderr
+++ b/src/tools/miri/tests/fail/shims/isolated_stdin.stderr
@@ -1,13 +1,14 @@
 error: unsupported operation: `read` from stdin not available when isolation is enabled
-  --> tests/fail-dep/libc/fs/isolated_stdin.rs:LL:CC
+  --> RUSTLIB/std/$FILE:LL:CC
    |
-LL |         libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `read` from stdin not available when isolation is enabled
+   | ^ `read` from stdin not available when isolation is enabled
    |
    = help: set `MIRIFLAGS=-Zmiri-disable-isolation` to disable isolation;
    = help: or set `MIRIFLAGS=-Zmiri-isolation-error=warn` to make Miri return an error code from isolated operations (if supported for that operation) and continue with a warning
-   = note: BACKTRACE:
-   = note: inside `main` at tests/fail-dep/libc/fs/isolated_stdin.rs:LL:CC
+note: inside `main`
+  --> tests/fail/shims/isolated_stdin.rs:LL:CC
+   |
+   | ^
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
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 61ddea64472..589e30d632e 100644
--- a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr
+++ b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr
@@ -11,12 +11,12 @@ LL |     extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
    = note: inside `std::sys::backtrace::__rust_begin_short_backtrace::<fn(), ()>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
    = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC
    = note: inside `std::ops::function::impls::<impl std::ops::FnOnce<()> for &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>::call_once` at RUSTLIB/core/src/ops/function.rs:LL:CC
-   = note: inside `std::panicking::r#try::do_call::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at RUSTLIB/std/src/panicking.rs:LL:CC
-   = 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::panicking::catch_unwind::do_call::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside `std::panicking::catch_unwind::<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#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::panicking::catch_unwind::do_call::<{closure@std::rt::lang_start_internal::{closure#0}}, isize>` at RUSTLIB/std/src/panicking.rs:LL:CC
+   = note: inside `std::panicking::catch_unwind::<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/fail/tail_calls/dangling-local-var.stderr b/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr
index 33e1e53ea06..15f73c8a9ae 100644
--- a/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr
+++ b/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr
@@ -14,8 +14,8 @@ LL |     let local = 0;
 help: ALLOC was deallocated here:
   --> tests/fail/tail_calls/dangling-local-var.rs:LL:CC
    |
-LL |     become g(ptr)
-   |     ^^^^^^^^^^^^^
+LL |     f(std::ptr::null());
+   |     ^^^^^^^^^^^^^^^^^^^
    = note: BACKTRACE (of the first span):
    = note: inside `g` at tests/fail/tail_calls/dangling-local-var.rs:LL:CC
 note: inside `main`
diff --git a/src/tools/miri/tests/fail/tree_borrows/cell-inside-struct.rs b/src/tools/miri/tests/fail/tree_borrows/cell-inside-struct.rs
new file mode 100644
index 00000000000..ff797877682
--- /dev/null
+++ b/src/tools/miri/tests/fail/tree_borrows/cell-inside-struct.rs
@@ -0,0 +1,33 @@
+//! A version of `cell_inside_struct` that dumps the tree so that we can see what is happening.
+//@compile-flags: -Zmiri-tree-borrows
+#[path = "../../utils/mod.rs"]
+#[macro_use]
+mod utils;
+
+use std::cell::Cell;
+
+struct Foo {
+    field1: u32,
+    field2: Cell<u32>,
+}
+
+pub fn main() {
+    let root = Foo { field1: 42, field2: Cell::new(88) };
+    unsafe {
+        let a = &root;
+
+        name!(a as *const Foo, "a");
+
+        let a: *const Foo = a as *const Foo;
+        let a: *mut Foo = a as *mut Foo;
+
+        let alloc_id = alloc_id!(a);
+        print_state!(alloc_id);
+
+        // Writing to `field2`, which is interior mutable, should be allowed.
+        (*a).field2.set(10);
+
+        // Writing to `field1`, which is frozen, should not be allowed.
+        (*a).field1 = 88; //~ ERROR: /write access through .* is forbidden/
+    }
+}
diff --git a/src/tools/miri/tests/fail/tree_borrows/cell-inside-struct.stderr b/src/tools/miri/tests/fail/tree_borrows/cell-inside-struct.stderr
new file mode 100644
index 00000000000..717f1419452
--- /dev/null
+++ b/src/tools/miri/tests/fail/tree_borrows/cell-inside-struct.stderr
@@ -0,0 +1,26 @@
+──────────────────────────────────────────────────
+Warning: this tree is indicative only. Some tags may have been hidden.
+0..   4..   8
+| Act | Act |    └─┬──<TAG=root of the allocation>
+| Frz |?Cel |      └────<TAG=a>
+──────────────────────────────────────────────────
+error: Undefined Behavior: write access through <TAG> (a) at ALLOC[0x0] is forbidden
+  --> tests/fail/tree_borrows/cell-inside-struct.rs:LL:CC
+   |
+LL |         (*a).field1 = 88;
+   |         ^^^^^^^^^^^^^^^^ write access through <TAG> (a) at ALLOC[0x0] is forbidden
+   |
+   = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
+   = help: the accessed tag <TAG> (a) has state Frozen which forbids this child write access
+help: the accessed tag <TAG> was created here, in the initial state Cell
+  --> tests/fail/tree_borrows/cell-inside-struct.rs:LL:CC
+   |
+LL |         let a = &root;
+   |                 ^^^^^
+   = note: BACKTRACE (of the first span):
+   = note: inside `main` at tests/fail/tree_borrows/cell-inside-struct.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/unaligned_pointers/atomic_unaligned.rs b/src/tools/miri/tests/fail/unaligned_pointers/atomic_unaligned.rs
index 29976836b0b..37c64c81944 100644
--- a/src/tools/miri/tests/fail/unaligned_pointers/atomic_unaligned.rs
+++ b/src/tools/miri/tests/fail/unaligned_pointers/atomic_unaligned.rs
@@ -1,5 +1,6 @@
 //@compile-flags: -Zmiri-symbolic-alignment-check -Cdebug-assertions=no
 #![feature(core_intrinsics)]
+use std::intrinsics;
 
 fn main() {
     // Do a 4-aligned u64 atomic access. That should be UB on all platforms,
@@ -7,7 +8,7 @@ fn main() {
     let z = [0u32; 2];
     let zptr = &z as *const _ as *const u64;
     unsafe {
-        ::std::intrinsics::atomic_load_seqcst(zptr);
+        intrinsics::atomic_load::<_, { intrinsics::AtomicOrdering::SeqCst }>(zptr);
         //~^ERROR: accessing memory with alignment 4, but alignment 8 is required
     }
 }
diff --git a/src/tools/miri/tests/fail/unaligned_pointers/atomic_unaligned.stderr b/src/tools/miri/tests/fail/unaligned_pointers/atomic_unaligned.stderr
index a9da740be1d..e0f9d011ce4 100644
--- a/src/tools/miri/tests/fail/unaligned_pointers/atomic_unaligned.stderr
+++ b/src/tools/miri/tests/fail/unaligned_pointers/atomic_unaligned.stderr
@@ -1,8 +1,8 @@
 error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required
   --> tests/fail/unaligned_pointers/atomic_unaligned.rs:LL:CC
    |
-LL |         ::std::intrinsics::atomic_load_seqcst(zptr);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required
+LL |         intrinsics::atomic_load::<_, { intrinsics::AtomicOrdering::SeqCst }>(zptr);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required
    |
    = help: this usually indicates that your program performed an invalid operation and caused Undefined Behavior
    = help: but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives
diff --git a/src/tools/miri/tests/fail/unsupported_foreign_function.stderr b/src/tools/miri/tests/fail/unsupported_foreign_function.stderr
index 4fe45b0868a..bbfc5c31256 100644
--- a/src/tools/miri/tests/fail/unsupported_foreign_function.stderr
+++ b/src/tools/miri/tests/fail/unsupported_foreign_function.stderr
@@ -4,8 +4,7 @@ error: unsupported operation: can't call foreign function `foo` on $OS
 LL |         foo();
    |         ^^^^^ can't call foreign function `foo` on $OS
    |
-   = help: if this is a basic API commonly used on this target, please report an issue with Miri
-   = help: however, note that Miri does not aim to support every FFI function out there; for instance, we will not support APIs for things such as GUIs, scripting languages, or databases
+   = help: this means the program tried to do something Miri does not support; it does not indicate a bug in the program
    = note: BACKTRACE:
    = note: inside `main` at tests/fail/unsupported_foreign_function.rs:LL:CC
 
diff --git a/src/tools/miri/tests/many-seeds/reentrant-lock.rs b/src/tools/miri/tests/many-seeds/reentrant-lock.rs
index 8a363179a9c..4c2dc463f48 100644
--- a/src/tools/miri/tests/many-seeds/reentrant-lock.rs
+++ b/src/tools/miri/tests/many-seeds/reentrant-lock.rs
@@ -1,6 +1,6 @@
 #![feature(reentrant_lock)]
 //! This is a regression test for
-//! <https://rust-lang.zulipchat.com/#narrow/channel/269128-miri/topic/reentrant.20lock.20failure.20on.20musl>.
+//! <https://rust-lang.zulipchat.com/#narrow/channel/269128-miri/topic/reentrant.20lock.20failure.20on.20mips>.
 
 use std::cell::Cell;
 use std::sync::ReentrantLock;
diff --git a/src/tools/miri/tests/native-lib/fail/function_not_in_so.stderr b/src/tools/miri/tests/native-lib/fail/function_not_in_so.stderr
index bf1cfd573b8..b663fd41457 100644
--- a/src/tools/miri/tests/native-lib/fail/function_not_in_so.stderr
+++ b/src/tools/miri/tests/native-lib/fail/function_not_in_so.stderr
@@ -4,8 +4,7 @@ error: unsupported operation: can't call foreign function `foo` on $OS
 LL |         foo();
    |         ^^^^^ can't call foreign function `foo` on $OS
    |
-   = help: if this is a basic API commonly used on this target, please report an issue with Miri
-   = help: however, note that Miri does not aim to support every FFI function out there; for instance, we will not support APIs for things such as GUIs, scripting languages, or databases
+   = help: this means the program tried to do something Miri does not support; it does not indicate a bug in the program
    = note: BACKTRACE:
    = note: inside `main` at tests/native-lib/fail/function_not_in_so.rs:LL:CC
 
diff --git a/src/tools/miri/tests/native-lib/fail/private_function.stderr b/src/tools/miri/tests/native-lib/fail/private_function.stderr
index 2cfc062212b..03681240015 100644
--- a/src/tools/miri/tests/native-lib/fail/private_function.stderr
+++ b/src/tools/miri/tests/native-lib/fail/private_function.stderr
@@ -4,8 +4,7 @@ error: unsupported operation: can't call foreign function `not_exported` on $OS
 LL |         not_exported();
    |         ^^^^^^^^^^^^^^ can't call foreign function `not_exported` on $OS
    |
-   = help: if this is a basic API commonly used on this target, please report an issue with Miri
-   = help: however, note that Miri does not aim to support every FFI function out there; for instance, we will not support APIs for things such as GUIs, scripting languages, or databases
+   = help: this means the program tried to do something Miri does not support; it does not indicate a bug in the program
    = note: BACKTRACE:
    = note: inside `main` at tests/native-lib/fail/private_function.rs:LL:CC
 
diff --git a/src/tools/miri/tests/panic/transmute_fat2.rs b/src/tools/miri/tests/panic/transmute_fat2.rs
index 0205433ad9f..e695ff2d57b 100644
--- a/src/tools/miri/tests/panic/transmute_fat2.rs
+++ b/src/tools/miri/tests/panic/transmute_fat2.rs
@@ -5,6 +5,8 @@ fn main() {
     let bad = unsafe { std::mem::transmute::<u128, &[u8]>(42 << 64) };
     #[cfg(all(target_endian = "little", target_pointer_width = "32"))]
     let bad = unsafe { std::mem::transmute::<u64, &[u8]>(42) };
+    #[cfg(all(target_endian = "big", target_pointer_width = "32"))]
+    let bad = unsafe { std::mem::transmute::<u64, &[u8]>(42 << 32) };
     // This created a slice with length 0, so the following will fail the bounds check.
     bad[0];
 }
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.rs
index cffcf4a867f..06a8cc7f487 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.rs
@@ -11,6 +11,10 @@ fn main() {
         assert!(libc::fcntl(1, libc::F_DUPFD, 0) >= 0);
     }
 
+    // Although `readlink` and `stat` require disable-isolation mode
+    // to properly run, they are tested with isolation mode on to check the error emitted
+    // with `-Zmiri-isolation-error=warn-nobacktrace`.
+
     // test `readlink`
     let mut buf = vec![0; "foo_link.txt".len() + 1];
     unsafe {
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs b/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs
index 05f6c870c3d..bc755af864c 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs
@@ -15,6 +15,8 @@ fn main() {
     ))]
     // `pipe2` only exists in some specific os.
     test_pipe2();
+    test_pipe_setfl_getfl();
+    test_pipe_fcntl_threaded();
 }
 
 fn test_pipe() {
@@ -127,3 +129,68 @@ fn test_pipe2() {
     let res = unsafe { libc::pipe2(fds.as_mut_ptr(), libc::O_NONBLOCK) };
     assert_eq!(res, 0);
 }
+
+/// Basic test for pipe fcntl's F_SETFL and F_GETFL flag.
+fn test_pipe_setfl_getfl() {
+    // Initialise pipe fds.
+    let mut fds = [-1, -1];
+    let res = unsafe { libc::pipe(fds.as_mut_ptr()) };
+    assert_eq!(res, 0);
+
+    // Both sides should either have O_RONLY or O_WRONLY.
+    let res = unsafe { libc::fcntl(fds[0], libc::F_GETFL) };
+    assert_eq!(res, libc::O_RDONLY);
+    let res = unsafe { libc::fcntl(fds[1], libc::F_GETFL) };
+    assert_eq!(res, libc::O_WRONLY);
+
+    // Add the O_NONBLOCK flag with F_SETFL.
+    let res = unsafe { libc::fcntl(fds[0], libc::F_SETFL, libc::O_NONBLOCK) };
+    assert_eq!(res, 0);
+
+    // Test if the O_NONBLOCK flag is successfully added.
+    let res = unsafe { libc::fcntl(fds[0], libc::F_GETFL) };
+    assert_eq!(res, libc::O_RDONLY | libc::O_NONBLOCK);
+
+    // The other side remains unchanged.
+    let res = unsafe { libc::fcntl(fds[1], libc::F_GETFL) };
+    assert_eq!(res, libc::O_WRONLY);
+
+    // Test if O_NONBLOCK flag can be unset.
+    let res = unsafe { libc::fcntl(fds[0], libc::F_SETFL, 0) };
+    assert_eq!(res, 0);
+    let res = unsafe { libc::fcntl(fds[0], libc::F_GETFL) };
+    assert_eq!(res, libc::O_RDONLY);
+}
+
+/// Test the behaviour of F_SETFL/F_GETFL when a fd is blocking.
+/// The expected execution is:
+/// 1. Main thread blocks on fds[0] `read`.
+/// 2. Thread 1 sets O_NONBLOCK flag on fds[0],
+///    checks the value of F_GETFL,
+///    then writes to fds[1] to unblock main thread's `read`.
+fn test_pipe_fcntl_threaded() {
+    let mut fds = [-1, -1];
+    let res = unsafe { libc::pipe(fds.as_mut_ptr()) };
+    assert_eq!(res, 0);
+    let mut buf: [u8; 5] = [0; 5];
+    let thread1 = thread::spawn(move || {
+        // Add O_NONBLOCK flag while pipe is still blocked on read.
+        let res = unsafe { libc::fcntl(fds[0], libc::F_SETFL, libc::O_NONBLOCK) };
+        assert_eq!(res, 0);
+
+        // Check the new flag value while the main thread is still blocked on fds[0].
+        let res = unsafe { libc::fcntl(fds[0], libc::F_GETFL) };
+        assert_eq!(res, libc::O_NONBLOCK);
+
+        // The write below will unblock the `read` in main thread: even though
+        // the socket is now "non-blocking", the shim needs to deal correctly
+        // with threads that were blocked before the socket was made non-blocking.
+        let data = "abcde".as_bytes().as_ptr();
+        let res = unsafe { libc::write(fds[1], data as *const libc::c_void, 5) };
+        assert_eq!(res, 5);
+    });
+    // The `read` below will block.
+    let res = unsafe { libc::read(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
+    thread1.join().unwrap();
+    assert_eq!(res, 5);
+}
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs b/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs
index 9e48410f704..c36f6b11224 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs
@@ -12,6 +12,7 @@ fn main() {
     test_race();
     test_blocking_read();
     test_blocking_write();
+    test_socketpair_setfl_getfl();
 }
 
 fn test_socketpair() {
@@ -182,3 +183,35 @@ fn test_blocking_write() {
     thread1.join().unwrap();
     thread2.join().unwrap();
 }
+
+/// Basic test for socketpair fcntl's F_SETFL and F_GETFL flag.
+fn test_socketpair_setfl_getfl() {
+    // Initialise socketpair fds.
+    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);
+
+    // Test if both sides have O_RDWR.
+    let res = unsafe { libc::fcntl(fds[0], libc::F_GETFL) };
+    assert_eq!(res, libc::O_RDWR);
+    let res = unsafe { libc::fcntl(fds[1], libc::F_GETFL) };
+    assert_eq!(res, libc::O_RDWR);
+
+    // Add the O_NONBLOCK flag with F_SETFL.
+    let res = unsafe { libc::fcntl(fds[0], libc::F_SETFL, libc::O_NONBLOCK) };
+    assert_eq!(res, 0);
+
+    // Test if the O_NONBLOCK flag is successfully added.
+    let res = unsafe { libc::fcntl(fds[0], libc::F_GETFL) };
+    assert_eq!(res, libc::O_RDWR | libc::O_NONBLOCK);
+
+    // The other side remains unchanged.
+    let res = unsafe { libc::fcntl(fds[1], libc::F_GETFL) };
+    assert_eq!(res, libc::O_RDWR);
+
+    // Test if O_NONBLOCK flag can be unset.
+    let res = unsafe { libc::fcntl(fds[0], libc::F_SETFL, 0) };
+    assert_eq!(res, 0);
+    let res = unsafe { libc::fcntl(fds[0], libc::F_GETFL) };
+    assert_eq!(res, libc::O_RDWR);
+}
diff --git a/src/tools/miri/tests/pass-dep/shims/freebsd-cpuset-affinity.rs b/src/tools/miri/tests/pass-dep/shims/freebsd-cpuset-affinity.rs
new file mode 100644
index 00000000000..9a868128d27
--- /dev/null
+++ b/src/tools/miri/tests/pass-dep/shims/freebsd-cpuset-affinity.rs
@@ -0,0 +1,51 @@
+//@only-target: freebsd
+//@compile-flags: -Zmiri-num-cpus=256
+
+use std::mem;
+
+fn getaffinity() {
+    let mut set: libc::cpuset_t = unsafe { mem::zeroed() };
+    unsafe {
+        if libc::cpuset_getaffinity(
+            libc::CPU_LEVEL_WHICH,
+            libc::CPU_WHICH_PID,
+            -1,
+            size_of::<libc::cpuset_t>(),
+            &mut set,
+        ) == 0
+        {
+            assert!(libc::CPU_COUNT(&set) == 256);
+        }
+    }
+}
+
+fn get_small_cpu_mask() {
+    let mut set: libc::cpuset_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() };
+
+    // 256 CPUs so we need 32 bytes to represent this mask.
+    // According to Freebsd only when `cpusetsize` is smaller than this value, does it return with ERANGE
+
+    let err = unsafe {
+        libc::cpuset_getaffinity(libc::CPU_LEVEL_WHICH, libc::CPU_WHICH_PID, -1, 32, &mut set)
+    };
+    assert_eq!(err, 0, "Success Expected");
+
+    // 31 is not enough, so it should fail.
+    let err = unsafe {
+        libc::cpuset_getaffinity(libc::CPU_LEVEL_WHICH, libc::CPU_WHICH_PID, -1, 31, &mut set)
+    };
+    assert_eq!(err, -1, "Expected Failure");
+    assert_eq!(std::io::Error::last_os_error().raw_os_error().unwrap(), libc::ERANGE);
+
+    // Zero should fail as well.
+    let err = unsafe {
+        libc::cpuset_getaffinity(libc::CPU_LEVEL_WHICH, libc::CPU_WHICH_PID, -1, 0, &mut set)
+    };
+    assert_eq!(err, -1, "Expected Failure");
+    assert_eq!(std::io::Error::last_os_error().raw_os_error().unwrap(), libc::ERANGE);
+}
+
+fn main() {
+    getaffinity();
+    get_small_cpu_mask();
+}
diff --git a/src/tools/miri/tests/pass-dep/shims/windows-fs.rs b/src/tools/miri/tests/pass-dep/shims/windows-fs.rs
index 698ca4e0b4b..4ca19046b67 100644
--- a/src/tools/miri/tests/pass-dep/shims/windows-fs.rs
+++ b/src/tools/miri/tests/pass-dep/shims/windows-fs.rs
@@ -2,25 +2,28 @@
 //@compile-flags: -Zmiri-disable-isolation
 #![allow(nonstandard_style)]
 
-use std::io::ErrorKind;
+use std::io::{ErrorKind, Read, Write};
 use std::os::windows::ffi::OsStrExt;
+use std::os::windows::io::AsRawHandle;
 use std::path::Path;
-use std::ptr;
+use std::{fs, ptr};
 
 #[path = "../../utils/mod.rs"]
 mod utils;
 
+use windows_sys::Wdk::Storage::FileSystem::{NtReadFile, NtWriteFile};
 use windows_sys::Win32::Foundation::{
     CloseHandle, ERROR_ACCESS_DENIED, ERROR_ALREADY_EXISTS, ERROR_IO_DEVICE, GENERIC_READ,
     GENERIC_WRITE, GetLastError, RtlNtStatusToDosError, STATUS_ACCESS_DENIED,
-    STATUS_IO_DEVICE_ERROR,
+    STATUS_IO_DEVICE_ERROR, STATUS_SUCCESS, SetLastError,
 };
 use windows_sys::Win32::Storage::FileSystem::{
     BY_HANDLE_FILE_INFORMATION, CREATE_ALWAYS, CREATE_NEW, CreateFileW, DeleteFileW,
-    FILE_ATTRIBUTE_DIRECTORY, FILE_ATTRIBUTE_NORMAL, FILE_FLAG_BACKUP_SEMANTICS,
-    FILE_FLAG_OPEN_REPARSE_POINT, FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE,
-    GetFileInformationByHandle, OPEN_ALWAYS, OPEN_EXISTING,
+    FILE_ATTRIBUTE_DIRECTORY, FILE_ATTRIBUTE_NORMAL, FILE_BEGIN, FILE_CURRENT,
+    FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT, FILE_SHARE_DELETE, FILE_SHARE_READ,
+    FILE_SHARE_WRITE, GetFileInformationByHandle, OPEN_ALWAYS, OPEN_EXISTING, SetFilePointerEx,
 };
+use windows_sys::Win32::System::IO::IO_STATUS_BLOCK;
 
 fn main() {
     unsafe {
@@ -31,6 +34,8 @@ fn main() {
         test_open_dir_reparse();
         test_delete_file();
         test_ntstatus_to_dos();
+        test_file_read_write();
+        test_file_seek();
     }
 }
 
@@ -199,13 +204,13 @@ unsafe fn test_open_dir_reparse() {
 unsafe fn test_delete_file() {
     let temp = utils::tmp().join("test_delete_file.txt");
     let raw_path = to_wide_cstr(&temp);
-    let _ = std::fs::File::create(&temp).unwrap();
+    let _ = fs::File::create(&temp).unwrap();
 
     if DeleteFileW(raw_path.as_ptr()) == 0 {
         panic!("Failed to delete file");
     }
 
-    match std::fs::File::open(temp) {
+    match fs::File::open(temp) {
         Ok(_) => panic!("File not deleted"),
         Err(e) => assert!(e.kind() == ErrorKind::NotFound, "File not deleted"),
     }
@@ -217,6 +222,82 @@ unsafe fn test_ntstatus_to_dos() {
     assert_eq!(RtlNtStatusToDosError(STATUS_ACCESS_DENIED), ERROR_ACCESS_DENIED);
 }
 
+unsafe fn test_file_read_write() {
+    let temp = utils::tmp().join("test_file_read_write.txt");
+    let file = fs::File::create(&temp).unwrap();
+    let handle = file.as_raw_handle();
+
+    // Testing NtWriteFile doesn't clobber the error
+    SetLastError(1234);
+
+    let text = b"Example text!";
+    let mut status = std::mem::zeroed::<IO_STATUS_BLOCK>();
+    let out = NtWriteFile(
+        handle,
+        ptr::null_mut(),
+        None,
+        ptr::null_mut(),
+        &mut status,
+        text.as_ptr().cast(),
+        text.len() as u32,
+        ptr::null_mut(),
+        ptr::null_mut(),
+    );
+
+    assert_eq!(out, status.Anonymous.Status);
+    assert_eq!(out, STATUS_SUCCESS);
+    assert_eq!(GetLastError(), 1234);
+
+    let file = fs::File::open(&temp).unwrap();
+    let handle = file.as_raw_handle();
+
+    // Testing NtReadFile doesn't clobber the error
+    SetLastError(1234);
+
+    let mut buffer = vec![0; 13];
+    let out = NtReadFile(
+        handle,
+        ptr::null_mut(),
+        None,
+        ptr::null_mut(),
+        &mut status,
+        buffer.as_mut_ptr().cast(),
+        buffer.len() as u32,
+        ptr::null_mut(),
+        ptr::null_mut(),
+    );
+
+    assert_eq!(out, status.Anonymous.Status);
+    assert_eq!(out, STATUS_SUCCESS);
+    assert_eq!(buffer, text);
+    assert_eq!(GetLastError(), 1234);
+}
+
+unsafe fn test_file_seek() {
+    let temp = utils::tmp().join("test_file_seek.txt");
+    let mut file = fs::File::options().create(true).write(true).read(true).open(&temp).unwrap();
+    file.write_all(b"Hello, World!\n").unwrap();
+
+    let handle = file.as_raw_handle();
+
+    if SetFilePointerEx(handle, 7, ptr::null_mut(), FILE_BEGIN) == 0 {
+        panic!("Failed to seek");
+    }
+
+    let mut buf = vec![0; 5];
+    file.read(&mut buf).unwrap();
+    assert_eq!(buf, b"World");
+
+    let mut pos = 0;
+    if SetFilePointerEx(handle, -7, &mut pos, FILE_CURRENT) == 0 {
+        panic!("Failed to seek");
+    }
+    buf.truncate(2);
+    file.read_exact(&mut buf).unwrap();
+    assert_eq!(buf, b", ");
+    assert_eq!(pos, 5);
+}
+
 fn to_wide_cstr(path: &Path) -> Vec<u16> {
     let mut raw_path = path.as_os_str().encode_wide().collect::<Vec<_>>();
     raw_path.extend([0, 0]);
diff --git a/src/tools/miri/tests/pass-dep/tokio/file-io.rs b/src/tools/miri/tests/pass-dep/tokio/file-io.rs
index 6e88b907f5d..067753203bb 100644
--- a/src/tools/miri/tests/pass-dep/tokio/file-io.rs
+++ b/src/tools/miri/tests/pass-dep/tokio/file-io.rs
@@ -20,7 +20,11 @@ async fn test_create_and_write() -> io::Result<()> {
     let mut file = File::create(&path).await?;
 
     // Write 10 bytes to the file.
-    file.write(b"some bytes").await?;
+    file.write_all(b"some bytes").await?;
+    // For tokio's file I/O, `await` does not have its usual semantics of waiting until the
+    // operation is completed, so we have to wait some more to make sure the write is completed.
+    file.flush().await?;
+    // Check that 10 bytes have been written.
     assert_eq!(file.metadata().await.unwrap().len(), 10);
 
     remove_file(&path).unwrap();
@@ -31,10 +35,10 @@ async fn test_create_and_read() -> io::Result<()> {
     let bytes = b"more bytes";
     let path = utils::prepare_with_content("foo.txt", bytes);
     let mut file = OpenOptions::new().read(true).open(&path).await.unwrap();
-    let mut buffer = [0u8; 10];
+    let mut buffer = vec![];
 
     // Read the whole file.
-    file.read(&mut buffer[..]).await?;
+    file.read_to_end(&mut buffer).await?;
     assert_eq!(&buffer, b"more bytes");
 
     remove_file(&path).unwrap();
diff --git a/src/tools/miri/tests/pass/alloc-access-tracking.rs b/src/tools/miri/tests/pass/alloc-access-tracking.rs
index c47063bef03..0e88951dc43 100644
--- a/src/tools/miri/tests/pass/alloc-access-tracking.rs
+++ b/src/tools/miri/tests/pass/alloc-access-tracking.rs
@@ -1,7 +1,7 @@
 #![no_std]
 #![no_main]
-//@compile-flags: -Zmiri-track-alloc-id=21 -Zmiri-track-alloc-accesses -Cpanic=abort
-//@normalize-stderr-test: "id 21" -> "id $$ALLOC"
+//@compile-flags: -Zmiri-track-alloc-id=20 -Zmiri-track-alloc-accesses -Cpanic=abort
+//@normalize-stderr-test: "id 20" -> "id $$ALLOC"
 //@only-target: linux # alloc IDs differ between OSes (due to extern static allocations)
 
 extern "Rust" {
diff --git a/src/tools/miri/tests/pass/atomic.rs b/src/tools/miri/tests/pass/atomic.rs
index 2b2e89e6d70..3de34e570c7 100644
--- a/src/tools/miri/tests/pass/atomic.rs
+++ b/src/tools/miri/tests/pass/atomic.rs
@@ -7,15 +7,17 @@
 #![allow(static_mut_refs)]
 
 use std::sync::atomic::Ordering::*;
-use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicPtr, AtomicU64, compiler_fence, fence};
+use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicPtr, AtomicUsize, compiler_fence, fence};
 
 fn main() {
     atomic_bool();
     atomic_all_ops();
-    atomic_u64();
     atomic_fences();
     atomic_ptr();
     weak_sometimes_fails();
+
+    #[cfg(target_has_atomic = "64")]
+    atomic_u64();
 }
 
 fn atomic_bool() {
@@ -36,25 +38,10 @@ fn atomic_bool() {
     }
 }
 
-// There isn't a trait to use to make this generic, so just use a macro
-macro_rules! compare_exchange_weak_loop {
-    ($atom:expr, $from:expr, $to:expr, $succ_order:expr, $fail_order:expr) => {
-        loop {
-            match $atom.compare_exchange_weak($from, $to, $succ_order, $fail_order) {
-                Ok(n) => {
-                    assert_eq!(n, $from);
-                    break;
-                }
-                Err(n) => assert_eq!(n, $from),
-            }
-        }
-    };
-}
-
 /// Make sure we can handle all the intrinsics
 fn atomic_all_ops() {
     static ATOMIC: AtomicIsize = AtomicIsize::new(0);
-    static ATOMIC_UNSIGNED: AtomicU64 = AtomicU64::new(0);
+    static ATOMIC_UNSIGNED: AtomicUsize = AtomicUsize::new(0);
 
     let load_orders = [Relaxed, Acquire, SeqCst];
     let stored_orders = [Relaxed, Release, SeqCst];
@@ -94,9 +81,26 @@ fn atomic_all_ops() {
     }
 }
 
+#[cfg(target_has_atomic = "64")]
 fn atomic_u64() {
+    use std::sync::atomic::AtomicU64;
     static ATOMIC: AtomicU64 = AtomicU64::new(0);
 
+    // There isn't a trait to use to make this generic, so just use a macro
+    macro_rules! compare_exchange_weak_loop {
+        ($atom:expr, $from:expr, $to:expr, $succ_order:expr, $fail_order:expr) => {
+            loop {
+                match $atom.compare_exchange_weak($from, $to, $succ_order, $fail_order) {
+                    Ok(n) => {
+                        assert_eq!(n, $from);
+                        break;
+                    }
+                    Err(n) => assert_eq!(n, $from),
+                }
+            }
+        };
+    }
+
     ATOMIC.store(1, SeqCst);
     assert_eq!(ATOMIC.compare_exchange(0, 0x100, AcqRel, Acquire), Err(1));
     assert_eq!(ATOMIC.compare_exchange(0, 1, Release, Relaxed), Err(1));
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 1ee5298f17d..8e167dbadef 100644
--- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr
+++ b/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.stderr
@@ -7,12 +7,12 @@ RUSTLIB/core/src/ops/function.rs:LL:CC (<fn() as std::ops::FnOnce<()>>::call_onc
 RUSTLIB/std/src/sys/backtrace.rs:LL:CC (std::sys::backtrace::__rust_begin_short_backtrace)
 RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start::{closure#0})
 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/panicking.rs:LL:CC (std::panicking::catch_unwind::do_call)
+RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::catch_unwind)
 RUSTLIB/std/src/panic.rs:LL:CC (std::panic::catch_unwind)
 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/panicking.rs:LL:CC (std::panicking::catch_unwind::do_call)
+RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::catch_unwind)
 RUSTLIB/std/src/panic.rs:LL:CC (std::panic::catch_unwind)
 RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start_internal)
 RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start)
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 26cdee18e3c..588bb85f35a 100644
--- a/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr
+++ b/src/tools/miri/tests/pass/backtrace/backtrace-global-alloc.stderr
@@ -8,17 +8,17 @@
  at RUSTLIB/std/src/rt.rs:LL:CC
    4: std::ops::function::impls::call_once
  at RUSTLIB/core/src/ops/function.rs:LL:CC
-   5: std::panicking::r#try::do_call
+   5: std::panicking::catch_unwind::do_call
  at RUSTLIB/std/src/panicking.rs:LL:CC
-   6: std::panicking::r#try
+   6: std::panicking::catch_unwind
  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#0}
  at RUSTLIB/std/src/rt.rs:LL:CC
-   9: std::panicking::r#try::do_call
+   9: std::panicking::catch_unwind::do_call
  at RUSTLIB/std/src/panicking.rs:LL:CC
-  10: std::panicking::r#try
+  10: std::panicking::catch_unwind
  at RUSTLIB/std/src/panicking.rs:LL:CC
   11: std::panic::catch_unwind
  at RUSTLIB/std/src/panic.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 d89ae3837b9..9c952755957 100644
--- a/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr
+++ b/src/tools/miri/tests/pass/backtrace/backtrace-std.stderr
@@ -16,17 +16,17 @@
  at RUSTLIB/std/src/rt.rs:LL:CC
    8: std::ops::function::impls::call_once
  at RUSTLIB/core/src/ops/function.rs:LL:CC
-   9: std::panicking::r#try::do_call
+   9: std::panicking::catch_unwind::do_call
  at RUSTLIB/std/src/panicking.rs:LL:CC
-  10: std::panicking::r#try
+  10: std::panicking::catch_unwind
  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#0}
  at RUSTLIB/std/src/rt.rs:LL:CC
-  13: std::panicking::r#try::do_call
+  13: std::panicking::catch_unwind::do_call
  at RUSTLIB/std/src/panicking.rs:LL:CC
-  14: std::panicking::r#try
+  14: std::panicking::catch_unwind
  at RUSTLIB/std/src/panicking.rs:LL:CC
   15: std::panic::catch_unwind
  at RUSTLIB/std/src/panic.rs:LL:CC
diff --git a/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs b/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs
index c76e7f2eebd..6a625e597df 100644
--- a/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs
+++ b/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs
@@ -1,6 +1,7 @@
 //@revisions: stack tree
 //@[tree]compile-flags: -Zmiri-tree-borrows
 #![feature(allocator_api)]
+use std::cell::Cell;
 use std::ptr;
 
 // Test various aliasing-model-related things.
@@ -22,6 +23,7 @@ fn main() {
     not_unpin_not_protected();
     write_does_not_invalidate_all_aliases();
     box_into_raw_allows_interior_mutable_alias();
+    cell_inside_struct()
 }
 
 // Make sure that reading from an `&mut` does, like reborrowing to `&`,
@@ -259,7 +261,7 @@ fn write_does_not_invalidate_all_aliases() {
 
 fn box_into_raw_allows_interior_mutable_alias() {
     unsafe {
-        let b = Box::new(std::cell::Cell::new(42));
+        let b = Box::new(Cell::new(42));
         let raw = Box::into_raw(b);
         let c = &*raw;
         let d = raw.cast::<i32>(); // bypassing `Cell` -- only okay in Miri tests
@@ -269,3 +271,19 @@ fn box_into_raw_allows_interior_mutable_alias() {
         drop(Box::from_raw(raw));
     }
 }
+
+fn cell_inside_struct() {
+    struct Foo {
+        field1: u32,
+        field2: Cell<u32>,
+    }
+
+    let mut root = Foo { field1: 42, field2: Cell::new(88) };
+    let a = &mut root;
+
+    // Writing to `field2`, which is interior mutable, should be allowed.
+    (*a).field2.set(10);
+
+    // Writing to `field1`, which is reserved, should also be allowed.
+    (*a).field1 = 88;
+}
diff --git a/src/tools/miri/tests/pass/both_borrows/unsafe_pinned.rs b/src/tools/miri/tests/pass/both_borrows/unsafe_pinned.rs
new file mode 100644
index 00000000000..0c75a07bfa2
--- /dev/null
+++ b/src/tools/miri/tests/pass/both_borrows/unsafe_pinned.rs
@@ -0,0 +1,16 @@
+//@revisions: stack tree
+//@[tree]compile-flags: -Zmiri-tree-borrows
+#![feature(unsafe_pinned)]
+
+use std::pin::UnsafePinned;
+
+fn mutate(x: &UnsafePinned<i32>) {
+    let ptr = x as *const _ as *mut i32;
+    unsafe { ptr.write(42) };
+}
+
+fn main() {
+    let x = UnsafePinned::new(0);
+    mutate(&x);
+    assert_eq!(x.into_inner(), 42);
+}
diff --git a/src/tools/miri/tests/pass/btreemap.rs b/src/tools/miri/tests/pass/btreemap.rs
index 1213f81a6f1..1d65e69bf72 100644
--- a/src/tools/miri/tests/pass/btreemap.rs
+++ b/src/tools/miri/tests/pass/btreemap.rs
@@ -50,7 +50,7 @@ pub fn main() {
     test_all_refs(&mut 13, b.values_mut());
 
     // Test forgetting the extractor.
-    let mut d = b.extract_if(|_, i| *i < 30);
+    let mut d = b.extract_if(.., |_, i| *i < 30);
     d.next().unwrap();
     mem::forget(d);
 }
diff --git a/src/tools/miri/tests/pass/fat_ptr.rs b/src/tools/miri/tests/pass/fat_ptr.rs
index c5603d2cf80..13608b8f898 100644
--- a/src/tools/miri/tests/pass/fat_ptr.rs
+++ b/src/tools/miri/tests/pass/fat_ptr.rs
@@ -19,11 +19,11 @@ fn fat_ptr_via_local(a: &[u8]) -> &[u8] {
     x
 }
 
-fn fat_ptr_from_struct(s: FatPtrContainer) -> &[u8] {
+fn fat_ptr_from_struct(s: FatPtrContainer<'_>) -> &[u8] {
     s.ptr
 }
 
-fn fat_ptr_to_struct(a: &[u8]) -> FatPtrContainer {
+fn fat_ptr_to_struct(a: &[u8]) -> FatPtrContainer<'_> {
     FatPtrContainer { ptr: a }
 }
 
diff --git a/src/tools/miri/tests/pass/iter_macro.rs b/src/tools/miri/tests/pass/iter_macro.rs
new file mode 100644
index 00000000000..367c13f9969
--- /dev/null
+++ b/src/tools/miri/tests/pass/iter_macro.rs
@@ -0,0 +1,22 @@
+#![feature(iter_macro, yield_expr)]
+
+use std::iter::iter;
+
+fn main() {
+    let i = iter! { || {
+        yield 0;
+        for x in 5..10 {
+            yield x * 2;
+        }
+    } };
+    let mut i = i();
+    assert_eq!(i.next(), Some(0));
+    assert_eq!(i.next(), Some(10));
+    assert_eq!(i.next(), Some(12));
+    assert_eq!(i.next(), Some(14));
+    assert_eq!(i.next(), Some(16));
+    assert_eq!(i.next(), Some(18));
+    assert_eq!(i.next(), None);
+    assert_eq!(i.next(), None);
+    assert_eq!(i.next(), None);
+}
diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs
index d0a7f245ee0..87df43ca7e5 100644
--- a/src/tools/miri/tests/pass/shims/fs.rs
+++ b/src/tools/miri/tests/pass/shims/fs.rs
@@ -17,20 +17,20 @@ mod utils;
 
 fn main() {
     test_path_conversion();
+    test_file();
     test_file_create_new();
+    test_metadata();
+    test_seek();
+    test_errors();
+    test_from_raw_os_error();
+    test_file_clone();
     // Windows file handling is very incomplete.
     if cfg!(not(windows)) {
-        test_file();
-        test_seek();
-        test_file_clone();
-        test_metadata();
         test_file_set_len();
         test_file_sync();
-        test_errors();
         test_rename();
         test_directory();
         test_canonicalize();
-        test_from_raw_os_error();
         #[cfg(unix)]
         test_pread_pwrite();
     }
diff --git a/src/tools/miri/tests/pass/shims/io.rs b/src/tools/miri/tests/pass/shims/io.rs
index 420ef95a0cb..a96b98c0227 100644
--- a/src/tools/miri/tests/pass/shims/io.rs
+++ b/src/tools/miri/tests/pass/shims/io.rs
@@ -1,8 +1,10 @@
-use std::io::{self, IsTerminal};
+use std::io::{self, IsTerminal, Write};
 
 fn main() {
-    // We can't really assume that this is truly a terminal, and anyway on Windows Miri will always
-    // return `false` here, but we can check that the call succeeds.
+    io::stdout().write_all(b"stdout\n").unwrap();
+    io::stderr().write_all(b"stderr\n").unwrap();
+
+    // We can't assume that this is truly a terminal, but we can check that the call succeeds.
     io::stdout().is_terminal();
 
     // Ensure we can format `io::Error` created from OS errors
diff --git a/src/tools/miri/tests/pass/shims/io.stderr b/src/tools/miri/tests/pass/shims/io.stderr
new file mode 100644
index 00000000000..af6415db3c7
--- /dev/null
+++ b/src/tools/miri/tests/pass/shims/io.stderr
@@ -0,0 +1 @@
+stderr
diff --git a/src/tools/miri/tests/pass/shims/io.stdout b/src/tools/miri/tests/pass/shims/io.stdout
new file mode 100644
index 00000000000..faa3a15c184
--- /dev/null
+++ b/src/tools/miri/tests/pass/shims/io.stdout
@@ -0,0 +1 @@
+stdout
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs
index 48633c0a7fe..8936ae8e912 100644
--- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs
@@ -2,8 +2,6 @@
 //@only-target: x86_64 i686
 //@compile-flags: -C target-feature=+aes,+vaes,+avx512f
 
-#![feature(stdarch_x86_avx512)]
-
 use core::mem::transmute;
 #[cfg(target_arch = "x86")]
 use std::arch::x86::*;
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs
index 0ec2f679d80..65d7b57d1ce 100644
--- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs
@@ -2,8 +2,6 @@
 //@only-target: x86_64 i686
 //@compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bitalg,+avx512vpopcntdq
 
-#![feature(stdarch_x86_avx512)]
-
 #[cfg(target_arch = "x86")]
 use std::arch::x86::*;
 #[cfg(target_arch = "x86_64")]
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs
index b58d68e2ef9..48958ef5810 100644
--- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-gfni.rs
@@ -6,7 +6,6 @@
 // be interpreted as integers; signedness does not make sense for them, but
 // __mXXXi happens to be defined in terms of signed integers.
 #![allow(overflowing_literals)]
-#![feature(stdarch_x86_avx512)]
 
 #[cfg(target_arch = "x86")]
 use std::arch::x86::*;
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs
index c7c9eb5e395..e2a045bf81f 100644
--- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs
@@ -8,7 +8,6 @@
 // be interpreted as integers; signedness does not make sense for them, but
 // __mXXXi happens to be defined in terms of signed integers.
 #![allow(overflowing_literals)]
-#![feature(stdarch_x86_avx512)]
 
 #[cfg(target_arch = "x86")]
 use std::arch::x86::*;
diff --git a/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.stderr b/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.stderr
index 75a30c9a083..e09aed2cf5d 100644
--- a/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.stderr
+++ b/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.stderr
@@ -3,8 +3,8 @@ Warning: this tree is indicative only. Some tags may have been hidden.
 0..   1
 | Act |    └─┬──<TAG=root of the allocation>
 | ReIM|      └─┬──<TAG=data>
-| Cel |        ├────<TAG=x>
-| Cel |        └────<TAG=y>
+|?Cel |        ├────<TAG=x>
+|?Cel |        └────<TAG=y>
 ──────────────────────────────────────────────────
 ──────────────────────────────────────────────────
 Warning: this tree is indicative only. Some tags may have been hidden.
diff --git a/src/tools/miri/tests/pass/tree_borrows/cell-lazy-write-to-surrounding.rs b/src/tools/miri/tests/pass/tree_borrows/cell-lazy-write-to-surrounding.rs
new file mode 100644
index 00000000000..abe08f2cd22
--- /dev/null
+++ b/src/tools/miri/tests/pass/tree_borrows/cell-lazy-write-to-surrounding.rs
@@ -0,0 +1,22 @@
+//@compile-flags: -Zmiri-tree-borrows
+
+use std::cell::Cell;
+
+fn foo(x: &Cell<i32>) {
+    unsafe {
+        let ptr = x as *const Cell<i32> as *mut Cell<i32> as *mut i32;
+        ptr.offset(1).write(0);
+    }
+}
+
+fn main() {
+    let arr = [Cell::new(1), Cell::new(1)];
+    foo(&arr[0]);
+
+    let pair = (Cell::new(1), 1);
+    // TODO: Ideally, this would result in UB since the second element
+    // in `pair` is Frozen.  We would need some way to express a
+    // "shared reference with permission to access surrounding
+    // interior mutable data".
+    foo(&pair.0);
+}
diff --git a/src/tools/opt-dist/src/training.rs b/src/tools/opt-dist/src/training.rs
index 47159a43140..36a7d6a7cba 100644
--- a/src/tools/opt-dist/src/training.rs
+++ b/src/tools/opt-dist/src/training.rs
@@ -36,7 +36,7 @@ fn init_compiler_benchmarks(
         profiles.join(",").as_str(),
         "--scenarios",
         scenarios.join(",").as_str(),
-        "--include",
+        "--exact-match",
         crates.join(",").as_str(),
     ])
     .env("RUST_LOG", "collector=debug")
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
index f9ff3921266..de8a42979bb 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
@@ -4458,20 +4458,6 @@ The tracking issue for this feature is: [#133214]
         deny_since: None,
     },
     Lint {
-        label: "const_eq_ignore_ascii_case",
-        description: r##"# `const_eq_ignore_ascii_case`
-
-The tracking issue for this feature is: [#131719]
-
-[#131719]: https://github.com/rust-lang/rust/issues/131719
-
-------------------------
-"##,
-        default_severity: Severity::Allow,
-        warn_since: None,
-        deny_since: None,
-    },
-    Lint {
         label: "const_eval_select",
         description: r##"# `const_eval_select`
 
diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock
index 0b389377011..8893846b5fa 100644
--- a/src/tools/rustbook/Cargo.lock
+++ b/src/tools/rustbook/Cargo.lock
@@ -344,17 +344,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "dbus"
-version = "0.9.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1bb21987b9fb1613058ba3843121dd18b163b254d8a6e797e144cbac14d96d1b"
-dependencies = [
- "libc",
- "libdbus-sys",
- "winapi",
-]
-
-[[package]]
 name = "derive_builder"
 version = "0.20.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -824,16 +813,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
 
 [[package]]
-name = "libdbus-sys"
-version = "0.2.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06085512b750d640299b79be4bad3d2fa90a9c00b1fd9e1b46364f66f0485c72"
-dependencies = [
- "cc",
- "pkg-config",
-]
-
-[[package]]
 name = "linereader"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -906,9 +885,9 @@ dependencies = [
 
 [[package]]
 name = "mdbook"
-version = "0.4.49"
+version = "0.4.51"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d1daacee059634081dee4250d2814763a365b92dfe14bfdef964bc27835209d4"
+checksum = "a87e65420ab45ca9c1b8cdf698f95b710cc826d373fa550f0f7fad82beac9328"
 dependencies = [
  "ammonia",
  "anyhow",
@@ -921,7 +900,6 @@ dependencies = [
  "hex",
  "log",
  "memchr",
- "once_cell",
  "opener",
  "pulldown-cmark 0.10.3",
  "regex",
@@ -1048,11 +1026,11 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
 
 [[package]]
 name = "onig"
-version = "6.4.0"
+version = "6.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f"
+checksum = "336b9c63443aceef14bea841b899035ae3abe89b7c486aaf4c5bd8aafedac3f0"
 dependencies = [
- "bitflags 1.3.2",
+ "bitflags 2.9.0",
  "libc",
  "once_cell",
  "onig_sys",
@@ -1060,9 +1038,9 @@ dependencies = [
 
 [[package]]
 name = "onig_sys"
-version = "69.8.1"
+version = "69.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b829e3d7e9cc74c7e315ee8edb185bf4190da5acde74afd7fc59c35b1f086e7"
+checksum = "c7f86c6eef3d6df15f23bcfb6af487cbd2fed4e5581d58d5bf1f5f8b7f6727dc"
 dependencies = [
  "cc",
  "pkg-config",
@@ -1070,12 +1048,11 @@ dependencies = [
 
 [[package]]
 name = "opener"
-version = "0.7.2"
+version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d0812e5e4df08da354c851a3376fead46db31c2214f849d3de356d774d057681"
+checksum = "de96cad6ee771be7f68df884d3767460b4684012308d8342ed5623fe62b2628c"
 dependencies = [
  "bstr",
- "dbus",
  "normpath",
  "windows-sys",
 ]
@@ -1906,22 +1883,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "winapi"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
-dependencies = [
- "winapi-i686-pc-windows-gnu",
- "winapi-x86_64-pc-windows-gnu",
-]
-
-[[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-
-[[package]]
 name = "winapi-util"
 version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1931,12 +1892,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
-
-[[package]]
 name = "windows-core"
 version = "0.61.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml
index 10fde31306d..69c0cfaf5c9 100644
--- a/src/tools/rustbook/Cargo.toml
+++ b/src/tools/rustbook/Cargo.toml
@@ -15,6 +15,6 @@ mdbook-i18n-helpers = "0.3.3"
 mdbook-spec = { path = "../../doc/reference/mdbook-spec" }
 
 [dependencies.mdbook]
-version = "0.4.49"
+version = "0.4.51"
 default-features = false
 features = ["search"]
diff --git a/src/tools/rustc-perf b/src/tools/rustc-perf
-Subproject c0f3b53c8e5de87714d18a5f42998859302ae03
+Subproject 6a70166b92a1b1560cb3cf056427b011b2a1f2b
diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs
index e79b7803c60..1a3897b51cb 100644
--- a/src/tools/rustfmt/src/items.rs
+++ b/src/tools/rustfmt/src/items.rs
@@ -1110,10 +1110,10 @@ impl<'a> StructParts<'a> {
 
     pub(crate) fn from_item(item: &'a ast::Item) -> Self {
         let (prefix, def, ident, generics) = match item.kind {
-            ast::ItemKind::Struct(ident, ref def, ref generics) => {
+            ast::ItemKind::Struct(ident, ref generics, ref def) => {
                 ("struct ", def, ident, generics)
             }
-            ast::ItemKind::Union(ident, ref def, ref generics) => ("union ", def, ident, generics),
+            ast::ItemKind::Union(ident, ref generics, ref def) => ("union ", def, ident, generics),
             _ => unreachable!(),
         };
         StructParts {
diff --git a/src/tools/rustfmt/src/lib.rs b/src/tools/rustfmt/src/lib.rs
index 08cda6913b9..942b42ec5f2 100644
--- a/src/tools/rustfmt/src/lib.rs
+++ b/src/tools/rustfmt/src/lib.rs
@@ -8,7 +8,6 @@
 // N.B. these crates are loaded from the sysroot, so they need extern crate.
 extern crate rustc_ast;
 extern crate rustc_ast_pretty;
-extern crate rustc_builtin_macros;
 extern crate rustc_data_structures;
 extern crate rustc_errors;
 extern crate rustc_expand;
diff --git a/src/tools/rustfmt/src/modules.rs b/src/tools/rustfmt/src/modules.rs
index bc5a6d3e704..44c8123517c 100644
--- a/src/tools/rustfmt/src/modules.rs
+++ b/src/tools/rustfmt/src/modules.rs
@@ -174,7 +174,7 @@ impl<'ast, 'psess, 'c> ModResolver<'ast, 'psess> {
     ) -> Result<(), ModuleResolutionError> {
         for item in items {
             if is_cfg_if(&item) {
-                self.visit_cfg_if(Cow::Owned(item.into_inner()))?;
+                self.visit_cfg_if(Cow::Owned(*item))?;
                 continue;
             }
 
diff --git a/src/tools/rustfmt/src/parse/macros/asm.rs b/src/tools/rustfmt/src/parse/macros/asm.rs
index 1a9614bacec..bfa9c6300c4 100644
--- a/src/tools/rustfmt/src/parse/macros/asm.rs
+++ b/src/tools/rustfmt/src/parse/macros/asm.rs
@@ -1,5 +1,5 @@
 use rustc_ast::ast;
-use rustc_builtin_macros::asm::{AsmArg, parse_asm_args};
+use rustc_parse::parser::asm::{AsmArg, parse_asm_args};
 
 use crate::rewrite::RewriteContext;
 
diff --git a/src/tools/rustfmt/src/parse/macros/cfg_if.rs b/src/tools/rustfmt/src/parse/macros/cfg_if.rs
index 30b83373c17..26bf6c5326f 100644
--- a/src/tools/rustfmt/src/parse/macros/cfg_if.rs
+++ b/src/tools/rustfmt/src/parse/macros/cfg_if.rs
@@ -62,7 +62,7 @@ fn parse_cfg_if_inner<'a>(
 
         while parser.token != TokenKind::CloseBrace && parser.token.kind != TokenKind::Eof {
             let item = match parser.parse_item(ForceCollect::No) {
-                Ok(Some(item_ptr)) => item_ptr.into_inner(),
+                Ok(Some(item_ptr)) => *item_ptr,
                 Ok(None) => continue,
                 Err(err) => {
                     err.cancel();
diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs
index 16d1f5105d5..f6a9a3f2cd1 100644
--- a/src/tools/rustfmt/src/visitor.rs
+++ b/src/tools/rustfmt/src/visitor.rs
@@ -521,7 +521,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
                 ast::ItemKind::Struct(..) | ast::ItemKind::Union(..) => {
                     self.visit_struct(&StructParts::from_item(item));
                 }
-                ast::ItemKind::Enum(ident, ref def, ref generics) => {
+                ast::ItemKind::Enum(ident, ref generics, ref def) => {
                     self.format_missing_with_indent(source!(self, item.span).lo());
                     self.visit_enum(ident, &item.vis, def, generics, item.span);
                     self.last_pos = source!(self, item.span).hi();
diff --git a/src/tools/test-float-parse/Cargo.lock b/src/tools/test-float-parse/Cargo.lock
new file mode 100644
index 00000000000..3f60423fed3
--- /dev/null
+++ b/src/tools/test-float-parse/Cargo.lock
@@ -0,0 +1,75 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "getrandom"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.147"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
+
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "test-float-parse"
+version = "0.1.0"
+dependencies = [
+ "rand",
+]
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
diff --git a/src/tools/test-float-parse/Cargo.toml b/src/tools/test-float-parse/Cargo.toml
new file mode 100644
index 00000000000..e407e322f9e
--- /dev/null
+++ b/src/tools/test-float-parse/Cargo.toml
@@ -0,0 +1,22 @@
+[package]
+name = "test-float-parse"
+version = "0.1.0"
+edition = "2024"
+publish = false
+
+[dependencies]
+indicatif = { version = "0.17.8", default-features = false }
+num = "0.4.3"
+rand = "0.9.0"
+rand_chacha = "0.9.0"
+rayon = "1"
+
+[lib]
+name = "test_float_parse"
+
+[lints.rust.unexpected_cfgs]
+level = "warn"
+check-cfg = [
+    # Internal features aren't marked known config by default
+    'cfg(target_has_reliable_f16)',
+]
diff --git a/src/tools/test-float-parse/README.md b/src/tools/test-float-parse/README.md
new file mode 100644
index 00000000000..5e2c43d1cad
--- /dev/null
+++ b/src/tools/test-float-parse/README.md
@@ -0,0 +1,55 @@
+# Float Parsing Tests
+
+These are tests designed to test decimal to float conversions (`dec2flt`) used
+by the standard library.
+
+It consists of a collection of test generators that each generate a set of
+patterns intended to test a specific property. In addition, there are exhaustive
+tests (for <= `f32`) and fuzzers (for anything that can't be run exhaustively).
+
+The generators work as follows:
+
+- Each generator is a struct that lives somewhere in the `gen` module. Usually
+  it is generic over a float type.
+- These generators must implement `Iterator`, which should return a context type
+  that can be used to construct a test string (but usually not the string
+  itself).
+- They must also implement the `Generator` trait, which provides a method to
+  write test context to a string as a test case, as well as some extra metadata.
+
+  The split between context generation and string construction is so that we can
+  reuse string allocations.
+- Each generator gets registered once for each float type. Each of these
+  generators then get their iterator called, and each test case checked against
+  the float type's parse implementation.
+
+Some generators produce decimal strings, others create bit patterns that need to
+be bitcasted to the float type, which then uses its `Display` implementation to
+write to a string. For these, float to decimal (`flt2dec`) conversions also get
+tested, if unintentionally.
+
+For each test case, the following is done:
+
+- The test string is parsed to the float type using the standard library's
+  implementation.
+- The test string is parsed separately to a `BigRational`, which acts as a
+  representation with infinite precision.
+- The rational value then gets checked that it is within the float's
+  representable values (absolute value greater than the smallest number to round
+  to zero, but less less than the first value to round to infinity). If these
+  limits are exceeded, check that the parsed float reflects that.
+- For real nonzero numbers, the parsed float is converted into a rational using
+  `significand * 2^exponent`. It is then checked against the actual rational
+  value, and verified to be within half a bit's precision of the parsed value.
+  Also it is checked that ties round to even.
+
+This is all highly parallelized with `rayon`; test generators can run in
+parallel, and their tests get chunked and run in parallel.
+
+There is a simple command line that allows filtering which tests are run,
+setting the number of iterations for fuzzing tests, limiting failures, setting
+timeouts, etc. See `main.rs` or run with `--help` for options.
+
+Note that when running via `./x`, only tests that take less than a few minutes
+are run by default. Navigate to the crate (or pass `-C` to Cargo) and run it
+directly to run all tests or pass specific arguments.
diff --git a/src/tools/test-float-parse/src/gen_/exhaustive.rs b/src/tools/test-float-parse/src/gen_/exhaustive.rs
new file mode 100644
index 00000000000..01458fb0b60
--- /dev/null
+++ b/src/tools/test-float-parse/src/gen_/exhaustive.rs
@@ -0,0 +1,42 @@
+use std::fmt::Write;
+use std::ops::RangeInclusive;
+
+use crate::{Float, Generator, Int};
+
+/// Test every possible bit pattern. This is infeasible to run on any float types larger than
+/// `f32` (which takes about an hour).
+pub struct Exhaustive<F: Float> {
+    iter: RangeInclusive<F::Int>,
+}
+
+impl<F: Float> Generator<F> for Exhaustive<F>
+where
+    RangeInclusive<F::Int>: Iterator<Item = F::Int>,
+{
+    const SHORT_NAME: &'static str = "exhaustive";
+
+    type WriteCtx = F;
+
+    fn total_tests() -> u64 {
+        1u64.checked_shl(F::Int::BITS).expect("More than u64::MAX tests")
+    }
+
+    fn new() -> Self {
+        Self { iter: F::Int::ZERO..=F::Int::MAX }
+    }
+
+    fn write_string(s: &mut String, ctx: Self::WriteCtx) {
+        write!(s, "{ctx:e}").unwrap();
+    }
+}
+
+impl<F: Float> Iterator for Exhaustive<F>
+where
+    RangeInclusive<F::Int>: Iterator<Item = F::Int>,
+{
+    type Item = F;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        Some(F::from_bits(self.iter.next()?))
+    }
+}
diff --git a/src/tools/test-float-parse/src/gen_/exponents.rs b/src/tools/test-float-parse/src/gen_/exponents.rs
new file mode 100644
index 00000000000..3748e9d380c
--- /dev/null
+++ b/src/tools/test-float-parse/src/gen_/exponents.rs
@@ -0,0 +1,95 @@
+use std::fmt::Write;
+use std::ops::RangeInclusive;
+
+use crate::traits::BoxGenIter;
+use crate::{Float, Generator};
+
+const SMALL_COEFF_MAX: i32 = 10_000;
+const SMALL_EXP_MAX: i32 = 300;
+
+const SMALL_COEFF_RANGE: RangeInclusive<i32> = (-SMALL_COEFF_MAX)..=SMALL_COEFF_MAX;
+const SMALL_EXP_RANGE: RangeInclusive<i32> = (-SMALL_EXP_MAX)..=SMALL_EXP_MAX;
+
+const LARGE_COEFF_RANGE: RangeInclusive<u32> = 0..=100_000;
+const LARGE_EXP_RANGE: RangeInclusive<u32> = 300..=350;
+
+/// Check exponential values around zero.
+pub struct SmallExponents<F: Float> {
+    iter: BoxGenIter<Self, F>,
+}
+
+impl<F: Float> Generator<F> for SmallExponents<F> {
+    const NAME: &'static str = "small exponents";
+    const SHORT_NAME: &'static str = "small exp";
+
+    /// `(coefficient, exponent)`
+    type WriteCtx = (i32, i32);
+
+    fn total_tests() -> u64 {
+        ((1 + SMALL_COEFF_RANGE.end() - SMALL_COEFF_RANGE.start())
+            * (1 + SMALL_EXP_RANGE.end() - SMALL_EXP_RANGE.start()))
+        .try_into()
+        .unwrap()
+    }
+
+    fn new() -> Self {
+        let iter = SMALL_EXP_RANGE.flat_map(|exp| SMALL_COEFF_RANGE.map(move |coeff| (coeff, exp)));
+
+        Self { iter: Box::new(iter) }
+    }
+
+    fn write_string(s: &mut String, ctx: Self::WriteCtx) {
+        let (coeff, exp) = ctx;
+        write!(s, "{coeff}e{exp}").unwrap();
+    }
+}
+
+impl<F: Float> Iterator for SmallExponents<F> {
+    type Item = (i32, i32);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.iter.next()
+    }
+}
+
+/// Check exponential values further from zero.
+pub struct LargeExponents<F: Float> {
+    iter: BoxGenIter<Self, F>,
+}
+
+impl<F: Float> Generator<F> for LargeExponents<F> {
+    const NAME: &'static str = "large positive exponents";
+    const SHORT_NAME: &'static str = "large exp";
+
+    /// `(coefficient, exponent, is_positive)`
+    type WriteCtx = (u32, u32, bool);
+
+    fn total_tests() -> u64 {
+        ((1 + LARGE_EXP_RANGE.end() - LARGE_EXP_RANGE.start())
+            * (1 + LARGE_COEFF_RANGE.end() - LARGE_COEFF_RANGE.start())
+            * 2)
+        .into()
+    }
+
+    fn new() -> Self {
+        let iter = LARGE_EXP_RANGE
+            .flat_map(|exp| LARGE_COEFF_RANGE.map(move |coeff| (coeff, exp)))
+            .flat_map(|(coeff, exp)| [(coeff, exp, false), (coeff, exp, true)]);
+
+        Self { iter: Box::new(iter) }
+    }
+
+    fn write_string(s: &mut String, ctx: Self::WriteCtx) {
+        let (coeff, exp, is_positive) = ctx;
+        let sign = if is_positive { "" } else { "-" };
+        write!(s, "{sign}{coeff}e{exp}").unwrap();
+    }
+}
+
+impl<F: Float> Iterator for LargeExponents<F> {
+    type Item = (u32, u32, bool);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.iter.next()
+    }
+}
diff --git a/src/tools/test-float-parse/src/gen_/fuzz.rs b/src/tools/test-float-parse/src/gen_/fuzz.rs
new file mode 100644
index 00000000000..1d6c5562a14
--- /dev/null
+++ b/src/tools/test-float-parse/src/gen_/fuzz.rs
@@ -0,0 +1,87 @@
+use std::any::{TypeId, type_name};
+use std::collections::BTreeMap;
+use std::fmt::Write;
+use std::marker::PhantomData;
+use std::ops::Range;
+use std::sync::Mutex;
+
+use rand::Rng;
+use rand::distr::{Distribution, StandardUniform};
+use rand_chacha::ChaCha8Rng;
+use rand_chacha::rand_core::SeedableRng;
+
+use crate::{Float, Generator, Int, SEED};
+
+/// Mapping of float types to the number of iterations that should be run.
+///
+/// We could probably make `Generator::new` take an argument instead of the global state,
+/// but we only load this once so it works.
+static FUZZ_COUNTS: Mutex<BTreeMap<TypeId, u64>> = Mutex::new(BTreeMap::new());
+
+/// Generic fuzzer; just tests deterministic random bit patterns N times.
+pub struct Fuzz<F> {
+    iter: Range<u64>,
+    rng: ChaCha8Rng,
+    /// Allow us to use generics in `Iterator`.
+    marker: PhantomData<F>,
+}
+
+impl<F: Float> Fuzz<F> {
+    /// Register how many iterations the fuzzer should run for a type. Uses some logic by
+    /// default, but if `from_cfg` is `Some`, that will be used instead.
+    pub fn set_iterations(from_cfg: Option<u64>) {
+        let count = if let Some(cfg_count) = from_cfg {
+            cfg_count
+        } else if F::BITS <= crate::MAX_BITS_FOR_EXHAUUSTIVE {
+            // If we run exhaustively, still fuzz but only do half as many bits. The only goal here is
+            // to catch failures from e.g. high bit patterns before exhaustive tests would get to them.
+            (F::Int::MAX >> (F::BITS / 2)).try_into().unwrap()
+        } else {
+            // Eveything bigger gets a fuzz test with as many iterations as `f32` exhaustive.
+            u32::MAX.into()
+        };
+
+        let _ = FUZZ_COUNTS.lock().unwrap().insert(TypeId::of::<F>(), count);
+    }
+}
+
+impl<F: Float> Generator<F> for Fuzz<F>
+where
+    StandardUniform: Distribution<<F as Float>::Int>,
+{
+    const SHORT_NAME: &'static str = "fuzz";
+
+    type WriteCtx = F;
+
+    fn total_tests() -> u64 {
+        *FUZZ_COUNTS
+            .lock()
+            .unwrap()
+            .get(&TypeId::of::<F>())
+            .unwrap_or_else(|| panic!("missing fuzz count for {}", type_name::<F>()))
+    }
+
+    fn new() -> Self {
+        let rng = ChaCha8Rng::from_seed(SEED);
+
+        Self { iter: 0..Self::total_tests(), rng, marker: PhantomData }
+    }
+
+    fn write_string(s: &mut String, ctx: Self::WriteCtx) {
+        write!(s, "{ctx:e}").unwrap();
+    }
+}
+
+impl<F: Float> Iterator for Fuzz<F>
+where
+    StandardUniform: Distribution<<F as Float>::Int>,
+{
+    type Item = <Self as Generator<F>>::WriteCtx;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let _ = self.iter.next()?;
+        let i: F::Int = self.rng.random();
+
+        Some(F::from_bits(i))
+    }
+}
diff --git a/src/tools/test-float-parse/src/gen_/integers.rs b/src/tools/test-float-parse/src/gen_/integers.rs
new file mode 100644
index 00000000000..070d188e88c
--- /dev/null
+++ b/src/tools/test-float-parse/src/gen_/integers.rs
@@ -0,0 +1,104 @@
+use std::fmt::Write;
+use std::ops::{Range, RangeInclusive};
+
+use crate::traits::BoxGenIter;
+use crate::{Float, Generator};
+
+const SMALL_MAX_POW2: u32 = 19;
+
+/// All values up to the max power of two
+const SMALL_VALUES: RangeInclusive<i32> = {
+    let max = 1i32 << SMALL_MAX_POW2;
+    (-max)..=max
+};
+
+/// Large values only get tested around powers of two
+const LARGE_POWERS: Range<u32> = SMALL_MAX_POW2..128;
+
+/// We perturbe each large value around these ranges
+const LARGE_PERTURBATIONS: RangeInclusive<i128> = -256..=256;
+
+/// Test all integers up to `2 ^ MAX_POW2`
+pub struct SmallInt {
+    iter: RangeInclusive<i32>,
+}
+
+impl<F: Float> Generator<F> for SmallInt {
+    const NAME: &'static str = "small integer values";
+    const SHORT_NAME: &'static str = "int small";
+
+    type WriteCtx = i32;
+
+    fn total_tests() -> u64 {
+        (SMALL_VALUES.end() + 1 - SMALL_VALUES.start()).try_into().unwrap()
+    }
+
+    fn new() -> Self {
+        Self { iter: SMALL_VALUES }
+    }
+
+    fn write_string(s: &mut String, ctx: Self::WriteCtx) {
+        write!(s, "{ctx}").unwrap();
+    }
+}
+
+impl Iterator for SmallInt {
+    type Item = i32;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.iter.next()
+    }
+}
+
+/// Test much bigger integers than [`SmallInt`].
+pub struct LargeInt<F: Float> {
+    iter: BoxGenIter<Self, F>,
+}
+
+impl<F: Float> LargeInt<F> {
+    const EDGE_CASES: [i128; 7] = [
+        i32::MIN as i128,
+        i32::MAX as i128,
+        i64::MIN as i128,
+        i64::MAX as i128,
+        u64::MAX as i128,
+        i128::MIN,
+        i128::MAX,
+    ];
+}
+
+impl<F: Float> Generator<F> for LargeInt<F> {
+    const NAME: &'static str = "large integer values";
+    const SHORT_NAME: &'static str = "int large";
+
+    type WriteCtx = i128;
+
+    fn total_tests() -> u64 {
+        u64::try_from(
+            (i128::from(LARGE_POWERS.end - LARGE_POWERS.start)
+                + i128::try_from(Self::EDGE_CASES.len()).unwrap())
+                * (LARGE_PERTURBATIONS.end() + 1 - LARGE_PERTURBATIONS.start()),
+        )
+        .unwrap()
+    }
+
+    fn new() -> Self {
+        let iter = LARGE_POWERS
+            .map(|pow| 1i128 << pow)
+            .chain(Self::EDGE_CASES)
+            .flat_map(|base| LARGE_PERTURBATIONS.map(move |perturb| base.saturating_add(perturb)));
+
+        Self { iter: Box::new(iter) }
+    }
+
+    fn write_string(s: &mut String, ctx: Self::WriteCtx) {
+        write!(s, "{ctx}").unwrap();
+    }
+}
+impl<F: Float> Iterator for LargeInt<F> {
+    type Item = i128;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.iter.next()
+    }
+}
diff --git a/src/tools/test-float-parse/src/gen_/long_fractions.rs b/src/tools/test-float-parse/src/gen_/long_fractions.rs
new file mode 100644
index 00000000000..b75148b779c
--- /dev/null
+++ b/src/tools/test-float-parse/src/gen_/long_fractions.rs
@@ -0,0 +1,58 @@
+use std::char;
+use std::fmt::Write;
+
+use crate::{Float, Generator};
+
+/// Number of decimal digits to check (all of them).
+const MAX_DIGIT: u32 = 9;
+/// Test with this many decimals in the string.
+const MAX_DECIMALS: usize = 410;
+const PREFIX: &str = "0.";
+
+/// Test e.g. `0.1`, `0.11`, `0.111`, `0.1111`, ..., `0.2`, `0.22`, ...
+pub struct RepeatingDecimal {
+    digit: u32,
+    buf: String,
+}
+
+impl<F: Float> Generator<F> for RepeatingDecimal {
+    const NAME: &'static str = "repeating decimal";
+    const SHORT_NAME: &'static str = "dec rep";
+
+    type WriteCtx = String;
+
+    fn total_tests() -> u64 {
+        u64::from(MAX_DIGIT + 1) * u64::try_from(MAX_DECIMALS + 1).unwrap() + 1
+    }
+
+    fn new() -> Self {
+        Self { digit: 0, buf: PREFIX.to_owned() }
+    }
+
+    fn write_string(s: &mut String, ctx: Self::WriteCtx) {
+        *s = ctx;
+    }
+}
+
+impl Iterator for RepeatingDecimal {
+    type Item = String;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.digit > MAX_DIGIT {
+            return None;
+        }
+
+        let digit = self.digit;
+        let inc_digit = self.buf.len() - PREFIX.len() > MAX_DECIMALS;
+
+        if inc_digit {
+            // Reset the string
+            self.buf.clear();
+            self.digit += 1;
+            self.buf.write_str(PREFIX).unwrap();
+        }
+
+        self.buf.push(char::from_digit(digit, 10).unwrap());
+        Some(self.buf.clone())
+    }
+}
diff --git a/src/tools/test-float-parse/src/gen_/many_digits.rs b/src/tools/test-float-parse/src/gen_/many_digits.rs
new file mode 100644
index 00000000000..741e11437fe
--- /dev/null
+++ b/src/tools/test-float-parse/src/gen_/many_digits.rs
@@ -0,0 +1,84 @@
+use std::char;
+use std::fmt::Write;
+use std::marker::PhantomData;
+use std::ops::{Range, RangeInclusive};
+
+use rand::distr::{Distribution, Uniform};
+use rand::{Rng, SeedableRng};
+use rand_chacha::ChaCha8Rng;
+
+use crate::{Float, Generator, SEED};
+
+/// Total iterations
+const ITERATIONS: u64 = 5_000_000;
+
+/// Possible lengths of the string, excluding decimals and exponents
+const POSSIBLE_NUM_DIGITS: RangeInclusive<usize> = 100..=400;
+
+/// Range of possible exponents
+const EXP_RANGE: Range<i32> = -4500..4500;
+
+/// Try strings of random digits.
+pub struct RandDigits<F> {
+    rng: ChaCha8Rng,
+    iter: Range<u64>,
+    uniform: Uniform<u32>,
+    /// Allow us to use generics in `Iterator`.
+    marker: PhantomData<F>,
+}
+
+impl<F: Float> Generator<F> for RandDigits<F> {
+    const NAME: &'static str = "random digits";
+
+    const SHORT_NAME: &'static str = "rand digits";
+
+    type WriteCtx = String;
+
+    fn total_tests() -> u64 {
+        ITERATIONS
+    }
+
+    fn new() -> Self {
+        let rng = ChaCha8Rng::from_seed(SEED);
+        let range = Uniform::try_from(0..10).unwrap();
+
+        Self { rng, iter: 0..ITERATIONS, uniform: range, marker: PhantomData }
+    }
+
+    fn write_string(s: &mut String, ctx: Self::WriteCtx) {
+        *s = ctx;
+    }
+}
+
+impl<F: Float> Iterator for RandDigits<F> {
+    type Item = String;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let _ = self.iter.next()?;
+        let num_digits = self.rng.random_range(POSSIBLE_NUM_DIGITS);
+        let has_decimal = self.rng.random_bool(0.2);
+        let has_exp = self.rng.random_bool(0.2);
+
+        let dec_pos = if has_decimal { Some(self.rng.random_range(0..num_digits)) } else { None };
+
+        let mut s = String::with_capacity(num_digits);
+
+        for pos in 0..num_digits {
+            let digit = char::from_digit(self.uniform.sample(&mut self.rng), 10).unwrap();
+            s.push(digit);
+
+            if let Some(dec_pos) = dec_pos {
+                if pos == dec_pos {
+                    s.push('.');
+                }
+            }
+        }
+
+        if has_exp {
+            let exp = self.rng.random_range(EXP_RANGE);
+            write!(s, "e{exp}").unwrap();
+        }
+
+        Some(s)
+    }
+}
diff --git a/src/tools/test-float-parse/src/gen_/sparse.rs b/src/tools/test-float-parse/src/gen_/sparse.rs
new file mode 100644
index 00000000000..72b65d4ce7f
--- /dev/null
+++ b/src/tools/test-float-parse/src/gen_/sparse.rs
@@ -0,0 +1,99 @@
+use std::fmt::Write;
+
+use crate::traits::BoxGenIter;
+use crate::{Float, Generator};
+
+const POWERS_OF_TWO: [u128; 128] = make_powers_of_two();
+
+const fn make_powers_of_two() -> [u128; 128] {
+    let mut ret = [0; 128];
+    let mut i = 0;
+    while i < 128 {
+        ret[i] = 1 << i;
+        i += 1;
+    }
+
+    ret
+}
+
+/// Can't clone this result because of lifetime errors, just use a macro.
+macro_rules! pow_iter {
+    () => {
+        (0..F::BITS).map(|i| F::Int::try_from(POWERS_OF_TWO[i as usize]).unwrap())
+    };
+}
+
+/// Test all numbers that include three 1s in the binary representation as integers.
+pub struct FewOnesInt<F: Float>
+where
+    FewOnesInt<F>: Generator<F>,
+{
+    iter: BoxGenIter<Self, F>,
+}
+
+impl<F: Float> Generator<F> for FewOnesInt<F>
+where
+    <F::Int as TryFrom<u128>>::Error: std::fmt::Debug,
+{
+    const SHORT_NAME: &'static str = "few ones int";
+
+    type WriteCtx = F::Int;
+
+    fn total_tests() -> u64 {
+        u64::from(F::BITS).pow(3)
+    }
+
+    fn new() -> Self {
+        let iter = pow_iter!()
+            .flat_map(move |a| pow_iter!().map(move |b| (a, b)))
+            .flat_map(move |(a, b)| pow_iter!().map(move |c| (a, b, c)))
+            .map(|(a, b, c)| a | b | c);
+
+        Self { iter: Box::new(iter) }
+    }
+
+    fn write_string(s: &mut String, ctx: Self::WriteCtx) {
+        write!(s, "{ctx}").unwrap();
+    }
+}
+
+impl<F: Float> Iterator for FewOnesInt<F> {
+    type Item = F::Int;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.iter.next()
+    }
+}
+
+/// Similar to `FewOnesInt` except test those bit patterns as a float.
+pub struct FewOnesFloat<F: Float>(FewOnesInt<F>);
+
+impl<F: Float> Generator<F> for FewOnesFloat<F>
+where
+    <F::Int as TryFrom<u128>>::Error: std::fmt::Debug,
+{
+    const NAME: &'static str = "few ones float";
+    const SHORT_NAME: &'static str = "few ones float";
+
+    type WriteCtx = F;
+
+    fn total_tests() -> u64 {
+        FewOnesInt::<F>::total_tests()
+    }
+
+    fn new() -> Self {
+        Self(FewOnesInt::new())
+    }
+
+    fn write_string(s: &mut String, ctx: Self::WriteCtx) {
+        write!(s, "{ctx:e}").unwrap();
+    }
+}
+
+impl<F: Float> Iterator for FewOnesFloat<F> {
+    type Item = F;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.0.next().map(|i| F::from_bits(i))
+    }
+}
diff --git a/src/tools/test-float-parse/src/gen_/spot_checks.rs b/src/tools/test-float-parse/src/gen_/spot_checks.rs
new file mode 100644
index 00000000000..18691f9d6cf
--- /dev/null
+++ b/src/tools/test-float-parse/src/gen_/spot_checks.rs
@@ -0,0 +1,101 @@
+use std::fmt::Write;
+
+use crate::traits::{Float, Generator};
+
+const SPECIAL: &[&str] = &[
+    "inf", "Inf", "iNf", "INF", "-inf", "-Inf", "-iNf", "-INF", "+inf", "+Inf", "+iNf", "+INF",
+    "nan", "NaN", "NAN", "nAn", "-nan", "-NaN", "-NAN", "-nAn", "+nan", "+NaN", "+NAN", "+nAn",
+    "1", "-1", "+1", "1e1", "-1e1", "+1e1", "1e-1", "-1e-1", "+1e-1", "1e+1", "-1e+1", "+1e+1",
+    "1E1", "-1E1", "+1E1", "1E-1", "-1E-1", "+1E-1", "1E+1", "-1E+1", "+1E+1", "0", "-0", "+0",
+];
+
+/// Check various non-numeric special strings.
+pub struct Special {
+    iter: std::slice::Iter<'static, &'static str>,
+}
+
+impl<F: Float> Generator<F> for Special {
+    const NAME: &'static str = "special values";
+
+    const SHORT_NAME: &'static str = "special";
+
+    type WriteCtx = &'static str;
+
+    fn total_tests() -> u64 {
+        SPECIAL.len().try_into().unwrap()
+    }
+
+    fn new() -> Self {
+        Self { iter: SPECIAL.iter() }
+    }
+
+    fn write_string(s: &mut String, ctx: Self::WriteCtx) {
+        s.write_str(ctx).unwrap();
+    }
+}
+
+impl Iterator for Special {
+    type Item = &'static str;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.iter.next().copied()
+    }
+}
+
+/// Strings that we know have failed in the past
+const REGRESSIONS: &[&str] = &[
+    // From <https://github.com/rust-lang/rust/issues/31407>
+    "1234567890123456789012345678901234567890e-340",
+    "2.225073858507201136057409796709131975934819546351645648023426109724822222021076945516529523908135087914149158913039621106870086438694594645527657207407820621743379988141063267329253552286881372149012981122451451889849057222307285255133155755015914397476397983411801999323962548289017107081850690630666655994938275772572015763062690663332647565300009245888316433037779791869612049497390377829704905051080609940730262937128958950003583799967207254304360284078895771796150945516748243471030702609144621572289880258182545180325707018860872113128079512233426288368622321503775666622503982534335974568884423900265498198385487948292206894721689831099698365846814022854243330660339850886445804001034933970427567186443383770486037861622771738545623065874679014086723327636718749999999999999999999999999999999999999e-308",
+    "2.22507385850720113605740979670913197593481954635164564802342610972482222202107694551652952390813508791414915891303962110687008643869459464552765720740782062174337998814106326732925355228688137214901298112245145188984905722230728525513315575501591439747639798341180199932396254828901710708185069063066665599493827577257201576306269066333264756530000924588831643303777979186961204949739037782970490505108060994073026293712895895000358379996720725430436028407889577179615094551674824347103070260914462157228988025818254518032570701886087211312807951223342628836862232150377566662250398253433597456888442390026549819838548794829220689472168983109969836584681402285424333066033985088644580400103493397042756718644338377048603786162277173854562306587467901408672332763671875e-308",
+    "0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000222507385850720138309023271733240406421921598046233183055332741688720443481391819585428315901251102056406733973103581100515243416155346010885601238537771882113077799353200233047961014744258363607192156504694250373420837525080665061665815894872049117996859163964850063590877011830487479978088775374994945158045160505091539985658247081864511353793580499211598108576605199243335211435239014879569960959128889160299264151106346631339366347758651302937176204732563178148566435087212282863764204484681140761391147706280168985324411002416144742161856716615054015428508471675290190316132277889672970737312333408698898317506783884692609277397797285865965494109136909540613646756870239867831529068098461721092462539672851562500000000000000001",
+    "179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497791.9999999999999999999999999999999999999999999999999999999999999999999999",
+    "2.47032822920623272e-324",
+    "6.631236871469758276785396630275967243399099947355303144249971758736286630139265439618068200788048744105960420552601852889715006376325666595539603330361800519107591783233358492337208057849499360899425128640718856616503093444922854759159988160304439909868291973931426625698663157749836252274523485312442358651207051292453083278116143932569727918709786004497872322193856150225415211997283078496319412124640111777216148110752815101775295719811974338451936095907419622417538473679495148632480391435931767981122396703443803335529756003353209830071832230689201383015598792184172909927924176339315507402234836120730914783168400715462440053817592702766213559042115986763819482654128770595766806872783349146967171293949598850675682115696218943412532098591327667236328125E-316",
+    "3.237883913302901289588352412501532174863037669423108059901297049552301970670676565786835742587799557860615776559838283435514391084153169252689190564396459577394618038928365305143463955100356696665629202017331344031730044369360205258345803431471660032699580731300954848363975548690010751530018881758184174569652173110473696022749934638425380623369774736560008997404060967498028389191878963968575439222206416981462690113342524002724385941651051293552601421155333430225237291523843322331326138431477823591142408800030775170625915670728657003151953664260769822494937951845801530895238439819708403389937873241463484205608000027270531106827387907791444918534771598750162812548862768493201518991668028251730299953143924168545708663913273994694463908672332763671875E-319",
+    "6.953355807847677105972805215521891690222119817145950754416205607980030131549636688806115726399441880065386399864028691275539539414652831584795668560082999889551357784961446896042113198284213107935110217162654939802416034676213829409720583759540476786936413816541621287843248433202369209916612249676005573022703244799714622116542188837770376022371172079559125853382801396219552418839469770514904192657627060319372847562301074140442660237844114174497210955449896389180395827191602886654488182452409583981389442783377001505462015745017848754574668342161759496661766020028752888783387074850773192997102997936619876226688096314989645766000479009083731736585750335262099860150896718774401964796827166283225641992040747894382698751809812609536720628966577351093292236328125E-310",
+    "3.339068557571188581835713701280943911923401916998521771655656997328440314559615318168849149074662609099998113009465566426808170378434065722991659642619467706034884424989741080790766778456332168200464651593995817371782125010668346652995912233993254584461125868481633343674905074271064409763090708017856584019776878812425312008812326260363035474811532236853359905334625575404216060622858633280744301892470300555678734689978476870369853549413277156622170245846166991655321535529623870646888786637528995592800436177901746286272273374471701452991433047257863864601424252024791567368195056077320885329384322332391564645264143400798619665040608077549162173963649264049738362290606875883456826586710961041737908872035803481241600376705491726170293986797332763671875E-319",
+    "2.4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328124999e-324",
+    "2.4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328125e-324",
+    "2.4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328125001e-324",
+    "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984374999e-324",
+    "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375e-324",
+    "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375001e-324",
+    "94393431193180696942841837085033647913224148539854e-358",
+    "104308485241983990666713401708072175773165034278685682646111762292409330928739751702404658197872319129036519947435319418387839758990478549477777586673075945844895981012024387992135617064532141489278815239849108105951619997829153633535314849999674266169258928940692239684771590065027025835804863585454872499320500023126142553932654370362024104462255244034053203998964360882487378334860197725139151265590832887433736189468858614521708567646743455601905935595381852723723645799866672558576993978025033590728687206296379801363024094048327273913079612469982585674824156000783167963081616214710691759864332339239688734656548790656486646106983450809073750535624894296242072010195710276073042036425579852459556183541199012652571123898996574563824424330960027873516082763671875e-1075",
+    "0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000247032822920623272088284396434110686182529901307162382212792841250337753635104375932649918180817996189898282347722858865463328355177969898199387398005390939063150356595155702263922908583924491051844359318028499365361525003193704576782492193656236698636584807570015857692699037063119282795585513329278343384093519780155312465972635795746227664652728272200563740064854999770965994704540208281662262378573934507363390079677619305775067401763246736009689513405355374585166611342237666786041621596804619144672918403005300575308490487653917113865916462395249126236538818796362393732804238910186723484976682350898633885879256283027559956575244555072551893136908362547791869486679949683240497058210285131854513962138377228261454376934125320985913276672363281249",
+    "0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000247032822920623272088284396434110686182529901307162382212792841250337753635104375932649918180817996189898282347722858865463328355177969898199387398005390939063150356595155702263922908583924491051844359318028499365361525003193704576782492193656236698636584807570015857692699037063119282795585513329278343384093519780155312465972635795746227664652728272200563740064854999770965994704540208281662262378573934507363390079677619305775067401763246736009689513405355374585166611342237666786041621596804619144672918403005300575308490487653917113865916462395249126236538818796362393732804238910186723484976682350898633885879256283027559956575244555072551893136908362547791869486679949683240497058210285131854513962138377228261454376934125320985913276672363281251",
+];
+
+/// Check items that failed in the past.
+pub struct RegressionCheck {
+    iter: std::slice::Iter<'static, &'static str>,
+}
+
+impl<F: Float> Generator<F> for RegressionCheck {
+    const NAME: &'static str = "regression check";
+
+    const SHORT_NAME: &'static str = "regression";
+
+    type WriteCtx = &'static str;
+
+    fn total_tests() -> u64 {
+        REGRESSIONS.len().try_into().unwrap()
+    }
+
+    fn new() -> Self {
+        Self { iter: REGRESSIONS.iter() }
+    }
+
+    fn write_string(s: &mut String, ctx: Self::WriteCtx) {
+        s.write_str(ctx).unwrap();
+    }
+}
+
+impl Iterator for RegressionCheck {
+    type Item = &'static str;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.iter.next().copied()
+    }
+}
diff --git a/src/tools/test-float-parse/src/gen_/subnorm.rs b/src/tools/test-float-parse/src/gen_/subnorm.rs
new file mode 100644
index 00000000000..654f324b9b0
--- /dev/null
+++ b/src/tools/test-float-parse/src/gen_/subnorm.rs
@@ -0,0 +1,108 @@
+use std::fmt::Write;
+use std::ops::RangeInclusive;
+
+use crate::{Float, Generator, Int};
+
+/// Spot check some edge cases for subnormals.
+pub struct SubnormEdgeCases<F: Float> {
+    cases: [F::Int; 6],
+    index: usize,
+}
+
+impl<F: Float> SubnormEdgeCases<F> {
+    /// Shorthand
+    const I1: F::Int = F::Int::ONE;
+
+    fn edge_cases() -> [F::Int; 6] {
+        // Comments use an 8-bit mantissa as a demo
+        [
+            // 0b00000001
+            Self::I1,
+            // 0b10000000
+            Self::I1 << (F::MAN_BITS - 1),
+            // 0b00001000
+            Self::I1 << ((F::MAN_BITS / 2) - 1),
+            // 0b00001111
+            Self::I1 << ((F::MAN_BITS / 2) - 1),
+            // 0b00001111
+            Self::I1 << ((F::MAN_BITS / 2) - 1),
+            // 0b11111111
+            F::MAN_MASK,
+        ]
+    }
+}
+
+impl<F: Float> Generator<F> for SubnormEdgeCases<F> {
+    const NAME: &'static str = "subnormal edge cases";
+    const SHORT_NAME: &'static str = "subnorm edge";
+
+    type WriteCtx = F;
+
+    fn new() -> Self {
+        Self { cases: Self::edge_cases(), index: 0 }
+    }
+
+    fn total_tests() -> u64 {
+        Self::edge_cases().len().try_into().unwrap()
+    }
+
+    fn write_string(s: &mut String, ctx: Self::WriteCtx) {
+        write!(s, "{ctx:e}").unwrap();
+    }
+}
+
+impl<F: Float> Iterator for SubnormEdgeCases<F> {
+    type Item = F;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let i = self.cases.get(self.index)?;
+        self.index += 1;
+
+        Some(F::from_bits(*i))
+    }
+}
+
+/// Test all subnormals up to `1 << 22`.
+pub struct SubnormComplete<F: Float> {
+    iter: RangeInclusive<F::Int>,
+}
+
+impl<F: Float> Generator<F> for SubnormComplete<F>
+where
+    RangeInclusive<F::Int>: Iterator<Item = F::Int>,
+{
+    const NAME: &'static str = "subnormal";
+    const SHORT_NAME: &'static str = "subnorm ";
+
+    type WriteCtx = F;
+
+    fn total_tests() -> u64 {
+        let iter = Self::new().iter;
+        (F::Int::ONE + *iter.end() - *iter.start()).try_into().unwrap()
+    }
+
+    fn new() -> Self {
+        let upper_lim = if F::MAN_BITS >= 22 {
+            F::Int::ONE << 22
+        } else {
+            (F::Int::ONE << F::MAN_BITS) - F::Int::ONE
+        };
+
+        Self { iter: F::Int::ZERO..=upper_lim }
+    }
+
+    fn write_string(s: &mut String, ctx: Self::WriteCtx) {
+        write!(s, "{ctx:e}").unwrap();
+    }
+}
+
+impl<F: Float> Iterator for SubnormComplete<F>
+where
+    RangeInclusive<F::Int>: Iterator<Item = F::Int>,
+{
+    type Item = F;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        Some(F::from_bits(self.iter.next()?))
+    }
+}
diff --git a/src/tools/test-float-parse/src/lib.rs b/src/tools/test-float-parse/src/lib.rs
new file mode 100644
index 00000000000..f590149523b
--- /dev/null
+++ b/src/tools/test-float-parse/src/lib.rs
@@ -0,0 +1,419 @@
+#![feature(f16)]
+#![feature(cfg_target_has_reliable_f16_f128)]
+#![expect(internal_features)] // reliable_f16_f128
+
+mod traits;
+mod ui;
+mod validate;
+
+use std::any::type_name;
+use std::cmp::min;
+use std::ops::RangeInclusive;
+use std::process::ExitCode;
+use std::sync::OnceLock;
+use std::sync::atomic::{AtomicU64, Ordering};
+use std::{fmt, time};
+
+use rand::distr::{Distribution, StandardUniform};
+use rayon::prelude::*;
+use time::{Duration, Instant};
+use traits::{Float, Generator, Int};
+use validate::CheckError;
+
+/// Test generators.
+mod gen_ {
+    pub mod exhaustive;
+    pub mod exponents;
+    pub mod fuzz;
+    pub mod integers;
+    pub mod long_fractions;
+    pub mod many_digits;
+    pub mod sparse;
+    pub mod spot_checks;
+    pub mod subnorm;
+}
+
+/// How many failures to exit after if unspecified.
+const DEFAULT_MAX_FAILURES: u64 = 20;
+
+/// Register exhaustive tests only for <= 32 bits. No more because it would take years.
+const MAX_BITS_FOR_EXHAUUSTIVE: u32 = 32;
+
+/// If there are more tests than this threshold, the test will be deferred until after all
+/// others run (so as to avoid thread pool starvation). They also can be excluded with
+/// `--skip-huge`.
+const HUGE_TEST_CUTOFF: u64 = 5_000_000;
+
+/// Seed for tests that use a deterministic RNG.
+const SEED: [u8; 32] = *b"3.141592653589793238462643383279";
+
+/// Global configuration.
+#[derive(Debug)]
+pub struct Config {
+    pub timeout: Duration,
+    /// Failures per test
+    pub max_failures: u64,
+    pub disable_max_failures: bool,
+    /// If `None`, the default will be used
+    pub fuzz_count: Option<u64>,
+    pub skip_huge: bool,
+}
+
+impl Default for Config {
+    fn default() -> Self {
+        Self {
+            timeout: Duration::from_secs(60 * 60 * 3),
+            max_failures: DEFAULT_MAX_FAILURES,
+            disable_max_failures: false,
+            fuzz_count: None,
+            skip_huge: false,
+        }
+    }
+}
+
+/// Collect, filter, and launch all tests.
+pub fn run(cfg: Config, include: &[String], exclude: &[String]) -> ExitCode {
+    // With default parallelism, the CPU doesn't saturate. We don't need to be nice to
+    // other processes, so do 1.5x to make sure we use all available resources.
+    let threads = std::thread::available_parallelism().map(Into::into).unwrap_or(0) * 3 / 2;
+    rayon::ThreadPoolBuilder::new().num_threads(threads).build_global().unwrap();
+
+    let mut tests = register_tests(&cfg);
+    println!("registered");
+    let initial_tests: Vec<_> = tests.iter().map(|t| t.name.clone()).collect();
+
+    let unmatched: Vec<_> = include
+        .iter()
+        .chain(exclude.iter())
+        .filter(|filt| !tests.iter().any(|t| t.matches(filt)))
+        .collect();
+
+    assert!(
+        unmatched.is_empty(),
+        "filters were provided that have no matching tests: {unmatched:#?}"
+    );
+
+    tests.retain(|test| !exclude.iter().any(|exc| test.matches(exc)));
+
+    if cfg.skip_huge {
+        tests.retain(|test| !test.is_huge_test());
+    }
+
+    if !include.is_empty() {
+        tests.retain(|test| include.iter().any(|inc| test.matches(inc)));
+    }
+
+    for exc in initial_tests.iter().filter(|orig_name| !tests.iter().any(|t| t.name == **orig_name))
+    {
+        println!("Skipping test '{exc}'");
+    }
+
+    println!("Launching all");
+    let elapsed = launch_tests(&mut tests, &cfg);
+    ui::finish_all(&tests, elapsed, &cfg)
+}
+
+/// Enumerate tests to run but don't actually run them.
+pub fn register_tests(cfg: &Config) -> Vec<TestInfo> {
+    let mut tests = Vec::new();
+
+    // Register normal generators for all floats.
+
+    #[cfg(not(bootstrap))]
+    #[cfg(target_has_reliable_f16)]
+    register_float::<f16>(&mut tests, cfg);
+    register_float::<f32>(&mut tests, cfg);
+    register_float::<f64>(&mut tests, cfg);
+
+    tests.sort_unstable_by_key(|t| (t.float_name, t.gen_name));
+    for i in 0..(tests.len() - 1) {
+        if tests[i].gen_name == tests[i + 1].gen_name {
+            panic!("duplicate test name {}", tests[i].gen_name);
+        }
+    }
+
+    tests
+}
+
+/// Register all generators for a single float.
+fn register_float<F: Float>(tests: &mut Vec<TestInfo>, cfg: &Config)
+where
+    RangeInclusive<F::Int>: Iterator<Item = F::Int>,
+    <F::Int as TryFrom<u128>>::Error: std::fmt::Debug,
+    StandardUniform: Distribution<<F as traits::Float>::Int>,
+{
+    if F::BITS <= MAX_BITS_FOR_EXHAUUSTIVE {
+        // Only run exhaustive tests if there is a chance of completion.
+        TestInfo::register::<F, gen_::exhaustive::Exhaustive<F>>(tests);
+    }
+
+    gen_::fuzz::Fuzz::<F>::set_iterations(cfg.fuzz_count);
+
+    TestInfo::register::<F, gen_::exponents::LargeExponents<F>>(tests);
+    TestInfo::register::<F, gen_::exponents::SmallExponents<F>>(tests);
+    TestInfo::register::<F, gen_::fuzz::Fuzz<F>>(tests);
+    TestInfo::register::<F, gen_::integers::LargeInt<F>>(tests);
+    TestInfo::register::<F, gen_::integers::SmallInt>(tests);
+    TestInfo::register::<F, gen_::long_fractions::RepeatingDecimal>(tests);
+    TestInfo::register::<F, gen_::many_digits::RandDigits<F>>(tests);
+    TestInfo::register::<F, gen_::sparse::FewOnesFloat<F>>(tests);
+    TestInfo::register::<F, gen_::sparse::FewOnesInt<F>>(tests);
+    TestInfo::register::<F, gen_::spot_checks::RegressionCheck>(tests);
+    TestInfo::register::<F, gen_::spot_checks::Special>(tests);
+    TestInfo::register::<F, gen_::subnorm::SubnormComplete<F>>(tests);
+    TestInfo::register::<F, gen_::subnorm::SubnormEdgeCases<F>>(tests);
+}
+
+/// Configuration for a single test.
+#[derive(Debug)]
+pub struct TestInfo {
+    pub name: String,
+    float_name: &'static str,
+    float_bits: u32,
+    gen_name: &'static str,
+    /// Name for display in the progress bar.
+    short_name: String,
+    /// Pad the short name to a common width for progress bar use.
+    short_name_padded: String,
+    total_tests: u64,
+    /// Function to launch this test.
+    launch: fn(&TestInfo, &Config),
+    /// Progress bar to be updated.
+    progress: Option<ui::Progress>,
+    /// Once completed, this will be set.
+    completed: OnceLock<Completed>,
+}
+
+impl TestInfo {
+    /// Check if either the name or short name is a match, for filtering.
+    fn matches(&self, pat: &str) -> bool {
+        self.short_name.contains(pat) || self.name.contains(pat)
+    }
+
+    /// Create a `TestInfo` for a given float and generator, then add it to a list.
+    fn register<F: Float, G: Generator<F>>(v: &mut Vec<Self>) {
+        let f_name = type_name::<F>();
+        let gen_name = G::NAME;
+        let gen_short_name = G::SHORT_NAME;
+        let name = format!("{f_name} {gen_name}");
+        let short_name = format!("{f_name} {gen_short_name}");
+        let short_name_padded = format!("{short_name:18}");
+
+        let info = TestInfo {
+            float_name: f_name,
+            float_bits: F::BITS,
+            gen_name,
+            progress: None,
+            name,
+            short_name_padded,
+            short_name,
+            launch: test_runner::<F, G>,
+            total_tests: G::total_tests(),
+            completed: OnceLock::new(),
+        };
+        v.push(info);
+    }
+
+    /// True if this should be run after all others.
+    fn is_huge_test(&self) -> bool {
+        self.total_tests >= HUGE_TEST_CUTOFF
+    }
+
+    /// When the test is finished, update progress bar messages and finalize.
+    fn complete(&self, c: Completed) {
+        self.progress.as_ref().unwrap().complete(&c, 0);
+        self.completed.set(c).unwrap();
+    }
+}
+
+/// Result of an input did not parsing successfully.
+#[derive(Clone, Debug)]
+enum CheckFailure {
+    /// Above the zero cutoff but got rounded to zero.
+    UnexpectedZero,
+    /// Below the infinity cutoff but got rounded to infinity.
+    UnexpectedInf,
+    /// Above the negative infinity cutoff but got rounded to negative infinity.
+    UnexpectedNegInf,
+    /// Got a `NaN` when none was expected.
+    UnexpectedNan,
+    /// Expected `NaN`, got none.
+    ExpectedNan,
+    /// Expected infinity, got finite.
+    ExpectedInf,
+    /// Expected negative infinity, got finite.
+    ExpectedNegInf,
+    /// The value exceeded its error tolerance.
+    InvalidReal {
+        /// Error from the expected value, as a float.
+        error_float: Option<f64>,
+        /// Error as a rational string (since it can't always be represented as a float).
+        error_str: Box<str>,
+        /// True if the error was caused by not rounding to even at the midpoint between
+        /// two representable values.
+        incorrect_midpoint_rounding: bool,
+    },
+    /// String did not parse successfully.
+    ParsingFailed(Box<str>),
+    /// A panic was caught.
+    Panic(Box<str>),
+}
+
+impl fmt::Display for CheckFailure {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            CheckFailure::UnexpectedZero => {
+                write!(f, "incorrectly rounded to 0 (expected nonzero)")
+            }
+            CheckFailure::UnexpectedInf => {
+                write!(f, "incorrectly rounded to +inf (expected finite)")
+            }
+            CheckFailure::UnexpectedNegInf => {
+                write!(f, "incorrectly rounded to -inf (expected finite)")
+            }
+            CheckFailure::UnexpectedNan => write!(f, "got a NaN where none was expected"),
+            CheckFailure::ExpectedNan => write!(f, "expected a NaN but did not get it"),
+            CheckFailure::ExpectedInf => write!(f, "expected +inf but did not get it"),
+            CheckFailure::ExpectedNegInf => write!(f, "expected -inf but did not get it"),
+            CheckFailure::InvalidReal { error_float, error_str, incorrect_midpoint_rounding } => {
+                if *incorrect_midpoint_rounding {
+                    write!(
+                        f,
+                        "midpoint between two representable values did not correctly \
+                        round to even; error: {error_str}"
+                    )?;
+                } else {
+                    write!(f, "real number did not parse correctly; error: {error_str}")?;
+                }
+
+                if let Some(float) = error_float {
+                    write!(f, " ({float})")?;
+                }
+                Ok(())
+            }
+            CheckFailure::ParsingFailed(e) => write!(f, "parsing failed: {e}"),
+            CheckFailure::Panic(e) => write!(f, "function panicked: {e}"),
+        }
+    }
+}
+
+/// Information about a completed test generator.
+#[derive(Clone, Debug)]
+struct Completed {
+    /// Finished tests (both successful and failed).
+    executed: u64,
+    /// Failed tests.
+    failures: u64,
+    /// Extra exit information if unsuccessful.
+    result: Result<FinishedAll, EarlyExit>,
+    /// If there is something to warn about (e.g bad estimate), leave it here.
+    warning: Option<Box<str>>,
+    /// Total time to run the test.
+    elapsed: Duration,
+}
+
+/// Marker for completing all tests (used in `Result` types).
+#[derive(Clone, Debug)]
+struct FinishedAll;
+
+/// Reasons for exiting early.
+#[derive(Clone, Debug)]
+enum EarlyExit {
+    Timeout,
+    MaxFailures,
+}
+
+/// Run all tests in `tests`.
+///
+/// This launches a main thread that receives messages and handlees UI updates, and uses the
+/// rest of the thread pool to execute the tests.
+fn launch_tests(tests: &mut [TestInfo], cfg: &Config) -> Duration {
+    // Run shorter tests and smaller float types first.
+    tests.sort_unstable_by_key(|test| (test.total_tests, test.float_bits));
+
+    for test in tests.iter() {
+        println!("Launching test '{}'", test.name);
+    }
+
+    let mut all_progress_bars = Vec::new();
+    let start = Instant::now();
+
+    for test in tests.iter_mut() {
+        test.progress = Some(ui::Progress::new(test, &mut all_progress_bars));
+        ui::set_panic_hook(&all_progress_bars);
+        ((test.launch)(test, cfg));
+    }
+
+    start.elapsed()
+}
+
+/// Test runer for a single generator.
+///
+/// This calls the generator's iterator multiple times (in parallel) and validates each output.
+fn test_runner<F: Float, G: Generator<F>>(test: &TestInfo, cfg: &Config) {
+    let gen_ = G::new();
+    let executed = AtomicU64::new(0);
+    let failures = AtomicU64::new(0);
+
+    let checks_per_update = min(test.total_tests, 1000);
+    let started = Instant::now();
+
+    // Function to execute for a single test iteration.
+    let check_one = |buf: &mut String, ctx: G::WriteCtx| {
+        let executed = executed.fetch_add(1, Ordering::Relaxed);
+        buf.clear();
+        G::write_string(buf, ctx);
+
+        match validate::validate::<F>(buf) {
+            Ok(()) => (),
+            Err(e) => {
+                let CheckError { fail, input, float_res } = e;
+                test.progress.as_ref().unwrap().println(&format!(
+                    "Failure in '{}': {fail}. parsing '{input}'. Parsed as: {float_res}",
+                    test.name
+                ));
+
+                let f = failures.fetch_add(1, Ordering::Relaxed);
+                // End early if the limit is exceeded.
+                if f >= cfg.max_failures {
+                    return Err(EarlyExit::MaxFailures);
+                }
+            }
+        };
+
+        // Send periodic updates
+        if executed % checks_per_update == 0 {
+            let failures = failures.load(Ordering::Relaxed);
+            test.progress.as_ref().unwrap().update(executed, failures);
+            if started.elapsed() > cfg.timeout {
+                return Err(EarlyExit::Timeout);
+            }
+        }
+
+        Ok(())
+    };
+
+    // Run the test iterations in parallel. Each thread gets a string buffer to write
+    // its check values to.
+    let res = gen_.par_bridge().try_for_each_init(String::new, check_one);
+
+    let elapsed = started.elapsed();
+    let executed = executed.into_inner();
+    let failures = failures.into_inner();
+
+    // Warn about bad estimates if relevant.
+    let warning = if executed != test.total_tests && res.is_ok() {
+        let msg = format!(
+            "executed tests != estimated ({executed} != {}) for {}",
+            test.total_tests,
+            G::NAME
+        );
+
+        Some(msg.into())
+    } else {
+        None
+    };
+
+    let result = res.map(|()| FinishedAll);
+    test.complete(Completed { executed, failures, result, warning, elapsed });
+}
diff --git a/src/tools/test-float-parse/src/main.rs b/src/tools/test-float-parse/src/main.rs
new file mode 100644
index 00000000000..9c6cad7324f
--- /dev/null
+++ b/src/tools/test-float-parse/src/main.rs
@@ -0,0 +1,129 @@
+use std::process::ExitCode;
+use std::time::Duration;
+
+use test_float_parse as tfp;
+
+static HELP: &str = r#"Usage:
+
+  ./test-float-parse [--timeout x] [--exclude x] [--max-failures x] [INCLUDE ...]
+  ./test-float-parse [--fuzz-count x] [INCLUDE ...]
+  ./test-float-parse [--skip-huge] [INCLUDE ...]
+  ./test-float-parse --list
+
+Args:
+
+  INCLUDE                  Include only tests with names containing these
+                           strings. If this argument is not specified, all tests
+                           are run.
+  --timeout N              Exit after this amount of time (in seconds).
+  --exclude FILTER         Skip tests containing this string. May be specified
+                           more than once.
+  --list                   List available tests.
+  --max-failures N         Limit to N failures per test. Defaults to 20. Pass
+                           "--max-failures none" to remove this limit.
+  --fuzz-count N           Run the fuzzer with N iterations. Only has an effect
+                           if fuzz tests are enabled. Pass `--fuzz-count none`
+                           to remove this limit.
+  --skip-huge              Skip tests that run for a long time.
+  --all                    Reset previous `--exclude`, `--skip-huge`, and
+                           `INCLUDE` arguments (useful for running all tests
+                           via `./x`).
+"#;
+
+enum ArgMode {
+    Any,
+    Timeout,
+    Exclude,
+    FuzzCount,
+    MaxFailures,
+}
+
+fn main() -> ExitCode {
+    if cfg!(debug_assertions) {
+        println!(
+            "WARNING: running in debug mode. Release mode is recommended to reduce test duration."
+        );
+        std::thread::sleep(Duration::from_secs(2));
+    }
+
+    let args: Vec<_> = std::env::args().skip(1).collect();
+    if args.iter().any(|arg| arg == "--help" || arg == "-h") {
+        println!("{HELP}");
+        return ExitCode::SUCCESS;
+    }
+
+    if args.iter().any(|arg| arg == "--list") {
+        let tests = tfp::register_tests(&tfp::Config::default());
+        println!("Available tests:");
+        for t in tests {
+            println!("{}", t.name);
+        }
+
+        return ExitCode::SUCCESS;
+    }
+
+    let (cfg, include, exclude) = parse_args(args);
+
+    tfp::run(cfg, &include, &exclude)
+}
+
+/// Simple command argument parser
+fn parse_args(args: Vec<String>) -> (tfp::Config, Vec<String>, Vec<String>) {
+    let mut cfg = tfp::Config::default();
+
+    let mut mode = ArgMode::Any;
+    let mut include = Vec::new();
+    let mut exclude = Vec::new();
+
+    for arg in args {
+        mode = match mode {
+            ArgMode::Any if arg == "--timeout" => ArgMode::Timeout,
+            ArgMode::Any if arg == "--exclude" => ArgMode::Exclude,
+            ArgMode::Any if arg == "--max-failures" => ArgMode::MaxFailures,
+            ArgMode::Any if arg == "--fuzz-count" => ArgMode::FuzzCount,
+            ArgMode::Any if arg == "--skip-huge" => {
+                cfg.skip_huge = true;
+                ArgMode::Any
+            }
+            ArgMode::Any if arg == "--all" => {
+                cfg.skip_huge = false;
+                include.clear();
+                exclude.clear();
+                ArgMode::Any
+            }
+            ArgMode::Any if arg.starts_with('-') => {
+                panic!("Unknown argument {arg}. Usage:\n{HELP}")
+            }
+            ArgMode::Any => {
+                include.push(arg);
+                ArgMode::Any
+            }
+            ArgMode::Timeout => {
+                cfg.timeout = Duration::from_secs(arg.parse().unwrap());
+                ArgMode::Any
+            }
+            ArgMode::MaxFailures => {
+                if arg == "none" {
+                    cfg.disable_max_failures = true;
+                } else {
+                    cfg.max_failures = arg.parse().unwrap();
+                }
+                ArgMode::Any
+            }
+            ArgMode::FuzzCount => {
+                if arg == "none" {
+                    cfg.fuzz_count = Some(u64::MAX);
+                } else {
+                    cfg.fuzz_count = Some(arg.parse().unwrap());
+                }
+                ArgMode::Any
+            }
+            ArgMode::Exclude => {
+                exclude.push(arg);
+                ArgMode::Any
+            }
+        }
+    }
+
+    (cfg, include, exclude)
+}
diff --git a/src/tools/test-float-parse/src/traits.rs b/src/tools/test-float-parse/src/traits.rs
new file mode 100644
index 00000000000..16484f8fe2c
--- /dev/null
+++ b/src/tools/test-float-parse/src/traits.rs
@@ -0,0 +1,206 @@
+//! Interfaces used throughout this crate.
+
+use std::str::FromStr;
+use std::{fmt, ops};
+
+use num::Integer;
+use num::bigint::ToBigInt;
+
+use crate::validate::Constants;
+
+/// Integer types.
+#[allow(dead_code)] // Some functions only used for testing
+pub trait Int:
+    Clone
+    + Copy
+    + fmt::Debug
+    + fmt::Display
+    + fmt::LowerHex
+    + ops::Add<Output = Self>
+    + ops::Sub<Output = Self>
+    + ops::Shl<u32, Output = Self>
+    + ops::Shr<u32, Output = Self>
+    + ops::BitAnd<Output = Self>
+    + ops::BitOr<Output = Self>
+    + ops::Not<Output = Self>
+    + ops::AddAssign
+    + ops::BitAndAssign
+    + ops::BitOrAssign
+    + From<u8>
+    + TryFrom<i8>
+    + TryFrom<u32, Error: fmt::Debug>
+    + TryFrom<u64, Error: fmt::Debug>
+    + TryFrom<u128, Error: fmt::Debug>
+    + TryInto<u64, Error: fmt::Debug>
+    + TryInto<u32, Error: fmt::Debug>
+    + ToBigInt
+    + PartialOrd
+    + Integer
+    + Send
+    + 'static
+{
+    type Signed: Int;
+    type Bytes: Default + AsMut<[u8]>;
+
+    const BITS: u32;
+    const ZERO: Self;
+    const ONE: Self;
+    const MAX: Self;
+
+    fn to_signed(self) -> Self::Signed;
+    fn wrapping_neg(self) -> Self;
+    fn trailing_zeros(self) -> u32;
+
+    fn hex(self) -> String {
+        format!("{self:x}")
+    }
+}
+
+macro_rules! impl_int {
+    ($($uty:ty, $sty:ty);+) => {
+        $(
+            impl Int for $uty {
+                type Signed = $sty;
+                type Bytes = [u8; Self::BITS as usize / 8];
+                const BITS: u32 = Self::BITS;
+                const ZERO: Self = 0;
+                const ONE: Self = 1;
+                const MAX: Self = Self::MAX;
+                fn to_signed(self) -> Self::Signed {
+                    self.try_into().unwrap()
+                }
+                fn wrapping_neg(self) -> Self {
+                    self.wrapping_neg()
+                }
+                fn trailing_zeros(self) -> u32 {
+                    self.trailing_zeros()
+                }
+            }
+
+            impl Int for $sty {
+                type Signed = Self;
+                type Bytes = [u8; Self::BITS as usize / 8];
+                const BITS: u32 = Self::BITS;
+                const ZERO: Self = 0;
+                const ONE: Self = 1;
+                const MAX: Self = Self::MAX;
+                fn to_signed(self) -> Self::Signed {
+                    self
+                }
+                fn wrapping_neg(self) -> Self {
+                    self.wrapping_neg()
+                }
+                fn trailing_zeros(self) -> u32 {
+                    self.trailing_zeros()
+                }
+            }
+        )+
+    }
+}
+
+impl_int!(u16, i16; u32, i32; u64, i64);
+
+/// Floating point types.
+pub trait Float:
+    Copy + fmt::Debug + fmt::LowerExp + FromStr<Err: fmt::Display> + Sized + Send + 'static
+{
+    /// Unsigned integer of same width
+    type Int: Int<Signed = Self::SInt>;
+    type SInt: Int;
+
+    /// Total bits
+    const BITS: u32;
+
+    /// (Stored) bits in the mantissa)
+    const MAN_BITS: u32;
+
+    /// Bits in the exponent
+    const EXP_BITS: u32 = Self::BITS - Self::MAN_BITS - 1;
+
+    /// A saturated exponent (all ones)
+    const EXP_SAT: u32 = (1 << Self::EXP_BITS) - 1;
+
+    /// The exponent bias, also its maximum value
+    const EXP_BIAS: u32 = Self::EXP_SAT >> 1;
+
+    const MAN_MASK: Self::Int;
+    const SIGN_MASK: Self::Int;
+
+    fn from_bits(i: Self::Int) -> Self;
+    fn to_bits(self) -> Self::Int;
+
+    /// Rational constants associated with this float type.
+    fn constants() -> &'static Constants;
+
+    fn is_sign_negative(self) -> bool {
+        (self.to_bits() & Self::SIGN_MASK) > Self::Int::ZERO
+    }
+
+    /// Exponent without adjustment for bias.
+    fn exponent(self) -> u32 {
+        ((self.to_bits() >> Self::MAN_BITS) & Self::EXP_SAT.try_into().unwrap()).try_into().unwrap()
+    }
+
+    fn mantissa(self) -> Self::Int {
+        self.to_bits() & Self::MAN_MASK
+    }
+}
+
+macro_rules! impl_float {
+    ($($fty:ty, $ity:ty);+) => {
+        $(
+            impl Float for $fty {
+                type Int = $ity;
+                type SInt = <Self::Int as Int>::Signed;
+                const BITS: u32 = <$ity>::BITS;
+                const MAN_BITS: u32 = Self::MANTISSA_DIGITS - 1;
+                const MAN_MASK: Self::Int = (Self::Int::ONE << Self::MAN_BITS) - Self::Int::ONE;
+                const SIGN_MASK: Self::Int = Self::Int::ONE << (Self::BITS-1);
+                fn from_bits(i: Self::Int) -> Self { Self::from_bits(i) }
+                fn to_bits(self) -> Self::Int { self.to_bits() }
+                fn constants() -> &'static Constants {
+                    use std::sync::LazyLock;
+                    static CONSTANTS: LazyLock<Constants> = LazyLock::new(Constants::new::<$fty>);
+                    &CONSTANTS
+                }
+            }
+        )+
+    }
+}
+
+impl_float!(f32, u32; f64, u64);
+
+#[cfg(not(bootstrap))]
+#[cfg(target_has_reliable_f16)]
+impl_float!(f16, u16);
+
+/// A test generator. Should provide an iterator that produces unique patterns to parse.
+///
+/// The iterator needs to provide a `WriteCtx` (could be anything), which is then used to
+/// write the string at a later step. This is done separately so that we can reuse string
+/// allocations (which otherwise turn out to be a pretty expensive part of these tests).
+pub trait Generator<F: Float>: Iterator<Item = Self::WriteCtx> + Send + 'static {
+    /// Full display and filtering name
+    const NAME: &'static str = Self::SHORT_NAME;
+
+    /// Name for display with the progress bar
+    const SHORT_NAME: &'static str;
+
+    /// The context needed to create a test string.
+    type WriteCtx: Send;
+
+    /// Number of tests that will be run.
+    fn total_tests() -> u64;
+
+    /// Constructor for this test generator.
+    fn new() -> Self;
+
+    /// Create a test string given write context, which was produced as a step from the iterator.
+    ///
+    /// `s` will be provided empty.
+    fn write_string(s: &mut String, ctx: Self::WriteCtx);
+}
+
+/// For tests that use iterator combinators, it is easier to just to box the iterator than trying
+/// to specify its type. This is a shorthand for the usual type.
+pub type BoxGenIter<This, F> = Box<dyn Iterator<Item = <This as Generator<F>>::WriteCtx> + Send>;
diff --git a/src/tools/test-float-parse/src/ui.rs b/src/tools/test-float-parse/src/ui.rs
new file mode 100644
index 00000000000..73473eef0bf
--- /dev/null
+++ b/src/tools/test-float-parse/src/ui.rs
@@ -0,0 +1,168 @@
+//! Progress bars and such.
+
+use std::any::type_name;
+use std::fmt;
+use std::io::{self, Write};
+use std::process::ExitCode;
+use std::time::Duration;
+
+use indicatif::{ProgressBar, ProgressStyle};
+
+use crate::{Completed, Config, EarlyExit, FinishedAll, TestInfo};
+
+/// Templates for progress bars.
+const PB_TEMPLATE: &str = "[{elapsed:3} {percent:3}%] {bar:20.cyan/blue} NAME \
+        {human_pos:>8}/{human_len:8} {msg} f {per_sec:14} eta {eta:8}";
+const PB_TEMPLATE_FINAL: &str = "[{elapsed:3} {percent:3}%] {bar:20.cyan/blue} NAME \
+        {human_pos:>8}/{human_len:8} {msg:.COLOR} {per_sec:18} {elapsed_precise}";
+
+/// Thin abstraction over our usage of a `ProgressBar`.
+#[derive(Debug)]
+pub struct Progress {
+    pb: ProgressBar,
+    make_final_style: NoDebug<Box<dyn Fn(&'static str) -> ProgressStyle + Sync>>,
+}
+
+impl Progress {
+    /// Create a new progress bar within a multiprogress bar.
+    pub fn new(test: &TestInfo, all_bars: &mut Vec<ProgressBar>) -> Self {
+        let initial_template = PB_TEMPLATE.replace("NAME", &test.short_name_padded);
+        let final_template = PB_TEMPLATE_FINAL.replace("NAME", &test.short_name_padded);
+        let initial_style =
+            ProgressStyle::with_template(&initial_template).unwrap().progress_chars("##-");
+        let make_final_style = move |color| {
+            ProgressStyle::with_template(&final_template.replace("COLOR", color))
+                .unwrap()
+                .progress_chars("##-")
+        };
+
+        let pb = ProgressBar::new(test.total_tests);
+        pb.set_style(initial_style);
+        pb.set_length(test.total_tests);
+        pb.set_message("0");
+        all_bars.push(pb.clone());
+
+        Progress { pb, make_final_style: NoDebug(Box::new(make_final_style)) }
+    }
+
+    /// Completed a out of b tests.
+    pub fn update(&self, completed: u64, failures: u64) {
+        // Infrequently update the progress bar.
+        if completed % 5_000 == 0 || failures > 0 {
+            self.pb.set_position(completed);
+        }
+
+        if failures > 0 {
+            self.pb.set_message(format! {"{failures}"});
+        }
+    }
+
+    /// Finalize the progress bar.
+    pub fn complete(&self, c: &Completed, real_total: u64) {
+        let f = c.failures;
+        let (color, msg, finish_fn): (&str, String, fn(&ProgressBar)) = match &c.result {
+            Ok(FinishedAll) if f > 0 => {
+                ("red", format!("{f} f (completed with errors)",), ProgressBar::finish)
+            }
+            Ok(FinishedAll) => {
+                ("green", format!("{f} f (completed successfully)",), ProgressBar::finish)
+            }
+            Err(EarlyExit::Timeout) => ("red", format!("{f} f (timed out)"), ProgressBar::abandon),
+            Err(EarlyExit::MaxFailures) => {
+                ("red", format!("{f} f (failure limit)"), ProgressBar::abandon)
+            }
+        };
+
+        self.pb.set_position(real_total);
+        self.pb.set_style(self.make_final_style.0(color));
+        self.pb.set_message(msg);
+        finish_fn(&self.pb);
+    }
+
+    /// Print a message to stdout above the current progress bar.
+    pub fn println(&self, msg: &str) {
+        self.pb.suspend(|| println!("{msg}"));
+    }
+}
+
+/// Print final messages after all tests are complete.
+pub fn finish_all(tests: &[TestInfo], total_elapsed: Duration, cfg: &Config) -> ExitCode {
+    println!("\n\nResults:");
+
+    let mut failed_generators = 0;
+    let mut stopped_generators = 0;
+
+    for t in tests {
+        let Completed { executed, failures, elapsed, warning, result } = t.completed.get().unwrap();
+
+        let stat = if result.is_err() {
+            stopped_generators += 1;
+            "STOPPED"
+        } else if *failures > 0 {
+            failed_generators += 1;
+            "FAILURE"
+        } else {
+            "SUCCESS"
+        };
+
+        println!(
+            "    {stat} for generator '{name}'. {passed}/{executed} passed in {elapsed:?}",
+            name = t.name,
+            passed = executed - failures,
+        );
+
+        if let Some(warning) = warning {
+            println!("      warning: {warning}");
+        }
+
+        match result {
+            Ok(FinishedAll) => (),
+            Err(EarlyExit::Timeout) => {
+                println!("      exited early; exceded {:?} timeout", cfg.timeout)
+            }
+            Err(EarlyExit::MaxFailures) => {
+                println!("      exited early; exceeded {:?} max failures", cfg.max_failures)
+            }
+        }
+    }
+
+    println!(
+        "{passed}/{} tests succeeded in {total_elapsed:?} ({passed} passed, {} failed, {} stopped)",
+        tests.len(),
+        failed_generators,
+        stopped_generators,
+        passed = tests.len() - failed_generators - stopped_generators,
+    );
+
+    if failed_generators > 0 || stopped_generators > 0 {
+        ExitCode::FAILURE
+    } else {
+        ExitCode::SUCCESS
+    }
+}
+
+/// indicatif likes to eat panic messages. This workaround isn't ideal, but it improves things.
+/// <https://github.com/console-rs/indicatif/issues/121>.
+pub fn set_panic_hook(drop_bars: &[ProgressBar]) {
+    let hook = std::panic::take_hook();
+    let drop_bars = drop_bars.to_owned();
+    std::panic::set_hook(Box::new(move |info| {
+        for bar in &drop_bars {
+            bar.abandon();
+            println!();
+            io::stdout().flush().unwrap();
+            io::stderr().flush().unwrap();
+        }
+        hook(info);
+    }));
+}
+
+/// Allow non-Debug items in a `derive(Debug)` struct.
+#[derive(Clone)]
+struct NoDebug<T>(T);
+
+impl<T> fmt::Debug for NoDebug<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str(type_name::<Self>())
+    }
+}
diff --git a/src/tools/test-float-parse/src/validate.rs b/src/tools/test-float-parse/src/validate.rs
new file mode 100644
index 00000000000..40dda274e3b
--- /dev/null
+++ b/src/tools/test-float-parse/src/validate.rs
@@ -0,0 +1,394 @@
+//! Everything related to verifying that parsed outputs are correct.
+
+use std::any::{Any, type_name};
+use std::collections::BTreeMap;
+use std::ops::RangeInclusive;
+use std::str::FromStr;
+use std::sync::LazyLock;
+
+use num::bigint::ToBigInt;
+use num::{BigInt, BigRational, FromPrimitive, Signed, ToPrimitive};
+
+use crate::{CheckFailure, Float, Int};
+
+/// Powers of two that we store for constants. Account for binary128 which has a 15-bit exponent.
+const POWERS_OF_TWO_RANGE: RangeInclusive<i32> = (-(2 << 15))..=(2 << 15);
+
+/// Powers of ten that we cache. Account for binary128, which can fit +4932/-4931
+const POWERS_OF_TEN_RANGE: RangeInclusive<i32> = -5_000..=5_000;
+
+/// Cached powers of 10 so we can look them up rather than recreating.
+static POWERS_OF_TEN: LazyLock<BTreeMap<i32, BigRational>> = LazyLock::new(|| {
+    POWERS_OF_TEN_RANGE.map(|exp| (exp, BigRational::from_u32(10).unwrap().pow(exp))).collect()
+});
+
+/// Rational property-related constants for a specific float type.
+#[allow(dead_code)]
+#[derive(Debug)]
+pub struct Constants {
+    /// The minimum positive value (a subnormal).
+    min_subnormal: BigRational,
+    /// The maximum possible finite value.
+    max: BigRational,
+    /// Cutoff between rounding to zero and rounding to the minimum value (min subnormal).
+    zero_cutoff: BigRational,
+    /// Cutoff between rounding to the max value and rounding to infinity.
+    inf_cutoff: BigRational,
+    /// Opposite of `inf_cutoff`
+    neg_inf_cutoff: BigRational,
+    /// The powers of two for all relevant integers.
+    powers_of_two: BTreeMap<i32, BigRational>,
+    /// Half of each power of two. ULP = "unit in last position".
+    ///
+    /// This is a mapping from integers to half the precision available at that exponent. In other
+    /// words, `0.5 * 2^n` = `2^(n-1)`, which is half the distance between `m * 2^n` and
+    /// `(m + 1) * 2^n`, m ∈ ℤ.
+    ///
+    /// So, this is the maximum error from a real number to its floating point representation,
+    /// assuming the float type can represent the exponent.
+    half_ulp: BTreeMap<i32, BigRational>,
+    /// Handy to have around so we don't need to reallocate for it
+    two: BigInt,
+}
+
+impl Constants {
+    pub fn new<F: Float>() -> Self {
+        let two_int = &BigInt::from_u32(2).unwrap();
+        let two = &BigRational::from_integer(2.into());
+
+        // The minimum subnormal (aka minimum positive) value. Most negative power of two is the
+        // minimum exponent (bias - 1) plus the extra from shifting within the mantissa bits.
+        let min_subnormal = two.pow(-(F::EXP_BIAS + F::MAN_BITS - 1).to_signed());
+
+        // The maximum value is the maximum exponent with a fully saturated mantissa. This
+        // is easiest to calculate by evaluating what the next value up would be if representable
+        // (zeroed mantissa, exponent increments by one, i.e. `2^(bias + 1)`), and subtracting
+        // a single LSB (`2 ^ (-mantissa_bits)`).
+        let max = (two - two.pow(-F::MAN_BITS.to_signed())) * (two.pow(F::EXP_BIAS.to_signed()));
+        let zero_cutoff = &min_subnormal / two_int;
+
+        let inf_cutoff = &max + two_int.pow(F::EXP_BIAS - F::MAN_BITS - 1);
+        let neg_inf_cutoff = -&inf_cutoff;
+
+        let powers_of_two: BTreeMap<i32, _> =
+            (POWERS_OF_TWO_RANGE).map(|n| (n, two.pow(n))).collect();
+        let mut half_ulp = powers_of_two.clone();
+        half_ulp.iter_mut().for_each(|(_k, v)| *v = &*v / two_int);
+
+        Self {
+            min_subnormal,
+            max,
+            zero_cutoff,
+            inf_cutoff,
+            neg_inf_cutoff,
+            powers_of_two,
+            half_ulp,
+            two: two_int.clone(),
+        }
+    }
+}
+
+/// Validate that a string parses correctly
+pub fn validate<F: Float>(input: &str) -> Result<(), CheckError> {
+    // Catch panics in case debug assertions within `std` fail.
+    let parsed = std::panic::catch_unwind(|| {
+        input.parse::<F>().map_err(|e| CheckError {
+            fail: CheckFailure::ParsingFailed(e.to_string().into()),
+            input: input.into(),
+            float_res: "none".into(),
+        })
+    })
+    .map_err(|e| convert_panic_error(&e, input))??;
+
+    // Parsed float, decoded into significand and exponent
+    let decoded = decode(parsed);
+
+    // Float parsed separately into a rational
+    let rational = Rational::parse(input);
+
+    // Verify that the values match
+    decoded.check(rational, input)
+}
+
+/// Turn panics into concrete error types.
+fn convert_panic_error(e: &dyn Any, input: &str) -> CheckError {
+    let msg = e
+        .downcast_ref::<String>()
+        .map(|s| s.as_str())
+        .or_else(|| e.downcast_ref::<&str>().copied())
+        .unwrap_or("(no contents)");
+
+    CheckError {
+        fail: CheckFailure::Panic(msg.into()),
+        input: input.into(),
+        float_res: "none".into(),
+    }
+}
+
+/// The result of parsing a string to a float type.
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum FloatRes<F: Float> {
+    Inf,
+    NegInf,
+    Zero,
+    Nan,
+    /// A real number with significand and exponent. Value is `sig * 2 ^ exp`.
+    Real {
+        sig: F::SInt,
+        exp: i32,
+    },
+}
+
+#[derive(Clone, Debug)]
+pub struct CheckError {
+    pub fail: CheckFailure,
+    /// String for which parsing was attempted.
+    pub input: Box<str>,
+    /// The parsed & decomposed `FloatRes`, already stringified so we don't need generics here.
+    pub float_res: Box<str>,
+}
+
+impl<F: Float> FloatRes<F> {
+    /// Given a known exact rational, check that this representation is accurate within the
+    /// limits of the float representation. If not, construct a failure `Update` to send.
+    fn check(self, expected: Rational, input: &str) -> Result<(), CheckError> {
+        let consts = F::constants();
+        // let bool_helper = |cond: bool, err| cond.then_some(()).ok_or(err);
+
+        let res = match (expected, self) {
+            // Easy correct cases
+            (Rational::Inf, FloatRes::Inf)
+            | (Rational::NegInf, FloatRes::NegInf)
+            | (Rational::Nan, FloatRes::Nan) => Ok(()),
+
+            // Easy incorrect cases
+            (
+                Rational::Inf,
+                FloatRes::NegInf | FloatRes::Zero | FloatRes::Nan | FloatRes::Real { .. },
+            ) => Err(CheckFailure::ExpectedInf),
+            (
+                Rational::NegInf,
+                FloatRes::Inf | FloatRes::Zero | FloatRes::Nan | FloatRes::Real { .. },
+            ) => Err(CheckFailure::ExpectedNegInf),
+            (
+                Rational::Nan,
+                FloatRes::Inf | FloatRes::NegInf | FloatRes::Zero | FloatRes::Real { .. },
+            ) => Err(CheckFailure::ExpectedNan),
+            (Rational::Finite(_), FloatRes::Nan) => Err(CheckFailure::UnexpectedNan),
+
+            // Cases near limits
+            (Rational::Finite(r), FloatRes::Zero) => {
+                if r <= consts.zero_cutoff {
+                    Ok(())
+                } else {
+                    Err(CheckFailure::UnexpectedZero)
+                }
+            }
+            (Rational::Finite(r), FloatRes::Inf) => {
+                if r >= consts.inf_cutoff {
+                    Ok(())
+                } else {
+                    Err(CheckFailure::UnexpectedInf)
+                }
+            }
+            (Rational::Finite(r), FloatRes::NegInf) => {
+                if r <= consts.neg_inf_cutoff {
+                    Ok(())
+                } else {
+                    Err(CheckFailure::UnexpectedNegInf)
+                }
+            }
+
+            // Actual numbers
+            (Rational::Finite(r), FloatRes::Real { sig, exp }) => Self::validate_real(r, sig, exp),
+        };
+
+        res.map_err(|fail| CheckError {
+            fail,
+            input: input.into(),
+            float_res: format!("{self:?}").into(),
+        })
+    }
+
+    /// Check that `sig * 2^exp` is the same as `rational`, within the float's error margin.
+    fn validate_real(rational: BigRational, sig: F::SInt, exp: i32) -> Result<(), CheckFailure> {
+        let consts = F::constants();
+
+        // `2^exp`. Use cached powers of two to be faster.
+        let two_exp = consts
+            .powers_of_two
+            .get(&exp)
+            .unwrap_or_else(|| panic!("missing exponent {exp} for {}", type_name::<F>()));
+
+        // Rational from the parsed value, `sig * 2^exp`
+        let parsed_rational = two_exp * sig.to_bigint().unwrap();
+        let error = (parsed_rational - &rational).abs();
+
+        // Determine acceptable error at this exponent, which is halfway between this value
+        // (`sig * 2^exp`) and the next value up (`(sig+1) * 2^exp`).
+        let half_ulp = consts.half_ulp.get(&exp).unwrap();
+
+        // If we are within one error value (but not equal) then we rounded correctly.
+        if &error < half_ulp {
+            return Ok(());
+        }
+
+        // For values where we are exactly between two representable values, meaning that the error
+        // is exactly one half of the precision at that exponent, we need to round to an even
+        // binary value (i.e. mantissa ends in 0).
+        let incorrect_midpoint_rounding = if &error == half_ulp {
+            if sig & F::SInt::ONE == F::SInt::ZERO {
+                return Ok(());
+            }
+
+            // We rounded to odd rather than even; failing based on midpoint rounding.
+            true
+        } else {
+            // We are out of spec for some other reason.
+            false
+        };
+
+        let one_ulp = consts.half_ulp.get(&(exp + 1)).unwrap();
+        assert_eq!(one_ulp, &(half_ulp * &consts.two), "ULP values are incorrect");
+
+        let relative_error = error / one_ulp;
+
+        Err(CheckFailure::InvalidReal {
+            error_float: relative_error.to_f64(),
+            error_str: relative_error.to_string().into(),
+            incorrect_midpoint_rounding,
+        })
+    }
+
+    /// Remove trailing zeros in the significand and adjust the exponent
+    #[cfg(test)]
+    fn normalize(self) -> Self {
+        use std::cmp::min;
+
+        match self {
+            Self::Real { sig, exp } => {
+                // If there are trailing zeroes, remove them and increment the exponent instead
+                let shift = min(sig.trailing_zeros(), exp.wrapping_neg().try_into().unwrap());
+                Self::Real { sig: sig >> shift, exp: exp + i32::try_from(shift).unwrap() }
+            }
+            _ => self,
+        }
+    }
+}
+
+/// Decompose a float into its integral components. This includes the implicit bit.
+///
+/// If `allow_nan` is `false`, panic if `NaN` values are reached.
+fn decode<F: Float>(f: F) -> FloatRes<F> {
+    let ione = F::SInt::ONE;
+    let izero = F::SInt::ZERO;
+
+    let mut exponent_biased = f.exponent();
+    let mut mantissa = f.mantissa().to_signed();
+
+    if exponent_biased == 0 {
+        if mantissa == izero {
+            return FloatRes::Zero;
+        }
+
+        exponent_biased += 1;
+    } else if exponent_biased == F::EXP_SAT {
+        if mantissa != izero {
+            return FloatRes::Nan;
+        }
+
+        if f.is_sign_negative() {
+            return FloatRes::NegInf;
+        }
+
+        return FloatRes::Inf;
+    } else {
+        // Set implicit bit
+        mantissa |= ione << F::MAN_BITS;
+    }
+
+    let mut exponent = i32::try_from(exponent_biased).unwrap();
+
+    // Adjust for bias and the rnage of the mantissa
+    exponent -= i32::try_from(F::EXP_BIAS + F::MAN_BITS).unwrap();
+
+    if f.is_sign_negative() {
+        mantissa = mantissa.wrapping_neg();
+    }
+
+    FloatRes::Real { sig: mantissa, exp: exponent }
+}
+
+/// A rational or its unrepresentable values.
+#[derive(Clone, Debug, PartialEq)]
+enum Rational {
+    Inf,
+    NegInf,
+    Nan,
+    Finite(BigRational),
+}
+
+impl Rational {
+    /// Turn a string into a rational. `None` if `NaN`.
+    fn parse(s: &str) -> Rational {
+        let mut s = s; // lifetime rules
+
+        if s.strip_prefix('+').unwrap_or(s).eq_ignore_ascii_case("nan")
+            || s.eq_ignore_ascii_case("-nan")
+        {
+            return Rational::Nan;
+        }
+
+        if s.strip_prefix('+').unwrap_or(s).eq_ignore_ascii_case("inf") {
+            return Rational::Inf;
+        }
+
+        if s.eq_ignore_ascii_case("-inf") {
+            return Rational::NegInf;
+        }
+
+        // Fast path; no decimals or exponents ot parse
+        if s.bytes().all(|b| b.is_ascii_digit() || b == b'-') {
+            return Rational::Finite(BigRational::from_str(s).unwrap());
+        }
+
+        let mut ten_exp: i32 = 0;
+
+        // Remove and handle e.g. `e-4`, `e+10`, `e5` suffixes
+        if let Some(pos) = s.bytes().position(|b| b == b'e' || b == b'E') {
+            let (dec, exp) = s.split_at(pos);
+            s = dec;
+            ten_exp = exp[1..].parse().unwrap();
+        }
+
+        // Remove the decimal and instead change our exponent
+        // E.g. "12.3456" becomes "123456 * 10^-4"
+        let mut s_owned;
+        if let Some(pos) = s.bytes().position(|b| b == b'.') {
+            ten_exp = ten_exp.checked_sub((s.len() - pos - 1).try_into().unwrap()).unwrap();
+            s_owned = s.to_owned();
+            s_owned.remove(pos);
+            s = &s_owned;
+        }
+
+        // let pow = BigRational::from_u32(10).unwrap().pow(ten_exp);
+        let pow =
+            POWERS_OF_TEN.get(&ten_exp).unwrap_or_else(|| panic!("missing power of ten {ten_exp}"));
+        let r = pow
+            * BigInt::from_str(s)
+                .unwrap_or_else(|e| panic!("`BigInt::from_str(\"{s}\")` failed with {e}"));
+        Rational::Finite(r)
+    }
+
+    #[cfg(test)]
+    fn expect_finite(self) -> BigRational {
+        let Self::Finite(r) = self else {
+            panic!("got non rational: {self:?}");
+        };
+
+        r
+    }
+}
+
+#[cfg(test)]
+mod tests;
diff --git a/src/tools/test-float-parse/src/validate/tests.rs b/src/tools/test-float-parse/src/validate/tests.rs
new file mode 100644
index 00000000000..ab0e7d8a7ba
--- /dev/null
+++ b/src/tools/test-float-parse/src/validate/tests.rs
@@ -0,0 +1,149 @@
+use num::ToPrimitive;
+
+use super::*;
+
+#[test]
+fn test_parse_rational() {
+    assert_eq!(Rational::parse("1234").expect_finite(), BigRational::new(1234.into(), 1.into()));
+    assert_eq!(
+        Rational::parse("-1234").expect_finite(),
+        BigRational::new((-1234).into(), 1.into())
+    );
+    assert_eq!(Rational::parse("1e+6").expect_finite(), BigRational::new(1000000.into(), 1.into()));
+    assert_eq!(Rational::parse("1e-6").expect_finite(), BigRational::new(1.into(), 1000000.into()));
+    assert_eq!(
+        Rational::parse("10.4e6").expect_finite(),
+        BigRational::new(10400000.into(), 1.into())
+    );
+    assert_eq!(
+        Rational::parse("10.4e+6").expect_finite(),
+        BigRational::new(10400000.into(), 1.into())
+    );
+    assert_eq!(
+        Rational::parse("10.4e-6").expect_finite(),
+        BigRational::new(13.into(), 1250000.into())
+    );
+    assert_eq!(
+        Rational::parse("10.4243566462342456234124").expect_finite(),
+        BigRational::new(104243566462342456234124_i128.into(), 10000000000000000000000_i128.into())
+    );
+    assert_eq!(Rational::parse("inf"), Rational::Inf);
+    assert_eq!(Rational::parse("+inf"), Rational::Inf);
+    assert_eq!(Rational::parse("-inf"), Rational::NegInf);
+    assert_eq!(Rational::parse("NaN"), Rational::Nan);
+}
+
+#[test]
+fn test_decode() {
+    assert_eq!(decode(0f32), FloatRes::Zero);
+    assert_eq!(decode(f32::INFINITY), FloatRes::Inf);
+    assert_eq!(decode(f32::NEG_INFINITY), FloatRes::NegInf);
+    assert_eq!(decode(1.0f32).normalize(), FloatRes::Real { sig: 1, exp: 0 });
+    assert_eq!(decode(-1.0f32).normalize(), FloatRes::Real { sig: -1, exp: 0 });
+    assert_eq!(decode(100.0f32).normalize(), FloatRes::Real { sig: 100, exp: 0 });
+    assert_eq!(decode(100.5f32).normalize(), FloatRes::Real { sig: 201, exp: -1 });
+    assert_eq!(decode(-4.004f32).normalize(), FloatRes::Real { sig: -8396997, exp: -21 });
+    assert_eq!(decode(0.0004f32).normalize(), FloatRes::Real { sig: 13743895, exp: -35 });
+    assert_eq!(decode(f32::from_bits(0x1)).normalize(), FloatRes::Real { sig: 1, exp: -149 });
+}
+
+#[test]
+fn test_validate() {
+    validate::<f32>("0").unwrap();
+    validate::<f32>("-0").unwrap();
+    validate::<f32>("1").unwrap();
+    validate::<f32>("-1").unwrap();
+    validate::<f32>("1.1").unwrap();
+    validate::<f32>("-1.1").unwrap();
+    validate::<f32>("1e10").unwrap();
+    validate::<f32>("1e1000").unwrap();
+    validate::<f32>("-1e1000").unwrap();
+    validate::<f32>("1e-1000").unwrap();
+    validate::<f32>("-1e-1000").unwrap();
+}
+
+#[test]
+fn test_validate_real() {
+    // Most of the arbitrary values come from checking against <http://weitz.de/ieee/>.
+    let r = &BigRational::from_float(10.0).unwrap();
+    FloatRes::<f32>::validate_real(r.clone(), 10, 0).unwrap();
+    FloatRes::<f32>::validate_real(r.clone(), 10, -1).unwrap_err();
+    FloatRes::<f32>::validate_real(r.clone(), 10, 1).unwrap_err();
+
+    let r = &BigRational::from_float(0.25).unwrap();
+    FloatRes::<f32>::validate_real(r.clone(), 1, -2).unwrap();
+    FloatRes::<f32>::validate_real(r.clone(), 2, -2).unwrap_err();
+
+    let r = &BigRational::from_float(1234.5678).unwrap();
+    FloatRes::<f32>::validate_real(r.clone(), 0b100110100101001000101011, -13).unwrap();
+    FloatRes::<f32>::validate_real(r.clone(), 0b100110100101001000101010, -13).unwrap_err();
+    FloatRes::<f32>::validate_real(r.clone(), 0b100110100101001000101100, -13).unwrap_err();
+
+    let r = &BigRational::from_float(-1234.5678).unwrap();
+    FloatRes::<f32>::validate_real(r.clone(), -0b100110100101001000101011, -13).unwrap();
+    FloatRes::<f32>::validate_real(r.clone(), -0b100110100101001000101010, -13).unwrap_err();
+    FloatRes::<f32>::validate_real(r.clone(), -0b100110100101001000101100, -13).unwrap_err();
+}
+
+#[test]
+#[allow(unused)]
+fn test_validate_real_rounding() {
+    // Check that we catch when values don't round to even.
+
+    // For f32, the cutoff between 1.0 and the next value up (1.0000001) is
+    // 1.000000059604644775390625. Anything below it should round down, anything above it should
+    // round up, and the value itself should round _down_ because `1.0` has an even significand but
+    // 1.0000001 is odd.
+    let v1_low_down = Rational::parse("1.00000005960464477539062499999").expect_finite();
+    let v1_mid_down = Rational::parse("1.000000059604644775390625").expect_finite();
+    let v1_high_up = Rational::parse("1.00000005960464477539062500001").expect_finite();
+
+    let exp = -(f32::MAN_BITS as i32);
+    let v1_down_sig = 1 << f32::MAN_BITS;
+    let v1_up_sig = (1 << f32::MAN_BITS) | 0b1;
+
+    FloatRes::<f32>::validate_real(v1_low_down.clone(), v1_down_sig, exp).unwrap();
+    FloatRes::<f32>::validate_real(v1_mid_down.clone(), v1_down_sig, exp).unwrap();
+    FloatRes::<f32>::validate_real(v1_high_up.clone(), v1_up_sig, exp).unwrap();
+    FloatRes::<f32>::validate_real(-v1_low_down.clone(), -v1_down_sig, exp).unwrap();
+    FloatRes::<f32>::validate_real(-v1_mid_down.clone(), -v1_down_sig, exp).unwrap();
+    FloatRes::<f32>::validate_real(-v1_high_up.clone(), -v1_up_sig, exp).unwrap();
+
+    // 1.000000178813934326171875 is between 1.0000001 and the next value up, 1.0000002. The middle
+    // value here should round _up_ since 1.0000002 has an even mantissa.
+    let v2_low_down = Rational::parse("1.00000017881393432617187499999").expect_finite();
+    let v2_mid_up = Rational::parse("1.000000178813934326171875").expect_finite();
+    let v2_high_up = Rational::parse("1.00000017881393432617187500001").expect_finite();
+
+    let v2_down_sig = v1_up_sig;
+    let v2_up_sig = (1 << f32::MAN_BITS) | 0b10;
+
+    FloatRes::<f32>::validate_real(v2_low_down.clone(), v2_down_sig, exp).unwrap();
+    FloatRes::<f32>::validate_real(v2_mid_up.clone(), v2_up_sig, exp).unwrap();
+    FloatRes::<f32>::validate_real(v2_high_up.clone(), v2_up_sig, exp).unwrap();
+    FloatRes::<f32>::validate_real(-v2_low_down.clone(), -v2_down_sig, exp).unwrap();
+    FloatRes::<f32>::validate_real(-v2_mid_up.clone(), -v2_up_sig, exp).unwrap();
+    FloatRes::<f32>::validate_real(-v2_high_up.clone(), -v2_up_sig, exp).unwrap();
+
+    // Rounding the wrong direction should error
+    for res in [
+        FloatRes::<f32>::validate_real(v1_mid_down.clone(), v1_up_sig, exp),
+        FloatRes::<f32>::validate_real(v2_mid_up.clone(), v2_down_sig, exp),
+        FloatRes::<f32>::validate_real(-v1_mid_down.clone(), -v1_up_sig, exp),
+        FloatRes::<f32>::validate_real(-v2_mid_up.clone(), -v2_down_sig, exp),
+    ] {
+        let e = res.unwrap_err();
+        let CheckFailure::InvalidReal { incorrect_midpoint_rounding: true, .. } = e else {
+            panic!("{e:?}");
+        };
+    }
+}
+
+/// Just a quick check that the constants are what we expect.
+#[test]
+fn check_constants() {
+    assert_eq!(f32::constants().max.to_f32().unwrap(), f32::MAX);
+    assert_eq!(f32::constants().min_subnormal.to_f32().unwrap(), f32::from_bits(0x1));
+    assert_eq!(f64::constants().max.to_f64().unwrap(), f64::MAX);
+    assert_eq!(f64::constants().min_subnormal.to_f64().unwrap(), f64::from_bits(0x1));
+}
diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml
index dfdbc0878f2..4835c220210 100644
--- a/src/tools/tidy/Cargo.toml
+++ b/src/tools/tidy/Cargo.toml
@@ -15,7 +15,7 @@ semver = "1.0"
 serde = { version = "1.0.125", features = ["derive"], optional = true }
 termcolor = "1.1.3"
 rustc-hash = "2.0.0"
-fluent-syntax = "0.11.1"
+fluent-syntax = "0.12"
 similar = "2.5.0"
 toml = "0.7.8"
 
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 9bb06c31c5c..fdca7a7a40e 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -74,13 +74,13 @@ pub(crate) const WORKSPACES: &[(&str, ExceptionList, Option<(&[&str], &[&str])>,
     ("compiler/rustc_codegen_gcc", EXCEPTIONS_GCC, None, &[]),
     ("src/bootstrap", EXCEPTIONS_BOOTSTRAP, None, &[]),
     ("src/ci/docker/host-x86_64/test-various/uefi_qemu_test", EXCEPTIONS_UEFI_QEMU_TEST, None, &[]),
-    ("src/etc/test-float-parse", EXCEPTIONS, None, &[]),
     ("src/tools/cargo", EXCEPTIONS_CARGO, None, &["src/tools/cargo"]),
     //("src/tools/miri/test-cargo-miri", &[], None), // FIXME uncomment once all deps are vendored
     //("src/tools/miri/test_dependencies", &[], None), // FIXME uncomment once all deps are vendored
     ("src/tools/rust-analyzer", EXCEPTIONS_RUST_ANALYZER, None, &[]),
     ("src/tools/rustbook", EXCEPTIONS_RUSTBOOK, None, &["src/doc/book", "src/doc/reference"]),
     ("src/tools/rustc-perf", EXCEPTIONS_RUSTC_PERF, None, &["src/tools/rustc-perf"]),
+    ("src/tools/test-float-parse", EXCEPTIONS, None, &[]),
     // tidy-alphabetical-end
 ];
 
@@ -200,6 +200,7 @@ const EXCEPTIONS_CRANELIFT: ExceptionList = &[
     ("cranelift-module", "Apache-2.0 WITH LLVM-exception"),
     ("cranelift-native", "Apache-2.0 WITH LLVM-exception"),
     ("cranelift-object", "Apache-2.0 WITH LLVM-exception"),
+    ("cranelift-srcgen", "Apache-2.0 WITH LLVM-exception"),
     ("foldhash", "Zlib"),
     ("mach2", "BSD-2-Clause OR MIT OR Apache-2.0"),
     ("regalloc2", "Apache-2.0 WITH LLVM-exception"),
@@ -525,6 +526,7 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
     "cranelift-module",
     "cranelift-native",
     "cranelift-object",
+    "cranelift-srcgen",
     "crc32fast",
     "equivalent",
     "fallible-iterator",
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index fcd7943e6e0..6093e7fd263 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -54,6 +54,7 @@ pub struct Feature {
     pub tracking_issue: Option<NonZeroU32>,
     pub file: PathBuf,
     pub line: usize,
+    pub description: Option<String>,
 }
 impl Feature {
     fn tracking_issue_display(&self) -> impl fmt::Display {
@@ -296,6 +297,7 @@ fn collect_lang_features_in(features: &mut Features, base: &Path, file: &str, ba
     let mut prev_names = vec![];
 
     let lines = contents.lines().zip(1..);
+    let mut doc_comments: Vec<String> = Vec::new();
     for (line, line_number) in lines {
         let line = line.trim();
 
@@ -332,6 +334,13 @@ fn collect_lang_features_in(features: &mut Features, base: &Path, file: &str, ba
             continue;
         }
 
+        if in_feature_group {
+            if let Some(doc_comment) = line.strip_prefix("///") {
+                doc_comments.push(doc_comment.trim().to_string());
+                continue;
+            }
+        }
+
         let mut parts = line.split(',');
         let level = match parts.next().map(|l| l.trim().trim_start_matches('(')) {
             Some("unstable") => Status::Unstable,
@@ -438,9 +447,15 @@ fn collect_lang_features_in(features: &mut Features, base: &Path, file: &str, ba
                     tracking_issue,
                     file: path.to_path_buf(),
                     line: line_number,
+                    description: if doc_comments.is_empty() {
+                        None
+                    } else {
+                        Some(doc_comments.join(" "))
+                    },
                 });
             }
         }
+        doc_comments.clear();
     }
 }
 
@@ -564,6 +579,7 @@ fn map_lib_features(
                         tracking_issue: find_attr_val(line, "issue").and_then(handle_issue_none),
                         file: file.to_path_buf(),
                         line: i + 1,
+                        description: None,
                     };
                     mf(Ok((feature_name, feature)), file, i + 1);
                     continue;
@@ -600,6 +616,7 @@ fn map_lib_features(
                     tracking_issue,
                     file: file.to_path_buf(),
                     line: i + 1,
+                    description: None,
                 };
                 if line.contains(']') {
                     mf(Ok((feature_name, feature)), file, i + 1);
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index 1d0ddd56eec..3e9d79224fd 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -939,7 +939,6 @@ ui/enum-discriminant/auxiliary/issue-41394.rs
 ui/enum-discriminant/issue-104519.rs
 ui/enum-discriminant/issue-41394-rpass.rs
 ui/enum-discriminant/issue-41394.rs
-ui/enum-discriminant/issue-43398.rs
 ui/enum-discriminant/issue-46519.rs
 ui/enum-discriminant/issue-50689.rs
 ui/enum-discriminant/issue-51582.rs
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index ca45f8bb84b..e8a12d56335 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -82,6 +82,7 @@ pub mod mir_opt_tests;
 pub mod pal;
 pub mod rustdoc_css_themes;
 pub mod rustdoc_gui_tests;
+pub mod rustdoc_js;
 pub mod rustdoc_templates;
 pub mod style;
 pub mod target_policy;
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index 48122129b01..776f1bde2eb 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -35,6 +35,7 @@ fn main() {
     let library_path = root_path.join("library");
     let compiler_path = root_path.join("compiler");
     let librustdoc_path = src_path.join("librustdoc");
+    let tools_path = src_path.join("tools");
     let crashes_path = tests_path.join("crashes");
 
     let args: Vec<String> = env::args().skip(1).collect();
@@ -108,6 +109,7 @@ fn main() {
         check!(rustdoc_gui_tests, &tests_path);
         check!(rustdoc_css_themes, &librustdoc_path);
         check!(rustdoc_templates, &librustdoc_path);
+        check!(rustdoc_js, &librustdoc_path, &tools_path, &src_path);
         check!(known_bug, &crashes_path);
         check!(unknown_revision, &tests_path);
 
diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs
index c708ff7150c..9b915e0f737 100644
--- a/src/tools/tidy/src/pal.rs
+++ b/src/tools/tidy/src/pal.rs
@@ -36,6 +36,7 @@ use crate::walk::{filter_dirs, walk};
 
 // Paths that may contain platform-specific code.
 const EXCEPTION_PATHS: &[&str] = &[
+    "library/compiler-builtins",
     "library/windows_targets",
     "library/panic_abort",
     "library/panic_unwind",
diff --git a/src/tools/tidy/src/rustdoc_js.rs b/src/tools/tidy/src/rustdoc_js.rs
new file mode 100644
index 00000000000..2517e2de12c
--- /dev/null
+++ b/src/tools/tidy/src/rustdoc_js.rs
@@ -0,0 +1,99 @@
+//! Tidy check to ensure that rustdoc templates didn't forget a `{# #}` to strip extra whitespace
+//! characters.
+
+use std::ffi::OsStr;
+use std::path::{Path, PathBuf};
+use std::process::Command;
+
+use ignore::DirEntry;
+
+use crate::walk::walk_no_read;
+
+fn run_eslint(args: &[PathBuf], config_folder: PathBuf, bad: &mut bool) {
+    let mut child = match Command::new("npx")
+        .arg("eslint")
+        .arg("-c")
+        .arg(config_folder.join(".eslintrc.js"))
+        .args(args)
+        .spawn()
+    {
+        Ok(child) => child,
+        Err(error) => {
+            *bad = true;
+            eprintln!("failed to run eslint: {error:?}");
+            return;
+        }
+    };
+    match child.wait() {
+        Ok(exit_status) => {
+            if exit_status.success() {
+                return;
+            }
+            eprintln!("eslint command failed");
+        }
+        Err(error) => eprintln!("eslint command failed: {error:?}"),
+    }
+    *bad = true;
+}
+
+fn get_eslint_version_inner(global: bool) -> Option<String> {
+    let mut command = Command::new("npm");
+    command.arg("list").arg("--parseable").arg("--long").arg("--depth=0");
+    if global {
+        command.arg("--global");
+    }
+    let output = command.output().ok()?;
+    let lines = String::from_utf8_lossy(&output.stdout);
+    lines.lines().find_map(|l| l.split(':').nth(1)?.strip_prefix("eslint@")).map(|v| v.to_owned())
+}
+
+fn get_eslint_version() -> Option<String> {
+    get_eslint_version_inner(false).or_else(|| get_eslint_version_inner(true))
+}
+
+pub fn check(librustdoc_path: &Path, tools_path: &Path, src_path: &Path, bad: &mut bool) {
+    let eslint_version_path =
+        src_path.join("ci/docker/host-x86_64/mingw-check-tidy/eslint.version");
+    let eslint_version = match std::fs::read_to_string(&eslint_version_path) {
+        Ok(version) => version.trim().to_string(),
+        Err(error) => {
+            *bad = true;
+            eprintln!("failed to read `{}`: {error:?}", eslint_version_path.display());
+            return;
+        }
+    };
+    match get_eslint_version() {
+        Some(version) => {
+            if version != eslint_version {
+                *bad = true;
+                eprintln!(
+                    "⚠️ Installed version of eslint (`{version}`) is different than the \
+                     one used in the CI (`{eslint_version}`)",
+                );
+                eprintln!(
+                    "You can install this version using `npm update eslint` or by using \
+                     `npm install eslint@{eslint_version}`",
+                );
+                return;
+            }
+        }
+        None => {
+            eprintln!("`eslint` doesn't seem to be installed. Skipping tidy check for JS files.");
+            eprintln!("You can install it using `npm install eslint@{eslint_version}`");
+            return;
+        }
+    }
+    let mut files_to_check = Vec::new();
+    walk_no_read(
+        &[&librustdoc_path.join("html/static/js")],
+        |path, is_dir| is_dir || !path.extension().is_some_and(|ext| ext == OsStr::new("js")),
+        &mut |path: &DirEntry| {
+            files_to_check.push(path.path().into());
+        },
+    );
+    println!("Running eslint on rustdoc JS files");
+    run_eslint(&files_to_check, librustdoc_path.join("html/static"), bad);
+
+    run_eslint(&[tools_path.join("rustdoc-js/tester.js")], tools_path.join("rustdoc-js"), bad);
+    run_eslint(&[tools_path.join("rustdoc-gui/tester.js")], tools_path.join("rustdoc-gui"), bad);
+}
diff --git a/src/tools/tidy/src/walk.rs b/src/tools/tidy/src/walk.rs
index 08ee5c16c12..c2c9eb8d250 100644
--- a/src/tools/tidy/src/walk.rs
+++ b/src/tools/tidy/src/walk.rs
@@ -14,6 +14,7 @@ pub fn filter_dirs(path: &Path) -> bool {
         "compiler/rustc_codegen_gcc",
         "src/llvm-project",
         "library/backtrace",
+        "library/compiler-builtins",
         "library/portable-simd",
         "library/stdarch",
         "src/tools/cargo",
diff --git a/src/tools/unstable-book-gen/src/SUMMARY.md b/src/tools/unstable-book-gen/src/SUMMARY.md
index 933c928e2f0..fd4ea1dada6 100644
--- a/src/tools/unstable-book-gen/src/SUMMARY.md
+++ b/src/tools/unstable-book-gen/src/SUMMARY.md
@@ -1,5 +1,7 @@
 [The Unstable Book](the-unstable-book.md)
 
+- [Compiler environment variables](compiler-environment-variables.md)
+{compiler_env_vars}
 - [Compiler flags](compiler-flags.md)
 {compiler_flags}
 - [Language features](language-features.md)
diff --git a/src/tools/unstable-book-gen/src/main.rs b/src/tools/unstable-book-gen/src/main.rs
index 6cbdc83d5b5..159a1d0fa17 100644
--- a/src/tools/unstable-book-gen/src/main.rs
+++ b/src/tools/unstable-book-gen/src/main.rs
@@ -12,13 +12,18 @@ use tidy::unstable_book::{
     collect_unstable_feature_names,
 };
 
-fn generate_stub_issue(path: &Path, name: &str, issue: u32) {
-    let content = format!(include_str!("stub-issue.md"), name = name, issue = issue);
+fn generate_stub_issue(path: &Path, name: &str, issue: u32, description: &str) {
+    let content = format!(
+        include_str!("stub-issue.md"),
+        name = name,
+        issue = issue,
+        description = description
+    );
     t!(write(path, content), path);
 }
 
-fn generate_stub_no_issue(path: &Path, name: &str) {
-    let content = format!(include_str!("stub-no-issue.md"), name = name);
+fn generate_stub_no_issue(path: &Path, name: &str, description: &str) {
+    let content = format!(include_str!("stub-no-issue.md"), name = name, description = description);
     t!(write(path, content), path);
 }
 
@@ -30,8 +35,12 @@ fn set_to_summary_str(set: &BTreeSet<String>, dir: &str) -> String {
 
 fn generate_summary(path: &Path, lang_features: &Features, lib_features: &Features) {
     let compiler_flags = collect_unstable_book_section_file_names(&path.join("src/compiler-flags"));
+    let compiler_env_vars =
+        collect_unstable_book_section_file_names(&path.join("src/compiler-environment-variables"));
 
     let compiler_flags_str = set_to_summary_str(&compiler_flags, "compiler-flags");
+    let compiler_env_vars_str =
+        set_to_summary_str(&compiler_env_vars, "compiler-environment-variables");
 
     let unstable_lang_features = collect_unstable_feature_names(&lang_features);
     let unstable_lib_features = collect_unstable_feature_names(&lib_features);
@@ -42,6 +51,7 @@ fn generate_summary(path: &Path, lang_features: &Features, lib_features: &Featur
     let summary_path = path.join("src/SUMMARY.md");
     let content = format!(
         include_str!("SUMMARY.md"),
+        compiler_env_vars = compiler_env_vars_str,
         compiler_flags = compiler_flags_str,
         language_features = lang_features_str,
         library_features = lib_features_str
@@ -58,11 +68,17 @@ fn generate_unstable_book_files(src: &Path, out: &Path, features: &Features) {
         let file_name = format!("{feature_name}.md");
         let out_file_path = out.join(&file_name);
         let feature = &features[&feature_name_underscore];
+        let description = feature.description.as_deref().unwrap_or_default();
 
         if let Some(issue) = feature.tracking_issue {
-            generate_stub_issue(&out_file_path, &feature_name_underscore, issue.get());
+            generate_stub_issue(
+                &out_file_path,
+                &feature_name_underscore,
+                issue.get(),
+                &description,
+            );
         } else {
-            generate_stub_no_issue(&out_file_path, &feature_name_underscore);
+            generate_stub_no_issue(&out_file_path, &feature_name_underscore, &description);
         }
     }
 }
diff --git a/src/tools/unstable-book-gen/src/stub-issue.md b/src/tools/unstable-book-gen/src/stub-issue.md
index 8698fb7278f..f1e91b4ac17 100644
--- a/src/tools/unstable-book-gen/src/stub-issue.md
+++ b/src/tools/unstable-book-gen/src/stub-issue.md
@@ -1,5 +1,7 @@
 # `{name}`
 
+{description}
+
 The tracking issue for this feature is: [#{issue}]
 
 [#{issue}]: https://github.com/rust-lang/rust/issues/{issue}
diff --git a/src/tools/unstable-book-gen/src/stub-no-issue.md b/src/tools/unstable-book-gen/src/stub-no-issue.md
index 3da140633d0..3674d0048ae 100644
--- a/src/tools/unstable-book-gen/src/stub-no-issue.md
+++ b/src/tools/unstable-book-gen/src/stub-no-issue.md
@@ -1,5 +1,7 @@
 # `{name}`
 
+{description}
+
 This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.
 
 ------------------------