about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml16
-rw-r--r--Cargo.lock34
-rw-r--r--README.md14
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs22
-rw-r--r--compiler/rustc_codegen_cranelift/.cirrus.yml2
-rw-r--r--compiler/rustc_codegen_cranelift/.github/workflows/main.yml10
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.lock52
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.toml12
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs9
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/prepare.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/tests.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/utils.rs10
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0002-rand-Disable-failing-test.patch24
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0003-rand-Disable-rand-tests-on-mingw.patch47
-rw-r--r--compiler/rustc_codegen_cranelift/patches/portable-simd-lock.toml304
-rw-r--r--compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml5
-rw-r--r--compiler/rustc_codegen_cranelift/rust-toolchain2
-rw-r--r--compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh27
-rwxr-xr-xcompiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh21
-rw-r--r--compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/aot.rs47
-rw-r--r--compiler/rustc_codegen_cranelift/src/global_asm.rs8
-rw-r--r--compiler/rustc_codegen_cranelift/src/inline_asm.rs59
-rw-r--r--compiler/rustc_codegen_cranelift/src/lib.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs115
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs101
-rw-r--r--compiler/rustc_data_structures/Cargo.toml1
-rw-r--r--compiler/rustc_data_structures/src/flock.rs13
-rw-r--r--compiler/rustc_data_structures/src/lib.rs33
-rw-r--r--compiler/rustc_data_structures/src/marker.rs31
-rw-r--r--compiler/rustc_data_structures/src/profiling.rs13
-rw-r--r--compiler/rustc_data_structures/src/sync.rs7
-rw-r--r--compiler/rustc_expand/messages.ftl1
-rw-r--r--compiler/rustc_expand/src/errors.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs24
-rw-r--r--compiler/rustc_hir_typeck/src/_match.rs1
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs13
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs34
-rw-r--r--compiler/rustc_middle/src/query/mod.rs6
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs1
-rw-r--r--compiler/rustc_mir_build/src/errors.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs25
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs282
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs258
-rw-r--r--compiler/rustc_mir_transform/src/coverage/counters.rs26
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mod.rs195
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans.rs42
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs65
-rw-r--r--compiler/rustc_monomorphize/src/partitioning.rs31
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs17
-rw-r--r--compiler/rustc_smir/src/rustc_internal/internal.rs61
-rw-r--r--compiler/rustc_smir/src/rustc_internal/mod.rs10
-rw-r--r--compiler/rustc_smir/src/rustc_smir/builder.rs55
-rw-r--r--compiler/rustc_smir/src/rustc_smir/mod.rs22
-rw-r--r--compiler/rustc_span/Cargo.toml1
-rw-r--r--compiler/rustc_span/src/analyze_source_file.rs8
-rw-r--r--compiler/rustc_span/src/lib.rs21
-rw-r--r--compiler/rustc_target/src/asm/csky.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs25
-rw-r--r--compiler/stable_mir/src/error.rs7
-rw-r--r--compiler/stable_mir/src/lib.rs4
-rw-r--r--compiler/stable_mir/src/mir/body.rs27
-rw-r--r--compiler/stable_mir/src/mir/mono.rs11
-rw-r--r--compiler/stable_mir/src/ty.rs1
-rw-r--r--library/alloc/src/boxed.rs2
-rw-r--r--library/std/build.rs10
-rw-r--r--library/std/src/os/freebsd/fs.rs10
-rwxr-xr-xsrc/ci/docker/host-x86_64/x86_64-gnu-llvm-15/script.sh56
-rw-r--r--src/ci/github-actions/ci.yml25
-rwxr-xr-xsrc/ci/scripts/install-awscli.sh29
-rw-r--r--src/doc/rustdoc/src/write-documentation/what-to-include.md2
-rw-r--r--src/tools/clippy/CHANGELOG.md2
-rw-r--r--src/tools/clippy/Cargo.toml2
-rw-r--r--src/tools/clippy/book/src/development/adding_lints.md19
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md12
-rw-r--r--src/tools/clippy/clippy_lints/src/async_yields_async.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/await_holding_invalid.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/box_default.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/exit.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs126
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/mod.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/item_name_repetitions.rs (renamed from src/tools/clippy/clippy_lints/src/enum_variants.rs)211
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs75
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/same_item_push.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_async_fn.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_bits.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/get_first.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_identity.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/search_is_some.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_doc.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_continue.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs104
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_question_mark.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs315
-rw-r--r--src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_async_block.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_locals.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/types/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/uninit_vec.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/use_self.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/conf.rs115
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs23
-rw-r--r--src/tools/clippy/clippy_utils/Cargo.toml1
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/higher.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs114
-rw-r--r--src/tools/clippy/clippy_utils/src/msrvs.rs90
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/str_utils.rs53
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/src/driver.rs6
-rw-r--r--src/tools/clippy/tests/compile-test.rs88
-rw-r--r--src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs2
-rw-r--r--src/tools/clippy/tests/ui-toml/borrow_interior_mutable_const/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/borrow_interior_mutable_const/ignore.rs37
-rw-r--r--src/tools/clippy/tests/ui-toml/declare_interior_mutable_const/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/declare_interior_mutable_const/ignore.rs46
-rw-r--r--src/tools/clippy/tests/ui-toml/enum_variant_names/enum_variant_names.rs16
-rw-r--r--src/tools/clippy/tests/ui-toml/enum_variant_names/enum_variant_names.stderr18
-rw-r--r--src/tools/clippy/tests/ui-toml/impl_trait_in_params/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/impl_trait_in_params/impl_trait_in_params.rs16
-rw-r--r--src/tools/clippy/tests/ui-toml/impl_trait_in_params/impl_trait_in_params.stderr15
-rw-r--r--src/tools/clippy/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs2
-rw-r--r--src/tools/clippy/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr6
-rw-r--r--src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold0/clippy.toml (renamed from src/tools/clippy/tests/ui-toml/enum_variants_threshold0/clippy.toml)1
-rw-r--r--src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold0/item_name_repetitions.rs (renamed from src/tools/clippy/tests/ui-toml/enum_variants_threshold0/enum_variants_name_threshold.rs)2
-rw-r--r--src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold5/clippy.toml (renamed from src/tools/clippy/tests/ui-toml/enum_variant_names/clippy.toml)1
-rw-r--r--src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.rs32
-rw-r--r--src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.stderr34
-rw-r--r--src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs1
-rw-r--r--src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr14
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr2
-rw-r--r--src/tools/clippy/tests/ui/author/macro_in_closure.rs5
-rw-r--r--src/tools/clippy/tests/ui/author/macro_in_closure.stdout39
-rw-r--r--src/tools/clippy/tests/ui/author/macro_in_loop.rs8
-rw-r--r--src/tools/clippy/tests/ui/author/macro_in_loop.stdout48
-rw-r--r--src/tools/clippy/tests/ui/get_first.fixed13
-rw-r--r--src/tools/clippy/tests/ui/get_first.rs13
-rw-r--r--src/tools/clippy/tests/ui/get_first.stderr18
-rw-r--r--src/tools/clippy/tests/ui/impl_trait_in_params.rs35
-rw-r--r--src/tools/clippy/tests/ui/impl_trait_in_params.stderr30
-rw-r--r--src/tools/clippy/tests/ui/into_iter_without_iter.rs34
-rw-r--r--src/tools/clippy/tests/ui/manual_filter_map.fixed1
-rw-r--r--src/tools/clippy/tests/ui/manual_filter_map.rs1
-rw-r--r--src/tools/clippy/tests/ui/manual_filter_map.stderr76
-rw-r--r--src/tools/clippy/tests/ui/manual_find_map.fixed1
-rw-r--r--src/tools/clippy/tests/ui/manual_find_map.rs1
-rw-r--r--src/tools/clippy/tests/ui/manual_find_map.stderr78
-rw-r--r--src/tools/clippy/tests/ui/manual_is_ascii_check.fixed4
-rw-r--r--src/tools/clippy/tests/ui/manual_is_ascii_check.rs4
-rw-r--r--src/tools/clippy/tests/ui/manual_is_ascii_check.stderr22
-rw-r--r--src/tools/clippy/tests/ui/map_identity.fixed3
-rw-r--r--src/tools/clippy/tests/ui/map_identity.rs3
-rw-r--r--src/tools/clippy/tests/ui/min_ident_chars.rs1
-rw-r--r--src/tools/clippy/tests/ui/min_ident_chars.stderr58
-rw-r--r--src/tools/clippy/tests/ui/misnamed_getters.fixed1
-rw-r--r--src/tools/clippy/tests/ui/misnamed_getters.rs1
-rw-r--r--src/tools/clippy/tests/ui/misnamed_getters.stderr36
-rw-r--r--src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs7
-rw-r--r--src/tools/clippy/tests/ui/needless_bool/fixable.fixed3
-rw-r--r--src/tools/clippy/tests/ui/needless_bool/fixable.rs3
-rw-r--r--src/tools/clippy/tests/ui/needless_bool/fixable.stderr42
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs32
-rw-r--r--src/tools/clippy/tests/ui/redundant_locals.rs8
-rw-r--r--src/tools/clippy/tests/ui/redundant_locals.stderr4
-rw-r--r--src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.rs1
-rw-r--r--src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr6
-rw-r--r--src/tools/clippy/tests/ui/struct_fields.rs331
-rw-r--r--src/tools/clippy/tests/ui/struct_fields.stderr265
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed3
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs3
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr94
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.rs5
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.stderr10
-rw-r--r--src/tools/clippy/triagebot.toml2
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/shims/backtrace.rs2
-rw-r--r--tests/coverage-map/fn_sig_into_try.cov-map53
-rw-r--r--tests/coverage-map/fn_sig_into_try.rs41
-rw-r--r--tests/coverage-map/status-quo/inline-dead.cov-map14
-rw-r--r--tests/coverage-map/status-quo/issue-84561.cov-map6
-rw-r--r--tests/run-coverage/fn_sig_into_try.coverage45
-rw-r--r--tests/run-coverage/fn_sig_into_try.rs41
-rw-r--r--tests/run-coverage/issue-84561.coverage2
-rw-r--r--tests/run-make/unknown-mod-stdin/unknown-mod.stderr1
-rw-r--r--tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.rs2
-rw-r--r--tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.stderr4
-rw-r--r--tests/ui-fulldeps/stable-mir/check_instance.rs (renamed from tests/ui-fulldeps/stable-mir/instance.rs)26
-rw-r--r--tests/ui/async-await/unnecessary-await.rs5
-rw-r--r--tests/ui/async-await/unnecessary-await.stderr15
-rw-r--r--tests/ui/error-codes/E0583.stderr1
-rw-r--r--tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs18
-rw-r--r--tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr101
-rw-r--r--tests/ui/invalid-compile-flags/invalid-llvm-passes.rs (renamed from tests/ui/invalid/invalid-llvm-passes.rs)0
-rw-r--r--tests/ui/invalid-compile-flags/invalid-llvm-passes.stderr (renamed from tests/ui/invalid/invalid-llvm-passes.stderr)0
-rw-r--r--tests/ui/invalid-module-declaration/invalid-module-declaration.stderr1
-rw-r--r--tests/ui/lifetimes/borrowck-let-suggestion.stderr4
-rw-r--r--tests/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr1
-rw-r--r--tests/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr1
-rw-r--r--tests/ui/modules/special_module_name.stderr2
-rw-r--r--tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed10
-rw-r--r--tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs10
-rw-r--r--tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr20
-rw-r--r--tests/ui/object-safety/assoc_type_bounds_sized_used.stderr4
-rw-r--r--tests/ui/parser/mod_file_not_exist.stderr1
-rw-r--r--tests/ui/parser/mod_file_not_exist_windows.stderr1
-rw-r--r--tests/ui/parser/unsafe-mod.stderr1
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.rs78
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.stderr125
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.rs8
-rw-r--r--tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr12
-rw-r--r--tests/ui/rfcs/rfc-2457-non-ascii-idents/mod_file_nonascii_forbidden.stderr1
-rw-r--r--tests/ui/suggestions/issue-81839.stderr15
-rw-r--r--tests/ui/suggestions/silenced-binding-typo.fixed5
-rw-r--r--tests/ui/suggestions/silenced-binding-typo.rs5
-rw-r--r--tests/ui/suggestions/silenced-binding-typo.stderr14
-rw-r--r--tests/ui/typeck/issue-36708.stderr7
-rw-r--r--tests/ui/wf/wf-unsafe-trait-obj-match.stderr4
-rw-r--r--triagebot.toml18
240 files changed, 4090 insertions, 2273 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 8c207e7ea11..9bde9c4fbff 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -93,6 +93,9 @@ jobs:
       - name: show the current environment
         run: src/ci/scripts/dump-environment.sh
         if: success() && !env.SKIP_JOB
+      - name: install awscli
+        run: src/ci/scripts/install-awscli.sh
+        if: success() && !env.SKIP_JOB
       - name: install sccache
         run: src/ci/scripts/install-sccache.sh
         if: success() && !env.SKIP_JOB
@@ -345,8 +348,8 @@ jobs:
             os: macos-13
           - name: dist-aarch64-apple
             env:
-              SCRIPT: "./x.py dist bootstrap --include-default-paths --stage 2"
-              RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --host=aarch64-apple-darwin --target=aarch64-apple-darwin --enable-full-tools --enable-sanitizers --enable-profiler --disable-docs --set rust.jemalloc --set llvm.ninja=false"
+              SCRIPT: "./x.py dist bootstrap --include-default-paths --host=aarch64-apple-darwin --target=aarch64-apple-darwin"
+              RUST_CONFIGURE_ARGS: "--enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false --set rust.lto=thin"
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
               SELECT_XCODE: /Applications/Xcode_13.4.1.app
               USE_XCODE_CLANG: 1
@@ -356,8 +359,7 @@ jobs:
               NO_DEBUG_ASSERTIONS: 1
               NO_OVERFLOW_CHECKS: 1
               DIST_REQUIRE_ALL_TOOLS: 1
-              JEMALLOC_SYS_WITH_LG_PAGE: 14
-            os: macos-13
+            os: macos-13-xlarge
           - name: x86_64-msvc
             env:
               RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler"
@@ -458,6 +460,9 @@ jobs:
       - name: show the current environment
         run: src/ci/scripts/dump-environment.sh
         if: success() && !env.SKIP_JOB
+      - name: install awscli
+        run: src/ci/scripts/install-awscli.sh
+        if: success() && !env.SKIP_JOB
       - name: install sccache
         run: src/ci/scripts/install-sccache.sh
         if: success() && !env.SKIP_JOB
@@ -578,6 +583,9 @@ jobs:
       - name: show the current environment
         run: src/ci/scripts/dump-environment.sh
         if: success() && !env.SKIP_JOB
+      - name: install awscli
+        run: src/ci/scripts/install-awscli.sh
+        if: success() && !env.SKIP_JOB
       - name: install sccache
         run: src/ci/scripts/install-sccache.sh
         if: success() && !env.SKIP_JOB
diff --git a/Cargo.lock b/Cargo.lock
index 232c9c9441f..6c96f415f44 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -564,7 +564,7 @@ dependencies = [
  "tester",
  "tokio",
  "toml 0.7.5",
- "ui_test 0.20.0",
+ "ui_test",
  "walkdir",
 ]
 
@@ -614,6 +614,7 @@ dependencies = [
  "if_chain",
  "itertools",
  "rustc-semver",
+ "serde",
 ]
 
 [[package]]
@@ -2511,7 +2512,7 @@ dependencies = [
  "rustc_version",
  "serde",
  "smallvec",
- "ui_test 0.21.2",
+ "ui_test",
 ]
 
 [[package]]
@@ -3696,7 +3697,6 @@ version = "0.0.0"
 dependencies = [
  "arrayvec",
  "bitflags 1.3.2",
- "cfg-if",
  "elsa",
  "ena",
  "indexmap 2.0.0",
@@ -4528,7 +4528,6 @@ dependencies = [
 name = "rustc_span"
 version = "0.0.0"
 dependencies = [
- "cfg-if",
  "indexmap 2.0.0",
  "md-5",
  "rustc_arena",
@@ -5742,33 +5741,6 @@ checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81"
 
 [[package]]
 name = "ui_test"
-version = "0.20.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfd8fb9b15c8332cf51bfc2dc4830063b2446a9c9d732421b56f2478024a3971"
-dependencies = [
- "annotate-snippets",
- "anyhow",
- "bstr",
- "cargo-platform",
- "cargo_metadata 0.15.4",
- "color-eyre",
- "colored",
- "comma",
- "crossbeam-channel",
- "indicatif",
- "lazy_static",
- "levenshtein",
- "prettydiff",
- "regex",
- "rustc_version",
- "rustfix",
- "serde",
- "serde_json",
- "tempfile",
-]
-
-[[package]]
-name = "ui_test"
 version = "0.21.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "aaf4bf7c184b8dfc7a4d3b90df789b1eb992ee42811cd115f32a7a1eb781058d"
diff --git a/README.md b/README.md
index f0c45f341d8..a88ee4b8bf0 100644
--- a/README.md
+++ b/README.md
@@ -11,6 +11,20 @@ standard library, and documentation.
 If you wish to _contribute_ to the compiler, you should read
 [CONTRIBUTING.md](CONTRIBUTING.md) instead.
 
+<details>
+<summary>Table of content</summary>
+
+- [Quick Start](#quick-start)
+- [Installing from Source](#installing-from-source)
+- [Building Documentation](#building-documentation)
+- [Notes](#notes)
+- [Getting Help](#getting-help)
+- [Contributing](#contributing)
+- [License](#license)
+- [Trademark](#trademark)
+
+</details>
+
 ## Quick Start
 
 Read ["Installation"] from [The Book].
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 00816c0f253..ecf7930ff6b 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -2263,6 +2263,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     current: usize,
                     found: usize,
                     prop_expr: Option<&'tcx hir::Expr<'tcx>>,
+                    call: Option<&'tcx hir::Expr<'tcx>>,
                 }
 
                 impl<'tcx> Visitor<'tcx> for NestedStatementVisitor<'tcx> {
@@ -2272,6 +2273,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         self.current -= 1;
                     }
                     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
+                        if let hir::ExprKind::MethodCall(_, rcvr, _, _) = expr.kind {
+                            if self.span == rcvr.span.source_callsite() {
+                                self.call = Some(expr);
+                            }
+                        }
                         if self.span == expr.span.source_callsite() {
                             self.found = self.current;
                             if self.prop_expr.is_none() {
@@ -2295,6 +2301,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             current: 0,
                             found: 0,
                             prop_expr: None,
+                            call: None,
                         };
                         visitor.visit_stmt(stmt);
 
@@ -2316,6 +2323,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             && let Some(p) = sm.span_to_margin(stmt.span)
                             && let Ok(s) = sm.span_to_snippet(proper_span)
                         {
+                            if let Some(call) = visitor.call
+                                && let hir::ExprKind::MethodCall(path, _, [], _) = call.kind
+                                && path.ident.name == sym::iter
+                                && let Some(ty) = expr_ty
+                            {
+                                err.span_suggestion_verbose(
+                                    path.ident.span,
+                                    format!(
+                                        "consider consuming the `{ty}` when turning it into an \
+                                         `Iterator`",
+                                    ),
+                                    "into_iter".to_string(),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
                             if !is_format_arguments_item {
                                 let addition = format!("let binding = {};\n{}", s, " ".repeat(p));
                                 err.multipart_suggestion_verbose(
diff --git a/compiler/rustc_codegen_cranelift/.cirrus.yml b/compiler/rustc_codegen_cranelift/.cirrus.yml
index 8b4efd4e394..aa1a2bad2cf 100644
--- a/compiler/rustc_codegen_cranelift/.cirrus.yml
+++ b/compiler/rustc_codegen_cranelift/.cirrus.yml
@@ -3,7 +3,7 @@ task:
   freebsd_instance:
     image: freebsd-13-2-release-amd64
   setup_rust_script:
-    - pkg install -y git bash
+    - pkg install -y git bash binutils
     - curl https://sh.rustup.rs -sSf --output rustup.sh
     - sh rustup.sh --default-toolchain none -y --profile=minimal
   target_cache:
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
index 652d6eca3f6..47d9a3b93f7 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
@@ -50,10 +50,12 @@ jobs:
           - os: ubuntu-latest
             env:
               TARGET_TRIPLE: aarch64-unknown-linux-gnu
-          # s390x requires QEMU 6.1 or greater, we could build it from source, but ubuntu 22.04 comes with 6.2 by default
           - os: ubuntu-latest
             env:
               TARGET_TRIPLE: s390x-unknown-linux-gnu
+          - os: ubuntu-latest
+            env:
+              TARGET_TRIPLE: riscv64gc-unknown-linux-gnu
           - os: windows-latest
             env:
               TARGET_TRIPLE: x86_64-pc-windows-msvc
@@ -92,6 +94,12 @@ jobs:
         sudo apt-get update
         sudo apt-get install -y gcc-s390x-linux-gnu qemu-user
 
+    - name: Install riscv64gc toolchain and qemu
+      if: matrix.env.TARGET_TRIPLE == 'riscv64gc-unknown-linux-gnu'
+      run: |
+        sudo apt-get update
+        sudo apt-get install -y gcc-riscv64-linux-gnu qemu-user
+
     - name: Prepare dependencies
       run: ./y.sh prepare
 
diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock
index 7c324421be9..8079913cb0f 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/Cargo.lock
@@ -45,18 +45,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "cranelift-bforest"
-version = "0.100.0"
+version = "0.101.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "03b9d1a9e776c27ad55d7792a380785d1fe8c2d7b099eed8dbd8f4af2b598192"
+checksum = "8e5e1df0da8488dd03b34afc134ba84b754d61862cc465932a9e5d07952f661e"
 dependencies = [
  "cranelift-entity",
 ]
 
 [[package]]
 name = "cranelift-codegen"
-version = "0.100.0"
+version = "0.101.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5528483314c2dd5da438576cd8a9d0b3cedad66fb8a4727f90cd319a81950038"
+checksum = "77a17ca4e699a0aaf49a0c88f6311a864f321048aa63f6b787cab20eb5f93f10"
 dependencies = [
  "bumpalo",
  "cranelift-bforest",
@@ -75,39 +75,39 @@ dependencies = [
 
 [[package]]
 name = "cranelift-codegen-meta"
-version = "0.100.0"
+version = "0.101.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f46a8318163f7682e35b8730ba93c1b586a2da8ce12a0ed545efc1218550f70"
+checksum = "022f2793cdade1d37a1f755ac42938a3f832f533eac6cafc8b26b209544c3c06"
 dependencies = [
  "cranelift-codegen-shared",
 ]
 
 [[package]]
 name = "cranelift-codegen-shared"
-version = "0.100.0"
+version = "0.101.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37d1239cfd50eecfaed468d46943f8650e32969591868ad50111613704da6c70"
+checksum = "a4d72dbb83c2ad788dec4ad0843070973cb48c35a3ca19b1e7437ac40834fd9c"
 
 [[package]]
 name = "cranelift-control"
-version = "0.100.0"
+version = "0.101.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bcc530560c8f16cc1d4dd7ea000c56f519c60d1a914977abe849ce555c35a61d"
+checksum = "ae07cf26dcc90d546826d747ac63b6c40c916f34b03e92a6ae0422c28d771b8a"
 dependencies = [
  "arbitrary",
 ]
 
 [[package]]
 name = "cranelift-entity"
-version = "0.100.0"
+version = "0.101.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f333fa641a9ad2bff0b107767dcb972c18c2bfab7969805a1d7e42449ccb0408"
+checksum = "c2fe6b7e49820893691aea497f36257e9d6f52061d8c4758d61d802d5f101a3d"
 
 [[package]]
 name = "cranelift-frontend"
-version = "0.100.0"
+version = "0.101.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06abf6563015a80f03f8bc4df307d0a81363f4eb73108df3a34f6e66fb6d5307"
+checksum = "44f497576ca3674581581601b6a55ccc1b43447217648c880e5bce70db3cf659"
 dependencies = [
  "cranelift-codegen",
  "log",
@@ -117,15 +117,15 @@ dependencies = [
 
 [[package]]
 name = "cranelift-isle"
-version = "0.100.0"
+version = "0.101.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0eb29d0edc8a5c029ed0f7ca77501f272738e3c410020b4a00f42ffe8ad2a8aa"
+checksum = "b96aa02eac00fffee13b0cd37d17874ccdb3d5458983041accd825ef78ce6454"
 
 [[package]]
 name = "cranelift-jit"
-version = "0.100.0"
+version = "0.101.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d16e8c5e212b1e63658aada17553497e7a259acab61f044d1f185527efa609fb"
+checksum = "b1d6e0e308c873eefc185745a6b21daec2a10f7554c9fb67e334c2d7d756d979"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -143,9 +143,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-module"
-version = "0.100.0"
+version = "0.101.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3b5fd273e1a959e920c7a9d790b1646d31acc8782bb549bad5ab85dd2fc9aa7"
+checksum = "c1aa8ebb06eced4e478c3f94f1d65d4e7c93493f4640057912b27a3e34b84841"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -154,9 +154,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-native"
-version = "0.100.0"
+version = "0.101.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "006056a7fa920870bad06bf8e1b3033d70cbb7ee625b035efa9d90882a931868"
+checksum = "2870170ca44054b202c737626607b87be6e35655084bd94a6ff807a5812ba7df"
 dependencies = [
  "cranelift-codegen",
  "libc",
@@ -165,9 +165,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-object"
-version = "0.100.0"
+version = "0.101.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c8be1b0e7720f30fec31be0c0b0b23caef2a73fa751190c6a251c1362e8f8c9"
+checksum = "20647761742d17dabac8205da958910ede78599550e06418a16711a3ee2fc897"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -374,9 +374,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
 
 [[package]]
 name = "wasmtime-jit-icache-coherence"
-version = "13.0.0"
+version = "14.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c6ff5f3707a5e3797deeeeac6ac26b2e1dd32dbc06693c0ab52e8ac4d18ec706"
+checksum = "a3a5dda53ad6993f9b0a2d65fb49e0348a7232a27a8794064122870d6ee19eb2"
 dependencies = [
  "cfg-if",
  "libc",
diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml
index 28a37b7995b..5ad5e0e8140 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.toml
+++ b/compiler/rustc_codegen_cranelift/Cargo.toml
@@ -8,12 +8,12 @@ crate-type = ["dylib"]
 
 [dependencies]
 # These have to be in sync with each other
-cranelift-codegen = { version = "0.100", features = ["unwind", "all-arch"] }
-cranelift-frontend = { version = "0.100" }
-cranelift-module = { version = "0.100" }
-cranelift-native = { version = "0.100" }
-cranelift-jit = { version = "0.100", optional = true }
-cranelift-object = { version = "0.100" }
+cranelift-codegen = { version = "0.101", features = ["unwind", "all-arch"] }
+cranelift-frontend = { version = "0.101" }
+cranelift-module = { version = "0.101" }
+cranelift-native = { version = "0.101" }
+cranelift-jit = { version = "0.101", optional = true }
+cranelift-object = { version = "0.101" }
 target-lexicon = "0.12.0"
 gimli = { version = "0.28", default-features = false, features = ["write"]}
 object = { version = "0.32", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
diff --git a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
index 31a4b209826..1ed896c6bf0 100644
--- a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
@@ -1,3 +1,4 @@
+use std::env;
 use std::fs;
 use std::path::{Path, PathBuf};
 use std::process::Command;
@@ -259,6 +260,14 @@ fn build_clif_sysroot_for_triple(
         // inlining.
         rustflags.push("-Zinline-mir".to_owned());
     }
+    if let Some(prefix) = env::var_os("CG_CLIF_STDLIB_REMAP_PATH_PREFIX") {
+        rustflags.push("--remap-path-prefix".to_owned());
+        rustflags.push(format!(
+            "{}={}",
+            STDLIB_SRC.to_path(dirs).to_str().unwrap(),
+            prefix.to_str().unwrap()
+        ));
+    }
     compiler.rustflags.extend(rustflags);
     let mut build_cmd = STANDARD_LIBRARY.build(&compiler, dirs);
     maybe_incremental(&mut build_cmd);
diff --git a/compiler/rustc_codegen_cranelift/build_system/prepare.rs b/compiler/rustc_codegen_cranelift/build_system/prepare.rs
index 16e7a4bafae..c68968b4fde 100644
--- a/compiler/rustc_codegen_cranelift/build_system/prepare.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/prepare.rs
@@ -143,6 +143,7 @@ impl GitRepo {
             RelPath::PATCHES.to_path(dirs).join(format!("{}-lock.toml", self.patch_name));
         let target_lockfile = download_dir.join("Cargo.lock");
         if source_lockfile.exists() {
+            assert!(!target_lockfile.exists());
             fs::copy(source_lockfile, target_lockfile).unwrap();
         } else {
             assert!(target_lockfile.exists());
diff --git a/compiler/rustc_codegen_cranelift/build_system/tests.rs b/compiler/rustc_codegen_cranelift/build_system/tests.rs
index 95ff6b75422..1e24d1b113f 100644
--- a/compiler/rustc_codegen_cranelift/build_system/tests.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/tests.rs
@@ -104,8 +104,8 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
 pub(crate) static RAND_REPO: GitRepo = GitRepo::github(
     "rust-random",
     "rand",
-    "f3dd0b885c4597b9617ca79987a0dd899ab29fcb",
-    "3f869e4fcd602b66",
+    "9a02c819cc1e4ec6959ae25eafbb5cf6acb68234",
+    "4934f0afb1d1c2ca",
     "rand",
 );
 
@@ -125,7 +125,7 @@ pub(crate) static PORTABLE_SIMD_REPO: GitRepo = GitRepo::github(
     "rust-lang",
     "portable-simd",
     "4825b2a64d765317066948867e8714674419359b",
-    "8b188cc41f5af835",
+    "9e67d07c00f5fb0b",
     "portable-simd",
 );
 
diff --git a/compiler/rustc_codegen_cranelift/build_system/utils.rs b/compiler/rustc_codegen_cranelift/build_system/utils.rs
index 9f24c043a50..149f1618f5c 100644
--- a/compiler/rustc_codegen_cranelift/build_system/utils.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/utils.rs
@@ -42,6 +42,16 @@ impl Compiler {
                     "/usr/s390x-linux-gnu".to_owned(),
                 ];
             }
+            "riscv64gc-unknown-linux-gnu" => {
+                // We are cross-compiling for riscv64. Use the correct linker and run tests in qemu.
+                self.rustflags.push("-Clinker=riscv64-linux-gnu-gcc".to_owned());
+                self.rustdocflags.push("-Clinker=riscv64-linux-gnu-gcc".to_owned());
+                self.runner = vec![
+                    "qemu-riscv64".to_owned(),
+                    "-L".to_owned(),
+                    "/usr/riscv64-linux-gnu".to_owned(),
+                ];
+            }
             "x86_64-pc-windows-gnu" => {
                 // We are cross-compiling for Windows. Run tests in wine.
                 self.runner = vec!["wine".to_owned()];
diff --git a/compiler/rustc_codegen_cranelift/patches/0002-rand-Disable-failing-test.patch b/compiler/rustc_codegen_cranelift/patches/0002-rand-Disable-failing-test.patch
deleted file mode 100644
index ae13ab3b0ca..00000000000
--- a/compiler/rustc_codegen_cranelift/patches/0002-rand-Disable-failing-test.patch
+++ /dev/null
@@ -1,24 +0,0 @@
-From a8fb97120d71252538b6b026695df40d02696bdb Mon Sep 17 00:00:00 2001
-From: bjorn3 <bjorn3@users.noreply.github.com>
-Date: Sat, 15 Aug 2020 20:04:38 +0200
-Subject: [PATCH] [rand] Disable failing test
-
----
- src/distributions/uniform.rs | 1 +
- 1 file changed, 1 insertion(+), 0 deletions(-)
-
-diff --git a/src/distributions/uniform.rs b/src/distributions/uniform.rs
-index 480b859..c80bb6f 100644
---- a/src/distributions/uniform.rs
-+++ b/src/distributions/uniform.rs
-@@ -1314,6 +1314,7 @@ mod tests {
-         not(target_arch = "wasm32"),
-         not(target_arch = "asmjs")
-     ))]
-+    #[ignore] // Requires unwinding
-     fn test_float_assertions() {
-         use super::SampleUniform;
-         use std::panic::catch_unwind;
--- 
-2.20.1
-
diff --git a/compiler/rustc_codegen_cranelift/patches/0003-rand-Disable-rand-tests-on-mingw.patch b/compiler/rustc_codegen_cranelift/patches/0003-rand-Disable-rand-tests-on-mingw.patch
deleted file mode 100644
index eb452c5cd37..00000000000
--- a/compiler/rustc_codegen_cranelift/patches/0003-rand-Disable-rand-tests-on-mingw.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From eec874c889b8d24e5ad50faded24288150f057b1 Mon Sep 17 00:00:00 2001
-From: Afonso Bordado <afonsobordado@az8.co>
-Date: Tue, 27 Sep 2022 08:13:58 +0100
-Subject: [PATCH] Disable rand tests on mingw
-
----
- rand_distr/src/pareto.rs            | 2 ++
- rand_distr/tests/value_stability.rs | 4 ++++
- 2 files changed, 6 insertions(+)
-
-diff --git a/rand_distr/src/pareto.rs b/rand_distr/src/pareto.rs
-index 217899e..9cedeb7 100644
---- a/rand_distr/src/pareto.rs
-+++ b/rand_distr/src/pareto.rs
-@@ -107,6 +107,8 @@ mod tests {
-     }
-
-     #[test]
-+    // This is broken on x86_64-pc-windows-gnu presumably due to a broken powf implementation
-+    #[cfg_attr(all(target_os = "windows", target_env = "gnu"), ignore)]
-     fn value_stability() {
-         fn test_samples<F: Float + Debug + Display + LowerExp, D: Distribution<F>>(
-             distr: D, thresh: F, expected: &[F],
-diff --git a/rand_distr/tests/value_stability.rs b/rand_distr/tests/value_stability.rs
-index 192ba74..0101ace 100644
---- a/rand_distr/tests/value_stability.rs
-+++ b/rand_distr/tests/value_stability.rs
-@@ -72,6 +72,8 @@ fn unit_disc_stability() {
- }
-
- #[test]
-+// This is broken on x86_64-pc-windows-gnu
-+#[cfg_attr(all(target_os = "windows", target_env = "gnu"), ignore)]
- fn pareto_stability() {
-     test_samples(213, Pareto::new(1.0, 1.0).unwrap(), &[
-         1.0423688f32, 2.1235929, 4.132709, 1.4679428,
-@@ -143,6 +145,8 @@ fn inverse_gaussian_stability() {
- }
-
- #[test]
-+// This is broken on x86_64-pc-windows-gnu
-+#[cfg_attr(all(target_os = "windows", target_env = "gnu"), ignore)]
- fn gamma_stability() {
-     // Gamma has 3 cases: shape == 1, shape < 1, shape > 1
-     test_samples(223, Gamma::new(1.0, 5.0).unwrap(), &[
---
-2.25.1
diff --git a/compiler/rustc_codegen_cranelift/patches/portable-simd-lock.toml b/compiler/rustc_codegen_cranelift/patches/portable-simd-lock.toml
deleted file mode 100644
index 5c9dc7b361f..00000000000
--- a/compiler/rustc_codegen_cranelift/patches/portable-simd-lock.toml
+++ /dev/null
@@ -1,304 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 3
-
-[[package]]
-name = "autocfg"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
-
-[[package]]
-name = "bitflags"
-version = "1.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
-
-[[package]]
-name = "bumpalo"
-version = "3.14.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
-
-[[package]]
-name = "byteorder"
-version = "1.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
-
-[[package]]
-name = "cfg-if"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
-
-[[package]]
-name = "console_error_panic_hook"
-version = "0.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
-dependencies = [
- "cfg-if",
- "wasm-bindgen",
-]
-
-[[package]]
-name = "core_simd"
-version = "0.1.0"
-dependencies = [
- "proptest",
- "std_float",
- "test_helpers",
- "wasm-bindgen",
- "wasm-bindgen-test",
-]
-
-[[package]]
-name = "js-sys"
-version = "0.3.64"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
-dependencies = [
- "wasm-bindgen",
-]
-
-[[package]]
-name = "log"
-version = "0.4.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
-
-[[package]]
-name = "num-traits"
-version = "0.2.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
-dependencies = [
- "autocfg",
-]
-
-[[package]]
-name = "once_cell"
-version = "1.18.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
-
-[[package]]
-name = "ppv-lite86"
-version = "0.2.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.67"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "proptest"
-version = "0.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12e6c80c1139113c28ee4670dc50cc42915228b51f56a9e407f0ec60f966646f"
-dependencies = [
- "bitflags",
- "byteorder",
- "num-traits",
- "rand",
- "rand_chacha",
- "rand_xorshift",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.33"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "rand"
-version = "0.7.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
-dependencies = [
- "rand_chacha",
- "rand_core",
- "rand_hc",
-]
-
-[[package]]
-name = "rand_chacha"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
-dependencies = [
- "ppv-lite86",
- "rand_core",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
-
-[[package]]
-name = "rand_hc"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
-dependencies = [
- "rand_core",
-]
-
-[[package]]
-name = "rand_xorshift"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8"
-dependencies = [
- "rand_core",
-]
-
-[[package]]
-name = "scoped-tls"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
-
-[[package]]
-name = "std_float"
-version = "0.1.0"
-dependencies = [
- "core_simd",
-]
-
-[[package]]
-name = "syn"
-version = "2.0.37"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "test_helpers"
-version = "0.1.0"
-dependencies = [
- "proptest",
-]
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
-
-[[package]]
-name = "wasm-bindgen"
-version = "0.2.87"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
-dependencies = [
- "cfg-if",
- "wasm-bindgen-macro",
-]
-
-[[package]]
-name = "wasm-bindgen-backend"
-version = "0.2.87"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
-dependencies = [
- "bumpalo",
- "log",
- "once_cell",
- "proc-macro2",
- "quote",
- "syn",
- "wasm-bindgen-shared",
-]
-
-[[package]]
-name = "wasm-bindgen-futures"
-version = "0.4.37"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03"
-dependencies = [
- "cfg-if",
- "js-sys",
- "wasm-bindgen",
- "web-sys",
-]
-
-[[package]]
-name = "wasm-bindgen-macro"
-version = "0.2.87"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
-dependencies = [
- "quote",
- "wasm-bindgen-macro-support",
-]
-
-[[package]]
-name = "wasm-bindgen-macro-support"
-version = "0.2.87"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
- "wasm-bindgen-backend",
- "wasm-bindgen-shared",
-]
-
-[[package]]
-name = "wasm-bindgen-shared"
-version = "0.2.87"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
-
-[[package]]
-name = "wasm-bindgen-test"
-version = "0.3.37"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e6e302a7ea94f83a6d09e78e7dc7d9ca7b186bc2829c24a22d0753efd680671"
-dependencies = [
- "console_error_panic_hook",
- "js-sys",
- "scoped-tls",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "wasm-bindgen-test-macro",
-]
-
-[[package]]
-name = "wasm-bindgen-test-macro"
-version = "0.3.37"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ecb993dd8c836930ed130e020e77d9b2e65dd0fbab1b67c790b0f5d80b11a575"
-dependencies = [
- "proc-macro2",
- "quote",
-]
-
-[[package]]
-name = "web-sys"
-version = "0.3.64"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
-dependencies = [
- "js-sys",
- "wasm-bindgen",
-]
diff --git a/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml b/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml
index de89c4f5eff..f10b4d6b9d4 100644
--- a/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml
+++ b/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml
@@ -174,9 +174,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.148"
+version = "0.2.149"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
+checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -361,7 +361,6 @@ version = "0.0.0"
 dependencies = [
  "addr2line",
  "alloc",
- "cc",
  "cfg-if",
  "compiler_builtins",
  "core",
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain
index 86ef127badd..3735ac1c17b 100644
--- a/compiler/rustc_codegen_cranelift/rust-toolchain
+++ b/compiler/rustc_codegen_cranelift/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2023-10-09"
+channel = "nightly-2023-10-21"
 components = ["rust-src", "rustc-dev", "llvm-tools"]
diff --git a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
index 60ac6bc9951..3e48fb006de 100644
--- a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
@@ -1,7 +1,10 @@
 #!/usr/bin/env bash
 set -e
 
-./y.sh build
+# Compiletest expects all standard library paths to start with /rustc/FAKE_PREFIX.
+# CG_CLIF_STDLIB_REMAP_PATH_PREFIX will cause cg_clif's build system to pass
+# --remap-path-prefix to handle this.
+CG_CLIF_STDLIB_REMAP_PATH_PREFIX=/rustc/FAKE_PREFIX ./y.sh build
 
 echo "[SETUP] Rust fork"
 git clone https://github.com/rust-lang/rust.git || true
@@ -13,23 +16,6 @@ git checkout "$(rustc -V | cut -d' ' -f3 | tr -d '(')"
 git -c user.name=Dummy -c user.email=dummy@example.com -c commit.gpgSign=false \
     am ../patches/*-stdlib-*.patch
 
-git apply - <<EOF
-diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
-index d95b5b7f17f..00b6f0e3635 100644
---- a/library/alloc/Cargo.toml
-+++ b/library/alloc/Cargo.toml
-@@ -8,7 +8,7 @@ edition = "2018"
-
- [dependencies]
- core = { path = "../core" }
--compiler_builtins = { version = "0.1.40", features = ['rustc-dep-of-std'] }
-+compiler_builtins = { version = "0.1.66", features = ['rustc-dep-of-std', 'no-asm'] }
-
- [dev-dependencies]
- rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
- rand_xorshift = "0.3.0"
-EOF
-
 cat > config.toml <<EOF
 change-id = 115898
 
@@ -49,11 +35,6 @@ verbose-tests = false
 EOF
 popd
 
-# FIXME remove once inline asm is fully supported
-export RUSTFLAGS="$RUSTFLAGS --cfg=rustix_use_libc"
-
-export CFG_VIRTUAL_RUST_SOURCE_BASE_DIR="$(cd build/stdlib; pwd)"
-
 # Allow the testsuite to use llvm tools
 host_triple=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ")
 export LLVM_BIN_DIR="$(rustc --print sysroot)/lib/rustlib/$host_triple/bin"
diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
index c83efa51e9e..b485f2571cc 100755
--- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
@@ -27,8 +27,6 @@ rm tests/ui/parser/unclosed-delimiter-in-dep.rs # submodule contains //~ERROR
 # missing features
 # ================
 
-rm -r tests/run-make/comment-section # cg_clif doesn't yet write the .comment section
-
 # requires stack unwinding
 # FIXME add needs-unwind to these tests
 rm -r tests/run-make/libtest-junit
@@ -44,10 +42,8 @@ rm tests/ui/proc-macro/allowed-signatures.rs
 rm tests/ui/proc-macro/no-mangle-in-proc-macro-issue-111888.rs
 
 # vendor intrinsics
-rm tests/ui/sse2.rs # cpuid not supported, so sse2 not detected
+rm tests/ui/sse2.rs # CodegenBackend::target_features not yet implemented
 rm tests/ui/simd/array-type.rs # "Index argument for `simd_insert` is not a constant"
-rm tests/ui/simd/intrinsic/generic-bswap-byte.rs # simd_bswap not yet implemented
-rm tests/ui/simd/intrinsic/generic-arithmetic-pass.rs # many missing simd intrinsics
 
 # exotic linkages
 rm tests/ui/issues/issue-33992.rs # unsupported linkages
@@ -115,21 +111,6 @@ rm tests/ui/consts/issue-33537.rs # same
 rm tests/ui/layout/valid_range_oob.rs # different ICE message
 rm tests/ui/const-generics/generic_const_exprs/issue-80742.rs # gives error instead of ICE with cg_clif
 
-rm tests/ui/consts/issue-miri-1910.rs # different error message
-rm tests/ui/consts/offset_ub.rs # same
-rm tests/ui/consts/const-eval/ub-slice-get-unchecked.rs # same
-rm tests/ui/intrinsics/panic-uninitialized-zeroed.rs # same
-rm tests/ui/lint/lint-const-item-mutation.rs # same
-rm tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs # same
-rm tests/ui/suggestions/derive-trait-for-method-call.rs # same
-rm tests/ui/typeck/issue-46112.rs # same
-rm tests/ui/consts/const_cmp_type_id.rs # same
-rm tests/ui/consts/issue-73976-monomorphic.rs # same
-rm tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.rs # same
-rm tests/ui/consts/const-eval/nonnull_as_ref_ub.rs # same
-rm tests/ui/consts/issue-94675.rs # same
-rm tests/ui/associated-types/issue-85103-layout-debug.rs # same
-
 # rustdoc-clif passes extra args, suppressing the help message when no args are passed
 rm -r tests/run-make/issue-88756-default-output
 
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
index 84bfe15c13f..e6edc452cfb 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
@@ -20,7 +20,7 @@ use crate::prelude::*;
 
 pub(crate) fn producer() -> String {
     format!(
-        "cg_clif (rustc {}, cranelift {})",
+        "rustc version {} with cranelift {}",
         rustc_interface::util::rustc_version_str().unwrap_or("unknown version"),
         cranelift_codegen::VERSION,
     )
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index 49f51f9f956..d3a7decc543 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -394,28 +394,31 @@ pub(crate) fn run_aot(
     let modules = tcx.sess.time("codegen mono items", || {
         cgus.iter()
             .enumerate()
-            .map(|(i, cgu)| match cgu_reuse[i] {
-                CguReuse::No => {
-                    let dep_node = cgu.codegen_dep_node(tcx);
-                    tcx.dep_graph
-                        .with_task(
-                            dep_node,
-                            tcx,
-                            (
-                                backend_config.clone(),
-                                global_asm_config.clone(),
-                                cgu.name(),
-                                concurrency_limiter.acquire(tcx.sess.diagnostic()),
-                            ),
-                            module_codegen,
-                            Some(rustc_middle::dep_graph::hash_result),
-                        )
-                        .0
-                }
-                CguReuse::PreLto => unreachable!("LTO not yet supported"),
-                CguReuse::PostLto => {
-                    concurrency_limiter.job_already_done();
-                    OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, cgu))
+            .map(|(i, cgu)| {
+                let cgu_reuse =
+                    if backend_config.disable_incr_cache { CguReuse::No } else { cgu_reuse[i] };
+                match cgu_reuse {
+                    CguReuse::No => {
+                        let dep_node = cgu.codegen_dep_node(tcx);
+                        tcx.dep_graph
+                            .with_task(
+                                dep_node,
+                                tcx,
+                                (
+                                    backend_config.clone(),
+                                    global_asm_config.clone(),
+                                    cgu.name(),
+                                    concurrency_limiter.acquire(tcx.sess.diagnostic()),
+                                ),
+                                module_codegen,
+                                Some(rustc_middle::dep_graph::hash_result),
+                            )
+                            .0
+                    }
+                    CguReuse::PreLto | CguReuse::PostLto => {
+                        concurrency_limiter.job_already_done();
+                        OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, cgu))
+                    }
                 }
             })
             .collect::<Vec<_>>()
diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs
index ebd9b728d90..6692d1b85ea 100644
--- a/compiler/rustc_codegen_cranelift/src/global_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs
@@ -81,6 +81,10 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String,
     }
 }
 
+pub(crate) fn asm_supported(tcx: TyCtxt<'_>) -> bool {
+    cfg!(feature = "inline_asm") && !tcx.sess.target.is_like_windows
+}
+
 #[derive(Debug)]
 pub(crate) struct GlobalAsmConfig {
     asm_enabled: bool,
@@ -90,10 +94,8 @@ pub(crate) struct GlobalAsmConfig {
 
 impl GlobalAsmConfig {
     pub(crate) fn new(tcx: TyCtxt<'_>) -> Self {
-        let asm_enabled = cfg!(feature = "inline_asm") && !tcx.sess.target.is_like_windows;
-
         GlobalAsmConfig {
-            asm_enabled,
+            asm_enabled: asm_supported(tcx),
             assembler: crate::toolchain::get_toolchain_binary(tcx.sess, "as"),
             output_filenames: tcx.output_filenames(()).clone(),
         }
diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
index dd2127d554d..ed077234254 100644
--- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
@@ -8,6 +8,7 @@ use rustc_span::sym;
 use rustc_target::asm::*;
 use target_lexicon::BinaryFormat;
 
+use crate::global_asm::asm_supported;
 use crate::prelude::*;
 
 enum CInlineAsmOperand<'tcx> {
@@ -44,9 +45,13 @@ pub(crate) fn codegen_inline_asm<'tcx>(
 ) {
     // FIXME add .eh_frame unwind info directives
 
-    if !template.is_empty()
-        && (cfg!(not(feature = "inline_asm")) || fx.tcx.sess.target.is_like_windows)
-    {
+    if !asm_supported(fx.tcx) {
+        if template.is_empty() {
+            let destination_block = fx.get_block(destination.unwrap());
+            fx.bcx.ins().jump(destination_block, &[]);
+            return;
+        }
+
         // Used by panic_abort
         if template[0] == InlineAsmTemplatePiece::String("int $$0x29".to_string()) {
             fx.bcx.ins().trap(TrapCode::User(1));
@@ -144,6 +149,16 @@ pub(crate) fn codegen_inline_asm<'tcx>(
             return;
         }
 
+        // Used by core::hint::spin_loop()
+        if template[0]
+            == InlineAsmTemplatePiece::String(".insn i 0x0F, 0, x0, x0, 0x010".to_string())
+            && template.len() == 1
+        {
+            let destination_block = fx.get_block(destination.unwrap());
+            fx.bcx.ins().jump(destination_block, &[]);
+            return;
+        }
+
         // Used by measureme
         if template[0] == InlineAsmTemplatePiece::String("xor %eax, %eax".to_string())
             && template[1] == InlineAsmTemplatePiece::String("\n".to_string())
@@ -223,6 +238,16 @@ pub(crate) fn codegen_inline_asm<'tcx>(
             fx.bcx.ins().jump(destination_block, &[]);
             return;
         }
+
+        if cfg!(not(feature = "inline_asm")) {
+            fx.tcx.sess.span_err(
+                span,
+                "asm! and global_asm! support is disabled while compiling rustc_codegen_cranelift",
+            );
+        } else {
+            fx.tcx.sess.span_err(span, "asm! and global_asm! are not yet supported on Windows");
+        }
+        return;
     }
 
     let operands = operands
@@ -745,6 +770,13 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
                 // x19 is reserved by LLVM for the "base pointer", so rustc doesn't allow using it
                 generated_asm.push_str("    mov x19, x0\n");
             }
+            InlineAsmArch::RiscV64 => {
+                generated_asm.push_str("    addi sp, sp, -16\n");
+                generated_asm.push_str("    sd ra, 8(sp)\n");
+                generated_asm.push_str("    sd s1, 0(sp)\n"); // s1 is callee saved
+                // s1/x9 is reserved by LLVM for the "base pointer", so rustc doesn't allow using it
+                generated_asm.push_str("    mv s1, a0\n");
+            }
             _ => unimplemented!("prologue for {:?}", arch),
         }
     }
@@ -761,6 +793,12 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
                 generated_asm.push_str("    ldp fp, lr, [sp], #32\n");
                 generated_asm.push_str("    ret\n");
             }
+            InlineAsmArch::RiscV64 => {
+                generated_asm.push_str("    ld s1, 0(sp)\n");
+                generated_asm.push_str("    ld ra, 8(sp)\n");
+                generated_asm.push_str("    addi sp, sp, 16\n");
+                generated_asm.push_str("    ret\n");
+            }
             _ => unimplemented!("epilogue for {:?}", arch),
         }
     }
@@ -771,7 +809,10 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
                 generated_asm.push_str("    ud2\n");
             }
             InlineAsmArch::AArch64 => {
-                generated_asm.push_str("    brk     #0x1");
+                generated_asm.push_str("    brk     #0x1\n");
+            }
+            InlineAsmArch::RiscV64 => {
+                generated_asm.push_str("    ebreak\n");
             }
             _ => unimplemented!("epilogue_noreturn for {:?}", arch),
         }
@@ -794,6 +835,11 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
                 reg.emit(generated_asm, InlineAsmArch::AArch64, None).unwrap();
                 writeln!(generated_asm, ", [x19, 0x{:x}]", offset.bytes()).unwrap();
             }
+            InlineAsmArch::RiscV64 => {
+                generated_asm.push_str("    sd ");
+                reg.emit(generated_asm, InlineAsmArch::RiscV64, None).unwrap();
+                writeln!(generated_asm, ", 0x{:x}(s1)", offset.bytes()).unwrap();
+            }
             _ => unimplemented!("save_register for {:?}", arch),
         }
     }
@@ -815,6 +861,11 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
                 reg.emit(generated_asm, InlineAsmArch::AArch64, None).unwrap();
                 writeln!(generated_asm, ", [x19, 0x{:x}]", offset.bytes()).unwrap();
             }
+            InlineAsmArch::RiscV64 => {
+                generated_asm.push_str("    ld ");
+                reg.emit(generated_asm, InlineAsmArch::RiscV64, None).unwrap();
+                writeln!(generated_asm, ", 0x{:x}(s1)", offset.bytes()).unwrap();
+            }
             _ => unimplemented!("restore_register for {:?}", arch),
         }
     }
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index 8992de5a923..148193b5a97 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -1,6 +1,6 @@
-#![cfg_attr(not(bootstrap), allow(internal_features))]
-#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
-#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(all(doc, not(bootstrap)), allow(internal_features))]
+#![cfg_attr(all(doc, not(bootstrap)), feature(rustdoc_internals))]
+#![cfg_attr(all(doc, not(bootstrap)), doc(rust_logo))]
 #![feature(rustc_private)]
 // Note: please avoid adding other feature gates where possible
 #![warn(rust_2018_idioms)]
@@ -189,7 +189,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
     }
 
     fn target_features(&self, _sess: &Session, _allow_unstable: bool) -> Vec<rustc_span::Symbol> {
-        vec![]
+        vec![] // FIXME necessary for #[cfg(target_feature]
     }
 
     fn print_version(&self) {
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index f75add90aa2..2f825b801ac 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -4,14 +4,16 @@ use crate::coverageinfo::ffi::CounterMappingRegion;
 use crate::coverageinfo::map_data::FunctionCoverage;
 use crate::llvm;
 
-use rustc_codegen_ssa::traits::ConstMethods;
+use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods};
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_index::IndexVec;
 use rustc_middle::bug;
+use rustc_middle::mir;
 use rustc_middle::mir::coverage::CodeRegion;
 use rustc_middle::ty::{self, TyCtxt};
+use rustc_span::def_id::DefIdSet;
 use rustc_span::Symbol;
 
 /// Generates and exports the Coverage Map.
@@ -94,8 +96,14 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
     // Generate the LLVM IR representation of the coverage map and store it in a well-known global
     let cov_data_val = generate_coverage_map(cx, version, filenames_size, filenames_val);
 
+    let mut unused_function_names = Vec::new();
+
     let covfun_section_name = coverageinfo::covfun_section_name(cx);
     for (mangled_function_name, source_hash, is_used, coverage_mapping_buffer) in function_data {
+        if !is_used {
+            unused_function_names.push(mangled_function_name);
+        }
+
         save_function_record(
             cx,
             &covfun_section_name,
@@ -107,6 +115,25 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
         );
     }
 
+    // For unused functions, we need to take their mangled names and store them
+    // in a specially-named global array. LLVM's `InstrProfiling` pass will
+    // detect this global and include those names in its `__llvm_prf_names`
+    // section. (See `llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp`.)
+    if !unused_function_names.is_empty() {
+        assert!(cx.codegen_unit.is_code_coverage_dead_code_cgu());
+
+        let name_globals = unused_function_names
+            .into_iter()
+            .map(|mangled_function_name| cx.const_str(mangled_function_name).0)
+            .collect::<Vec<_>>();
+        let initializer = cx.const_array(cx.type_ptr(), &name_globals);
+
+        let array = llvm::add_global(cx.llmod, cx.val_ty(initializer), "__llvm_coverage_names");
+        llvm::set_global_constant(array, true);
+        llvm::set_linkage(array, llvm::Linkage::InternalLinkage);
+        llvm::set_initializer(array, initializer);
+    }
+
     // Save the coverage data value to LLVM IR
     coverageinfo::save_cov_data_to_mod(cx, cov_data_val);
 }
@@ -287,13 +314,12 @@ fn save_function_record(
 /// `-Clink-dead-code` will not generate code for unused generic functions.)
 ///
 /// We can find the unused functions (including generic functions) by the set difference of all MIR
-/// `DefId`s (`tcx` query `mir_keys`) minus the codegenned `DefId`s (`tcx` query
-/// `codegened_and_inlined_items`).
+/// `DefId`s (`tcx` query `mir_keys`) minus the codegenned `DefId`s (`codegenned_and_inlined_items`).
 ///
-/// These unused functions are then codegen'd in one of the CGUs which is marked as the
-/// "code coverage dead code cgu" during the partitioning process. This prevents us from generating
-/// code regions for the same function more than once which can lead to linker errors regarding
-/// duplicate symbols.
+/// These unused functions don't need to be codegenned, but we do need to add them to the function
+/// coverage map (in a single designated CGU) so that we still emit coverage mappings for them.
+/// We also end up adding their symbol names to a special global array that LLVM will include in
+/// its embedded coverage data.
 fn add_unused_functions(cx: &CodegenCx<'_, '_>) {
     assert!(cx.codegen_unit.is_code_coverage_dead_code_cgu());
 
@@ -324,19 +350,80 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) {
         })
         .collect();
 
-    let codegenned_def_ids = tcx.codegened_and_inlined_items(());
+    let codegenned_def_ids = codegenned_and_inlined_items(tcx);
 
-    for non_codegenned_def_id in
-        eligible_def_ids.into_iter().filter(|id| !codegenned_def_ids.contains(id))
-    {
+    // For each `DefId` that should have coverage instrumentation but wasn't
+    // codegenned, add it to the function coverage map as an unused function.
+    for def_id in eligible_def_ids.into_iter().filter(|id| !codegenned_def_ids.contains(id)) {
         // Skip any function that didn't have coverage data added to it by the
         // coverage instrumentor.
-        let body = tcx.instance_mir(ty::InstanceDef::Item(non_codegenned_def_id));
+        let body = tcx.instance_mir(ty::InstanceDef::Item(def_id));
         let Some(function_coverage_info) = body.function_coverage_info.as_deref() else {
             continue;
         };
 
-        debug!("generating unused fn: {:?}", non_codegenned_def_id);
-        cx.define_unused_fn(non_codegenned_def_id, function_coverage_info);
+        debug!("generating unused fn: {def_id:?}");
+        let instance = declare_unused_fn(tcx, def_id);
+        add_unused_function_coverage(cx, instance, function_coverage_info);
+    }
+}
+
+/// All items participating in code generation together with (instrumented)
+/// items inlined into them.
+fn codegenned_and_inlined_items(tcx: TyCtxt<'_>) -> DefIdSet {
+    let (items, cgus) = tcx.collect_and_partition_mono_items(());
+    let mut visited = DefIdSet::default();
+    let mut result = items.clone();
+
+    for cgu in cgus {
+        for item in cgu.items().keys() {
+            if let mir::mono::MonoItem::Fn(ref instance) = item {
+                let did = instance.def_id();
+                if !visited.insert(did) {
+                    continue;
+                }
+                let body = tcx.instance_mir(instance.def);
+                for block in body.basic_blocks.iter() {
+                    for statement in &block.statements {
+                        let mir::StatementKind::Coverage(_) = statement.kind else { continue };
+                        let scope = statement.source_info.scope;
+                        if let Some(inlined) = scope.inlined_instance(&body.source_scopes) {
+                            result.insert(inlined.def_id());
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    result
+}
+
+fn declare_unused_fn<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::Instance<'tcx> {
+    ty::Instance::new(
+        def_id,
+        ty::GenericArgs::for_item(tcx, def_id, |param, _| {
+            if let ty::GenericParamDefKind::Lifetime = param.kind {
+                tcx.lifetimes.re_erased.into()
+            } else {
+                tcx.mk_param_from_def(param)
+            }
+        }),
+    )
+}
+
+fn add_unused_function_coverage<'tcx>(
+    cx: &CodegenCx<'_, 'tcx>,
+    instance: ty::Instance<'tcx>,
+    function_coverage_info: &'tcx mir::coverage::FunctionCoverageInfo,
+) {
+    // An unused function's mappings will automatically be rewritten to map to
+    // zero, because none of its counters/expressions are marked as seen.
+    let function_coverage = FunctionCoverage::unused(instance, function_coverage_info);
+
+    if let Some(coverage_context) = cx.coverage_context() {
+        coverage_context.function_coverage_map.borrow_mut().insert(instance, function_coverage);
+    } else {
+        bug!("Could not get the `coverage_context`");
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index 204a73b788a..cf7c7e6be60 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -1,6 +1,5 @@
 use crate::llvm;
 
-use crate::abi::Abi;
 use crate::builder::Builder;
 use crate::common::CodegenCx;
 use crate::coverageinfo::ffi::{CounterExpression, CounterMappingRegion};
@@ -12,17 +11,12 @@ use rustc_codegen_ssa::traits::{
     StaticMethods,
 };
 use rustc_data_structures::fx::FxHashMap;
-use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
 use rustc_llvm::RustString;
 use rustc_middle::bug;
-use rustc_middle::mir::coverage::{CounterId, CoverageKind, FunctionCoverageInfo};
+use rustc_middle::mir::coverage::CoverageKind;
 use rustc_middle::mir::Coverage;
-use rustc_middle::ty;
-use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
-use rustc_middle::ty::GenericArgs;
+use rustc_middle::ty::layout::HasTyCtxt;
 use rustc_middle::ty::Instance;
-use rustc_middle::ty::Ty;
 
 use std::cell::RefCell;
 
@@ -30,8 +24,6 @@ pub(crate) mod ffi;
 pub(crate) mod map_data;
 pub mod mapgen;
 
-const UNUSED_FUNCTION_COUNTER_ID: CounterId = CounterId::START;
-
 const VAR_ALIGN_BYTES: usize = 8;
 
 /// A context object for maintaining all state needed by the coverageinfo module.
@@ -76,25 +68,6 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
             bug!("Could not get the `coverage_context`");
         }
     }
-
-    /// Functions with MIR-based coverage are normally codegenned _only_ if
-    /// called. LLVM coverage tools typically expect every function to be
-    /// defined (even if unused), with at least one call to LLVM intrinsic
-    /// `instrprof.increment`.
-    ///
-    /// Codegen a small function that will never be called, with one counter
-    /// that will never be incremented.
-    ///
-    /// For used/called functions, the coverageinfo was already added to the
-    /// `function_coverage_map` (keyed by function `Instance`) during codegen.
-    /// But in this case, since the unused function was _not_ previously
-    /// codegenned, collect the function coverage info from MIR and add an
-    /// "unused" entry to the function coverage map.
-    fn define_unused_fn(&self, def_id: DefId, function_coverage_info: &'tcx FunctionCoverageInfo) {
-        let instance = declare_unused_fn(self, def_id);
-        codegen_unused_fn_and_counter(self, instance);
-        add_unused_function_coverage(self, instance, function_coverage_info);
-    }
 }
 
 impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
@@ -159,76 +132,6 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
     }
 }
 
-fn declare_unused_fn<'tcx>(cx: &CodegenCx<'_, 'tcx>, def_id: DefId) -> Instance<'tcx> {
-    let tcx = cx.tcx;
-
-    let instance = Instance::new(
-        def_id,
-        GenericArgs::for_item(tcx, def_id, |param, _| {
-            if let ty::GenericParamDefKind::Lifetime = param.kind {
-                tcx.lifetimes.re_erased.into()
-            } else {
-                tcx.mk_param_from_def(param)
-            }
-        }),
-    );
-
-    let llfn = cx.declare_fn(
-        tcx.symbol_name(instance).name,
-        cx.fn_abi_of_fn_ptr(
-            ty::Binder::dummy(tcx.mk_fn_sig(
-                [Ty::new_unit(tcx)],
-                Ty::new_unit(tcx),
-                false,
-                hir::Unsafety::Unsafe,
-                Abi::Rust,
-            )),
-            ty::List::empty(),
-        ),
-        None,
-    );
-
-    llvm::set_linkage(llfn, llvm::Linkage::PrivateLinkage);
-    llvm::set_visibility(llfn, llvm::Visibility::Default);
-
-    assert!(cx.instances.borrow_mut().insert(instance, llfn).is_none());
-
-    instance
-}
-
-fn codegen_unused_fn_and_counter<'tcx>(cx: &CodegenCx<'_, 'tcx>, instance: Instance<'tcx>) {
-    let llfn = cx.get_fn(instance);
-    let llbb = Builder::append_block(cx, llfn, "unused_function");
-    let mut bx = Builder::build(cx, llbb);
-    let fn_name = bx.get_pgo_func_name_var(instance);
-    let hash = bx.const_u64(0);
-    let num_counters = bx.const_u32(1);
-    let index = bx.const_u32(u32::from(UNUSED_FUNCTION_COUNTER_ID));
-    debug!(
-        "codegen intrinsic instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?},
-            index={:?}) for unused function: {:?}",
-        fn_name, hash, num_counters, index, instance
-    );
-    bx.instrprof_increment(fn_name, hash, num_counters, index);
-    bx.ret_void();
-}
-
-fn add_unused_function_coverage<'tcx>(
-    cx: &CodegenCx<'_, 'tcx>,
-    instance: Instance<'tcx>,
-    function_coverage_info: &'tcx FunctionCoverageInfo,
-) {
-    // An unused function's mappings will automatically be rewritten to map to
-    // zero, because none of its counters/expressions are marked as seen.
-    let function_coverage = FunctionCoverage::unused(instance, function_coverage_info);
-
-    if let Some(coverage_context) = cx.coverage_context() {
-        coverage_context.function_coverage_map.borrow_mut().insert(instance, function_coverage);
-    } else {
-        bug!("Could not get the `coverage_context`");
-    }
-}
-
 /// Calls llvm::createPGOFuncNameVar() with the given function instance's
 /// mangled function name. The LLVM API returns an llvm::GlobalVariable
 /// containing the function name, with the specific variable name and linkage
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index f77bd53e76c..dce4e199e17 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -8,7 +8,6 @@ edition = "2021"
 [dependencies]
 arrayvec = { version = "0.7", default-features = false }
 bitflags = "1.2.1"
-cfg-if = "1.0"
 ena = "0.14.2"
 indexmap = { version = "2.0.0" }
 jobserver_crate = { version = "0.1.13", package = "jobserver" }
diff --git a/compiler/rustc_data_structures/src/flock.rs b/compiler/rustc_data_structures/src/flock.rs
index efdb44248d1..008565e4c7b 100644
--- a/compiler/rustc_data_structures/src/flock.rs
+++ b/compiler/rustc_data_structures/src/flock.rs
@@ -4,17 +4,20 @@
 //! green/native threading. This is just a bare-bones enough solution for
 //! librustdoc, it is not production quality at all.
 
-cfg_if! {
-    if #[cfg(target_os = "linux")] {
+cfg_match! {
+    cfg(target_os = "linux") => {
         mod linux;
         use linux as imp;
-    } else if #[cfg(unix)] {
+    }
+    cfg(unix) => {
         mod unix;
         use unix as imp;
-    } else if #[cfg(windows)] {
+    }
+    cfg(windows) => {
         mod windows;
         use self::windows as imp;
-    } else {
+    }
+    _ => {
         mod unsupported;
         use unsupported as imp;
     }
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 9511f1700e1..5d7f385c6e4 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -6,43 +6,44 @@
 //!
 //! This API is completely unstable and subject to change.
 
+// tidy-alphabetical-start
+#![allow(internal_features)]
+#![allow(rustc::default_hash_types)]
+#![allow(rustc::potential_query_instability)]
 #![cfg_attr(not(bootstrap), doc(rust_logo))]
 #![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![deny(rustc::diagnostic_outside_of_impl)]
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(unsafe_op_in_unsafe_fn)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(allocator_api)]
 #![feature(array_windows)]
 #![feature(auto_traits)]
 #![feature(cell_leak)]
+#![feature(cfg_match)]
 #![feature(core_intrinsics)]
 #![feature(extend_one)]
 #![feature(hash_raw_entry)]
 #![feature(hasher_prefixfree_extras)]
+#![feature(lazy_cell)]
+#![feature(lint_reasons)]
+#![feature(macro_metavar_expr)]
 #![feature(maybe_uninit_uninit_array)]
 #![feature(min_specialization)]
+#![feature(negative_impls)]
 #![feature(never_type)]
-#![feature(type_alias_impl_trait)]
-#![feature(lazy_cell)]
+#![feature(ptr_alignment_type)]
 #![feature(rustc_attrs)]
-#![feature(negative_impls)]
+#![feature(strict_provenance)]
 #![feature(test)]
 #![feature(thread_id_value)]
-#![feature(allocator_api)]
-#![feature(lint_reasons)]
+#![feature(type_alias_impl_trait)]
 #![feature(unwrap_infallible)]
-#![feature(strict_provenance)]
-#![feature(ptr_alignment_type)]
-#![feature(macro_metavar_expr)]
-#![allow(rustc::default_hash_types)]
-#![allow(rustc::potential_query_instability)]
-#![deny(rustc::untranslatable_diagnostic)]
-#![deny(rustc::diagnostic_outside_of_impl)]
-#![allow(internal_features)]
-#![deny(unsafe_op_in_unsafe_fn)]
+// tidy-alphabetical-end
 
 #[macro_use]
 extern crate tracing;
 #[macro_use]
-extern crate cfg_if;
-#[macro_use]
 extern crate rustc_macros;
 
 use std::fmt;
diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs
index b067f9d4502..a8c442377fb 100644
--- a/compiler/rustc_data_structures/src/marker.rs
+++ b/compiler/rustc_data_structures/src/marker.rs
@@ -1,11 +1,12 @@
-cfg_if!(
-    if #[cfg(not(parallel_compiler))] {
+cfg_match! {
+    cfg(not(parallel_compiler)) => {
         pub auto trait DynSend {}
         pub auto trait DynSync {}
 
         impl<T> DynSend for T {}
         impl<T> DynSync for T {}
-    } else {
+    }
+    _ => {
         #[rustc_on_unimplemented(
             message = "`{Self}` doesn't implement `DynSend`. \
             Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Send`"
@@ -48,13 +49,10 @@ cfg_if!(
             [std::io::StdoutLock<'_>]
             [std::io::StderrLock<'_>]
         );
-        cfg_if!(
-            // Consistent with `std`
-            // `os_imp::Env` is `!Send` in these platforms
-            if #[cfg(any(unix, target_os = "hermit", target_os = "wasi", target_os = "solid_asp3"))] {
-                impl !DynSend for std::env::VarsOs {}
-            }
-        );
+
+        #[cfg(any(unix, target_os = "hermit", target_os = "wasi", target_os = "solid_asp3"))]
+        // Consistent with `std`, `os_imp::Env` is `!Sync` in these platforms
+        impl !DynSend for std::env::VarsOs {}
 
         macro_rules! already_send {
             ($([$ty: ty])*) => {
@@ -123,13 +121,10 @@ cfg_if!(
             [std::sync::mpsc::Receiver<T> where T]
             [std::sync::mpsc::Sender<T> where T]
         );
-        cfg_if!(
-            // Consistent with `std`
-            // `os_imp::Env` is `!Sync` in these platforms
-            if #[cfg(any(unix, target_os = "hermit", target_os = "wasi", target_os = "solid_asp3"))] {
-                impl !DynSync for std::env::VarsOs {}
-            }
-        );
+
+        #[cfg(any(unix, target_os = "hermit", target_os = "wasi", target_os = "solid_asp3"))]
+        // Consistent with `std`, `os_imp::Env` is `!Sync` in these platforms
+        impl !DynSync for std::env::VarsOs {}
 
         macro_rules! already_sync {
             ($([$ty: ty])*) => {
@@ -183,7 +178,7 @@ cfg_if!(
             [thin_vec::ThinVec<T> where T: DynSync]
         );
     }
-);
+}
 
 pub fn assert_dyn_sync<T: ?Sized + DynSync>() {}
 pub fn assert_dyn_send<T: ?Sized + DynSend>() {}
diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs
index e688feb5fe1..ef7375a7320 100644
--- a/compiler/rustc_data_structures/src/profiling.rs
+++ b/compiler/rustc_data_structures/src/profiling.rs
@@ -859,8 +859,8 @@ fn get_thread_id() -> u32 {
 }
 
 // Memory reporting
-cfg_if! {
-    if #[cfg(windows)] {
+cfg_match! {
+    cfg(windows) => {
         pub fn get_resident_set_size() -> Option<usize> {
             use std::mem;
 
@@ -885,7 +885,8 @@ cfg_if! {
 
             Some(pmc.WorkingSetSize)
         }
-    } else if #[cfg(target_os = "macos")] {
+    }
+    cfg(target_os = "macos")  => {
         pub fn get_resident_set_size() -> Option<usize> {
             use libc::{c_int, c_void, getpid, proc_pidinfo, proc_taskinfo, PROC_PIDTASKINFO};
             use std::mem;
@@ -903,7 +904,8 @@ cfg_if! {
                 }
             }
         }
-    } else if #[cfg(unix)] {
+    }
+    cfg(unix) => {
         pub fn get_resident_set_size() -> Option<usize> {
             let field = 1;
             let contents = fs::read("/proc/self/statm").ok()?;
@@ -912,7 +914,8 @@ cfg_if! {
             let npages = s.parse::<usize>().ok()?;
             Some(npages * 4096)
         }
-    } else {
+    }
+    _ => {
         pub fn get_resident_set_size() -> Option<usize> {
             None
         }
diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs
index cca043ba0d1..62fff604f81 100644
--- a/compiler/rustc_data_structures/src/sync.rs
+++ b/compiler/rustc_data_structures/src/sync.rs
@@ -109,8 +109,8 @@ mod mode {
 
 pub use mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode};
 
-cfg_if! {
-    if #[cfg(not(parallel_compiler))] {
+cfg_match! {
+    cfg(not(parallel_compiler)) => {
         use std::ops::Add;
         use std::cell::Cell;
 
@@ -251,7 +251,8 @@ cfg_if! {
                 MTLock(self.0.clone())
             }
         }
-    } else {
+    }
+    _ => {
         pub use std::marker::Send as Send;
         pub use std::marker::Sync as Sync;
 
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index 6c7e68246ea..8b93829623d 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -86,6 +86,7 @@ expand_module_circular =
 expand_module_file_not_found =
     file not found for module `{$name}`
     .help = to create the module `{$name}`, create file "{$default_path}" or "{$secondary_path}"
+    .note = if there is a `mod {$name}` elsewhere in the crate already, import it with `use crate::...` instead
 
 expand_module_in_block =
     cannot declare a non-inline module inside a block unless it has a path attribute
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index e3a0ae3570e..d86632c47fc 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -350,6 +350,7 @@ pub(crate) struct ModuleInBlockName {
 #[derive(Diagnostic)]
 #[diag(expand_module_file_not_found, code = "E0583")]
 #[help]
+#[note]
 pub(crate) struct ModuleFileNotFound {
     #[primary_span]
     pub span: Span,
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index a1470cc69c3..74e2b157dd0 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -1557,38 +1557,24 @@ fn compare_number_of_generics<'tcx>(
                 DiagnosticId::Error("E0049".into()),
             );
 
-            let mut suffix = None;
-
+            let msg =
+                format!("expected {trait_count} {kind} parameter{}", pluralize!(trait_count),);
             if let Some(spans) = trait_spans {
                 let mut spans = spans.iter();
                 if let Some(span) = spans.next() {
-                    err.span_label(
-                        *span,
-                        format!(
-                            "expected {} {} parameter{}",
-                            trait_count,
-                            kind,
-                            pluralize!(trait_count),
-                        ),
-                    );
+                    err.span_label(*span, msg);
                 }
                 for span in spans {
                     err.span_label(*span, "");
                 }
             } else {
-                suffix = Some(format!(", expected {trait_count}"));
+                err.span_label(tcx.def_span(trait_.def_id), msg);
             }
 
             if let Some(span) = span {
                 err.span_label(
                     span,
-                    format!(
-                        "found {} {} parameter{}{}",
-                        impl_count,
-                        kind,
-                        pluralize!(impl_count),
-                        suffix.unwrap_or_default(),
-                    ),
+                    format!("found {} {} parameter{}", impl_count, kind, pluralize!(impl_count),),
                 );
             }
 
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index aef880acbe1..84e986488a6 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -121,6 +121,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         prior_arm_ty,
                         prior_arm_span,
                         scrut_span: scrut.span,
+                        scrut_hir_id: scrut.hir_id,
                         source: match_src,
                         prior_arms: other_arms.clone(),
                         opt_suggest_box_span,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index fdeaf7f6850..97ab3d0b751 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -776,6 +776,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 ref prior_arms,
                 opt_suggest_box_span,
                 scrut_span,
+                scrut_hir_id,
                 ..
             }) => match source {
                 hir::MatchSource::TryDesugar(scrut_hir_id) => {
@@ -843,6 +844,18 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     ) {
                         err.subdiagnostic(subdiag);
                     }
+                    if let Some(hir::Node::Expr(m)) = self.tcx.hir().find_parent(scrut_hir_id)
+                        && let Some(hir::Node::Stmt(stmt)) = self.tcx.hir().find_parent(m.hir_id)
+                        && let hir::StmtKind::Expr(_) = stmt.kind
+                    {
+                        err.span_suggestion_verbose(
+                            stmt.span.shrink_to_hi(),
+                            "consider using a semicolon here, but this will discard any values \
+                             in the match arms",
+                            ";",
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
                     if let Some(ret_sp) = opt_suggest_box_span {
                         // Get return type span and point to it.
                         self.suggest_boxing_for_return_impl_trait(
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index c8d42937f7b..918e484b9f4 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -3953,8 +3953,13 @@ declare_lint! {
 }
 
 declare_lint! {
-    /// The `non_exhaustive_omitted_patterns` lint detects when a wildcard (`_` or `..`) in a
-    /// pattern for a `#[non_exhaustive]` struct or enum is reachable.
+    /// The `non_exhaustive_omitted_patterns` lint aims to help consumers of a `#[non_exhaustive]`
+    /// struct or enum who want to match all of its fields/variants explicitly.
+    ///
+    /// The `#[non_exhaustive]` annotation forces matches to use wildcards, so exhaustiveness
+    /// checking cannot be used to ensure that all fields/variants are matched explicitly. To remedy
+    /// this, this allow-by-default lint warns the user when a match mentions some but not all of
+    /// the fields/variants of a `#[non_exhaustive]` struct or enum.
     ///
     /// ### Example
     ///
@@ -3968,9 +3973,9 @@ declare_lint! {
     ///
     /// // in crate B
     /// #![feature(non_exhaustive_omitted_patterns_lint)]
+    /// #[warn(non_exhaustive_omitted_patterns)]
     /// match Bar::A {
     ///     Bar::A => {},
-    ///     #[warn(non_exhaustive_omitted_patterns)]
     ///     _ => {},
     /// }
     /// ```
@@ -3978,29 +3983,32 @@ declare_lint! {
     /// This will produce:
     ///
     /// ```text
-    /// warning: reachable patterns not covered of non exhaustive enum
+    /// warning: some variants are not matched explicitly
     ///    --> $DIR/reachable-patterns.rs:70:9
     ///    |
-    /// LL |         _ => {}
-    ///    |         ^ pattern `B` not covered
+    /// LL |         match Bar::A {
+    ///    |               ^ pattern `Bar::B` not covered
     ///    |
     ///  note: the lint level is defined here
     ///   --> $DIR/reachable-patterns.rs:69:16
     ///    |
     /// LL |         #[warn(non_exhaustive_omitted_patterns)]
     ///    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-    ///    = help: ensure that all possible cases are being handled by adding the suggested match arms
+    ///    = help: ensure that all variants are matched explicitly by adding the suggested match arms
     ///    = note: the matched value is of type `Bar` and the `non_exhaustive_omitted_patterns` attribute was found
     /// ```
     ///
+    /// Warning: setting this to `deny` will make upstream non-breaking changes (adding fields or
+    /// variants to a `#[non_exhaustive]` struct or enum) break your crate. This goes against
+    /// expected semver behavior.
+    ///
     /// ### Explanation
     ///
-    /// Structs and enums tagged with `#[non_exhaustive]` force the user to add a
-    /// (potentially redundant) wildcard when pattern-matching, to allow for future
-    /// addition of fields or variants. The `non_exhaustive_omitted_patterns` lint
-    /// detects when such a wildcard happens to actually catch some fields/variants.
-    /// In other words, when the match without the wildcard would not be exhaustive.
-    /// This lets the user be informed if new fields/variants were added.
+    /// Structs and enums tagged with `#[non_exhaustive]` force the user to add a (potentially
+    /// redundant) wildcard when pattern-matching, to allow for future addition of fields or
+    /// variants. The `non_exhaustive_omitted_patterns` lint detects when such a wildcard happens to
+    /// actually catch some fields/variants. In other words, when the match without the wildcard
+    /// would not be exhaustive. This lets the user be informed if new fields/variants were added.
     pub NON_EXHAUSTIVE_OMITTED_PATTERNS,
     Allow,
     "detect when patterns of types marked `non_exhaustive` are missed",
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index b5f873c9257..cd5206a837f 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1882,12 +1882,6 @@ rustc_queries! {
         desc { |tcx| "determining whether `{}` needs codegen", tcx.def_path_str(def_id) }
     }
 
-    /// All items participating in code generation together with items inlined into them.
-    query codegened_and_inlined_items(_: ()) -> &'tcx DefIdSet {
-        eval_always
-        desc { "collecting codegened and inlined items" }
-    }
-
     query codegen_unit(sym: Symbol) -> &'tcx CodegenUnit<'tcx> {
         desc { "getting codegen unit `{sym}`" }
     }
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 9397e98343e..9e2ff3820af 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -541,6 +541,7 @@ pub struct MatchExpressionArmCause<'tcx> {
     pub prior_arm_ty: Ty<'tcx>,
     pub prior_arm_span: Span,
     pub scrut_span: Span,
+    pub scrut_hir_id: hir::HirId,
     pub source: hir::MatchSource,
     pub prior_arms: Vec<Span>,
     pub opt_suggest_box_span: Option<Span>,
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 4f98932a88d..c09dd186418 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -1,6 +1,6 @@
 use crate::{
     fluent_generated as fluent,
-    thir::pattern::{deconstruct_pat::DeconstructedPat, MatchCheckCtxt},
+    thir::pattern::{deconstruct_pat::WitnessPat, MatchCheckCtxt},
 };
 use rustc_errors::{
     error_code, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
@@ -810,7 +810,7 @@ impl<'tcx> Uncovered<'tcx> {
     pub fn new<'p>(
         span: Span,
         cx: &MatchCheckCtxt<'p, 'tcx>,
-        witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
+        witnesses: Vec<WitnessPat<'tcx>>,
     ) -> Self {
         let witness_1 = witnesses.get(0).unwrap().to_pat(cx);
         Self {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 9d38087fdeb..9156af3425a 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -1,4 +1,4 @@
-use super::deconstruct_pat::{Constructor, DeconstructedPat};
+use super::deconstruct_pat::{Constructor, DeconstructedPat, WitnessPat};
 use super::usefulness::{
     compute_match_usefulness, MatchArm, MatchCheckCtxt, Reachability, UsefulnessReport,
 };
@@ -279,7 +279,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
 
         let scrut = &self.thir[scrut];
         let scrut_ty = scrut.ty;
-        let report = compute_match_usefulness(&cx, &tarms, self.lint_level, scrut_ty);
+        let report = compute_match_usefulness(&cx, &tarms, self.lint_level, scrut_ty, scrut.span);
 
         match source {
             // Don't report arm reachability of desugared `match $iter.into_iter() { iter => .. }`
@@ -473,7 +473,8 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
         let pattern = self.lower_pattern(&mut cx, pat);
         let pattern_ty = pattern.ty();
         let arm = MatchArm { pat: pattern, hir_id: self.lint_level, has_guard: false };
-        let report = compute_match_usefulness(&cx, &[arm], self.lint_level, pattern_ty);
+        let report =
+            compute_match_usefulness(&cx, &[arm], self.lint_level, pattern_ty, pattern.span());
 
         // Note: we ignore whether the pattern is unreachable (i.e. whether the type is empty). We
         // only care about exhaustiveness here.
@@ -662,7 +663,7 @@ fn is_let_irrefutable<'p, 'tcx>(
     pat: &'p DeconstructedPat<'p, 'tcx>,
 ) -> bool {
     let arms = [MatchArm { pat, hir_id: pat_id, has_guard: false }];
-    let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty());
+    let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty(), pat.span());
 
     // Report if the pattern is unreachable, which can only occur when the type is uninhabited.
     // This also reports unreachable sub-patterns though, so we can't just replace it with an
@@ -701,8 +702,8 @@ fn report_arm_reachability<'p, 'tcx>(
     }
 }
 
-fn collect_non_exhaustive_tys<'p, 'tcx>(
-    pat: &DeconstructedPat<'p, 'tcx>,
+fn collect_non_exhaustive_tys<'tcx>(
+    pat: &WitnessPat<'tcx>,
     non_exhaustive_tys: &mut FxHashSet<Ty<'tcx>>,
 ) {
     if matches!(pat.ctor(), Constructor::NonExhaustive) {
@@ -718,7 +719,7 @@ fn non_exhaustive_match<'p, 'tcx>(
     thir: &Thir<'tcx>,
     scrut_ty: Ty<'tcx>,
     sp: Span,
-    witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
+    witnesses: Vec<WitnessPat<'tcx>>,
     arms: &[ArmId],
     expr_span: Span,
 ) -> ErrorGuaranteed {
@@ -896,10 +897,10 @@ fn non_exhaustive_match<'p, 'tcx>(
 
 pub(crate) fn joined_uncovered_patterns<'p, 'tcx>(
     cx: &MatchCheckCtxt<'p, 'tcx>,
-    witnesses: &[DeconstructedPat<'p, 'tcx>],
+    witnesses: &[WitnessPat<'tcx>],
 ) -> String {
     const LIMIT: usize = 3;
-    let pat_to_str = |pat: &DeconstructedPat<'p, 'tcx>| pat.to_pat(cx).to_string();
+    let pat_to_str = |pat: &WitnessPat<'tcx>| pat.to_pat(cx).to_string();
     match witnesses {
         [] => bug!(),
         [witness] => format!("`{}`", witness.to_pat(cx)),
@@ -916,7 +917,7 @@ pub(crate) fn joined_uncovered_patterns<'p, 'tcx>(
 }
 
 pub(crate) fn pattern_not_covered_label(
-    witnesses: &[DeconstructedPat<'_, '_>],
+    witnesses: &[WitnessPat<'_>],
     joined_patterns: &str,
 ) -> String {
     format!("pattern{} {} not covered", rustc_errors::pluralize!(witnesses.len()), joined_patterns)
@@ -927,7 +928,7 @@ fn adt_defined_here<'p, 'tcx>(
     cx: &MatchCheckCtxt<'p, 'tcx>,
     err: &mut Diagnostic,
     ty: Ty<'tcx>,
-    witnesses: &[DeconstructedPat<'p, 'tcx>],
+    witnesses: &[WitnessPat<'tcx>],
 ) {
     let ty = ty.peel_refs();
     if let ty::Adt(def, _) = ty.kind() {
@@ -958,7 +959,7 @@ fn adt_defined_here<'p, 'tcx>(
 fn maybe_point_at_variant<'a, 'p: 'a, 'tcx: 'a>(
     cx: &MatchCheckCtxt<'p, 'tcx>,
     def: AdtDef<'tcx>,
-    patterns: impl Iterator<Item = &'a DeconstructedPat<'p, 'tcx>>,
+    patterns: impl Iterator<Item = &'a WitnessPat<'tcx>>,
 ) -> Vec<Span> {
     use Constructor::*;
     let mut covered = vec![];
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index bbc0aeb66cf..86018340a69 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -629,18 +629,11 @@ pub(super) enum Constructor<'tcx> {
     /// `#[doc(hidden)]` ones.
     Hidden,
     /// Fake extra constructor for constructors that are not seen in the matrix, as explained in the
-    /// code for [`Constructor::split`]. The carried `bool` is used for the
-    /// `non_exhaustive_omitted_patterns` lint.
-    Missing {
-        nonexhaustive_enum_missing_visible_variants: bool,
-    },
+    /// code for [`Constructor::split`].
+    Missing,
 }
 
 impl<'tcx> Constructor<'tcx> {
-    pub(super) fn is_wildcard(&self) -> bool {
-        matches!(self, Wildcard)
-    }
-
     pub(super) fn is_non_exhaustive(&self) -> bool {
         matches!(self, NonExhaustive)
     }
@@ -778,14 +771,8 @@ impl<'tcx> Constructor<'tcx> {
                     let all_missing = split_set.present.is_empty();
                     let report_when_all_missing =
                         pcx.is_top_level && !IntRange::is_integral(pcx.ty);
-                    let ctor = if all_missing && !report_when_all_missing {
-                        Wildcard
-                    } else {
-                        Missing {
-                            nonexhaustive_enum_missing_visible_variants: split_set
-                                .nonexhaustive_enum_missing_visible_variants,
-                        }
-                    };
+                    let ctor =
+                        if all_missing && !report_when_all_missing { Wildcard } else { Missing };
                     smallvec![ctor]
                 } else {
                     split_set.present
@@ -905,11 +892,9 @@ pub(super) enum ConstructorSet {
 ///     either fully included in or disjoint from each constructor in the column. This avoids
 ///     non-trivial intersections like between `0..10` and `5..15`.
 #[derive(Debug)]
-struct SplitConstructorSet<'tcx> {
-    present: SmallVec<[Constructor<'tcx>; 1]>,
-    missing: Vec<Constructor<'tcx>>,
-    /// For the `non_exhaustive_omitted_patterns` lint.
-    nonexhaustive_enum_missing_visible_variants: bool,
+pub(super) struct SplitConstructorSet<'tcx> {
+    pub(super) present: SmallVec<[Constructor<'tcx>; 1]>,
+    pub(super) missing: Vec<Constructor<'tcx>>,
 }
 
 impl ConstructorSet {
@@ -1039,7 +1024,7 @@ impl ConstructorSet {
     /// constructors to 1/ determine which constructors of the type (if any) are missing; 2/ split
     /// constructors to handle non-trivial intersections e.g. on ranges or slices.
     #[instrument(level = "debug", skip(self, pcx, ctors), ret)]
-    fn split<'a, 'tcx>(
+    pub(super) fn split<'a, 'tcx>(
         &self,
         pcx: &PatCtxt<'_, '_, 'tcx>,
         ctors: impl Iterator<Item = &'a Constructor<'tcx>> + Clone,
@@ -1051,7 +1036,6 @@ impl ConstructorSet {
         let mut missing = Vec::new();
         // Constructors in `ctors`, except wildcards.
         let mut seen = ctors.filter(|c| !(matches!(c, Opaque | Wildcard)));
-        let mut nonexhaustive_enum_missing_visible_variants = false;
         match self {
             ConstructorSet::Single => {
                 if seen.next().is_none() {
@@ -1063,6 +1047,7 @@ impl ConstructorSet {
             ConstructorSet::Variants { visible_variants, hidden_variants, non_exhaustive } => {
                 let seen_set: FxHashSet<_> = seen.map(|c| c.as_variant().unwrap()).collect();
                 let mut skipped_a_hidden_variant = false;
+
                 for variant in visible_variants {
                     let ctor = Variant(*variant);
                     if seen_set.contains(&variant) {
@@ -1071,8 +1056,6 @@ impl ConstructorSet {
                         missing.push(ctor);
                     }
                 }
-                nonexhaustive_enum_missing_visible_variants =
-                    *non_exhaustive && !missing.is_empty();
 
                 for variant in hidden_variants {
                     let ctor = Variant(*variant);
@@ -1159,7 +1142,7 @@ impl ConstructorSet {
             ConstructorSet::Uninhabited => {}
         }
 
-        SplitConstructorSet { present, missing, nonexhaustive_enum_missing_visible_variants }
+        SplitConstructorSet { present, missing }
     }
 
     /// Compute the set of constructors missing from this column.
@@ -1312,9 +1295,10 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
 
 /// Values and patterns can be represented as a constructor applied to some fields. This represents
 /// a pattern in this form.
-/// This also keeps track of whether the pattern has been found reachable during analysis. For this
-/// reason we should be careful not to clone patterns for which we care about that. Use
-/// `clone_and_forget_reachability` if you're sure.
+/// This also uses interior mutability to keep track of whether the pattern has been found reachable
+/// during analysis. For this reason they cannot be cloned.
+/// A `DeconstructedPat` will almost always come from user input; the only exception are some
+/// `Wildcard`s introduced during specialization.
 pub(crate) struct DeconstructedPat<'p, 'tcx> {
     ctor: Constructor<'tcx>,
     fields: Fields<'p, 'tcx>,
@@ -1337,20 +1321,6 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
         DeconstructedPat { ctor, fields, ty, span, reachable: Cell::new(false) }
     }
 
-    /// Construct a pattern that matches everything that starts with this constructor.
-    /// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern
-    /// `Some(_)`.
-    pub(super) fn wild_from_ctor(pcx: &PatCtxt<'_, 'p, 'tcx>, ctor: Constructor<'tcx>) -> Self {
-        let fields = Fields::wildcards(pcx, &ctor);
-        DeconstructedPat::new(ctor, fields, pcx.ty, pcx.span)
-    }
-
-    /// Clone this value. This method emphasizes that cloning loses reachability information and
-    /// should be done carefully.
-    pub(super) fn clone_and_forget_reachability(&self) -> Self {
-        DeconstructedPat::new(self.ctor.clone(), self.fields, self.ty, self.span)
-    }
-
     pub(crate) fn from_pat(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &Pat<'tcx>) -> Self {
         let mkpat = |pat| DeconstructedPat::from_pat(cx, pat);
         let ctor;
@@ -1533,98 +1503,16 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
         DeconstructedPat::new(ctor, fields, pat.ty, pat.span)
     }
 
-    pub(crate) fn to_pat(&self, cx: &MatchCheckCtxt<'p, 'tcx>) -> Pat<'tcx> {
-        let is_wildcard = |pat: &Pat<'_>| {
-            matches!(pat.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild)
-        };
-        let mut subpatterns = self.iter_fields().map(|p| Box::new(p.to_pat(cx)));
-        let kind = match &self.ctor {
-            Single | Variant(_) => match self.ty.kind() {
-                ty::Tuple(..) => PatKind::Leaf {
-                    subpatterns: subpatterns
-                        .enumerate()
-                        .map(|(i, pattern)| FieldPat { field: FieldIdx::new(i), pattern })
-                        .collect(),
-                },
-                ty::Adt(adt_def, _) if adt_def.is_box() => {
-                    // Without `box_patterns`, the only legal pattern of type `Box` is `_` (outside
-                    // of `std`). So this branch is only reachable when the feature is enabled and
-                    // the pattern is a box pattern.
-                    PatKind::Deref { subpattern: subpatterns.next().unwrap() }
-                }
-                ty::Adt(adt_def, args) => {
-                    let variant_index = self.ctor.variant_index_for_adt(*adt_def);
-                    let variant = &adt_def.variant(variant_index);
-                    let subpatterns = Fields::list_variant_nonhidden_fields(cx, self.ty, variant)
-                        .zip(subpatterns)
-                        .map(|((field, _ty), pattern)| FieldPat { field, pattern })
-                        .collect();
-
-                    if adt_def.is_enum() {
-                        PatKind::Variant { adt_def: *adt_def, args, variant_index, subpatterns }
-                    } else {
-                        PatKind::Leaf { subpatterns }
-                    }
-                }
-                // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should
-                // be careful to reconstruct the correct constant pattern here. However a string
-                // literal pattern will never be reported as a non-exhaustiveness witness, so we
-                // ignore this issue.
-                ty::Ref(..) => PatKind::Deref { subpattern: subpatterns.next().unwrap() },
-                _ => bug!("unexpected ctor for type {:?} {:?}", self.ctor, self.ty),
-            },
-            Slice(slice) => {
-                match slice.kind {
-                    FixedLen(_) => PatKind::Slice {
-                        prefix: subpatterns.collect(),
-                        slice: None,
-                        suffix: Box::new([]),
-                    },
-                    VarLen(prefix, _) => {
-                        let mut subpatterns = subpatterns.peekable();
-                        let mut prefix: Vec<_> = subpatterns.by_ref().take(prefix).collect();
-                        if slice.array_len.is_some() {
-                            // Improves diagnostics a bit: if the type is a known-size array, instead
-                            // of reporting `[x, _, .., _, y]`, we prefer to report `[x, .., y]`.
-                            // This is incorrect if the size is not known, since `[_, ..]` captures
-                            // arrays of lengths `>= 1` whereas `[..]` captures any length.
-                            while !prefix.is_empty() && is_wildcard(prefix.last().unwrap()) {
-                                prefix.pop();
-                            }
-                            while subpatterns.peek().is_some()
-                                && is_wildcard(subpatterns.peek().unwrap())
-                            {
-                                subpatterns.next();
-                            }
-                        }
-                        let suffix: Box<[_]> = subpatterns.collect();
-                        let wild = Pat::wildcard_from_ty(self.ty);
-                        PatKind::Slice {
-                            prefix: prefix.into_boxed_slice(),
-                            slice: Some(Box::new(wild)),
-                            suffix,
-                        }
-                    }
-                }
-            }
-            &Str(value) => PatKind::Constant { value },
-            IntRange(range) => return range.to_pat(cx.tcx, self.ty),
-            Wildcard | NonExhaustive | Hidden => PatKind::Wild,
-            Missing { .. } => bug!(
-                "trying to convert a `Missing` constructor into a `Pat`; this is probably a bug,
-                `Missing` should have been processed in `apply_constructors`"
-            ),
-            F32Range(..) | F64Range(..) | Opaque | Or => {
-                bug!("can't convert to pattern: {:?}", self)
-            }
-        };
-
-        Pat { ty: self.ty, span: DUMMY_SP, kind }
-    }
-
     pub(super) fn is_or_pat(&self) -> bool {
         matches!(self.ctor, Or)
     }
+    pub(super) fn flatten_or_pat(&'p self) -> SmallVec<[&'p Self; 1]> {
+        if self.is_or_pat() {
+            self.iter_fields().flat_map(|p| p.flatten_or_pat()).collect()
+        } else {
+            smallvec![self]
+        }
+    }
 
     pub(super) fn ctor(&self) -> &Constructor<'tcx> {
         &self.ctor
@@ -1804,3 +1692,131 @@ impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> {
         }
     }
 }
+
+/// Same idea as `DeconstructedPat`, except this is a fictitious pattern built up for diagnostics
+/// purposes. As such they don't use interning and can be cloned.
+#[derive(Debug, Clone)]
+pub(crate) struct WitnessPat<'tcx> {
+    ctor: Constructor<'tcx>,
+    pub(crate) fields: Vec<WitnessPat<'tcx>>,
+    ty: Ty<'tcx>,
+}
+
+impl<'tcx> WitnessPat<'tcx> {
+    pub(super) fn new(ctor: Constructor<'tcx>, fields: Vec<Self>, ty: Ty<'tcx>) -> Self {
+        Self { ctor, fields, ty }
+    }
+    pub(super) fn wildcard(ty: Ty<'tcx>) -> Self {
+        Self::new(Wildcard, Vec::new(), ty)
+    }
+
+    /// Construct a pattern that matches everything that starts with this constructor.
+    /// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern
+    /// `Some(_)`.
+    pub(super) fn wild_from_ctor(pcx: &PatCtxt<'_, '_, 'tcx>, ctor: Constructor<'tcx>) -> Self {
+        // Reuse `Fields::wildcards` to get the types.
+        let fields = Fields::wildcards(pcx, &ctor)
+            .iter_patterns()
+            .map(|deco_pat| Self::wildcard(deco_pat.ty()))
+            .collect();
+        Self::new(ctor, fields, pcx.ty)
+    }
+
+    pub(super) fn ctor(&self) -> &Constructor<'tcx> {
+        &self.ctor
+    }
+    pub(super) fn ty(&self) -> Ty<'tcx> {
+        self.ty
+    }
+
+    pub(crate) fn to_pat(&self, cx: &MatchCheckCtxt<'_, 'tcx>) -> Pat<'tcx> {
+        let is_wildcard = |pat: &Pat<'_>| matches!(pat.kind, PatKind::Wild);
+        let mut subpatterns = self.iter_fields().map(|p| Box::new(p.to_pat(cx)));
+        let kind = match &self.ctor {
+            Single | Variant(_) => match self.ty.kind() {
+                ty::Tuple(..) => PatKind::Leaf {
+                    subpatterns: subpatterns
+                        .enumerate()
+                        .map(|(i, pattern)| FieldPat { field: FieldIdx::new(i), pattern })
+                        .collect(),
+                },
+                ty::Adt(adt_def, _) if adt_def.is_box() => {
+                    // Without `box_patterns`, the only legal pattern of type `Box` is `_` (outside
+                    // of `std`). So this branch is only reachable when the feature is enabled and
+                    // the pattern is a box pattern.
+                    PatKind::Deref { subpattern: subpatterns.next().unwrap() }
+                }
+                ty::Adt(adt_def, args) => {
+                    let variant_index = self.ctor.variant_index_for_adt(*adt_def);
+                    let variant = &adt_def.variant(variant_index);
+                    let subpatterns = Fields::list_variant_nonhidden_fields(cx, self.ty, variant)
+                        .zip(subpatterns)
+                        .map(|((field, _ty), pattern)| FieldPat { field, pattern })
+                        .collect();
+
+                    if adt_def.is_enum() {
+                        PatKind::Variant { adt_def: *adt_def, args, variant_index, subpatterns }
+                    } else {
+                        PatKind::Leaf { subpatterns }
+                    }
+                }
+                // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should
+                // be careful to reconstruct the correct constant pattern here. However a string
+                // literal pattern will never be reported as a non-exhaustiveness witness, so we
+                // ignore this issue.
+                ty::Ref(..) => PatKind::Deref { subpattern: subpatterns.next().unwrap() },
+                _ => bug!("unexpected ctor for type {:?} {:?}", self.ctor, self.ty),
+            },
+            Slice(slice) => {
+                match slice.kind {
+                    FixedLen(_) => PatKind::Slice {
+                        prefix: subpatterns.collect(),
+                        slice: None,
+                        suffix: Box::new([]),
+                    },
+                    VarLen(prefix, _) => {
+                        let mut subpatterns = subpatterns.peekable();
+                        let mut prefix: Vec<_> = subpatterns.by_ref().take(prefix).collect();
+                        if slice.array_len.is_some() {
+                            // Improves diagnostics a bit: if the type is a known-size array, instead
+                            // of reporting `[x, _, .., _, y]`, we prefer to report `[x, .., y]`.
+                            // This is incorrect if the size is not known, since `[_, ..]` captures
+                            // arrays of lengths `>= 1` whereas `[..]` captures any length.
+                            while !prefix.is_empty() && is_wildcard(prefix.last().unwrap()) {
+                                prefix.pop();
+                            }
+                            while subpatterns.peek().is_some()
+                                && is_wildcard(subpatterns.peek().unwrap())
+                            {
+                                subpatterns.next();
+                            }
+                        }
+                        let suffix: Box<[_]> = subpatterns.collect();
+                        let wild = Pat::wildcard_from_ty(self.ty);
+                        PatKind::Slice {
+                            prefix: prefix.into_boxed_slice(),
+                            slice: Some(Box::new(wild)),
+                            suffix,
+                        }
+                    }
+                }
+            }
+            &Str(value) => PatKind::Constant { value },
+            IntRange(range) => return range.to_pat(cx.tcx, self.ty),
+            Wildcard | NonExhaustive | Hidden => PatKind::Wild,
+            Missing { .. } => bug!(
+                "trying to convert a `Missing` constructor into a `Pat`; this is probably a bug,
+                `Missing` should have been processed in `apply_constructors`"
+            ),
+            F32Range(..) | F64Range(..) | Opaque | Or => {
+                bug!("can't convert to pattern: {:?}", self)
+            }
+        };
+
+        Pat { ty: self.ty, span: DUMMY_SP, kind }
+    }
+
+    pub(super) fn iter_fields<'a>(&'a self) -> impl Iterator<Item = &'a WitnessPat<'tcx>> {
+        self.fields.iter()
+    }
+}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index 6cd73c7eaa9..a8cee5a61ed 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -213,7 +213,7 @@
 //! or-patterns in the first column are expanded before being stored in the matrix. Specialization
 //! for a single patstack is done from a combination of [`Constructor::is_covered_by`] and
 //! [`PatStack::pop_head_constructor`]. The internals of how it's done mostly live in the
-//! [`Fields`] struct.
+//! [`super::deconstruct_pat::Fields`] struct.
 //!
 //!
 //! # Computing usefulness
@@ -307,7 +307,7 @@
 
 use self::ArmType::*;
 use self::Usefulness::*;
-use super::deconstruct_pat::{Constructor, ConstructorSet, DeconstructedPat, Fields};
+use super::deconstruct_pat::{Constructor, ConstructorSet, DeconstructedPat, WitnessPat};
 use crate::errors::{NonExhaustiveOmittedPattern, Uncovered};
 
 use rustc_data_structures::captures::Captures;
@@ -322,7 +322,6 @@ use rustc_span::{Span, DUMMY_SP};
 
 use smallvec::{smallvec, SmallVec};
 use std::fmt;
-use std::iter::once;
 
 pub(crate) struct MatchCheckCtxt<'p, 'tcx> {
     pub(crate) tcx: TyCtxt<'tcx>,
@@ -555,20 +554,20 @@ impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> {
 /// exhaustiveness of a whole match, we use the `WithWitnesses` variant, which carries a list of
 /// witnesses of non-exhaustiveness when there are any.
 /// Which variant to use is dictated by `ArmType`.
-#[derive(Debug)]
-enum Usefulness<'p, 'tcx> {
+#[derive(Debug, Clone)]
+enum Usefulness<'tcx> {
     /// If we don't care about witnesses, simply remember if the pattern was useful.
     NoWitnesses { useful: bool },
     /// Carries a list of witnesses of non-exhaustiveness. If empty, indicates that the whole
     /// pattern is unreachable.
-    WithWitnesses(Vec<Witness<'p, 'tcx>>),
+    WithWitnesses(Vec<WitnessStack<'tcx>>),
 }
 
-impl<'p, 'tcx> Usefulness<'p, 'tcx> {
+impl<'tcx> Usefulness<'tcx> {
     fn new_useful(preference: ArmType) -> Self {
         match preference {
             // A single (empty) witness of reachability.
-            FakeExtraWildcard => WithWitnesses(vec![Witness(vec![])]),
+            FakeExtraWildcard => WithWitnesses(vec![WitnessStack(vec![])]),
             RealArm => NoWitnesses { useful: true },
         }
     }
@@ -605,8 +604,8 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> {
     /// with the results of specializing with the other constructors.
     fn apply_constructor(
         self,
-        pcx: &PatCtxt<'_, 'p, 'tcx>,
-        matrix: &Matrix<'p, 'tcx>, // used to compute missing ctors
+        pcx: &PatCtxt<'_, '_, 'tcx>,
+        matrix: &Matrix<'_, 'tcx>, // used to compute missing ctors
         ctor: &Constructor<'tcx>,
     ) -> Self {
         match self {
@@ -627,25 +626,18 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> {
                     // wildcards for fields, i.e. that matches everything that can be built with it.
                     // For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get
                     // the pattern `Some(_)`.
-                    let new_patterns: Vec<DeconstructedPat<'_, '_>> = missing
+                    let new_patterns: Vec<WitnessPat<'_>> = missing
                         .into_iter()
-                        .map(|missing_ctor| {
-                            DeconstructedPat::wild_from_ctor(pcx, missing_ctor.clone())
-                        })
+                        .map(|missing_ctor| WitnessPat::wild_from_ctor(pcx, missing_ctor.clone()))
                         .collect();
 
                     witnesses
                         .into_iter()
                         .flat_map(|witness| {
                             new_patterns.iter().map(move |pat| {
-                                Witness(
-                                    witness
-                                        .0
-                                        .iter()
-                                        .chain(once(pat))
-                                        .map(DeconstructedPat::clone_and_forget_reachability)
-                                        .collect(),
-                                )
+                                let mut stack = witness.clone();
+                                stack.0.push(pat.clone());
+                                stack
                             })
                         })
                         .collect()
@@ -667,15 +659,17 @@ enum ArmType {
     RealArm,
 }
 
-/// A witness of non-exhaustiveness for error reporting, represented
-/// as a list of patterns (in reverse order of construction) with
-/// wildcards inside to represent elements that can take any inhabitant
-/// of the type as a value.
+/// A witness-tuple of non-exhaustiveness for error reporting, represented as a list of patterns (in
+/// reverse order of construction) with wildcards inside to represent elements that can take any
+/// inhabitant of the type as a value.
 ///
-/// A witness against a list of patterns should have the same types
-/// and length as the pattern matched against. Because Rust `match`
-/// is always against a single pattern, at the end the witness will
-/// have length 1, but in the middle of the algorithm, it can contain
+/// This mirrors `PatStack`: they function similarly, except `PatStack` contains user patterns we
+/// are inspecting, and `WitnessStack` contains witnesses we are constructing.
+/// FIXME(Nadrieril): use the same order of patterns for both
+///
+/// A `WitnessStack` should have the same types and length as the `PatStacks` we are inspecting
+/// (except we store the patterns in reverse order). Because Rust `match` is always against a single
+/// pattern, at the end the stack will have length 1. In the middle of the algorithm, it can contain
 /// multiple patterns.
 ///
 /// For example, if we are constructing a witness for the match against
@@ -690,23 +684,37 @@ enum ArmType {
 /// # }
 /// ```
 ///
-/// We'll perform the following steps:
-/// 1. Start with an empty witness
-///     `Witness(vec![])`
-/// 2. Push a witness `true` against the `false`
-///     `Witness(vec![true])`
-/// 3. Push a witness `Some(_)` against the `None`
-///     `Witness(vec![true, Some(_)])`
-/// 4. Apply the `Pair` constructor to the witnesses
-///     `Witness(vec![Pair(Some(_), true)])`
+/// We'll perform the following steps (among others):
+/// - Start with a matrix representing the match
+///     `PatStack(vec![Pair(None, _)])`
+///     `PatStack(vec![Pair(_, false)])`
+/// - Specialize with `Pair`
+///     `PatStack(vec![None, _])`
+///     `PatStack(vec![_, false])`
+/// - Specialize with `Some`
+///     `PatStack(vec![_, false])`
+/// - Specialize with `_`
+///     `PatStack(vec![false])`
+/// - Specialize with `true`
+///     // no patstacks left
+/// - This is a non-exhaustive match: we have the empty witness stack as a witness.
+///     `WitnessStack(vec![])`
+/// - Apply `true`
+///     `WitnessStack(vec![true])`
+/// - Apply `_`
+///     `WitnessStack(vec![true, _])`
+/// - Apply `Some`
+///     `WitnessStack(vec![true, Some(_)])`
+/// - Apply `Pair`
+///     `WitnessStack(vec![Pair(Some(_), true)])`
 ///
 /// The final `Pair(Some(_), true)` is then the resulting witness.
-#[derive(Debug)]
-pub(crate) struct Witness<'p, 'tcx>(Vec<DeconstructedPat<'p, 'tcx>>);
+#[derive(Debug, Clone)]
+pub(crate) struct WitnessStack<'tcx>(Vec<WitnessPat<'tcx>>);
 
-impl<'p, 'tcx> Witness<'p, 'tcx> {
+impl<'tcx> WitnessStack<'tcx> {
     /// Asserts that the witness contains a single pattern, and returns it.
-    fn single_pattern(self) -> DeconstructedPat<'p, 'tcx> {
+    fn single_pattern(self) -> WitnessPat<'tcx> {
         assert_eq!(self.0.len(), 1);
         self.0.into_iter().next().unwrap()
     }
@@ -724,13 +732,12 @@ impl<'p, 'tcx> Witness<'p, 'tcx> {
     ///
     /// left_ty: struct X { a: (bool, &'static str), b: usize}
     /// pats: [(false, "foo"), 42]  => X { a: (false, "foo"), b: 42 }
-    fn apply_constructor(mut self, pcx: &PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>) -> Self {
+    fn apply_constructor(mut self, pcx: &PatCtxt<'_, '_, 'tcx>, ctor: &Constructor<'tcx>) -> Self {
         let pat = {
             let len = self.0.len();
             let arity = ctor.arity(pcx);
-            let pats = self.0.drain((len - arity)..).rev();
-            let fields = Fields::from_iter(pcx.cx, pats);
-            DeconstructedPat::new(ctor.clone(), fields, pcx.ty, pcx.span)
+            let fields = self.0.drain((len - arity)..).rev().collect();
+            WitnessPat::new(ctor.clone(), fields, pcx.ty)
         };
 
         self.0.push(pat);
@@ -770,7 +777,7 @@ fn is_useful<'p, 'tcx>(
     lint_root: HirId,
     is_under_guard: bool,
     is_top_level: bool,
-) -> Usefulness<'p, 'tcx> {
+) -> Usefulness<'tcx> {
     debug!(?matrix, ?v);
     let Matrix { patterns: rows, .. } = matrix;
 
@@ -837,8 +844,6 @@ fn is_useful<'p, 'tcx>(
         }
         // We split the head constructor of `v`.
         let split_ctors = v_ctor.split(pcx, matrix.heads().map(DeconstructedPat::ctor));
-        let is_non_exhaustive_and_wild =
-            cx.is_foreign_non_exhaustive_enum(ty) && v_ctor.is_wildcard();
         // For each constructor, we compute whether there's a value that starts with it that would
         // witness the usefulness of `v`.
         let start_matrix = &matrix;
@@ -859,50 +864,6 @@ fn is_useful<'p, 'tcx>(
                 )
             });
             let usefulness = usefulness.apply_constructor(pcx, start_matrix, &ctor);
-
-            // When all the conditions are met we have a match with a `non_exhaustive` enum
-            // that has the potential to trigger the `non_exhaustive_omitted_patterns` lint.
-            // To understand the workings checkout `Constructor::split` and `SplitWildcard::new/into_ctors`
-            if is_non_exhaustive_and_wild
-                // Only emit a lint on refutable patterns.
-                && cx.refutable
-                // We check that the match has a wildcard pattern and that wildcard is useful,
-                // meaning there are variants that are covered by the wildcard. Without the check
-                // for `witness_preference` the lint would trigger on `if let NonExhaustiveEnum::A = foo {}`
-                && usefulness.is_useful() && matches!(witness_preference, RealArm)
-                && matches!(
-                    &ctor,
-                    Constructor::Missing { nonexhaustive_enum_missing_visible_variants: true }
-                )
-            {
-                let missing = ConstructorSet::for_ty(pcx.cx, pcx.ty)
-                    .compute_missing(pcx, matrix.heads().map(DeconstructedPat::ctor));
-                // Construct for each missing constructor a "wild" version of this constructor, that
-                // matches everything that can be built with it. For example, if `ctor` is a
-                // `Constructor::Variant` for `Option::Some`, we get the pattern `Some(_)`.
-                let patterns = missing
-                    .into_iter()
-                    // Because of how we computed `nonexhaustive_enum_missing_visible_variants`,
-                    // this will not return an empty `Vec`.
-                    .filter(|c| !(matches!(c, Constructor::NonExhaustive | Constructor::Hidden)))
-                    .map(|missing_ctor| DeconstructedPat::wild_from_ctor(pcx, missing_ctor))
-                    .collect::<Vec<_>>();
-
-                // Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns`
-                // is not exhaustive enough.
-                //
-                // NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`.
-                cx.tcx.emit_spanned_lint(
-                    NON_EXHAUSTIVE_OMITTED_PATTERNS,
-                    lint_root,
-                    pcx.span,
-                    NonExhaustiveOmittedPattern {
-                        scrut_ty: pcx.ty,
-                        uncovered: Uncovered::new(pcx.span, pcx.cx, patterns),
-                    },
-                );
-            }
-
             ret.extend(usefulness);
         }
     }
@@ -914,6 +875,80 @@ fn is_useful<'p, 'tcx>(
     ret
 }
 
+/// Traverse the patterns to collect any variants of a non_exhaustive enum that fail to be mentioned
+/// in a given column. This traverses patterns column-by-column, where a column is the intuitive
+/// notion of "subpatterns that inspect the same subvalue".
+/// Despite similarities with `is_useful`, this traversal is different. Notably this is linear in the
+/// depth of patterns, whereas `is_useful` is worst-case exponential (exhaustiveness is NP-complete).
+fn collect_nonexhaustive_missing_variants<'p, 'tcx>(
+    cx: &MatchCheckCtxt<'p, 'tcx>,
+    column: &[&DeconstructedPat<'p, 'tcx>],
+) -> Vec<WitnessPat<'tcx>> {
+    let ty = column[0].ty();
+    let pcx = &PatCtxt { cx, ty, span: DUMMY_SP, is_top_level: false };
+
+    let set = ConstructorSet::for_ty(pcx.cx, pcx.ty).split(pcx, column.iter().map(|p| p.ctor()));
+    if set.present.is_empty() {
+        // We can't consistently handle the case where no constructors are present (since this would
+        // require digging deep through any type in case there's a non_exhaustive enum somewhere),
+        // so for consistency we refuse to handle the top-level case, where we could handle it.
+        return vec![];
+    }
+
+    let mut witnesses = Vec::new();
+    if cx.is_foreign_non_exhaustive_enum(ty) {
+        witnesses.extend(
+            set.missing
+                .into_iter()
+                // This will list missing visible variants.
+                .filter(|c| !matches!(c, Constructor::Hidden | Constructor::NonExhaustive))
+                .map(|missing_ctor| WitnessPat::wild_from_ctor(pcx, missing_ctor)),
+        )
+    }
+
+    // Recurse into the fields.
+    for ctor in set.present {
+        let arity = ctor.arity(pcx);
+        if arity == 0 {
+            continue;
+        }
+
+        // We specialize the column by `ctor`. This gives us `arity`-many columns of patterns. These
+        // columns may have different lengths in the presence of or-patterns (this is why we can't
+        // reuse `Matrix`).
+        let mut specialized_columns: Vec<Vec<_>> = (0..arity).map(|_| Vec::new()).collect();
+        let relevant_patterns = column.iter().filter(|pat| ctor.is_covered_by(pcx, pat.ctor()));
+        for pat in relevant_patterns {
+            let specialized = pat.specialize(pcx, &ctor);
+            for (subpat, sub_column) in specialized.iter().zip(&mut specialized_columns) {
+                if subpat.is_or_pat() {
+                    sub_column.extend(subpat.iter_fields())
+                } else {
+                    sub_column.push(subpat)
+                }
+            }
+        }
+        debug_assert!(
+            !specialized_columns[0].is_empty(),
+            "ctor {ctor:?} was listed as present but isn't"
+        );
+
+        let wild_pat = WitnessPat::wild_from_ctor(pcx, ctor);
+        for (i, col_i) in specialized_columns.iter().enumerate() {
+            // Compute witnesses for each column.
+            let wits_for_col_i = collect_nonexhaustive_missing_variants(cx, col_i.as_slice());
+            // For each witness, we build a new pattern in the shape of `ctor(_, _, wit, _, _)`,
+            // adding enough wildcards to match `arity`.
+            for wit in wits_for_col_i {
+                let mut pat = wild_pat.clone();
+                pat.fields[i] = wit;
+                witnesses.push(pat);
+            }
+        }
+    }
+    witnesses
+}
+
 /// The arm of a match expression.
 #[derive(Clone, Copy, Debug)]
 pub(crate) struct MatchArm<'p, 'tcx> {
@@ -940,7 +975,7 @@ pub(crate) struct UsefulnessReport<'p, 'tcx> {
     pub(crate) arm_usefulness: Vec<(MatchArm<'p, 'tcx>, Reachability)>,
     /// If the match is exhaustive, this is empty. If not, this contains witnesses for the lack of
     /// exhaustiveness.
-    pub(crate) non_exhaustiveness_witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
+    pub(crate) non_exhaustiveness_witnesses: Vec<WitnessPat<'tcx>>,
 }
 
 /// The entrypoint for the usefulness algorithm. Computes whether a match is exhaustive and which
@@ -954,6 +989,7 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>(
     arms: &[MatchArm<'p, 'tcx>],
     lint_root: HirId,
     scrut_ty: Ty<'tcx>,
+    scrut_span: Span,
 ) -> UsefulnessReport<'p, 'tcx> {
     let mut matrix = Matrix::empty();
     let arm_usefulness: Vec<_> = arms
@@ -978,9 +1014,39 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>(
     let wild_pattern = cx.pattern_arena.alloc(DeconstructedPat::wildcard(scrut_ty, DUMMY_SP));
     let v = PatStack::from_pattern(wild_pattern);
     let usefulness = is_useful(cx, &matrix, &v, FakeExtraWildcard, lint_root, false, true);
-    let non_exhaustiveness_witnesses = match usefulness {
+    let non_exhaustiveness_witnesses: Vec<_> = match usefulness {
         WithWitnesses(pats) => pats.into_iter().map(|w| w.single_pattern()).collect(),
         NoWitnesses { .. } => bug!(),
     };
+
+    // Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hitting
+    // `if let`s. Only run if the match is exhaustive otherwise the error is redundant.
+    if cx.refutable
+        && non_exhaustiveness_witnesses.is_empty()
+        && !matches!(
+            cx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, lint_root).0,
+            rustc_session::lint::Level::Allow
+        )
+    {
+        let pat_column = arms.iter().flat_map(|arm| arm.pat.flatten_or_pat()).collect::<Vec<_>>();
+        let witnesses = collect_nonexhaustive_missing_variants(cx, &pat_column);
+
+        if !witnesses.is_empty() {
+            // Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns`
+            // is not exhaustive enough.
+            //
+            // NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`.
+            cx.tcx.emit_spanned_lint(
+                NON_EXHAUSTIVE_OMITTED_PATTERNS,
+                lint_root,
+                scrut_span,
+                NonExhaustiveOmittedPattern {
+                    scrut_ty,
+                    uncovered: Uncovered::new(scrut_span, cx, witnesses),
+                },
+            );
+        }
+    }
+
     UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses }
 }
diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs
index a83ccf8fc3c..d07f59bc72a 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters.rs
@@ -169,22 +169,22 @@ impl CoverageCounters {
         self.bcb_counters[bcb].as_ref()
     }
 
-    pub(super) fn take_bcb_counter(&mut self, bcb: BasicCoverageBlock) -> Option<BcbCounter> {
-        self.bcb_counters[bcb].take()
-    }
-
-    pub(super) fn drain_bcb_counters(
-        &mut self,
-    ) -> impl Iterator<Item = (BasicCoverageBlock, BcbCounter)> + '_ {
+    pub(super) fn bcb_node_counters(
+        &self,
+    ) -> impl Iterator<Item = (BasicCoverageBlock, &BcbCounter)> {
         self.bcb_counters
-            .iter_enumerated_mut()
-            .filter_map(|(bcb, counter)| Some((bcb, counter.take()?)))
+            .iter_enumerated()
+            .filter_map(|(bcb, counter_kind)| Some((bcb, counter_kind.as_ref()?)))
     }
 
-    pub(super) fn drain_bcb_edge_counters(
-        &mut self,
-    ) -> impl Iterator<Item = ((BasicCoverageBlock, BasicCoverageBlock), BcbCounter)> + '_ {
-        self.bcb_edge_counters.drain()
+    /// For each edge in the BCB graph that has an associated counter, yields
+    /// that edge's *from* and *to* nodes, and its counter.
+    pub(super) fn bcb_edge_counters(
+        &self,
+    ) -> impl Iterator<Item = (BasicCoverageBlock, BasicCoverageBlock, &BcbCounter)> {
+        self.bcb_edge_counters
+            .iter()
+            .map(|(&(from_bcb, to_bcb), counter_kind)| (from_bcb, to_bcb, counter_kind))
     }
 
     pub(super) fn take_expressions(&mut self) -> IndexVec<ExpressionId, Expression> {
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index 6fdaff6b4c0..c9b36ba25ac 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -8,7 +8,7 @@ mod spans;
 mod tests;
 
 use self::counters::{BcbCounter, CoverageCounters};
-use self::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
+use self::graph::CoverageGraph;
 use self::spans::CoverageSpans;
 
 use crate::MirPass;
@@ -104,7 +104,6 @@ struct Instrumentor<'a, 'tcx> {
     function_source_hash: u64,
     basic_coverage_blocks: CoverageGraph,
     coverage_counters: CoverageCounters,
-    mappings: Vec<Mapping>,
 }
 
 impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
@@ -145,7 +144,6 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
             function_source_hash,
             basic_coverage_blocks,
             coverage_counters,
-            mappings: Vec::new(),
         }
     }
 
@@ -168,148 +166,99 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
         // and all `Expression` dependencies (operands) are also generated, for any other
         // `BasicCoverageBlock`s not already associated with a coverage span.
         let bcb_has_coverage_spans = |bcb| coverage_spans.bcb_has_coverage_spans(bcb);
-        let result = self
-            .coverage_counters
-            .make_bcb_counters(&mut self.basic_coverage_blocks, bcb_has_coverage_spans);
-
-        if let Ok(()) = result {
-            ////////////////////////////////////////////////////
-            // Remove the counter or edge counter from of each coverage cpan's associated
-            // `BasicCoverageBlock`, and inject a `Coverage` statement into the MIR.
-            //
-            // `Coverage` statements injected from coverage spans will include the code regions
-            // (source code start and end positions) to be counted by the associated counter.
-            //
-            // These coverage-span-associated counters are removed from their associated
-            // `BasicCoverageBlock`s so that the only remaining counters in the `CoverageGraph`
-            // are indirect counters (to be injected next, without associated code regions).
-            self.inject_coverage_span_counters(&coverage_spans);
-
-            ////////////////////////////////////////////////////
-            // For any remaining `BasicCoverageBlock` counters (that were not associated with
-            // any coverage span), inject `Coverage` statements (_without_ code region spans)
-            // to ensure `BasicCoverageBlock` counters that other `Expression`s may depend on
-            // are in fact counted, even though they don't directly contribute to counting
-            // their own independent code region's coverage.
-            self.inject_indirect_counters();
-        };
+        self.coverage_counters
+            .make_bcb_counters(&mut self.basic_coverage_blocks, bcb_has_coverage_spans)
+            .unwrap_or_else(|e| {
+                bug!("Error processing: {:?}: {:?}", self.mir_body.source.def_id(), e.message)
+            });
 
-        if let Err(e) = result {
-            bug!("Error processing: {:?}: {:?}", self.mir_body.source.def_id(), e.message)
-        };
+        let mappings = self.create_mappings_and_inject_coverage_statements(&coverage_spans);
 
         self.mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo {
             function_source_hash: self.function_source_hash,
             num_counters: self.coverage_counters.num_counters(),
             expressions: self.coverage_counters.take_expressions(),
-            mappings: std::mem::take(&mut self.mappings),
+            mappings,
         }));
     }
 
-    /// Injects a single [`StatementKind::Coverage`] for each BCB that has one
-    /// or more coverage spans.
-    fn inject_coverage_span_counters(&mut self, coverage_spans: &CoverageSpans) {
-        let tcx = self.tcx;
-        let source_map = tcx.sess.source_map();
+    /// For each [`BcbCounter`] associated with a BCB node or BCB edge, create
+    /// any corresponding mappings (for BCB nodes only), and inject any necessary
+    /// coverage statements into MIR.
+    fn create_mappings_and_inject_coverage_statements(
+        &mut self,
+        coverage_spans: &CoverageSpans,
+    ) -> Vec<Mapping> {
+        let source_map = self.tcx.sess.source_map();
         let body_span = self.body_span;
 
         use rustc_session::RemapFileNameExt;
         let file_name =
             Symbol::intern(&self.source_file.name.for_codegen(self.tcx.sess).to_string_lossy());
 
-        for (bcb, spans) in coverage_spans.bcbs_with_coverage_spans() {
-            let counter_kind = self.coverage_counters.take_bcb_counter(bcb).unwrap_or_else(|| {
-                bug!("Every BasicCoverageBlock should have a Counter or Expression");
-            });
-
-            let term = counter_kind.as_term();
-            self.mappings.extend(spans.iter().map(|&span| {
-                let code_region = make_code_region(source_map, file_name, span, body_span);
-                Mapping { code_region, term }
-            }));
-
-            inject_statement(
-                self.mir_body,
-                self.make_mir_coverage_kind(&counter_kind),
-                self.bcb_leader_bb(bcb),
-            );
-        }
-    }
+        let mut mappings = Vec::new();
+
+        // Process the counters and spans associated with BCB nodes.
+        for (bcb, counter_kind) in self.coverage_counters.bcb_node_counters() {
+            let spans = coverage_spans.spans_for_bcb(bcb);
+            let has_mappings = !spans.is_empty();
+
+            // If this BCB has any coverage spans, add corresponding mappings to
+            // the mappings table.
+            if has_mappings {
+                let term = counter_kind.as_term();
+                mappings.extend(spans.iter().map(|&span| {
+                    let code_region = make_code_region(source_map, file_name, span, body_span);
+                    Mapping { code_region, term }
+                }));
+            }
 
-    /// At this point, any BCB with coverage counters has already had its counter injected
-    /// into MIR, and had its counter removed from `coverage_counters` (via `take_counter()`).
-    ///
-    /// Any other counter associated with a `BasicCoverageBlock`, or its incoming edge, but not
-    /// associated with a coverage span, should only exist if the counter is an `Expression`
-    /// dependency (one of the expression operands). Collect them, and inject the additional
-    /// counters into the MIR, without a reportable coverage span.
-    fn inject_indirect_counters(&mut self) {
-        let mut bcb_counters_without_direct_coverage_spans = Vec::new();
-        for (target_bcb, counter_kind) in self.coverage_counters.drain_bcb_counters() {
-            bcb_counters_without_direct_coverage_spans.push((None, target_bcb, counter_kind));
-        }
-        for ((from_bcb, target_bcb), counter_kind) in
-            self.coverage_counters.drain_bcb_edge_counters()
-        {
-            bcb_counters_without_direct_coverage_spans.push((
-                Some(from_bcb),
-                target_bcb,
-                counter_kind,
-            ));
+            let do_inject = match counter_kind {
+                // Counter-increment statements always need to be injected.
+                BcbCounter::Counter { .. } => true,
+                // The only purpose of expression-used statements is to detect
+                // when a mapping is unreachable, so we only inject them for
+                // expressions with one or more mappings.
+                BcbCounter::Expression { .. } => has_mappings,
+            };
+            if do_inject {
+                inject_statement(
+                    self.mir_body,
+                    self.make_mir_coverage_kind(counter_kind),
+                    self.basic_coverage_blocks[bcb].leader_bb(),
+                );
+            }
         }
 
-        for (edge_from_bcb, target_bcb, counter_kind) in bcb_counters_without_direct_coverage_spans
-        {
-            match counter_kind {
-                BcbCounter::Counter { .. } => {
-                    let inject_to_bb = if let Some(from_bcb) = edge_from_bcb {
-                        // The MIR edge starts `from_bb` (the outgoing / last BasicBlock in
-                        // `from_bcb`) and ends at `to_bb` (the incoming / first BasicBlock in the
-                        // `target_bcb`; also called the `leader_bb`).
-                        let from_bb = self.bcb_last_bb(from_bcb);
-                        let to_bb = self.bcb_leader_bb(target_bcb);
-
-                        let new_bb = inject_edge_counter_basic_block(self.mir_body, from_bb, to_bb);
-                        debug!(
-                            "Edge {:?} (last {:?}) -> {:?} (leader {:?}) requires a new MIR \
-                            BasicBlock {:?}, for unclaimed edge counter {:?}",
-                            edge_from_bcb, from_bb, target_bcb, to_bb, new_bb, counter_kind,
-                        );
-                        new_bb
-                    } else {
-                        let target_bb = self.bcb_last_bb(target_bcb);
-                        debug!(
-                            "{:?} ({:?}) gets a new Coverage statement for unclaimed counter {:?}",
-                            target_bcb, target_bb, counter_kind,
-                        );
-                        target_bb
-                    };
-
-                    inject_statement(
-                        self.mir_body,
-                        self.make_mir_coverage_kind(&counter_kind),
-                        inject_to_bb,
-                    );
-                }
-                // Experessions with no associated spans don't need to inject a statement.
-                BcbCounter::Expression { .. } => {}
+        // Process the counters associated with BCB edges.
+        for (from_bcb, to_bcb, counter_kind) in self.coverage_counters.bcb_edge_counters() {
+            let do_inject = match counter_kind {
+                // Counter-increment statements always need to be injected.
+                BcbCounter::Counter { .. } => true,
+                // BCB-edge expressions never have mappings, so they never need
+                // a corresponding statement.
+                BcbCounter::Expression { .. } => false,
+            };
+            if !do_inject {
+                continue;
             }
-        }
-    }
 
-    #[inline]
-    fn bcb_leader_bb(&self, bcb: BasicCoverageBlock) -> BasicBlock {
-        self.bcb_data(bcb).leader_bb()
-    }
+            // We need to inject a coverage statement into a new BB between the
+            // last BB of `from_bcb` and the first BB of `to_bcb`.
+            let from_bb = self.basic_coverage_blocks[from_bcb].last_bb();
+            let to_bb = self.basic_coverage_blocks[to_bcb].leader_bb();
 
-    #[inline]
-    fn bcb_last_bb(&self, bcb: BasicCoverageBlock) -> BasicBlock {
-        self.bcb_data(bcb).last_bb()
-    }
+            let new_bb = inject_edge_counter_basic_block(self.mir_body, from_bb, to_bb);
+            debug!(
+                "Edge {from_bcb:?} (last {from_bb:?}) -> {to_bcb:?} (leader {to_bb:?}) \
+                requires a new MIR BasicBlock {new_bb:?} for edge counter {counter_kind:?}",
+            );
+
+            // Inject a counter into the newly-created BB.
+            inject_statement(self.mir_body, self.make_mir_coverage_kind(&counter_kind), new_bb);
+        }
 
-    #[inline]
-    fn bcb_data(&self, bcb: BasicCoverageBlock) -> &BasicCoverageBlockData {
-        &self.basic_coverage_blocks[bcb]
+        mappings
     }
 
     fn make_mir_coverage_kind(&self, counter_kind: &BcbCounter) -> CoverageKind {
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index 3f7ba572510..704eea413e1 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -2,7 +2,7 @@ use std::cell::OnceCell;
 
 use rustc_data_structures::graph::WithNumNodes;
 use rustc_index::IndexVec;
-use rustc_middle::mir::{self, AggregateKind, Rvalue, Statement, StatementKind};
+use rustc_middle::mir;
 use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol, DUMMY_SP};
 
 use super::graph::{BasicCoverageBlock, CoverageGraph, START_BCB};
@@ -41,13 +41,8 @@ impl CoverageSpans {
         !self.bcb_to_spans[bcb].is_empty()
     }
 
-    pub(super) fn bcbs_with_coverage_spans(
-        &self,
-    ) -> impl Iterator<Item = (BasicCoverageBlock, &[Span])> {
-        self.bcb_to_spans.iter_enumerated().filter_map(|(bcb, spans)| {
-            // Only yield BCBs that have at least one coverage span.
-            (!spans.is_empty()).then_some((bcb, spans.as_slice()))
-        })
+    pub(super) fn spans_for_bcb(&self, bcb: BasicCoverageBlock) -> &[Span] {
+        &self.bcb_to_spans[bcb]
     }
 }
 
@@ -75,29 +70,15 @@ struct CoverageSpan {
 
 impl CoverageSpan {
     pub fn for_fn_sig(fn_sig_span: Span) -> Self {
-        Self {
-            span: fn_sig_span,
-            expn_span: fn_sig_span,
-            current_macro_or_none: Default::default(),
-            bcb: START_BCB,
-            merged_spans: vec![],
-            is_closure: false,
-        }
+        Self::new(fn_sig_span, fn_sig_span, START_BCB, false)
     }
 
-    pub fn for_statement(
-        statement: &Statement<'_>,
+    pub(super) fn new(
         span: Span,
         expn_span: Span,
         bcb: BasicCoverageBlock,
+        is_closure: bool,
     ) -> Self {
-        let is_closure = match statement.kind {
-            StatementKind::Assign(box (_, Rvalue::Aggregate(box ref kind, _))) => {
-                matches!(kind, AggregateKind::Closure(_, _) | AggregateKind::Coroutine(_, _, _))
-            }
-            _ => false,
-        };
-
         Self {
             span,
             expn_span,
@@ -108,17 +89,6 @@ impl CoverageSpan {
         }
     }
 
-    pub fn for_terminator(span: Span, expn_span: Span, bcb: BasicCoverageBlock) -> Self {
-        Self {
-            span,
-            expn_span,
-            current_macro_or_none: Default::default(),
-            bcb,
-            merged_spans: vec![span],
-            is_closure: false,
-        }
-    }
-
     pub fn merge_from(&mut self, mut other: CoverageSpan) {
         debug_assert!(self.is_mergeable(&other));
         self.span = self.span.to(other.span);
diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
index 02e2cf6b05e..6189e5379ea 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
@@ -1,5 +1,7 @@
+use rustc_data_structures::captures::Captures;
 use rustc_middle::mir::{
-    self, FakeReadCause, Statement, StatementKind, Terminator, TerminatorKind,
+    self, AggregateKind, FakeReadCause, Rvalue, Statement, StatementKind, Terminator,
+    TerminatorKind,
 };
 use rustc_span::Span;
 
@@ -12,7 +14,7 @@ pub(super) fn mir_to_initial_sorted_coverage_spans(
     body_span: Span,
     basic_coverage_blocks: &CoverageGraph,
 ) -> Vec<CoverageSpan> {
-    let mut initial_spans = Vec::<CoverageSpan>::with_capacity(mir_body.basic_blocks.len() * 2);
+    let mut initial_spans = Vec::with_capacity(mir_body.basic_blocks.len() * 2);
     for (bcb, bcb_data) in basic_coverage_blocks.iter_enumerated() {
         initial_spans.extend(bcb_to_initial_coverage_spans(mir_body, body_span, bcb, bcb_data));
     }
@@ -50,34 +52,41 @@ pub(super) fn mir_to_initial_sorted_coverage_spans(
 // for each `Statement` and `Terminator`. (Note that subsequent stages of coverage analysis will
 // merge some `CoverageSpan`s, at which point a `CoverageSpan` may represent multiple
 // `Statement`s and/or `Terminator`s.)
-fn bcb_to_initial_coverage_spans(
-    mir_body: &mir::Body<'_>,
+fn bcb_to_initial_coverage_spans<'a, 'tcx>(
+    mir_body: &'a mir::Body<'tcx>,
     body_span: Span,
     bcb: BasicCoverageBlock,
-    bcb_data: &BasicCoverageBlockData,
-) -> Vec<CoverageSpan> {
-    bcb_data
-        .basic_blocks
-        .iter()
-        .flat_map(|&bb| {
-            let data = &mir_body[bb];
-            data.statements
-                .iter()
-                .filter_map(move |statement| {
-                    filtered_statement_span(statement).map(|span| {
-                        CoverageSpan::for_statement(
-                            statement,
-                            function_source_span(span, body_span),
-                            span,
-                            bcb,
-                        )
-                    })
-                })
-                .chain(filtered_terminator_span(data.terminator()).map(|span| {
-                    CoverageSpan::for_terminator(function_source_span(span, body_span), span, bcb)
-                }))
-        })
-        .collect()
+    bcb_data: &'a BasicCoverageBlockData,
+) -> impl Iterator<Item = CoverageSpan> + Captures<'a> + Captures<'tcx> {
+    bcb_data.basic_blocks.iter().flat_map(move |&bb| {
+        let data = &mir_body[bb];
+
+        let statement_spans = data.statements.iter().filter_map(move |statement| {
+            let expn_span = filtered_statement_span(statement)?;
+            let span = function_source_span(expn_span, body_span);
+
+            Some(CoverageSpan::new(span, expn_span, bcb, is_closure(statement)))
+        });
+
+        let terminator_span = Some(data.terminator()).into_iter().filter_map(move |terminator| {
+            let expn_span = filtered_terminator_span(terminator)?;
+            let span = function_source_span(expn_span, body_span);
+
+            Some(CoverageSpan::new(span, expn_span, bcb, false))
+        });
+
+        statement_spans.chain(terminator_span)
+    })
+}
+
+fn is_closure(statement: &Statement<'_>) -> bool {
+    match statement.kind {
+        StatementKind::Assign(box (_, Rvalue::Aggregate(box ref agg_kind, _))) => match agg_kind {
+            AggregateKind::Closure(_, _) | AggregateKind::Coroutine(_, _, _) => true,
+            _ => false,
+        },
+        _ => false,
+    }
 }
 
 /// If the MIR `Statement` has a span contributive to computing coverage spans,
diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs
index 1d8cbe0e21b..4009e289240 100644
--- a/compiler/rustc_monomorphize/src/partitioning.rs
+++ b/compiler/rustc_monomorphize/src/partitioning.rs
@@ -105,7 +105,6 @@ use rustc_hir::def_id::{DefId, DefIdSet, LOCAL_CRATE};
 use rustc_hir::definitions::DefPathDataName;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel};
-use rustc_middle::mir;
 use rustc_middle::mir::mono::{
     CodegenUnit, CodegenUnitNameBuilder, InstantiationMode, Linkage, MonoItem, MonoItemData,
     Visibility,
@@ -1279,38 +1278,8 @@ fn dump_mono_items_stats<'tcx>(
     Ok(())
 }
 
-fn codegened_and_inlined_items(tcx: TyCtxt<'_>, (): ()) -> &DefIdSet {
-    let (items, cgus) = tcx.collect_and_partition_mono_items(());
-    let mut visited = DefIdSet::default();
-    let mut result = items.clone();
-
-    for cgu in cgus {
-        for item in cgu.items().keys() {
-            if let MonoItem::Fn(ref instance) = item {
-                let did = instance.def_id();
-                if !visited.insert(did) {
-                    continue;
-                }
-                let body = tcx.instance_mir(instance.def);
-                for block in body.basic_blocks.iter() {
-                    for statement in &block.statements {
-                        let mir::StatementKind::Coverage(_) = statement.kind else { continue };
-                        let scope = statement.source_info.scope;
-                        if let Some(inlined) = scope.inlined_instance(&body.source_scopes) {
-                            result.insert(inlined.def_id());
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    tcx.arena.alloc(result)
-}
-
 pub fn provide(providers: &mut Providers) {
     providers.collect_and_partition_mono_items = collect_and_partition_mono_items;
-    providers.codegened_and_inlined_items = codegened_and_inlined_items;
 
     providers.is_codegened_item = |tcx, def_id| {
         let (all_mono_items, _) = tcx.collect_and_partition_mono_items(());
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 925ee615b09..4ad838e5aed 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -1511,9 +1511,22 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 ),
             );
         }
+
+        let (span, sugg, post) = if let SuggestionTarget::SimilarlyNamed = suggestion.target
+            && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
+            && let Some(span) = suggestion.span
+            && let Some(candidate) = suggestion.candidate.as_str().strip_prefix("_")
+            && snippet == candidate
+        {
+            // When the suggested binding change would be from `x` to `_x`, suggest changing the
+            // original binding definition instead. (#60164)
+            (span, snippet, ", consider changing it")
+        } else {
+            (span, suggestion.candidate.to_string(), "")
+        };
         let msg = match suggestion.target {
             SuggestionTarget::SimilarlyNamed => format!(
-                "{} {} with a similar name exists",
+                "{} {} with a similar name exists{post}",
                 suggestion.res.article(),
                 suggestion.res.descr()
             ),
@@ -1521,7 +1534,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 format!("maybe you meant this {}", suggestion.res.descr())
             }
         };
-        err.span_suggestion(span, msg, suggestion.candidate, Applicability::MaybeIncorrect);
+        err.span_suggestion(span, msg, sugg, Applicability::MaybeIncorrect);
         true
     }
 
diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs
new file mode 100644
index 00000000000..f42a9739320
--- /dev/null
+++ b/compiler/rustc_smir/src/rustc_internal/internal.rs
@@ -0,0 +1,61 @@
+//! Module containing the translation from stable mir constructs to the rustc counterpart.
+//!
+//! This module will only include a few constructs to allow users to invoke internal rustc APIs
+//! due to incomplete stable coverage.
+
+// Prefer importing stable_mir over internal rustc constructs to make this file more readable.
+use crate::rustc_smir::{MaybeStable, Tables};
+use rustc_middle::ty::{self as rustc_ty, Ty as InternalTy};
+use stable_mir::ty::{Const, GenericArgKind, GenericArgs, Region, Ty};
+use stable_mir::DefId;
+
+use super::RustcInternal;
+
+impl<'tcx> RustcInternal<'tcx> for DefId {
+    type T = rustc_span::def_id::DefId;
+    fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        tables.def_ids[*self]
+    }
+}
+
+impl<'tcx> RustcInternal<'tcx> for GenericArgs {
+    type T = rustc_ty::GenericArgsRef<'tcx>;
+    fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        tables.tcx.mk_args_from_iter(self.0.iter().map(|arg| arg.internal(tables)))
+    }
+}
+
+impl<'tcx> RustcInternal<'tcx> for GenericArgKind {
+    type T = rustc_ty::GenericArg<'tcx>;
+    fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        match self {
+            GenericArgKind::Lifetime(reg) => reg.internal(tables).into(),
+            GenericArgKind::Type(ty) => ty.internal(tables).into(),
+            GenericArgKind::Const(cnst) => cnst.internal(tables).into(),
+        }
+    }
+}
+
+impl<'tcx> RustcInternal<'tcx> for Region {
+    type T = rustc_ty::Region<'tcx>;
+    fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T {
+        todo!()
+    }
+}
+
+impl<'tcx> RustcInternal<'tcx> for Ty {
+    type T = InternalTy<'tcx>;
+    fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
+        match tables.types[self.0] {
+            MaybeStable::Stable(_) => todo!(),
+            MaybeStable::Rustc(ty) => ty,
+        }
+    }
+}
+
+impl<'tcx> RustcInternal<'tcx> for Const {
+    type T = rustc_ty::Const<'tcx>;
+    fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T {
+        todo!()
+    }
+}
diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs
index 61227e5d38f..b1ea5e898b8 100644
--- a/compiler/rustc_smir/src/rustc_internal/mod.rs
+++ b/compiler/rustc_smir/src/rustc_internal/mod.rs
@@ -20,6 +20,8 @@ use std::fmt::Debug;
 use std::hash::Hash;
 use std::ops::{ControlFlow, Index};
 
+mod internal;
+
 impl<'tcx> Index<stable_mir::DefId> for Tables<'tcx> {
     type Output = DefId;
 
@@ -231,3 +233,11 @@ impl<K: PartialEq + Hash + Eq, V: Copy + Debug + PartialEq + IndexedVal> Index<V
         k
     }
 }
+
+/// Trait used to translate a stable construct to its rustc counterpart.
+///
+/// This is basically a mirror of [crate::rustc_smir::Stable].
+pub(crate) trait RustcInternal<'tcx> {
+    type T;
+    fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T;
+}
diff --git a/compiler/rustc_smir/src/rustc_smir/builder.rs b/compiler/rustc_smir/src/rustc_smir/builder.rs
new file mode 100644
index 00000000000..8ff3958da7b
--- /dev/null
+++ b/compiler/rustc_smir/src/rustc_smir/builder.rs
@@ -0,0 +1,55 @@
+//! Logic required to produce a monomorphic stable body.
+//!
+//! We first retrieve and monomorphize the rustc body representation, i.e., we generate a
+//! monomorphic body using internal representation.
+//! After that, we convert the internal representation into a stable one.
+use crate::rustc_smir::{Stable, Tables};
+use rustc_middle::mir;
+use rustc_middle::mir::visit::MutVisitor;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+
+/// Builds a monomorphic body for a given instance.
+pub struct BodyBuilder<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    instance: ty::Instance<'tcx>,
+}
+
+impl<'tcx> BodyBuilder<'tcx> {
+    pub fn new(tcx: TyCtxt<'tcx>, instance: ty::Instance<'tcx>) -> Self {
+        BodyBuilder { tcx, instance }
+    }
+
+    pub fn build(mut self, tables: &mut Tables<'tcx>) -> stable_mir::mir::Body {
+        let mut body = self.tcx.instance_mir(self.instance.def).clone();
+        let generics = self.tcx.generics_of(self.instance.def_id());
+        if generics.requires_monomorphization(self.tcx) {
+            self.visit_body(&mut body);
+        }
+        body.stable(tables)
+    }
+
+    fn monomorphize<T>(&self, value: T) -> T
+    where
+        T: ty::TypeFoldable<TyCtxt<'tcx>>,
+    {
+        self.instance.instantiate_mir_and_normalize_erasing_regions(
+            self.tcx,
+            ty::ParamEnv::reveal_all(),
+            ty::EarlyBinder::bind(value),
+        )
+    }
+}
+
+impl<'tcx> MutVisitor<'tcx> for BodyBuilder<'tcx> {
+    fn visit_ty_const(&mut self, ct: &mut ty::Const<'tcx>, _location: mir::Location) {
+        *ct = self.monomorphize(*ct);
+    }
+
+    fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: mir::visit::TyContext) {
+        *ty = self.monomorphize(*ty);
+    }
+
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+}
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index 8a1b6b6bfe9..d5379797f1c 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -7,7 +7,7 @@
 //!
 //! For now, we are developing everything inside `rustc`, thus, we keep this module private.
 
-use crate::rustc_internal::IndexMap;
+use crate::rustc_internal::{IndexMap, RustcInternal};
 use crate::rustc_smir::hir::def::DefKind;
 use crate::rustc_smir::stable_mir::ty::{BoundRegion, EarlyBoundRegion, Region};
 use rustc_hir as hir;
@@ -26,6 +26,7 @@ use stable_mir::{self, opaque, Context, Filename};
 use tracing::debug;
 
 mod alloc;
+mod builder;
 
 impl<'tcx> Context for Tables<'tcx> {
     fn local_crate(&self) -> stable_mir::Crate {
@@ -171,8 +172,9 @@ impl<'tcx> Context for Tables<'tcx> {
         }
     }
 
-    fn instance_body(&mut self, _def: InstanceDef) -> Body {
-        todo!("Monomorphize the body")
+    fn instance_body(&mut self, def: InstanceDef) -> Body {
+        let instance = self.instances[def];
+        builder::BodyBuilder::new(self.tcx, instance).build(self)
     }
 
     fn instance_ty(&mut self, def: InstanceDef) -> stable_mir::ty::Ty {
@@ -195,9 +197,21 @@ impl<'tcx> Context for Tables<'tcx> {
         let def_id = self[def_id];
         let generics = self.tcx.generics_of(def_id);
         let result = generics.requires_monomorphization(self.tcx);
-        println!("req {result}: {def_id:?}");
         result
     }
+
+    fn resolve_instance(
+        &mut self,
+        def: stable_mir::ty::FnDef,
+        args: &stable_mir::ty::GenericArgs,
+    ) -> Option<stable_mir::mir::mono::Instance> {
+        let def_id = def.0.internal(self);
+        let args_ref = args.internal(self);
+        match Instance::resolve(self.tcx, ParamEnv::reveal_all(), def_id, args_ref) {
+            Ok(Some(instance)) => Some(instance.stable(self)),
+            Ok(None) | Err(_) => None,
+        }
+    }
 }
 
 #[derive(Clone)]
diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml
index ee93f74e750..31c2a56faa5 100644
--- a/compiler/rustc_span/Cargo.toml
+++ b/compiler/rustc_span/Cargo.toml
@@ -13,7 +13,6 @@ rustc_index = { path = "../rustc_index" }
 rustc_arena = { path = "../rustc_arena" }
 scoped-tls = "1.0"
 unicode-width = "0.1.4"
-cfg-if = "1.0"
 tracing = "0.1"
 sha1 = "0.10.0"
 sha2 = "0.10.1"
diff --git a/compiler/rustc_span/src/analyze_source_file.rs b/compiler/rustc_span/src/analyze_source_file.rs
index 450d5455ff9..7da7dc610ec 100644
--- a/compiler/rustc_span/src/analyze_source_file.rs
+++ b/compiler/rustc_span/src/analyze_source_file.rs
@@ -33,8 +33,8 @@ pub fn analyze_source_file(
     (lines, multi_byte_chars, non_narrow_chars)
 }
 
-cfg_if::cfg_if! {
-    if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
+cfg_match! {
+    cfg(any(target_arch = "x86", target_arch = "x86_64")) => {
         fn analyze_source_file_dispatch(src: &str,
                                     lines: &mut Vec<RelativeBytePos>,
                                     multi_byte_chars: &mut Vec<MultiByteChar>,
@@ -172,8 +172,8 @@ cfg_if::cfg_if! {
                                         non_narrow_chars);
             }
         }
-    } else {
-
+    }
+    _ => {
         // The target (or compiler version) does not support SSE2 ...
         fn analyze_source_file_dispatch(src: &str,
                                     lines: &mut Vec<RelativeBytePos>,
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 49b4042d148..8bb64aa5f12 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -13,21 +13,24 @@
 //!
 //! This API is completely unstable and subject to change.
 
-#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+// tidy-alphabetical-start
+#![allow(internal_features)]
 #![cfg_attr(not(bootstrap), doc(rust_logo))]
 #![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![deny(rustc::diagnostic_outside_of_impl)]
+#![deny(rustc::untranslatable_diagnostic)]
+#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(array_windows)]
+#![feature(cfg_match)]
 #![feature(if_let_guard)]
-#![feature(negative_impls)]
-#![feature(min_specialization)]
-#![feature(rustc_attrs)]
 #![feature(let_chains)]
-#![feature(round_char_boundary)]
-#![feature(read_buf)]
+#![feature(min_specialization)]
+#![feature(negative_impls)]
 #![feature(new_uninit)]
-#![deny(rustc::untranslatable_diagnostic)]
-#![deny(rustc::diagnostic_outside_of_impl)]
-#![allow(internal_features)]
+#![feature(read_buf)]
+#![feature(round_char_boundary)]
+#![feature(rustc_attrs)]
+// tidy-alphabetical-end
 
 #[macro_use]
 extern crate rustc_macros;
diff --git a/compiler/rustc_target/src/asm/csky.rs b/compiler/rustc_target/src/asm/csky.rs
index 6f0e7f79949..db3d8106040 100644
--- a/compiler/rustc_target/src/asm/csky.rs
+++ b/compiler/rustc_target/src/asm/csky.rs
@@ -64,9 +64,9 @@ def_regs! {
         r20: reg = ["r20","t4"],// feature high-register
         r21: reg = ["r21","t5"],// feature high-register
         r22: reg = ["r22","t6"],// feature high-register
-        r23: reg = ["r23","t7", "fp"],// feature high-register
-        r24: reg = ["r24","t8", "sop"],// feature high-register
-        r25: reg = ["r25","t9","tp", "bsp"],// feature high-register
+        r23: reg = ["r23","t7"],// feature high-register
+        r24: reg = ["r24","t8"],// feature high-register
+        r25: reg = ["r25","t9"],// feature high-register
         f0: freg = ["fr0","vr0"],
         f1: freg = ["fr1","vr1"],
         f2: freg = ["fr2","vr2"],
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 86328cb78ab..78b466907b3 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1644,7 +1644,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
 
             // use nth(1) to skip one layer of desugaring from `IntoIter::into_iter`
             if let Some((_, hir::Node::Expr(await_expr))) = hir.parent_iter(*hir_id).nth(1)
-                && let Some(expr_span) = expr.span.find_ancestor_inside(await_expr.span)
+                && let Some(expr_span) = expr.span.find_ancestor_inside_same_ctxt(await_expr.span)
             {
                 let removal_span = self
                     .tcx
@@ -2665,6 +2665,29 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             // Check for foreign traits being reachable.
                             self.tcx.visible_parent_map(()).get(&def_id).is_some()
                         };
+                        if Some(def_id) == self.tcx.lang_items().sized_trait()
+                            && let Some(hir::Node::TraitItem(hir::TraitItem {
+                                ident,
+                                kind: hir::TraitItemKind::Type(bounds, None),
+                                ..
+                            })) = tcx.hir().get_if_local(item_def_id)
+                            // Do not suggest relaxing if there is an explicit `Sized` obligation.
+                            && !bounds.iter()
+                                .filter_map(|bound| bound.trait_ref())
+                                .any(|tr| tr.trait_def_id() == self.tcx.lang_items().sized_trait())
+                        {
+                            let (span, separator) = if let [.., last] = bounds {
+                                (last.span().shrink_to_hi(), " +")
+                            } else {
+                                (ident.span.shrink_to_hi(), ":")
+                            };
+                            err.span_suggestion_verbose(
+                                span,
+                                "consider relaxing the implicit `Sized` restriction",
+                                format!("{separator} ?Sized"),
+                                Applicability::MachineApplicable,
+                            );
+                        }
                         if let DefKind::Trait = tcx.def_kind(item_def_id)
                             && !visible_item
                         {
diff --git a/compiler/stable_mir/src/error.rs b/compiler/stable_mir/src/error.rs
index 12ac8f1ca65..19910691456 100644
--- a/compiler/stable_mir/src/error.rs
+++ b/compiler/stable_mir/src/error.rs
@@ -4,6 +4,7 @@
 //! - [CompilerError]: This represents errors that can be raised when invoking the compiler.
 //! - [Error]: Generic error that represents the reason why a request that could not be fulfilled.
 
+use std::convert::From;
 use std::fmt::{Debug, Display, Formatter};
 use std::{error, fmt};
 
@@ -31,6 +32,12 @@ impl Error {
     }
 }
 
+impl From<&str> for Error {
+    fn from(value: &str) -> Self {
+        Self(value.into())
+    }
+}
+
 impl Display for Error {
     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
         Display::fmt(&self.0, f)
diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs
index 59af3f64ad3..be5ccac78c7 100644
--- a/compiler/stable_mir/src/lib.rs
+++ b/compiler/stable_mir/src/lib.rs
@@ -39,6 +39,7 @@ pub mod visitor;
 
 pub use error::*;
 use mir::mono::Instance;
+use ty::{FnDef, GenericArgs};
 
 /// Use String for now but we should replace it.
 pub type Symbol = String;
@@ -233,6 +234,9 @@ pub trait Context {
 
     /// Item requires monomorphization.
     fn requires_monomorphization(&self, def_id: DefId) -> bool;
+
+    /// Resolve an instance from the given function definition and generic arguments.
+    fn resolve_instance(&mut self, def: FnDef, args: &GenericArgs) -> Option<Instance>;
 }
 
 // A thread local variable that stores a pointer to the tables mapping between TyCtxt
diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs
index ea30fe6dbcd..5eee1ec00df 100644
--- a/compiler/stable_mir/src/mir/body.rs
+++ b/compiler/stable_mir/src/mir/body.rs
@@ -5,9 +5,11 @@ use crate::{ty::Ty, Span};
 #[derive(Clone, Debug)]
 pub struct Body {
     pub blocks: Vec<BasicBlock>,
-    pub locals: Vec<LocalDecl>,
+    pub locals: LocalDecls,
 }
 
+type LocalDecls = Vec<LocalDecl>;
+
 #[derive(Clone, Debug)]
 pub struct LocalDecl {
     pub ty: Ty,
@@ -344,6 +346,7 @@ pub enum Operand {
 #[derive(Clone, Debug)]
 pub struct Place {
     pub local: Local,
+    /// projection out of a place (access a field, deref a pointer, etc)
     pub projection: String,
 }
 
@@ -462,3 +465,25 @@ pub enum NullOp {
     /// Returns the offset of a field.
     OffsetOf(Vec<FieldIdx>),
 }
+
+impl Operand {
+    pub fn ty(&self, locals: &LocalDecls) -> Ty {
+        match self {
+            Operand::Copy(place) | Operand::Move(place) => place.ty(locals),
+            Operand::Constant(c) => c.ty(),
+        }
+    }
+}
+
+impl Constant {
+    pub fn ty(&self) -> Ty {
+        self.literal.ty
+    }
+}
+
+impl Place {
+    pub fn ty(&self, locals: &LocalDecls) -> Ty {
+        let _start_ty = locals[self.local].ty;
+        todo!("Implement projection")
+    }
+}
diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs
index d8e8ccb0454..997576fc7cb 100644
--- a/compiler/stable_mir/src/mir/mono.rs
+++ b/compiler/stable_mir/src/mir/mono.rs
@@ -1,5 +1,5 @@
 use crate::mir::Body;
-use crate::ty::{IndexedVal, Ty};
+use crate::ty::{FnDef, GenericArgs, IndexedVal, Ty};
 use crate::{with, CrateItem, DefId, Error, Opaque};
 use std::fmt::Debug;
 
@@ -41,6 +41,15 @@ impl Instance {
     pub fn ty(&self) -> Ty {
         with(|context| context.instance_ty(self.def))
     }
+
+    /// Resolve an instance starting from a function definition and generic arguments.
+    pub fn resolve(def: FnDef, args: &GenericArgs) -> Result<Instance, crate::Error> {
+        with(|context| {
+            context.resolve_instance(def, args).ok_or_else(|| {
+                crate::Error::new(format!("Failed to resolve `{def:?}` with `{args:?}`"))
+            })
+        })
+    }
 }
 
 /// Try to convert a crate item into an instance.
diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs
index 0ed2813bccf..8f7f8bd4e38 100644
--- a/compiler/stable_mir/src/ty.rs
+++ b/compiler/stable_mir/src/ty.rs
@@ -225,6 +225,7 @@ pub struct ImplDef(pub DefId);
 #[derive(Clone, PartialEq, Eq, Debug)]
 pub struct RegionDef(pub DefId);
 
+/// A list of generic arguments.
 #[derive(Clone, Debug)]
 pub struct GenericArgs(pub Vec<GenericArgKind>);
 
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index 8ab851a0ea6..4a62013c685 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -207,7 +207,7 @@ impl<T> Box<T> {
     /// ```
     /// let five = Box::new(5);
     /// ```
-    #[cfg(all(not(no_global_oom_handling)))]
+    #[cfg(not(no_global_oom_handling))]
     #[inline(always)]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use]
diff --git a/library/std/build.rs b/library/std/build.rs
index 046ac488b1f..ad0a82eab8c 100644
--- a/library/std/build.rs
+++ b/library/std/build.rs
@@ -3,17 +3,11 @@ use std::env;
 fn main() {
     println!("cargo:rerun-if-changed=build.rs");
     let target = env::var("TARGET").expect("TARGET was not set");
-    if target.contains("freebsd") {
-        if env::var("RUST_STD_FREEBSD_12_ABI").is_ok() {
-            println!("cargo:rustc-cfg=freebsd12");
-        } else if env::var("RUST_STD_FREEBSD_13_ABI").is_ok() {
-            println!("cargo:rustc-cfg=freebsd12");
-            println!("cargo:rustc-cfg=freebsd13");
-        }
-    } else if target.contains("linux")
+    if target.contains("linux")
         || target.contains("netbsd")
         || target.contains("dragonfly")
         || target.contains("openbsd")
+        || target.contains("freebsd")
         || target.contains("solaris")
         || target.contains("illumos")
         || target.contains("apple-darwin")
diff --git a/library/std/src/os/freebsd/fs.rs b/library/std/src/os/freebsd/fs.rs
index 8db3a950c40..5689a82e00a 100644
--- a/library/std/src/os/freebsd/fs.rs
+++ b/library/std/src/os/freebsd/fs.rs
@@ -76,12 +76,7 @@ impl MetadataExt for Metadata {
     fn as_raw_stat(&self) -> &raw::stat {
         // The methods below use libc::stat, so they work fine when libc is built with FreeBSD 12 ABI.
         // This method would just return nonsense.
-        #[cfg(freebsd12)]
         panic!("as_raw_stat not supported with FreeBSD 12 ABI");
-        #[cfg(not(freebsd12))]
-        unsafe {
-            &*(self.as_inner().as_inner() as *const libc::stat as *const raw::stat)
-        }
     }
     fn st_dev(&self) -> u64 {
         self.as_inner().as_inner().st_dev as u64
@@ -143,12 +138,7 @@ impl MetadataExt for Metadata {
     fn st_flags(&self) -> u32 {
         self.as_inner().as_inner().st_flags as u32
     }
-    #[cfg(freebsd12)]
     fn st_lspare(&self) -> u32 {
         panic!("st_lspare not supported with FreeBSD 12 ABI");
     }
-    #[cfg(not(freebsd12))]
-    fn st_lspare(&self) -> u32 {
-        self.as_inner().as_inner().st_lspare as u32
-    }
 }
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/script.sh b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/script.sh
index 918b19612ae..7d40db2ee23 100755
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/script.sh
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/script.sh
@@ -4,34 +4,34 @@ set -ex
 
 # Only run the stage 1 tests on merges, not on PR CI jobs.
 if [[ -z "${PR_CI_JOB}" ]]; then
-     ../x.py --stage 1 test --skip src/tools/tidy && \
-     # Run the `mir-opt` tests again but this time for a 32-bit target.
-     # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have
-     # both 32-bit and 64-bit outputs updated by the PR author, before
-     # the PR is approved and tested for merging.
-     # It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`,
-     # despite having different output on 32-bit vs 64-bit targets.
-     ../x.py --stage 1 test tests/mir-opt \
-          --host='' --target=i686-unknown-linux-gnu && \
-     # Run `ui-fulldeps` in `--stage=1`, which actually uses the stage0
-     # compiler, and is sensitive to the addition of new flags.
-     ../x.py --stage 1 test tests/ui-fulldeps
+    ../x.py --stage 1 test --skip src/tools/tidy
+
+    # Run the `mir-opt` tests again but this time for a 32-bit target.
+    # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have
+    # both 32-bit and 64-bit outputs updated by the PR author, before
+    # the PR is approved and tested for merging.
+    # It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`,
+    # despite having different output on 32-bit vs 64-bit targets.
+    ../x.py --stage 1 test tests/mir-opt --host='' --target=i686-unknown-linux-gnu
+
+    # Run `ui-fulldeps` in `--stage=1`, which actually uses the stage0
+    # compiler, and is sensitive to the addition of new flags.
+    ../x.py --stage 1 test tests/ui-fulldeps
 fi
 
 # NOTE: intentionally uses all of `x.py`, `x`, and `x.ps1` to make sure they all work on Linux.
-../x.py --stage 2 test --skip src/tools/tidy && \
-     # Run the `mir-opt` tests again but this time for a 32-bit target.
-     # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have
-     # both 32-bit and 64-bit outputs updated by the PR author, before
-     # the PR is approved and tested for merging.
-     # It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`,
-     # despite having different output on 32-bit vs 64-bit targets.
-     ../x --stage 2 test tests/mir-opt \
-                       --host='' --target=i686-unknown-linux-gnu && \
-     # Run the UI test suite again, but in `--pass=check` mode
-     #
-     # This is intended to make sure that both `--pass=check` continues to
-     # work.
-     #
-     ../x.ps1 --stage 2 test tests/ui --pass=check \
-                       --host='' --target=i686-unknown-linux-gnu
+../x.py --stage 2 test --skip src/tools/tidy
+
+# Run the `mir-opt` tests again but this time for a 32-bit target.
+# This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have
+# both 32-bit and 64-bit outputs updated by the PR author, before
+# the PR is approved and tested for merging.
+# It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`,
+# despite having different output on 32-bit vs 64-bit targets.
+../x --stage 2 test tests/mir-opt --host='' --target=i686-unknown-linux-gnu
+
+# Run the UI test suite again, but in `--pass=check` mode
+#
+# This is intended to make sure that both `--pass=check` continues to
+# work.
+../x.ps1 --stage 2 test tests/ui --pass=check --host='' --target=i686-unknown-linux-gnu
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index 93b07350ac1..5136aec9896 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -91,6 +91,10 @@ x--expand-yaml-anchors--remove:
     os: macos-13 # We use the standard runner for now
     <<: *base-job
 
+  - &job-macos-m1
+    os: macos-13-xlarge
+    <<: *base-job
+
   - &job-windows-8c
     os: windows-2019-8core-32gb
     <<: *base-job
@@ -153,6 +157,10 @@ x--expand-yaml-anchors--remove:
         run: src/ci/scripts/dump-environment.sh
         <<: *step
 
+      - name: install awscli
+        run: src/ci/scripts/install-awscli.sh
+        <<: *step
+
       - name: install sccache
         run: src/ci/scripts/install-sccache.sh
         <<: *step
@@ -523,17 +531,14 @@ jobs:
           # This target only needs to support 11.0 and up as nothing else supports the hardware
           - name: dist-aarch64-apple
             env:
-              SCRIPT: ./x.py dist bootstrap --include-default-paths --stage 2
+              SCRIPT: ./x.py dist bootstrap --include-default-paths --host=aarch64-apple-darwin --target=aarch64-apple-darwin
               RUST_CONFIGURE_ARGS: >-
-                --build=x86_64-apple-darwin
-                --host=aarch64-apple-darwin
-                --target=aarch64-apple-darwin
                 --enable-full-tools
                 --enable-sanitizers
                 --enable-profiler
-                --disable-docs
                 --set rust.jemalloc
                 --set llvm.ninja=false
+                --set rust.lto=thin
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
               SELECT_XCODE: /Applications/Xcode_13.4.1.app
               USE_XCODE_CLANG: 1
@@ -543,15 +548,7 @@ jobs:
               NO_DEBUG_ASSERTIONS: 1
               NO_OVERFLOW_CHECKS: 1
               DIST_REQUIRE_ALL_TOOLS: 1
-              # Corresponds to 16K page size
-              #
-              # Shouldn't be needed if jemalloc-sys is updated to
-              # handle this platform like iOS or if we build on
-              # aarch64-apple-darwin itself.
-              #
-              # https://github.com/gnzlbg/jemallocator/blob/c27a859e98e3cb790dc269773d9da71a1e918458/jemalloc-sys/build.rs#L237
-              JEMALLOC_SYS_WITH_LG_PAGE: 14
-            <<: *job-macos-xl
+            <<: *job-macos-m1
 
           ######################
           #  Windows Builders  #
diff --git a/src/ci/scripts/install-awscli.sh b/src/ci/scripts/install-awscli.sh
new file mode 100755
index 00000000000..b4a239fd3bc
--- /dev/null
+++ b/src/ci/scripts/install-awscli.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+# This script downloads and installs the awscli binaries directly from
+# Amazon.
+
+set -euo pipefail
+IFS=$'\n\t'
+
+source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
+
+AWS_VERSION="2.13.25"
+
+# Only the macOS arm64/aarch64 GitHub Actions runner needs to have AWS
+# installed; other platforms have it preinstalled.
+
+if isMacOS; then
+    platform=$(uname -m)
+    case $platform in
+        x86_64)
+            ;;
+        arm64)
+            file="https://awscli.amazonaws.com/AWSCLIV2-${AWS_VERSION}.pkg"
+            retry curl -f "${file}" -o "AWSCLIV2.pkg"
+            sudo installer -pkg "AWSCLIV2.pkg" -target /
+            ;;
+        *)
+            echo "unsupported architecture: ${platform}"
+            exit 1
+    esac
+fi
diff --git a/src/doc/rustdoc/src/write-documentation/what-to-include.md b/src/doc/rustdoc/src/write-documentation/what-to-include.md
index 16457ed0ff8..4bcae4d222c 100644
--- a/src/doc/rustdoc/src/write-documentation/what-to-include.md
+++ b/src/doc/rustdoc/src/write-documentation/what-to-include.md
@@ -117,7 +117,7 @@ rustdoc --theme awesome.css src/lib.rs
 
 Here is an example of a new theme, [Ayu].
 
-[Ayu]: https://github.com/rust-lang/rust/blob/master/src/librustdoc/html/static/css/themes/ayu.css
+[Ayu]: https://github.com/rust-lang/rust/blob/master/src/librustdoc/html/static/css/rustdoc.css#L2384-L2574
 [API Guidelines]: https://rust-lang.github.io/api-guidelines/documentation.html#rustdoc-does-not-show-unhelpful-implementation-details-c-hidden
 [Documentation tests]: documentation-tests.md
 [on this blog]: https://blog.guillaume-gomez.fr/articles/2016-09-16+Generating+doc+with+rustdoc+and+a+custom+theme
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index fef25ad8635..26c9877dbff 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -5463,6 +5463,7 @@ Released 2018-09-13
 [`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string
 [`strlen_on_c_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#strlen_on_c_strings
 [`struct_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools
+[`struct_field_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_field_names
 [`stutter`]: https://rust-lang.github.io/rust-clippy/master/index.html#stutter
 [`suboptimal_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#suboptimal_flops
 [`suspicious_arithmetic_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_arithmetic_impl
@@ -5625,6 +5626,7 @@ Released 2018-09-13
 [`single-char-binding-names-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#single-char-binding-names-threshold
 [`too-large-for-stack`]: https://doc.rust-lang.org/clippy/lint_configuration.html#too-large-for-stack
 [`enum-variant-name-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enum-variant-name-threshold
+[`struct-field-name-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#struct-field-name-threshold
 [`enum-variant-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enum-variant-size-threshold
 [`verbose-bit-mask-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#verbose-bit-mask-threshold
 [`literal-representation-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#literal-representation-threshold
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index cbcb42dad79..2c50addfd7d 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -29,7 +29,7 @@ color-print = "0.3.4" # Sync version with Cargo
 anstream = "0.5.0"
 
 [dev-dependencies]
-ui_test = "0.20"
+ui_test = "0.21.2"
 tester = "0.9"
 regex = "1.5"
 toml = "0.7.3"
diff --git a/src/tools/clippy/book/src/development/adding_lints.md b/src/tools/clippy/book/src/development/adding_lints.md
index e001197842b..55c0e105b30 100644
--- a/src/tools/clippy/book/src/development/adding_lints.md
+++ b/src/tools/clippy/book/src/development/adding_lints.md
@@ -30,6 +30,7 @@ because that's clearly a non-descriptive name.
   - [Documentation](#documentation)
   - [Running rustfmt](#running-rustfmt)
   - [Debugging](#debugging)
+  - [Conflicting lints](#conflicting-lints)
   - [PR Checklist](#pr-checklist)
   - [Adding configuration to a lint](#adding-configuration-to-a-lint)
   - [Cheat Sheet](#cheat-sheet)
@@ -612,6 +613,24 @@ output in the `stdout` part.
 
 [`dbg!`]: https://doc.rust-lang.org/std/macro.dbg.html
 
+## Conflicting lints
+
+There are several lints that deal with the same pattern but suggest different approaches. In other words, some lints
+may suggest modifications that go in the opposite direction to what some other lints already propose for the same
+code, creating conflicting diagnostics.
+
+When you are creating a lint that ends up in this scenario, the following tips should be encouraged to guide
+classification:
+
+* The only case where they should be in the same category is if that category is `restriction`. For example,
+`semicolon_inside_block` and `semicolon_outside_block`.
+* For all the other cases, they should be in different categories with different levels of allowance. For example,
+`implicit_return` (restriction, allow) and `needless_return` (style, warn).
+
+For lints that are in different categories, it is also recommended that at least one of them should be in the
+`restriction` category. The reason for this is that the `restriction` group is the only group where we don't
+recommend to enable the entire set, but cherry pick lints out of.
+
 ## PR Checklist
 
 Before submitting your PR make sure you followed all the basic requirements:
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index 2c958ccbbc2..c7eeed17954 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -100,7 +100,7 @@ Suppress lints whenever the suggested change would cause breakage for other crat
 ## `msrv`
 The minimum rust version that the project supports
 
-**Default Value:** `None` (`Option<String>`)
+**Default Value:** `Msrv { stack: [] }` (`crate::Msrv`)
 
 ---
 **Affected lints:**
@@ -273,6 +273,16 @@ The minimum number of enum variants for the lints about variant names to trigger
 * [`enum_variant_names`](https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names)
 
 
+## `struct-field-name-threshold`
+The minimum number of struct fields for the lints about field names to trigger
+
+**Default Value:** `3` (`u64`)
+
+---
+**Affected lints:**
+* [`struct_variant_names`](https://rust-lang.github.io/rust-clippy/master/index.html#struct_variant_names)
+
+
 ## `enum-variant-size-threshold`
 The maximum size of an enum's variant to avoid box suggestion
 
diff --git a/src/tools/clippy/clippy_lints/src/async_yields_async.rs b/src/tools/clippy/clippy_lints/src/async_yields_async.rs
index 96a90d599ab..56f56fff1e7 100644
--- a/src/tools/clippy/clippy_lints/src/async_yields_async.rs
+++ b/src/tools/clippy/clippy_lints/src/async_yields_async.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::implements_trait;
 use rustc_errors::Applicability;
-use rustc_hir::{AsyncCoroutineKind, Body, BodyId, ExprKind, CoroutineKind, QPath};
+use rustc_hir::{AsyncCoroutineKind, Body, BodyId, CoroutineKind, ExprKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
index 60f9bbd7458..ae8618dcaa0 100644
--- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
+++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
@@ -287,5 +287,8 @@ fn is_mutex_guard(cx: &LateContext<'_>, def_id: DefId) -> bool {
 }
 
 fn is_refcell_ref(cx: &LateContext<'_>, def_id: DefId) -> bool {
-    matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::RefCellRef | sym::RefCellRefMut))
+    matches!(
+        cx.tcx.get_diagnostic_name(def_id),
+        Some(sym::RefCellRef | sym::RefCellRefMut)
+    )
 }
diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs
index 3f1ff66b8cf..cc9bd727937 100644
--- a/src/tools/clippy/clippy_lints/src/box_default.rs
+++ b/src/tools/clippy/clippy_lints/src/box_default.rs
@@ -3,8 +3,9 @@ use clippy_utils::macros::macro_backtrace;
 use clippy_utils::ty::expr_sig;
 use clippy_utils::{get_parent_node, is_default_equivalent, path_def_id};
 use rustc_errors::Applicability;
+use rustc_hir::def::Res;
 use rustc_hir::intravisit::{walk_ty, Visitor};
-use rustc_hir::{def::Res, Block, Expr, ExprKind, Local, Node, QPath, TyKind};
+use rustc_hir::{Block, Expr, ExprKind, Local, Node, QPath, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::print::with_forced_trimmed_paths;
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 481c44031cf..77438b27f90 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -154,9 +154,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::endian_bytes::LITTLE_ENDIAN_BYTES_INFO,
     crate::entry::MAP_ENTRY_INFO,
     crate::enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT_INFO,
-    crate::enum_variants::ENUM_VARIANT_NAMES_INFO,
-    crate::enum_variants::MODULE_INCEPTION_INFO,
-    crate::enum_variants::MODULE_NAME_REPETITIONS_INFO,
     crate::equatable_if_let::EQUATABLE_IF_LET_INFO,
     crate::error_impl_error::ERROR_IMPL_ERROR_INFO,
     crate::escape::BOXED_LOCAL_INFO,
@@ -226,6 +223,10 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::instant_subtraction::UNCHECKED_DURATION_SUBTRACTION_INFO,
     crate::int_plus_one::INT_PLUS_ONE_INFO,
     crate::invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS_INFO,
+    crate::item_name_repetitions::ENUM_VARIANT_NAMES_INFO,
+    crate::item_name_repetitions::MODULE_INCEPTION_INFO,
+    crate::item_name_repetitions::MODULE_NAME_REPETITIONS_INFO,
+    crate::item_name_repetitions::STRUCT_FIELD_NAMES_INFO,
     crate::items_after_statements::ITEMS_AFTER_STATEMENTS_INFO,
     crate::items_after_test_module::ITEMS_AFTER_TEST_MODULE_INFO,
     crate::iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs b/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs
index 3d6d257e386..2d11fa6b647 100644
--- a/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs
+++ b/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_with_context;
 use clippy_utils::last_path_segment;
+use clippy_utils::source::snippet_with_context;
 use rustc_errors::Applicability;
 use rustc_hir::{def, Expr, ExprKind, GenericArg, QPath, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
diff --git a/src/tools/clippy/clippy_lints/src/exit.rs b/src/tools/clippy/clippy_lints/src/exit.rs
index 5de79133c7d..5ecd0ffadf3 100644
--- a/src/tools/clippy/clippy_lints/src/exit.rs
+++ b/src/tools/clippy/clippy_lints/src/exit.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::{is_entrypoint_fn};
+use clippy_utils::is_entrypoint_fn;
 use if_chain::if_chain;
 use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node};
 use rustc_lint::{LateContext, LateLintPass};
diff --git a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
index d82ea6d2fc8..617c96b4fcb 100644
--- a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::ty::is_c_void;
 use clippy_utils::path_def_id;
+use clippy_utils::ty::is_c_void;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{Expr, ExprKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
diff --git a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
index 597fca88885..ee66c841ed2 100644
--- a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
@@ -1,50 +1,104 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_in_test_function;
 
+use rustc_hir as hir;
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Body, HirId};
+use rustc_hir::{Body, GenericParam, Generics, HirId, ImplItem, ImplItemKind, TraitItem, TraitItemKind};
 use rustc_lint::LateContext;
-use rustc_span::Span;
+use rustc_span::symbol::Ident;
+use rustc_span::{BytePos, Span};
 
 use super::IMPL_TRAIT_IN_PARAMS;
 
+fn report(
+    cx: &LateContext<'_>,
+    param: &GenericParam<'_>,
+    ident: &Ident,
+    generics: &Generics<'_>,
+    first_param_span: Span,
+) {
+    // No generics with nested generics, and no generics like FnMut(x)
+    span_lint_and_then(
+        cx,
+        IMPL_TRAIT_IN_PARAMS,
+        param.span,
+        "`impl Trait` used as a function parameter",
+        |diag| {
+            if let Some(gen_span) = generics.span_for_param_suggestion() {
+                // If there's already a generic param with the same bound, do not lint **this** suggestion.
+                diag.span_suggestion_with_style(
+                    gen_span,
+                    "add a type parameter",
+                    format!(", {{ /* Generic name */ }}: {}", &param.name.ident().as_str()[5..]),
+                    rustc_errors::Applicability::HasPlaceholders,
+                    rustc_errors::SuggestionStyle::ShowAlways,
+                );
+            } else {
+                diag.span_suggestion_with_style(
+                    Span::new(
+                        first_param_span.lo() - rustc_span::BytePos(1),
+                        ident.span.hi(),
+                        ident.span.ctxt(),
+                        ident.span.parent(),
+                    ),
+                    "add a type parameter",
+                    format!("<{{ /* Generic name */ }}: {}>", &param.name.ident().as_str()[5..]),
+                    rustc_errors::Applicability::HasPlaceholders,
+                    rustc_errors::SuggestionStyle::ShowAlways,
+                );
+            }
+        },
+    );
+}
+
 pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: &'tcx Body<'_>, hir_id: HirId) {
-    if cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public() && !is_in_test_function(cx.tcx, hir_id)
-    {
-        if let FnKind::ItemFn(ident, generics, _) = kind {
+    if_chain! {
+        if let FnKind::ItemFn(ident, generics, _) = kind;
+        if cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public();
+        if !is_in_test_function(cx.tcx, hir_id);
+        then {
             for param in generics.params {
                 if param.is_impl_trait() {
-                    // No generics with nested generics, and no generics like FnMut(x)
-                    span_lint_and_then(
-                        cx,
-                        IMPL_TRAIT_IN_PARAMS,
-                        param.span,
-                        "'`impl Trait` used as a function parameter'",
-                        |diag| {
-                            if let Some(gen_span) = generics.span_for_param_suggestion() {
-                                diag.span_suggestion_with_style(
-                                    gen_span,
-                                    "add a type parameter",
-                                    format!(", {{ /* Generic name */ }}: {}", &param.name.ident().as_str()[5..]),
-                                    rustc_errors::Applicability::HasPlaceholders,
-                                    rustc_errors::SuggestionStyle::ShowAlways,
-                                );
-                            } else {
-                                diag.span_suggestion_with_style(
-                                    Span::new(
-                                        body.params[0].span.lo() - rustc_span::BytePos(1),
-                                        ident.span.hi(),
-                                        ident.span.ctxt(),
-                                        ident.span.parent(),
-                                    ),
-                                    "add a type parameter",
-                                    format!("<{{ /* Generic name */ }}: {}>", &param.name.ident().as_str()[5..]),
-                                    rustc_errors::Applicability::HasPlaceholders,
-                                    rustc_errors::SuggestionStyle::ShowAlways,
-                                );
-                            }
-                        },
-                    );
+                    report(cx, param, ident, generics, body.params[0].span);
+                };
+            }
+        }
+    }
+}
+
+pub(super) fn check_impl_item(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) {
+    if_chain! {
+        if let ImplItemKind::Fn(_, body_id) = impl_item.kind;
+        if let hir::Node::Item(item) = cx.tcx.hir().get_parent(impl_item.hir_id());
+        if let hir::ItemKind::Impl(impl_) = item.kind;
+        if let hir::Impl { of_trait, .. } = *impl_;
+        if of_trait.is_none();
+        let body = cx.tcx.hir().body(body_id);
+        if cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public();
+        if !is_in_test_function(cx.tcx, impl_item.hir_id());
+        then {
+            for param in impl_item.generics.params {
+                if param.is_impl_trait() {
+                    report(cx, param, &impl_item.ident, impl_item.generics, body.params[0].span);
+                }
+            }
+        }
+    }
+}
+
+pub(super) fn check_trait_item(cx: &LateContext<'_>, trait_item: &TraitItem<'_>, avoid_breaking_exported_api: bool) {
+    if_chain! {
+        if !avoid_breaking_exported_api;
+        if let TraitItemKind::Fn(_, _) = trait_item.kind;
+        if let hir::Node::Item(item) = cx.tcx.hir().get_parent(trait_item.hir_id());
+        // ^^ (Will always be a trait)
+        if !item.vis_span.is_empty(); // Is public
+        if !is_in_test_function(cx.tcx, trait_item.hir_id());
+        then {
+            for param in trait_item.generics.params {
+                if param.is_impl_trait() {
+                    let sp = trait_item.ident.span.with_hi(trait_item.ident.span.hi() + BytePos(1));
+                    report(cx, param, &trait_item.ident, trait_item.generics, sp.shrink_to_hi());
                 }
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs
index ee10334c67f..716908483e9 100644
--- a/src/tools/clippy/clippy_lints/src/functions/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs
@@ -360,18 +360,26 @@ declare_clippy_lint! {
 }
 
 #[derive(Copy, Clone)]
+#[allow(clippy::struct_field_names)]
 pub struct Functions {
     too_many_arguments_threshold: u64,
     too_many_lines_threshold: u64,
     large_error_threshold: u64,
+    avoid_breaking_exported_api: bool,
 }
 
 impl Functions {
-    pub fn new(too_many_arguments_threshold: u64, too_many_lines_threshold: u64, large_error_threshold: u64) -> Self {
+    pub fn new(
+        too_many_arguments_threshold: u64,
+        too_many_lines_threshold: u64,
+        large_error_threshold: u64,
+        avoid_breaking_exported_api: bool,
+    ) -> Self {
         Self {
             too_many_arguments_threshold,
             too_many_lines_threshold,
             large_error_threshold,
+            avoid_breaking_exported_api,
         }
     }
 }
@@ -415,6 +423,7 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
         must_use::check_impl_item(cx, item);
         result::check_impl_item(cx, item, self.large_error_threshold);
+        impl_trait_in_params::check_impl_item(cx, item);
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
@@ -422,5 +431,6 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
         not_unsafe_ptr_arg_deref::check_trait_item(cx, item);
         must_use::check_trait_item(cx, item);
         result::check_trait_item(cx, item, self.large_error_threshold);
+        impl_trait_in_params::check_trait_item(cx, item, self.avoid_breaking_exported_api);
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/enum_variants.rs b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
index e332f681b6d..8b4984da3dd 100644
--- a/src/tools/clippy/clippy_lints/src/enum_variants.rs
+++ b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
@@ -1,9 +1,10 @@
 //! lint on enum variants that are prefixed or suffixed by the same characters
 
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_hir};
+use clippy_utils::macros::span_is_local;
 use clippy_utils::source::is_present_in_source;
-use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start};
-use rustc_hir::{EnumDef, Item, ItemKind, OwnerId, Variant};
+use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start, to_camel_case, to_snake_case};
+use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, Variant, VariantData};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
@@ -103,32 +104,184 @@ declare_clippy_lint! {
     style,
     "modules that have the same name as their parent module"
 }
+declare_clippy_lint! {
+    /// ### What it does
+    /// Detects struct fields that are prefixed or suffixed
+    /// by the same characters or the name of the struct itself.
+    ///
+    /// ### Why is this bad?
+    /// Information common to all struct fields is better represented in the struct name.
+    ///
+    /// ### Limitations
+    /// Characters with no casing will be considered when comparing prefixes/suffixes
+    /// This applies to numbers and non-ascii characters without casing
+    /// e.g. `foo1` and `foo2` is considered to have different prefixes
+    /// (the prefixes are `foo1` and `foo2` respectively), as also `bar螃`, `bar蟹`
+    ///
+    /// ### Example
+    /// ```rust
+    /// struct Cake {
+    ///     cake_sugar: u8,
+    ///     cake_flour: u8,
+    ///     cake_eggs: u8
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// struct Cake {
+    ///     sugar: u8,
+    ///     flour: u8,
+    ///     eggs: u8
+    /// }
+    /// ```
+    #[clippy::version = "1.75.0"]
+    pub STRUCT_FIELD_NAMES,
+    pedantic,
+    "structs where all fields share a prefix/postfix or contain the name of the struct"
+}
 
-pub struct EnumVariantNames {
+pub struct ItemNameRepetitions {
     modules: Vec<(Symbol, String, OwnerId)>,
-    threshold: u64,
+    enum_threshold: u64,
+    struct_threshold: u64,
     avoid_breaking_exported_api: bool,
     allow_private_module_inception: bool,
 }
 
-impl EnumVariantNames {
+impl ItemNameRepetitions {
     #[must_use]
-    pub fn new(threshold: u64, avoid_breaking_exported_api: bool, allow_private_module_inception: bool) -> Self {
+    pub fn new(
+        enum_threshold: u64,
+        struct_threshold: u64,
+        avoid_breaking_exported_api: bool,
+        allow_private_module_inception: bool,
+    ) -> Self {
         Self {
             modules: Vec::new(),
-            threshold,
+            enum_threshold,
+            struct_threshold,
             avoid_breaking_exported_api,
             allow_private_module_inception,
         }
     }
 }
 
-impl_lint_pass!(EnumVariantNames => [
+impl_lint_pass!(ItemNameRepetitions => [
     ENUM_VARIANT_NAMES,
+    STRUCT_FIELD_NAMES,
     MODULE_NAME_REPETITIONS,
     MODULE_INCEPTION
 ]);
 
+#[must_use]
+fn have_no_extra_prefix(prefixes: &[&str]) -> bool {
+    prefixes.iter().all(|p| p == &"" || p == &"_")
+}
+
+fn check_fields(cx: &LateContext<'_>, threshold: u64, item: &Item<'_>, fields: &[FieldDef<'_>]) {
+    if (fields.len() as u64) < threshold {
+        return;
+    }
+
+    check_struct_name_repetition(cx, item, fields);
+
+    // if the SyntaxContext of the identifiers of the fields and struct differ dont lint them.
+    // this prevents linting in macros in which the location of the field identifier names differ
+    if !fields.iter().all(|field| item.ident.span.eq_ctxt(field.ident.span)) {
+        return;
+    }
+
+    let mut pre: Vec<&str> = match fields.first() {
+        Some(first_field) => first_field.ident.name.as_str().split('_').collect(),
+        None => return,
+    };
+    let mut post = pre.clone();
+    post.reverse();
+    for field in fields {
+        let field_split: Vec<&str> = field.ident.name.as_str().split('_').collect();
+        if field_split.len() == 1 {
+            return;
+        }
+
+        pre = pre
+            .into_iter()
+            .zip(field_split.iter())
+            .take_while(|(a, b)| &a == b)
+            .map(|e| e.0)
+            .collect();
+        post = post
+            .into_iter()
+            .zip(field_split.iter().rev())
+            .take_while(|(a, b)| &a == b)
+            .map(|e| e.0)
+            .collect();
+    }
+    let prefix = pre.join("_");
+    post.reverse();
+    let postfix = match post.last() {
+        Some(&"") => post.join("_") + "_",
+        Some(_) | None => post.join("_"),
+    };
+    if fields.len() > 1 {
+        let (what, value) = match (
+            prefix.is_empty() || prefix.chars().all(|c| c == '_'),
+            postfix.is_empty(),
+        ) {
+            (true, true) => return,
+            (false, _) => ("pre", prefix),
+            (true, false) => ("post", postfix),
+        };
+        span_lint_and_help(
+            cx,
+            STRUCT_FIELD_NAMES,
+            item.span,
+            &format!("all fields have the same {what}fix: `{value}`"),
+            None,
+            &format!("remove the {what}fixes"),
+        );
+    }
+}
+
+fn check_struct_name_repetition(cx: &LateContext<'_>, item: &Item<'_>, fields: &[FieldDef<'_>]) {
+    let snake_name = to_snake_case(item.ident.name.as_str());
+    let item_name_words: Vec<&str> = snake_name.split('_').collect();
+    for field in fields {
+        if field.ident.span.eq_ctxt(item.ident.span) {
+            //consider linting only if the field identifier has the same SyntaxContext as the item(struct)
+            let field_words: Vec<&str> = field.ident.name.as_str().split('_').collect();
+            if field_words.len() >= item_name_words.len() {
+                // if the field name is shorter than the struct name it cannot contain it
+                if field_words.iter().zip(item_name_words.iter()).all(|(a, b)| a == b) {
+                    span_lint_hir(
+                        cx,
+                        STRUCT_FIELD_NAMES,
+                        field.hir_id,
+                        field.span,
+                        "field name starts with the struct's name",
+                    );
+                }
+                if field_words.len() > item_name_words.len() {
+                    // lint only if the end is not covered by the start
+                    if field_words
+                        .iter()
+                        .rev()
+                        .zip(item_name_words.iter().rev())
+                        .all(|(a, b)| a == b)
+                    {
+                        span_lint_hir(
+                            cx,
+                            STRUCT_FIELD_NAMES,
+                            field.hir_id,
+                            field.span,
+                            "field name ends with the struct's name",
+                        );
+                    }
+                }
+            }
+        }
+    }
+}
+
 fn check_enum_start(cx: &LateContext<'_>, item_name: &str, variant: &Variant<'_>) {
     let name = variant.ident.name.as_str();
     let item_name_chars = item_name.chars().count();
@@ -218,35 +371,7 @@ fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_n
     );
 }
 
-#[must_use]
-fn have_no_extra_prefix(prefixes: &[&str]) -> bool {
-    prefixes.iter().all(|p| p == &"" || p == &"_")
-}
-
-#[must_use]
-fn to_camel_case(item_name: &str) -> String {
-    let mut s = String::new();
-    let mut up = true;
-    for c in item_name.chars() {
-        if c.is_uppercase() {
-            // we only turn snake case text into CamelCase
-            return item_name.to_string();
-        }
-        if c == '_' {
-            up = true;
-            continue;
-        }
-        if up {
-            up = false;
-            s.extend(c.to_uppercase());
-        } else {
-            s.push(c);
-        }
-    }
-    s
-}
-
-impl LateLintPass<'_> for EnumVariantNames {
+impl LateLintPass<'_> for ItemNameRepetitions {
     fn check_item_post(&mut self, _cx: &LateContext<'_>, _item: &Item<'_>) {
         let last = self.modules.pop();
         assert!(last.is_some());
@@ -303,9 +428,15 @@ impl LateLintPass<'_> for EnumVariantNames {
                 }
             }
         }
-        if let ItemKind::Enum(ref def, _) = item.kind {
-            if !(self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(item.owner_id.def_id)) {
-                check_variant(cx, self.threshold, def, item_name, item.span);
+        if !(self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(item.owner_id.def_id))
+            && span_is_local(item.span)
+        {
+            match item.kind {
+                ItemKind::Enum(def, _) => check_variant(cx, self.enum_threshold, &def, item_name, item.span),
+                ItemKind::Struct(VariantData::Struct(fields, _), _) => {
+                    check_fields(cx, self.struct_threshold, item, fields);
+                },
+                _ => (),
             }
         }
         self.modules.push((item.ident.name, item_camel, item.owner_id));
diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
index 43e1b92c9b9..0ee291a4e9d 100644
--- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
@@ -9,6 +9,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::{sym, Symbol};
+use std::iter;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -52,12 +53,13 @@ declare_clippy_lint! {
 declare_clippy_lint! {
     /// ### What it does
     /// This is the opposite of the `iter_without_into_iter` lint.
-    /// It looks for `IntoIterator for (&|&mut) Type` implementations without an inherent `iter` or `iter_mut` method.
+    /// It looks for `IntoIterator for (&|&mut) Type` implementations without an inherent `iter` or `iter_mut` method
+    /// on the type or on any of the types in its `Deref` chain.
     ///
     /// ### Why is this bad?
     /// It's not bad, but having them is idiomatic and allows the type to be used in iterator chains
-    /// by just calling `.iter()`, instead of the more awkward `<&Type>::into_iter` or `(&val).iter()` syntax
-    /// in case of ambiguity with another `Intoiterator` impl.
+    /// by just calling `.iter()`, instead of the more awkward `<&Type>::into_iter` or `(&val).into_iter()` syntax
+    /// in case of ambiguity with another `IntoIterator` impl.
     ///
     /// ### Example
     /// ```rust
@@ -102,7 +104,20 @@ fn is_nameable_in_impl_trait(ty: &rustc_hir::Ty<'_>) -> bool {
     !matches!(ty.kind, TyKind::OpaqueDef(..))
 }
 
-fn type_has_inherent_method(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool {
+/// Returns the deref chain of a type, starting with the type itself.
+fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl Iterator<Item = Ty<'tcx>> + 'cx {
+    iter::successors(Some(ty), |&ty| {
+        if let Some(deref_did) = cx.tcx.lang_items().deref_trait()
+            && implements_trait(cx, ty, deref_did, &[])
+        {
+            make_normalized_projection(cx.tcx, cx.param_env, deref_did, sym::Target, [ty])
+        } else {
+            None
+        }
+    })
+}
+
+fn adt_has_inherent_method(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool {
     if let Some(ty_did) = ty.ty_adt_def().map(ty::AdtDef::did) {
         cx.tcx.inherent_impls(ty_did).iter().any(|&did| {
             cx.tcx
@@ -127,7 +142,11 @@ impl LateLintPass<'_> for IterWithoutIntoIter {
                 Mutability::Mut => sym::iter_mut,
                 Mutability::Not => sym::iter,
             }
-            && !type_has_inherent_method(cx, ty, expected_method_name)
+            && !deref_chain(cx, ty)
+                .any(|ty| {
+                    // We can't check inherent impls for slices, but we know that they have an `iter(_mut)` method
+                    ty.peel_refs().is_slice() || adt_has_inherent_method(cx, ty, expected_method_name)
+                })
             && let Some(iter_assoc_span) = imp.items.iter().find_map(|item| {
                 if item.ident.name == sym!(IntoIter) {
                     Some(cx.tcx.hir().impl_item(item.id).expect_type().span)
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 0f35ec27665..a70a38ee08b 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -50,9 +50,6 @@ extern crate clippy_utils;
 #[macro_use]
 extern crate declare_clippy_lint;
 
-use std::io;
-use std::path::PathBuf;
-
 use clippy_utils::msrvs::Msrv;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_lint::{Lint, LintId};
@@ -121,7 +118,6 @@ mod empty_structs_with_brackets;
 mod endian_bytes;
 mod entry;
 mod enum_clike;
-mod enum_variants;
 mod equatable_if_let;
 mod error_impl_error;
 mod escape;
@@ -166,6 +162,7 @@ mod inline_fn_without_body;
 mod instant_subtraction;
 mod int_plus_one;
 mod invalid_upcast_comparisons;
+mod item_name_repetitions;
 mod items_after_statements;
 mod items_after_test_module;
 mod iter_not_returning_iterator;
@@ -362,7 +359,6 @@ mod zero_sized_map_values;
 // end lints modules, do not remove this comment, it’s used in `update_lints`
 
 use crate::utils::conf::metadata::get_configuration_metadata;
-use crate::utils::conf::TryConf;
 pub use crate::utils::conf::{lookup_conf_file, Conf};
 use crate::utils::FindAll;
 
@@ -374,65 +370,13 @@ use crate::utils::FindAll;
 /// level (i.e `#![cfg_attr(...)]`) will still be expanded even when using a pre-expansion pass.
 ///
 /// Used in `./src/driver.rs`.
-pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
+pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     // NOTE: Do not add any more pre-expansion passes. These should be removed eventually.
-    let msrv = Msrv::read(&conf.msrv, sess);
-    let msrv = move || msrv.clone();
+    let msrv = || conf.msrv.clone();
 
     store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes { msrv: msrv() }));
 }
 
-#[doc(hidden)]
-pub fn read_conf(sess: &Session, path: &io::Result<(Option<PathBuf>, Vec<String>)>) -> Conf {
-    if let Ok((_, warnings)) = path {
-        for warning in warnings {
-            sess.warn(warning.clone());
-        }
-    }
-    let file_name = match path {
-        Ok((Some(path), _)) => path,
-        Ok((None, _)) => return Conf::default(),
-        Err(error) => {
-            sess.err(format!("error finding Clippy's configuration file: {error}"));
-            return Conf::default();
-        },
-    };
-
-    let TryConf { conf, errors, warnings } = utils::conf::read(sess, file_name);
-    // all conf errors are non-fatal, we just use the default conf in case of error
-    for error in errors {
-        if let Some(span) = error.span {
-            sess.span_err(
-                span,
-                format!("error reading Clippy's configuration file: {}", error.message),
-            );
-        } else {
-            sess.err(format!(
-                "error reading Clippy's configuration file `{}`: {}",
-                file_name.display(),
-                error.message
-            ));
-        }
-    }
-
-    for warning in warnings {
-        if let Some(span) = warning.span {
-            sess.span_warn(
-                span,
-                format!("error reading Clippy's configuration file: {}", warning.message),
-            );
-        } else {
-            sess.warn(format!(
-                "error reading Clippy's configuration file `{}`: {}",
-                file_name.display(),
-                warning.message
-            ));
-        }
-    }
-
-    conf
-}
-
 #[derive(Default)]
 struct RegistrationGroups {
     all: Vec<LintId>,
@@ -558,7 +502,7 @@ fn register_categories(store: &mut rustc_lint::LintStore) {
 ///
 /// Used in `./src/driver.rs`.
 #[expect(clippy::too_many_lines)]
-pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
+pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &'static Conf) {
     register_removed_non_tool_lints(store);
     register_categories(store);
 
@@ -660,8 +604,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions));
     store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports));
 
-    let msrv = Msrv::read(&conf.msrv, sess);
-    let msrv = move || msrv.clone();
+    let msrv = || conf.msrv.clone();
     let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
     let allow_expect_in_tests = conf.allow_expect_in_tests;
     let allow_unwrap_in_tests = conf.allow_unwrap_in_tests;
@@ -762,6 +705,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
             too_many_arguments_threshold,
             too_many_lines_threshold,
             large_error_threshold,
+            avoid_breaking_exported_api,
         ))
     });
     let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
@@ -806,7 +750,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
             suppress_restriction_lint_in_const,
         ))
     });
-    store.register_late_pass(|_| Box::new(non_copy_const::NonCopyConst));
+    let ignore_interior_mutability = conf.ignore_interior_mutability.clone();
+    store.register_late_pass(move |_| Box::new(non_copy_const::NonCopyConst::new(ignore_interior_mutability.clone())));
     store.register_late_pass(|_| Box::new(ptr_offset_with_cast::PtrOffsetWithCast));
     store.register_late_pass(|_| Box::new(redundant_clone::RedundantClone));
     store.register_late_pass(|_| Box::new(slow_vector_initialization::SlowVectorInit));
@@ -851,10 +796,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         ))
     });
     let enum_variant_name_threshold = conf.enum_variant_name_threshold;
+    let struct_field_name_threshold = conf.struct_field_name_threshold;
     let allow_private_module_inception = conf.allow_private_module_inception;
     store.register_late_pass(move |_| {
-        Box::new(enum_variants::EnumVariantNames::new(
+        Box::new(item_name_repetitions::ItemNameRepetitions::new(
             enum_variant_name_threshold,
+            struct_field_name_threshold,
             avoid_breaking_exported_api,
             allow_private_module_inception,
         ))
diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
index f7b3b2358a0..5fffb27cda2 100644
--- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
@@ -185,7 +185,7 @@ fn get_vec_push<'tcx>(
             if let StmtKind::Semi(semi_stmt) = &stmt.kind;
             if let ExprKind::MethodCall(path, self_expr, args, _) = &semi_stmt.kind;
             // Figure out the parameters for the method call
-            if let Some(pushed_item) = args.get(0);
+            if let Some(pushed_item) = args.first();
             // Check that the method being called is push() on a Vec
             if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec);
             if path.ident.name.as_str() == "push";
diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
index 914ceca2995..5a87e75722d 100644
--- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
@@ -4,7 +4,7 @@ use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
-    AsyncCoroutineKind, Block, Body, Closure, Expr, ExprKind, FnDecl, FnRetTy, CoroutineKind, GenericArg, GenericBound,
+    AsyncCoroutineKind, Block, Body, Closure, CoroutineKind, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, GenericBound,
     ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, TypeBindingKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
diff --git a/src/tools/clippy/clippy_lints/src/manual_bits.rs b/src/tools/clippy/clippy_lints/src/manual_bits.rs
index 6c7c57ba1d6..552c57d5e02 100644
--- a/src/tools/clippy/clippy_lints/src/manual_bits.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_bits.rs
@@ -103,9 +103,9 @@ fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<
         if let ExprKind::Path(ref count_func_qpath) = count_func.kind;
 
         if let QPath::Resolved(_, count_func_path) = count_func_qpath;
-        if let Some(segment_zero) = count_func_path.segments.get(0);
+        if let Some(segment_zero) = count_func_path.segments.first();
         if let Some(args) = segment_zero.args;
-        if let Some(GenericArg::Type(real_ty)) = args.args.get(0);
+        if let Some(GenericArg::Type(real_ty)) = args.args.first();
 
         if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id();
         if cx.tcx.is_diagnostic_item(sym::mem_size_of, def_id);
diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
index f264424470d..9da20a28fba 100644
--- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
@@ -15,12 +15,13 @@ use rustc_span::{sym, Span};
 declare_clippy_lint! {
     /// ### What it does
     /// Suggests to use dedicated built-in methods,
-    /// `is_ascii_(lowercase|uppercase|digit)` for checking on corresponding ascii range
+    /// `is_ascii_(lowercase|uppercase|digit|hexdigit)` for checking on corresponding
+    /// ascii range
     ///
     /// ### Why is this bad?
     /// Using the built-in functions is more readable and makes it
     /// clear that it's not a specific subset of characters, but all
-    /// ASCII (lowercase|uppercase|digit) characters.
+    /// ASCII (lowercase|uppercase|digit|hexdigit) characters.
     /// ### Example
     /// ```rust
     /// fn main() {
@@ -28,6 +29,7 @@ declare_clippy_lint! {
     ///     assert!(matches!(b'X', b'A'..=b'Z'));
     ///     assert!(matches!('2', '0'..='9'));
     ///     assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
+    ///     assert!(matches!('C', '0'..='9' | 'a'..='f' | 'A'..='F'));
     ///
     ///     ('0'..='9').contains(&'0');
     ///     ('a'..='z').contains(&'a');
@@ -41,6 +43,7 @@ declare_clippy_lint! {
     ///     assert!(b'X'.is_ascii_uppercase());
     ///     assert!('2'.is_ascii_digit());
     ///     assert!('x'.is_ascii_alphabetic());
+    ///     assert!('C'.is_ascii_hexdigit());
     ///
     ///     '0'.is_ascii_digit();
     ///     'a'.is_ascii_lowercase();
@@ -75,6 +78,12 @@ enum CharRange {
     FullChar,
     /// '0..=9'
     Digit,
+    /// 'a..=f'
+    LowerHexLetter,
+    /// 'A..=F'
+    UpperHexLetter,
+    /// '0..=9' | 'a..=f' | 'A..=F'
+    HexDigit,
     Otherwise,
 }
 
@@ -116,7 +125,8 @@ fn check_is_ascii(cx: &LateContext<'_>, span: Span, recv: &Expr<'_>, range: &Cha
         CharRange::LowerChar => Some("is_ascii_lowercase"),
         CharRange::FullChar => Some("is_ascii_alphabetic"),
         CharRange::Digit => Some("is_ascii_digit"),
-        CharRange::Otherwise => None,
+        CharRange::HexDigit => Some("is_ascii_hexdigit"),
+        CharRange::Otherwise | CharRange::LowerHexLetter | CharRange::UpperHexLetter => None,
     } {
         let default_snip = "..";
         let mut app = Applicability::MachineApplicable;
@@ -141,6 +151,12 @@ fn check_pat(pat_kind: &PatKind<'_>) -> CharRange {
 
             if ranges.len() == 2 && ranges.contains(&CharRange::UpperChar) && ranges.contains(&CharRange::LowerChar) {
                 CharRange::FullChar
+            } else if ranges.len() == 3
+                && ranges.contains(&CharRange::Digit)
+                && ranges.contains(&CharRange::LowerHexLetter)
+                && ranges.contains(&CharRange::UpperHexLetter)
+            {
+                CharRange::HexDigit
             } else {
                 CharRange::Otherwise
             }
@@ -156,6 +172,8 @@ fn check_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange {
         match (&start_lit.node, &end_lit.node) {
             (Char('a'), Char('z')) | (Byte(b'a'), Byte(b'z')) => CharRange::LowerChar,
             (Char('A'), Char('Z')) | (Byte(b'A'), Byte(b'Z')) => CharRange::UpperChar,
+            (Char('a'), Char('f')) | (Byte(b'a'), Byte(b'f')) => CharRange::LowerHexLetter,
+            (Char('A'), Char('F')) | (Byte(b'A'), Byte(b'F')) => CharRange::UpperHexLetter,
             (Char('0'), Char('9')) | (Byte(b'0'), Byte(b'9')) => CharRange::Digit,
             _ => CharRange::Otherwise,
         }
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index a23000e5fe1..b5ab94b3a2f 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -967,7 +967,6 @@ declare_clippy_lint! {
     "checks for unnecessary guards in match expressions"
 }
 
-#[derive(Default)]
 pub struct Matches {
     msrv: Msrv,
     infallible_destructuring_match_linted: bool,
@@ -978,7 +977,7 @@ impl Matches {
     pub fn new(msrv: Msrv) -> Self {
         Self {
             msrv,
-            ..Matches::default()
+            infallible_destructuring_match_linted: false,
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs
index 3337b250c0e..20878f1e4df 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::{is_expr_identity_function, is_trait_method};
+use clippy_utils::{is_expr_untyped_identity_function, is_trait_method};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -9,7 +9,7 @@ use rustc_span::sym;
 use super::FILTER_MAP_IDENTITY;
 
 pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_map_arg: &hir::Expr<'_>, filter_map_span: Span) {
-    if is_trait_method(cx, expr, sym::Iterator) && is_expr_identity_function(cx, filter_map_arg) {
+    if is_trait_method(cx, expr, sym::Iterator) && is_expr_untyped_identity_function(cx, filter_map_arg) {
         span_lint_and_sugg(
             cx,
             FILTER_MAP_IDENTITY,
diff --git a/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs
index 84a21de0ac8..8849a4f4942 100644
--- a/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::{is_expr_identity_function, is_trait_method};
+use clippy_utils::{is_expr_untyped_identity_function, is_trait_method};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -15,7 +15,7 @@ pub(super) fn check<'tcx>(
     flat_map_arg: &'tcx hir::Expr<'_>,
     flat_map_span: Span,
 ) {
-    if is_trait_method(cx, expr, sym::Iterator) && is_expr_identity_function(cx, flat_map_arg) {
+    if is_trait_method(cx, expr, sym::Iterator) && is_expr_untyped_identity_function(cx, flat_map_arg) {
         span_lint_and_sugg(
             cx,
             FLAT_MAP_IDENTITY,
diff --git a/src/tools/clippy/clippy_lints/src/methods/get_first.rs b/src/tools/clippy/clippy_lints/src/methods/get_first.rs
index ee063adac64..e7b4564c651 100644
--- a/src/tools/clippy/clippy_lints/src/methods/get_first.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/get_first.rs
@@ -1,5 +1,4 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_slice_of_primitives;
 use clippy_utils::source::snippet_with_applicability;
 use if_chain::if_chain;
 use rustc_ast::LitKind;
@@ -20,7 +19,6 @@ pub(super) fn check<'tcx>(
         if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
         if cx.tcx.type_of(impl_id).instantiate_identity().is_slice();
-        if let Some(_) = is_slice_of_primitives(cx, recv);
         if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = arg.kind;
         then {
             let mut app = Applicability::MachineApplicable;
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 7be1ce483f6..57581363cfa 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_expr_identity_function, is_trait_method};
+use clippy_utils::{is_expr_untyped_identity_function, is_trait_method};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -23,7 +23,7 @@ pub(super) fn check(
         if is_trait_method(cx, expr, sym::Iterator)
             || is_type_diagnostic_item(cx, caller_ty, sym::Result)
             || is_type_diagnostic_item(cx, caller_ty, sym::Option);
-        if is_expr_identity_function(cx, map_arg);
+        if is_expr_untyped_identity_function(cx, map_arg);
         if let Some(sugg_span) = expr.span.trim_start(caller.span);
         then {
             span_lint_and_sugg(
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 afdb8ce94ac..04ddaaa2f46 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
@@ -39,7 +39,7 @@ pub(super) fn check<'tcx>(
                 if search_method == "find";
                 if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind;
                 let closure_body = cx.tcx.hir().body(body);
-                if let Some(closure_arg) = closure_body.params.get(0);
+                if let Some(closure_arg) = closure_body.params.first();
                 then {
                     if let hir::PatKind::Ref(..) = closure_arg.pat.kind {
                         Some(search_snippet.replacen('&', "", 1))
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
index 47e2e744112..4a651396f14 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
@@ -2,6 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{eager_or_lazy, is_from_proc_macro, usage};
+use hir::FnRetTy;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -27,7 +28,7 @@ pub(super) fn check<'tcx>(
     let is_bool = cx.typeck_results().expr_ty(recv).is_bool();
 
     if is_option || is_result || is_bool {
-        if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = arg.kind {
+        if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl, .. }) = arg.kind {
             let body = cx.tcx.hir().body(body);
             let body_expr = &body.value;
 
@@ -48,7 +49,14 @@ pub(super) fn check<'tcx>(
                     .iter()
                     // bindings are checked to be unused above
                     .all(|param| matches!(param.pat.kind, hir::PatKind::Binding(..) | hir::PatKind::Wild))
-                {
+                    && matches!(
+                        fn_decl.output,
+                        FnRetTy::DefaultReturn(_)
+                            | FnRetTy::Return(hir::Ty {
+                                kind: hir::TyKind::Infer,
+                                ..
+                            })
+                    ) {
                     Applicability::MachineApplicable
                 } else {
                     // replacing the lambda may break type inference
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index f2773cad400..0629dee4f72 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -67,7 +67,7 @@ impl MissingDoc {
         if_chain! {
             if let Some(meta) = meta;
             if let MetaItemKind::List(list) = meta.kind;
-            if let Some(meta) = list.get(0);
+            if let Some(meta) = list.first();
             if let Some(name) = meta.ident();
             then {
                 name.name == sym::include
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 96d83e114a4..fc088710e42 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
@@ -17,6 +17,9 @@ declare_clippy_lint! {
     /// Checks for imports that do not rename the item as specified
     /// in the `enforce-import-renames` config option.
     ///
+    /// Note: Even though this lint is warn-by-default, it will only trigger if
+    /// import renames are defined in the clippy.toml file.
+    ///
     /// ### Why is this bad?
     /// Consistency is important, if a project has defined import
     /// renames they should be followed. More practically, some item names are too
@@ -38,7 +41,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.55.0"]
     pub MISSING_ENFORCED_IMPORT_RENAMES,
-    restriction,
+    style,
     "enforce import renames"
 }
 
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 f0b865be804..d205237a591 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
@@ -1,9 +1,9 @@
 use std::ops::ControlFlow;
 
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_path_lang_item;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::{for_each_expr, Visitable};
-use clippy_utils::is_path_lang_item;
 use rustc_ast::LitKind;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::{DefKind, Res};
diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
index fe35126aab2..2c42a7a3676 100644
--- a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
+++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
@@ -9,7 +9,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::Span;
+use rustc_span::{DesugaringKind, Span};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -64,7 +64,10 @@ declare_lint_pass!(MultipleUnsafeOpsPerBlock => [MULTIPLE_UNSAFE_OPS_PER_BLOCK])
 
 impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock {
     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
-        if !matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) || in_external_macro(cx.tcx.sess, block.span) {
+        if !matches!(block.rules, BlockCheckMode::UnsafeBlock(_))
+            || in_external_macro(cx.tcx.sess, block.span)
+            || block.span.is_desugaring(DesugaringKind::Await)
+        {
             return;
         }
         let mut unsafe_ops = vec![];
diff --git a/src/tools/clippy/clippy_lints/src/needless_continue.rs b/src/tools/clippy/clippy_lints/src/needless_continue.rs
index 38a75034cd3..377cbef7b99 100644
--- a/src/tools/clippy/clippy_lints/src/needless_continue.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_continue.rs
@@ -189,7 +189,7 @@ fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&ast::Label>)
 }
 
 fn is_first_block_stmt_continue(block: &ast::Block, label: Option<&ast::Label>) -> bool {
-    block.stmts.get(0).map_or(false, |stmt| match stmt.kind {
+    block.stmts.first().map_or(false, |stmt| match stmt.kind {
         ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => {
             if let ast::ExprKind::Continue(ref l) = e.kind {
                 compare_labels(label, l.as_ref())
@@ -434,7 +434,7 @@ fn erode_from_back(s: &str) -> String {
 }
 
 fn span_of_first_expr_in_block(block: &ast::Block) -> Option<Span> {
-    block.stmts.get(0).map(|stmt| stmt.span)
+    block.stmts.first().map(|stmt| stmt.span)
 }
 
 #[cfg(test)]
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
index 212d6234bdb..1d5874f6fea 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
@@ -7,7 +7,8 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_qpath, FnKind, Visitor};
 use rustc_hir::{
-    Body, Closure, Expr, ExprKind, FnDecl, HirId, HirIdMap, HirIdSet, Impl, ItemKind, Mutability, Node, PatKind, QPath,
+    BlockCheckMode, Body, Closure, Expr, ExprKind, FnDecl, HirId, HirIdMap, HirIdSet, Impl, ItemKind, Mutability, Node,
+    PatKind, QPath,
 };
 use rustc_hir_typeck::expr_use_visitor as euv;
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
@@ -139,13 +140,23 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
         let hir_id = cx.tcx.hir().local_def_id_to_hir_id(fn_def_id);
         let is_async = match kind {
             FnKind::ItemFn(.., header) => {
+                if header.is_unsafe() {
+                    // We don't check unsafe functions.
+                    return;
+                }
                 let attrs = cx.tcx.hir().attrs(hir_id);
                 if header.abi != Abi::Rust || requires_exact_signature(attrs) {
                     return;
                 }
                 header.is_async()
             },
-            FnKind::Method(.., sig) => sig.header.is_async(),
+            FnKind::Method(.., sig) => {
+                if sig.header.is_unsafe() {
+                    // We don't check unsafe functions.
+                    return;
+                }
+                sig.header.is_async()
+            },
             FnKind::Closure => return,
         };
 
@@ -186,20 +197,21 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
             };
             let infcx = cx.tcx.infer_ctxt().build();
             euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body);
-            if is_async {
-                let mut checked_closures = FxHashSet::default();
-
-                // We retrieve all the closures declared in the async function because they will
-                // not be found by `euv::Delegate`.
-                let mut closures: FxHashSet<LocalDefId> = FxHashSet::default();
-                for_each_expr_with_closures(cx, body, |expr| {
-                    if let ExprKind::Closure(closure) = expr.kind {
-                        closures.insert(closure.def_id);
-                    }
-                    ControlFlow::<()>::Continue(())
-                });
-                check_closures(&mut ctx, cx, &infcx, &mut checked_closures, closures);
 
+            let mut checked_closures = FxHashSet::default();
+
+            // We retrieve all the closures declared in the function because they will not be found
+            // by `euv::Delegate`.
+            let mut closures: FxHashSet<LocalDefId> = FxHashSet::default();
+            for_each_expr_with_closures(cx, body, |expr| {
+                if let ExprKind::Closure(closure) = expr.kind {
+                    closures.insert(closure.def_id);
+                }
+                ControlFlow::<()>::Continue(())
+            });
+            check_closures(&mut ctx, cx, &infcx, &mut checked_closures, closures);
+
+            if is_async {
                 while !ctx.async_closures.is_empty() {
                     let async_closures = ctx.async_closures.clone();
                     ctx.async_closures.clear();
@@ -304,10 +316,27 @@ impl<'tcx> MutablyUsedVariablesCtxt<'tcx> {
         }
         self.aliases.insert(alias, target);
     }
+
+    // The goal here is to find if the current scope is unsafe or not. It stops when it finds
+    // a function or an unsafe block.
+    fn is_in_unsafe_block(&self, item: HirId) -> bool {
+        let hir = self.tcx.hir();
+        for (parent, node) in hir.parent_iter(item) {
+            if let Some(fn_sig) = hir.fn_sig_by_hir_id(parent) {
+                return fn_sig.header.is_unsafe();
+            } else if let Node::Block(block) = node {
+                if matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) {
+                    return true;
+                }
+            }
+        }
+        false
+    }
 }
 
 impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
-    fn consume(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId) {
+    #[allow(clippy::if_same_then_else)]
+    fn consume(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId) {
         if let euv::Place {
             base:
                 euv::PlaceBase::Local(vid)
@@ -327,13 +356,18 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
                 && matches!(base_ty.ref_mutability(), Some(Mutability::Mut))
             {
                 self.add_mutably_used_var(*vid);
+            } else if self.is_in_unsafe_block(id) {
+                // If we are in an unsafe block, any operation on this variable must not be warned
+                // upon!
+                self.add_mutably_used_var(*vid);
             }
             self.prev_bind = None;
             self.prev_move_to_closure.remove(vid);
         }
     }
 
-    fn borrow(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId, borrow: ty::BorrowKind) {
+    #[allow(clippy::if_same_then_else)]
+    fn borrow(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId, borrow: ty::BorrowKind) {
         self.prev_bind = None;
         if let euv::Place {
             base:
@@ -355,6 +389,10 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
                 || (borrow == ty::BorrowKind::UniqueImmBorrow && base_ty.ref_mutability() == Some(Mutability::Mut))
             {
                 self.add_mutably_used_var(*vid);
+            } else if self.is_in_unsafe_block(id) {
+                // If we are in an unsafe block, any operation on this variable must not be warned
+                // upon!
+                self.add_mutably_used_var(*vid);
             }
         } else if borrow == ty::ImmBorrow {
             // If there is an `async block`, it'll contain a call to a closure which we need to
@@ -397,7 +435,21 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
         }
     }
 
-    fn copy(&mut self, _cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId) {
+    fn copy(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId) {
+        if let euv::Place {
+            base:
+                euv::PlaceBase::Local(vid)
+                | euv::PlaceBase::Upvar(UpvarId {
+                    var_path: UpvarPath { hir_id: vid },
+                    ..
+                }),
+            ..
+        } = &cmt.place
+        {
+            if self.is_in_unsafe_block(id) {
+                self.add_mutably_used_var(*vid);
+            }
+        }
         self.prev_bind = None;
     }
 
@@ -427,8 +479,22 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
         }
     }
 
-    fn bind(&mut self, _cmt: &euv::PlaceWithHirId<'tcx>, id: HirId) {
+    fn bind(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId) {
         self.prev_bind = Some(id);
+        if let euv::Place {
+            base:
+                euv::PlaceBase::Local(vid)
+                | euv::PlaceBase::Upvar(UpvarId {
+                    var_path: UpvarPath { hir_id: vid },
+                    ..
+                }),
+            ..
+        } = &cmt.place
+        {
+            if self.is_in_unsafe_block(id) {
+                self.add_mutably_used_var(*vid);
+            }
+        }
     }
 }
 
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 6d7df2eac62..f3c0d616473 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
@@ -1,10 +1,10 @@
 use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
+use clippy_utils::is_self;
 use clippy_utils::ptr::get_spans;
 use clippy_utils::source::{snippet, snippet_opt};
 use clippy_utils::ty::{
     implements_trait, implements_trait_with_env_from_iter, is_copy, is_type_diagnostic_item, is_type_lang_item,
 };
-use clippy_utils::is_self;
 use if_chain::if_chain;
 use rustc_ast::ast::Attribute;
 use rustc_errors::{Applicability, Diagnostic};
diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
index d267b3de7f2..ed279a3813d 100644
--- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
@@ -4,7 +4,7 @@ use clippy_utils::source::snippet;
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{AsyncCoroutineKind, Block, Body, Expr, ExprKind, CoroutineKind, LangItem, MatchSource, QPath};
+use rustc_hir::{AsyncCoroutineKind, Block, Body, CoroutineKind, Expr, ExprKind, LangItem, MatchSource, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
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 2b4e3260c56..613afa46a91 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -5,9 +5,10 @@
 use std::ptr;
 
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::in_constant;
 use clippy_utils::macros::macro_backtrace;
+use clippy_utils::{def_path_def_ids, in_constant};
 use if_chain::if_chain;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{
@@ -15,9 +16,10 @@ use rustc_hir::{
 };
 use rustc_lint::{LateContext, LateLintPass, Lint};
 use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId};
+use rustc_middle::query::Key;
 use rustc_middle::ty::adjustment::Adjust;
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{sym, InnerSpan, Span};
 use rustc_target::abi::VariantIdx;
 
@@ -126,128 +128,6 @@ declare_clippy_lint! {
     "referencing `const` with interior mutability"
 }
 
-fn is_unfrozen<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
-    // Ignore types whose layout is unknown since `is_freeze` reports every generic types as `!Freeze`,
-    // making it indistinguishable from `UnsafeCell`. i.e. it isn't a tool to prove a type is
-    // 'unfrozen'. However, this code causes a false negative in which
-    // a type contains a layout-unknown type, but also an unsafe cell like `const CELL: Cell<T>`.
-    // Yet, it's better than `ty.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_PROJECTION)`
-    // since it works when a pointer indirection involves (`Cell<*const T>`).
-    // Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option;
-    // but I'm not sure whether it's a decent way, if possible.
-    cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx, cx.param_env)
-}
-
-fn is_value_unfrozen_raw<'tcx>(
-    cx: &LateContext<'tcx>,
-    result: Result<Option<ty::ValTree<'tcx>>, ErrorHandled>,
-    ty: Ty<'tcx>,
-) -> bool {
-    fn inner<'tcx>(cx: &LateContext<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> bool {
-        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, _) => val.unwrap_branch().iter().any(|field| inner(cx, *field, ty)),
-            ty::Adt(def, _) if def.is_union() => false,
-            ty::Adt(def, args) if def.is_enum() => {
-                let (&variant_index, fields) = val.unwrap_branch().split_first().unwrap();
-                let variant_index = VariantIdx::from_u32(variant_index.unwrap_leaf().try_to_u32().ok().unwrap());
-                fields
-                    .iter()
-                    .copied()
-                    .zip(
-                        def.variants()[variant_index]
-                            .fields
-                            .iter()
-                            .map(|field| field.ty(cx.tcx, args)),
-                    )
-                    .any(|(field, ty)| inner(cx, field, ty))
-            },
-            ty::Adt(def, args) => val
-                .unwrap_branch()
-                .iter()
-                .zip(def.non_enum_variant().fields.iter().map(|field| field.ty(cx.tcx, args)))
-                .any(|(field, ty)| inner(cx, *field, ty)),
-            ty::Tuple(tys) => val
-                .unwrap_branch()
-                .iter()
-                .zip(tys)
-                .any(|(field, ty)| inner(cx, *field, ty)),
-            _ => false,
-        }
-    }
-    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 the 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| val.map_or(true, |val| inner(cx, val, ty)),
-    )
-}
-
-fn is_value_unfrozen_poly<'tcx>(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(def_id, args);
-    let cid = rustc_middle::mir::interpret::GlobalId {
-        instance,
-        promoted: None,
-    };
-    let param_env = cx.tcx.param_env(def_id).with_reveal_all_normalized(cx.tcx);
-    let result = cx.tcx.const_eval_global_id_for_typeck(param_env, cid, None);
-    is_value_unfrozen_raw(cx, result, ty)
-}
-
-fn is_value_unfrozen_expr<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool {
-    let args = cx.typeck_results().node_args(hir_id);
-
-    let result = const_eval_resolve(cx.tcx, cx.param_env, ty::UnevaluatedConst::new(def_id, args), None);
-    is_value_unfrozen_raw(cx, result, ty)
-}
-
-pub fn const_eval_resolve<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    ct: ty::UnevaluatedConst<'tcx>,
-    span: Option<Span>,
-) -> EvalToValTreeResult<'tcx> {
-    match ty::Instance::resolve(tcx, param_env, ct.def, ct.args) {
-        Ok(Some(instance)) => {
-            let cid = GlobalId {
-                instance,
-                promoted: None,
-            };
-            tcx.const_eval_global_id_for_typeck(param_env, cid, span)
-        },
-        Ok(None) => Err(ErrorHandled::TooGeneric(span.unwrap_or(rustc_span::DUMMY_SP))),
-        Err(err) => Err(ErrorHandled::Reported(err.into(), span.unwrap_or(rustc_span::DUMMY_SP))),
-    }
-}
-
 #[derive(Copy, Clone)]
 enum Source {
     Item { item: Span },
@@ -292,13 +172,178 @@ fn lint(cx: &LateContext<'_>, source: Source) {
     });
 }
 
-declare_lint_pass!(NonCopyConst => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST]);
+#[derive(Clone)]
+pub struct NonCopyConst {
+    ignore_interior_mutability: Vec<String>,
+    ignore_mut_def_ids: FxHashSet<DefId>,
+}
+
+impl_lint_pass!(NonCopyConst => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST]);
+
+impl NonCopyConst {
+    pub fn new(ignore_interior_mutability: Vec<String>) -> Self {
+        Self {
+            ignore_interior_mutability,
+            ignore_mut_def_ids: FxHashSet::default(),
+        }
+    }
+
+    fn is_ty_ignored(&self, ty: Ty<'_>) -> bool {
+        matches!(ty.ty_adt_id(), Some(adt_id) if self.ignore_mut_def_ids.contains(&adt_id))
+    }
+
+    fn is_unfrozen<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+        // Ignore types whose layout is unknown since `is_freeze` reports every generic types as `!Freeze`,
+        // making it indistinguishable from `UnsafeCell`. i.e. it isn't a tool to prove a type is
+        // 'unfrozen'. However, this code causes a false negative in which
+        // a type contains a layout-unknown type, but also an unsafe cell like `const CELL: Cell<T>`.
+        // Yet, it's better than `ty.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_PROJECTION)`
+        // since it works when a pointer indirection involves (`Cell<*const T>`).
+        // Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option;
+        // but I'm not sure whether it's a decent way, if possible.
+        cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx, cx.param_env)
+    }
+
+    fn is_value_unfrozen_raw_inner<'tcx>(&self, cx: &LateContext<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> bool {
+        if self.is_ty_ignored(ty) {
+            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, _) => val
+                .unwrap_branch()
+                .iter()
+                .any(|field| self.is_value_unfrozen_raw_inner(cx, *field, ty)),
+            ty::Adt(def, _) if def.is_union() => false,
+            ty::Adt(def, args) if def.is_enum() => {
+                let (&variant_index, fields) = val.unwrap_branch().split_first().unwrap();
+                let variant_index = VariantIdx::from_u32(variant_index.unwrap_leaf().try_to_u32().ok().unwrap());
+                fields
+                    .iter()
+                    .copied()
+                    .zip(
+                        def.variants()[variant_index]
+                            .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) => val
+                .unwrap_branch()
+                .iter()
+                .zip(def.non_enum_variant().fields.iter().map(|field| field.ty(cx.tcx, args)))
+                .any(|(field, ty)| self.is_value_unfrozen_raw_inner(cx, *field, ty)),
+            ty::Tuple(tys) => val
+                .unwrap_branch()
+                .iter()
+                .zip(tys)
+                .any(|(field, ty)| self.is_value_unfrozen_raw_inner(cx, *field, ty)),
+            _ => false,
+        }
+    }
+
+    fn is_value_unfrozen_raw<'tcx>(
+        &self,
+        cx: &LateContext<'tcx>,
+        result: Result<Option<ty::ValTree<'tcx>>, ErrorHandled>,
+        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 the 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| val.map_or(true, |val| self.is_value_unfrozen_raw_inner(cx, val, ty)),
+        )
+    }
+
+    fn is_value_unfrozen_poly<'tcx>(&self, 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(def_id, args);
+        let cid = rustc_middle::mir::interpret::GlobalId {
+            instance,
+            promoted: None,
+        };
+        let param_env = cx.tcx.param_env(def_id).with_reveal_all_normalized(cx.tcx);
+        let result = cx.tcx.const_eval_global_id_for_typeck(param_env, cid, None);
+        self.is_value_unfrozen_raw(cx, result, ty)
+    }
+
+    fn is_value_unfrozen_expr<'tcx>(&self, 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.param_env, ty::UnevaluatedConst::new(def_id, args), None);
+        self.is_value_unfrozen_raw(cx, result, ty)
+    }
+
+    pub fn const_eval_resolve<'tcx>(
+        tcx: TyCtxt<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        ct: ty::UnevaluatedConst<'tcx>,
+        span: Option<Span>,
+    ) -> EvalToValTreeResult<'tcx> {
+        match ty::Instance::resolve(tcx, param_env, ct.def, ct.args) {
+            Ok(Some(instance)) => {
+                let cid = GlobalId {
+                    instance,
+                    promoted: None,
+                };
+                tcx.const_eval_global_id_for_typeck(param_env, cid, span)
+            },
+            Ok(None) => Err(ErrorHandled::TooGeneric(span.unwrap_or(rustc_span::DUMMY_SP))),
+            Err(err) => Err(ErrorHandled::Reported(err.into(), span.unwrap_or(rustc_span::DUMMY_SP))),
+        }
+    }
+}
 
 impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
+    fn check_crate(&mut self, cx: &LateContext<'tcx>) {
+        self.ignore_mut_def_ids.clear();
+        let mut path = Vec::new();
+        for ty in &self.ignore_interior_mutability {
+            path.extend(ty.split("::"));
+            for id in def_path_def_ids(cx, &path[..]) {
+                self.ignore_mut_def_ids.insert(id);
+            }
+            path.clear();
+        }
+    }
+
     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) && is_unfrozen(cx, ty) && is_value_unfrozen_poly(cx, body_id, ty) {
+            if !ignored_macro(cx, it)
+                && !self.is_ty_ignored(ty)
+                && Self::is_unfrozen(cx, ty)
+                && self.is_value_unfrozen_poly(cx, body_id, ty)
+            {
                 lint(cx, Source::Item { item: it.span });
             }
         }
@@ -311,7 +356,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
             // Normalize assoc types because ones originated from generic params
             // bounded other traits could have their bound.
             let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
-            if is_unfrozen(cx, normalized)
+            if !self.is_ty_ignored(ty) && Self::is_unfrozen(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,
@@ -324,7 +369,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
                 // 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.map_or(true, |body_id| is_value_unfrozen_poly(cx, body_id, normalized))
+                && body_id_opt.map_or(true, |body_id| self.is_value_unfrozen_poly(cx, body_id, normalized))
             {
                 lint(cx, Source::Assoc { item: trait_item.span });
             }
@@ -367,8 +412,8 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
                             // 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.param_env, ty);
-                        if is_unfrozen(cx, normalized);
-                        if is_value_unfrozen_poly(cx, *body_id, normalized);
+                        if !self.is_ty_ignored(ty) && Self::is_unfrozen(cx, normalized);
+                        if self.is_value_unfrozen_poly(cx, *body_id, normalized);
                         then {
                             lint(
                                cx,
@@ -384,7 +429,10 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
                     // Normalize assoc types originated from generic params.
                     let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
 
-                    if is_unfrozen(cx, ty) && is_value_unfrozen_poly(cx, *body_id, normalized) {
+                    if !self.is_ty_ignored(ty)
+                        && Self::is_unfrozen(cx, ty)
+                        && self.is_value_unfrozen_poly(cx, *body_id, normalized)
+                    {
                         lint(cx, Source::Assoc { item: impl_item.span });
                     }
                 },
@@ -478,7 +526,10 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
                 cx.typeck_results().expr_ty(dereferenced_expr)
             };
 
-            if is_unfrozen(cx, ty) && is_value_unfrozen_expr(cx, expr.hir_id, item_def_id, ty) {
+            if !self.is_ty_ignored(ty)
+                && Self::is_unfrozen(cx, ty)
+                && self.is_value_unfrozen_expr(cx, expr.hir_id, item_def_id, ty)
+            {
                 lint(cx, Source::Expr { expr: expr.span });
             }
         }
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 d388dfc08f3..62ef48c8a90 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
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_lint_allowed;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::{implements_trait, is_copy};
-use clippy_utils::is_lint_allowed;
 use rustc_ast::ImplPolarity;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{FieldDef, Item, ItemKind, Node};
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 3dc652f9dc0..f0f8d510c7e 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
@@ -134,6 +134,7 @@ impl Usage {
 /// The parameters being checked by the lint, indexed by both the parameter's `HirId` and the
 /// `DefId` of the function paired with the parameter's index.
 #[derive(Default)]
+#[allow(clippy::struct_field_names)]
 struct Params {
     params: Vec<Param>,
     by_id: HirIdMap<usize>,
diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
index 136642d69dc..ea8ed28ba62 100644
--- a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::path_def_id;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::{implements_trait, is_copy};
-use clippy_utils::path_def_id;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
 use rustc_lint::LateContext;
diff --git a/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs b/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs
index 1a127c2bcf6..bd0ca66b761 100644
--- a/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs
+++ b/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs
@@ -1,8 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher::VecArgs;
+use clippy_utils::last_path_segment;
 use clippy_utils::macros::root_macro_call_first_node;
 use clippy_utils::source::{indent_of, snippet};
-use clippy_utils::last_path_segment;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, QPath, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
diff --git a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
index b8f787e1f1f..2e895d5f236 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
@@ -5,7 +5,7 @@ use clippy_utils::peel_blocks;
 use clippy_utils::source::{snippet, walk_span_to_context};
 use clippy_utils::visitors::for_each_expr;
 use rustc_errors::Applicability;
-use rustc_hir::{AsyncCoroutineKind, Closure, Expr, ExprKind, CoroutineKind, MatchSource};
+use rustc_hir::{AsyncCoroutineKind, Closure, CoroutineKind, Expr, ExprKind, MatchSource};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::UpvarCapture;
diff --git a/src/tools/clippy/clippy_lints/src/redundant_locals.rs b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
index 197742b5dd4..a1a0e8f3520 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_locals.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
@@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantLocals {
             if let Res::Local(binding_id) = cx.qpath_res(&qpath, expr.hir_id);
             if let Node::Pat(binding_pat) = cx.tcx.hir().get(binding_id);
             // the previous binding has the same mutability
-            if find_binding(binding_pat, ident).unwrap().1 == mutability;
+            if find_binding(binding_pat, ident).is_some_and(|bind| bind.1 == mutability);
             // the local does not change the effect of assignments to the binding. see #11290
             if !affects_assignments(cx, mutability, binding_id, local.hir_id);
             // the local does not affect the code's drop behavior
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 9db18c2976c..2278e41be37 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -335,7 +335,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VectorInitializationVisitor<'a, 'tcx> {
 
     fn visit_block(&mut self, block: &'tcx Block<'_>) {
         if self.initialization_found {
-            if let Some(s) = block.stmts.get(0) {
+            if let Some(s) = block.stmts.first() {
                 self.visit_stmt(s);
             }
 
diff --git a/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs b/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs
index 3685432a253..4bfbe3bf37e 100644
--- a/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::source::snippet_with_context;
 use clippy_utils::path_def_id;
+use clippy_utils::source::snippet_with_context;
 use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index 71a4b3fba1b..788678a63b7 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -578,7 +578,7 @@ impl Types {
     }
 }
 
-#[allow(clippy::struct_excessive_bools)]
+#[allow(clippy::struct_excessive_bools, clippy::struct_field_names)]
 #[derive(Clone, Copy, Default)]
 struct CheckTyContext {
     is_in_trait_impl: bool,
diff --git a/src/tools/clippy/clippy_lints/src/uninit_vec.rs b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
index 6756df8e716..72569e10f05 100644
--- a/src/tools/clippy/clippy_lints/src/uninit_vec.rs
+++ b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
@@ -201,7 +201,7 @@ fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Opt
     let expr = peel_hir_expr_while(expr, |e| {
         if let ExprKind::Block(block, _) = e.kind {
             // Extract the first statement/expression
-            match (block.stmts.get(0).map(|stmt| &stmt.kind), block.expr) {
+            match (block.stmts.first().map(|stmt| &stmt.kind), block.expr) {
                 (None, Some(expr)) => Some(expr),
                 (Some(StmtKind::Expr(expr) | StmtKind::Semi(expr)), _) => Some(expr),
                 _ => None,
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs b/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs
index 5aa057580e9..894de0d85c1 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs
@@ -40,7 +40,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor {
             let (constructor_path, constructor_item) =
                 if let hir::ExprKind::Call(constructor, constructor_args) = recv.kind
                     && let hir::ExprKind::Path(constructor_path) = constructor.kind
-                    && let Some(arg) = constructor_args.get(0)
+                    && let Some(arg) = constructor_args.first()
                 {
                     if constructor.span.from_expansion() || arg.span.from_expansion() {
                         return;
@@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor {
                 _ => return,
             }
 
-            if let Some(map_arg) = args.get(0)
+            if let Some(map_arg) = args.first()
                 && let hir::ExprKind::Path(fun) = map_arg.kind
             {
                 if map_arg.span.from_expansion() {
diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs
index 50231d930d0..f10ed4b3d41 100644
--- a/src/tools/clippy/clippy_lints/src/use_self.rs
+++ b/src/tools/clippy/clippy_lints/src/use_self.rs
@@ -54,7 +54,6 @@ declare_clippy_lint! {
     "unnecessary structure name repetition whereas `Self` is applicable"
 }
 
-#[derive(Default)]
 pub struct UseSelf {
     msrv: Msrv,
     stack: Vec<StackItem>,
@@ -65,7 +64,7 @@ impl UseSelf {
     pub fn new(msrv: Msrv) -> Self {
         Self {
             msrv,
-            ..Self::default()
+            stack: Vec::new(),
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index f02c33cc674..aecb0c6dbfa 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -268,8 +268,8 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
     fn qpath(&self, qpath: &Binding<&QPath<'_>>) {
         if let QPath::LangItem(lang_item, ..) = *qpath.value {
             chain!(self, "matches!({qpath}, QPath::LangItem(LangItem::{lang_item:?}, _))");
-        } else {
-            chain!(self, "match_qpath({qpath}, &[{}])", path_to_string(qpath.value));
+        } else if let Ok(path) = path_to_string(qpath.value) {
+            chain!(self, "match_qpath({qpath}, &[{}])", path);
         }
     }
 
@@ -738,8 +738,8 @@ fn has_attr(cx: &LateContext<'_>, hir_id: hir::HirId) -> bool {
     get_attr(cx.sess(), attrs, "author").count() > 0
 }
 
-fn path_to_string(path: &QPath<'_>) -> String {
-    fn inner(s: &mut String, path: &QPath<'_>) {
+fn path_to_string(path: &QPath<'_>) -> Result<String, ()> {
+    fn inner(s: &mut String, path: &QPath<'_>) -> Result<(), ()> {
         match *path {
             QPath::Resolved(_, path) => {
                 for (i, segment) in path.segments.iter().enumerate() {
@@ -751,16 +751,18 @@ fn path_to_string(path: &QPath<'_>) -> String {
             },
             QPath::TypeRelative(ty, segment) => match &ty.kind {
                 hir::TyKind::Path(inner_path) => {
-                    inner(s, inner_path);
+                    inner(s, inner_path)?;
                     *s += ", ";
                     write!(s, "{:?}", segment.ident.as_str()).unwrap();
                 },
                 other => write!(s, "/* unimplemented: {other:?}*/").unwrap(),
             },
-            QPath::LangItem(..) => panic!("path_to_string: called for lang item qpath"),
+            QPath::LangItem(..) => return Err(()),
         }
+
+        Ok(())
     }
     let mut s = String::new();
-    inner(&mut s, path);
-    s
+    inner(&mut s, path)?;
+    Ok(s)
 }
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index 23da1de7730..8829f188fe7 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -8,8 +8,9 @@ use serde::de::{Deserializer, IgnoredAny, IntoDeserializer, MapAccess, Visitor};
 use serde::Deserialize;
 use std::fmt::{Debug, Display, Formatter};
 use std::ops::Range;
-use std::path::{Path, PathBuf};
+use std::path::PathBuf;
 use std::str::FromStr;
+use std::sync::OnceLock;
 use std::{cmp, env, fmt, fs, io};
 
 #[rustfmt::skip]
@@ -78,62 +79,35 @@ pub struct TryConf {
 
 impl TryConf {
     fn from_toml_error(file: &SourceFile, error: &toml::de::Error) -> Self {
-        ConfError::from_toml(file, error).into()
-    }
-}
-
-impl From<ConfError> for TryConf {
-    fn from(value: ConfError) -> Self {
         Self {
             conf: Conf::default(),
-            errors: vec![value],
+            errors: vec![ConfError::from_toml(file, error)],
             warnings: vec![],
         }
     }
 }
 
-impl From<io::Error> for TryConf {
-    fn from(value: io::Error) -> Self {
-        ConfError::from(value).into()
-    }
-}
-
 #[derive(Debug)]
 pub struct ConfError {
     pub message: String,
-    pub span: Option<Span>,
+    pub span: Span,
 }
 
 impl ConfError {
     fn from_toml(file: &SourceFile, error: &toml::de::Error) -> Self {
-        if let Some(span) = error.span() {
-            Self::spanned(file, error.message(), span)
-        } else {
-            Self {
-                message: error.message().to_string(),
-                span: None,
-            }
-        }
+        let span = error.span().unwrap_or(0..file.source_len.0 as usize);
+        Self::spanned(file, error.message(), span)
     }
 
     fn spanned(file: &SourceFile, message: impl Into<String>, span: Range<usize>) -> Self {
         Self {
             message: message.into(),
-            span: Some(Span::new(
+            span: Span::new(
                 file.start_pos + BytePos::from_usize(span.start),
                 file.start_pos + BytePos::from_usize(span.end),
                 SyntaxContext::root(),
                 None,
-            )),
-        }
-    }
-}
-
-impl From<io::Error> for ConfError {
-    fn from(value: io::Error) -> Self {
-        Self {
-            message: value.to_string(),
-            span: None,
+            ),
         }
     }
 }
@@ -297,7 +271,7 @@ define_Conf! {
     /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE.
     ///
     /// The minimum rust version that the project supports
-    (msrv: Option<String> = None),
+    (msrv: crate::Msrv = crate::Msrv::empty()),
     /// DEPRECATED LINT: BLACKLISTED_NAME.
     ///
     /// Use the Disallowed Names lint instead
@@ -360,6 +334,10 @@ define_Conf! {
     ///
     /// The minimum number of enum variants for the lints about variant names to trigger
     (enum_variant_name_threshold: u64 = 3),
+    /// Lint: STRUCT_VARIANT_NAMES.
+    ///
+    /// The minimum number of struct fields for the lints about field names to trigger
+    (struct_field_name_threshold: u64 = 3),
     /// Lint: LARGE_ENUM_VARIANT.
     ///
     /// The maximum size of an enum's variant to avoid box suggestion
@@ -641,15 +619,8 @@ pub fn lookup_conf_file() -> io::Result<(Option<PathBuf>, Vec<String>)> {
     }
 }
 
-/// Read the `toml` configuration file.
-///
-/// In case of error, the function tries to continue as much as possible.
-pub fn read(sess: &Session, path: &Path) -> TryConf {
-    let file = match sess.source_map().load_file(path) {
-        Err(e) => return e.into(),
-        Ok(file) => file,
-    };
-    match toml::de::Deserializer::new(file.src.as_ref().unwrap()).deserialize_map(ConfVisitor(&file)) {
+fn deserialize(file: &SourceFile) -> TryConf {
+    match toml::de::Deserializer::new(file.src.as_ref().unwrap()).deserialize_map(ConfVisitor(file)) {
         Ok(mut conf) => {
             extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS);
             extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES);
@@ -662,7 +633,7 @@ pub fn read(sess: &Session, path: &Path) -> TryConf {
 
             conf
         },
-        Err(e) => TryConf::from_toml_error(&file, &e),
+        Err(e) => TryConf::from_toml_error(file, &e),
     }
 }
 
@@ -672,6 +643,60 @@ fn extend_vec_if_indicator_present(vec: &mut Vec<String>, default: &[&str]) {
     }
 }
 
+impl Conf {
+    pub fn read(sess: &Session, path: &io::Result<(Option<PathBuf>, Vec<String>)>) -> &'static Conf {
+        static CONF: OnceLock<Conf> = OnceLock::new();
+        CONF.get_or_init(|| Conf::read_inner(sess, path))
+    }
+
+    fn read_inner(sess: &Session, path: &io::Result<(Option<PathBuf>, Vec<String>)>) -> Conf {
+        match path {
+            Ok((_, warnings)) => {
+                for warning in warnings {
+                    sess.warn(warning.clone());
+                }
+            },
+            Err(error) => {
+                sess.err(format!("error finding Clippy's configuration file: {error}"));
+            },
+        }
+
+        let TryConf {
+            mut conf,
+            errors,
+            warnings,
+        } = match path {
+            Ok((Some(path), _)) => match sess.source_map().load_file(path) {
+                Ok(file) => deserialize(&file),
+                Err(error) => {
+                    sess.err(format!("failed to read `{}`: {error}", path.display()));
+                    TryConf::default()
+                },
+            },
+            _ => TryConf::default(),
+        };
+
+        conf.msrv.read_cargo(sess);
+
+        // all conf errors are non-fatal, we just use the default conf in case of error
+        for error in errors {
+            sess.span_err(
+                error.span,
+                format!("error reading Clippy's configuration file: {}", error.message),
+            );
+        }
+
+        for warning in warnings {
+            sess.span_warn(
+                warning.span,
+                format!("error reading Clippy's configuration file: {}", warning.message),
+            );
+        }
+
+        conf
+    }
+}
+
 const SEPARATOR_WIDTH: usize = 4;
 
 #[derive(Debug)]
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs
index fe2f12fe833..8cdd5ea8903 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs
@@ -30,7 +30,7 @@ impl<'tcx> LateLintPass<'tcx> for IfChainStyle {
                 if_chain_local_span(cx, local, if_chain_span),
                 "`let` expression should be above the `if_chain!`",
             );
-        } else if local.span.ctxt() == block.span.ctxt() && is_if_chain_then(after, block.expr, if_chain_span) {
+        } else if local.span.eq_ctxt(block.span) && is_if_chain_then(after, block.expr, if_chain_span) {
             span_lint(
                 cx,
                 IF_CHAIN_STYLE,
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
index 82f9d4e41e8..fc9afe5ca8b 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
@@ -13,6 +13,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir::ConstValue;
 use rustc_middle::ty;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::sym;
 use rustc_span::symbol::Symbol;
 
 use std::borrow::Cow;
@@ -160,12 +161,8 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
 
 impl InterningDefinedSymbol {
     fn symbol_str_expr<'tcx>(&self, expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> Option<SymbolStrExpr<'tcx>> {
-        static IDENT_STR_PATHS: &[&[&str]] = &[&paths::IDENT_AS_STR, &paths::TO_STRING_METHOD];
-        static SYMBOL_STR_PATHS: &[&[&str]] = &[
-            &paths::SYMBOL_AS_STR,
-            &paths::SYMBOL_TO_IDENT_STRING,
-            &paths::TO_STRING_METHOD,
-        ];
+        static IDENT_STR_PATHS: &[&[&str]] = &[&paths::IDENT_AS_STR];
+        static SYMBOL_STR_PATHS: &[&[&str]] = &[&paths::SYMBOL_AS_STR, &paths::SYMBOL_TO_IDENT_STRING];
         let call = if_chain! {
             if let ExprKind::AddrOf(_, _, e) = expr.kind;
             if let ExprKind::Unary(UnOp::Deref, e) = e.kind;
@@ -186,9 +183,19 @@ impl InterningDefinedSymbol {
             };
             // ...which converts it to a string
             let paths = if is_ident { IDENT_STR_PATHS } else { SYMBOL_STR_PATHS };
-            if let Some(path) = paths.iter().find(|path| match_def_path(cx, did, path));
+            if let Some(is_to_owned) = paths
+                .iter()
+                .find_map(|path| if match_def_path(cx, did, path) {
+                    Some(path == &paths::SYMBOL_TO_IDENT_STRING)
+                } else {
+                    None
+                })
+                .or_else(|| if cx.tcx.is_diagnostic_item(sym::to_string_method, did) {
+                    Some(true)
+                } else {
+                    None
+                });
             then {
-                let is_to_owned = path.last().unwrap().ends_with("string");
                 return Some(SymbolStrExpr::Expr {
                     item,
                     is_ident,
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index 8522493f67b..90091ca927a 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -9,6 +9,7 @@ arrayvec = { version = "0.7", default-features = false }
 if_chain = "1.0"
 itertools = "0.10.1"
 rustc-semver = "1.1"
+serde = { version = "1.0" }
 
 [features]
 deny-warnings = []
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index 0bae7056c4f..79c04c7c7f4 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -504,7 +504,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
             },
             (Some(Constant::Vec(vec)), _) => {
                 if !vec.is_empty() && vec.iter().all(|x| *x == vec[0]) {
-                    match vec.get(0) {
+                    match vec.first() {
                         Some(Constant::F32(x)) => Some(Constant::F32(*x)),
                         Some(Constant::F64(x)) => Some(Constant::F64(*x)),
                         _ => None,
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index 741f9f54883..edea4b3667f 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -449,7 +449,7 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -
                 } else if name.ident.name == symbol::kw::Default {
                     return Some(VecInitKind::Default);
                 } else if name.ident.name.as_str() == "with_capacity" {
-                    let arg = args.get(0)?;
+                    let arg = args.first()?;
                     return match constant_simple(cx, cx.typeck_results(), arg) {
                         Some(Constant::Int(num)) => Some(VecInitKind::WithConstCapacity(num)),
                         _ => Some(VecInitKind::WithExprCapacity(arg.hir_id)),
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index c2c97259d38..93b37022822 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -2027,48 +2027,88 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     did.map_or(false, |did| cx.tcx.has_attr(did, sym::must_use))
 }
 
-/// Checks if an expression represents the identity function
-/// Only examines closures and `std::convert::identity`
-pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    /// Checks if a function's body represents the identity function. Looks for bodies of the form:
-    /// * `|x| x`
-    /// * `|x| return x`
-    /// * `|x| { return x }`
-    /// * `|x| { return x; }`
-    fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
-        let id = if_chain! {
-            if let [param] = func.params;
-            if let PatKind::Binding(_, id, _, _) = param.pat.kind;
-            then {
-                id
-            } else {
-                return false;
-            }
-        };
+/// Checks if a function's body represents the identity function. Looks for bodies of the form:
+/// * `|x| x`
+/// * `|x| return x`
+/// * `|x| { return x }`
+/// * `|x| { return x; }`
+///
+/// Consider calling [`is_expr_untyped_identity_function`] or [`is_expr_identity_function`] instead.
+fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
+    let id = if_chain! {
+        if let [param] = func.params;
+        if let PatKind::Binding(_, id, _, _) = param.pat.kind;
+        then {
+            id
+        } else {
+            return false;
+        }
+    };
 
-        let mut expr = func.value;
-        loop {
-            match expr.kind {
-                #[rustfmt::skip]
-                ExprKind::Block(&Block { stmts: [], expr: Some(e), .. }, _, )
-                | ExprKind::Ret(Some(e)) => expr = e,
-                #[rustfmt::skip]
-                ExprKind::Block(&Block { stmts: [stmt], expr: None, .. }, _) => {
-                    if_chain! {
-                        if let StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind;
-                        if let ExprKind::Ret(Some(ret_val)) = e.kind;
-                        then {
-                            expr = ret_val;
-                        } else {
-                            return false;
-                        }
-                    }
+    let mut expr = func.value;
+    loop {
+        match expr.kind {
+            ExprKind::Block(
+                &Block {
+                    stmts: [],
+                    expr: Some(e),
+                    ..
                 },
-                _ => return path_to_local_id(expr, id) && cx.typeck_results().expr_adjustments(expr).is_empty(),
-            }
+                _,
+            )
+            | ExprKind::Ret(Some(e)) => expr = e,
+            ExprKind::Block(
+                &Block {
+                    stmts: [stmt],
+                    expr: None,
+                    ..
+                },
+                _,
+            ) => {
+                if_chain! {
+                    if let StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind;
+                    if let ExprKind::Ret(Some(ret_val)) = e.kind;
+                    then {
+                        expr = ret_val;
+                    } else {
+                        return false;
+                    }
+                }
+            },
+            _ => return path_to_local_id(expr, id) && cx.typeck_results().expr_adjustments(expr).is_empty(),
         }
     }
+}
 
+/// This is the same as [`is_expr_identity_function`], but does not consider closures
+/// with type annotations for its bindings (or similar) as identity functions:
+/// * `|x: u8| x`
+/// * `std::convert::identity::<u8>`
+pub fn is_expr_untyped_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    match expr.kind {
+        ExprKind::Closure(&Closure { body, fn_decl, .. })
+            if fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer)) =>
+        {
+            is_body_identity_function(cx, cx.tcx.hir().body(body))
+        },
+        ExprKind::Path(QPath::Resolved(_, path))
+            if path.segments.iter().all(|seg| seg.infer_args)
+                && let Some(did) = path.res.opt_def_id() => {
+            cx.tcx.is_diagnostic_item(sym::convert_identity, did)
+        },
+        _ => false,
+    }
+}
+
+/// Checks if an expression represents the identity function
+/// Only examines closures and `std::convert::identity`
+///
+/// NOTE: If you want to use this function to find out if a closure is unnecessary, you likely want
+/// to call [`is_expr_untyped_identity_function`] instead, which makes sure that the closure doesn't
+/// have type annotations. This is important because removing a closure with bindings can
+/// remove type information that helped type inference before, which can then lead to compile
+/// errors.
+pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     match expr.kind {
         ExprKind::Closure(&Closure { body, .. }) => is_body_identity_function(cx, cx.tcx.hir().body(body)),
         _ => path_def_id(cx, expr).map_or(false, |id| cx.tcx.is_diagnostic_item(sym::convert_identity, id)),
diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs
index df839c2106f..c6a48874e09 100644
--- a/src/tools/clippy/clippy_utils/src/msrvs.rs
+++ b/src/tools/clippy/clippy_utils/src/msrvs.rs
@@ -1,9 +1,7 @@
-use std::sync::OnceLock;
-
 use rustc_ast::Attribute;
 use rustc_semver::RustcVersion;
 use rustc_session::Session;
-use rustc_span::Span;
+use serde::Deserialize;
 
 use crate::attrs::get_unique_attr;
 
@@ -53,65 +51,45 @@ msrv_aliases! {
     1,15,0 { MAYBE_BOUND_IN_WHERE }
 }
 
-fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option<Span>) -> Option<RustcVersion> {
-    if let Ok(version) = RustcVersion::parse(msrv) {
-        return Some(version);
-    } else if let Some(sess) = sess {
-        if let Some(span) = span {
-            sess.span_err(span, format!("`{msrv}` is not a valid Rust version"));
-        }
-    }
-    None
-}
-
 /// Tracks the current MSRV from `clippy.toml`, `Cargo.toml` or set via `#[clippy::msrv]`
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Clone)]
 pub struct Msrv {
     stack: Vec<RustcVersion>,
 }
 
+impl<'de> Deserialize<'de> for Msrv {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: serde::Deserializer<'de>,
+    {
+        let v = String::deserialize(deserializer)?;
+        RustcVersion::parse(&v)
+            .map(|v| Msrv { stack: vec![v] })
+            .map_err(|_| serde::de::Error::custom("not a valid Rust version"))
+    }
+}
+
 impl Msrv {
-    fn new(initial: Option<RustcVersion>) -> Self {
-        Self {
-            stack: Vec::from_iter(initial),
-        }
+    pub fn empty() -> Msrv {
+        Msrv { stack: Vec::new() }
     }
 
-    fn read_inner(conf_msrv: &Option<String>, sess: &Session) -> Self {
+    pub fn read_cargo(&mut self, sess: &Session) {
         let cargo_msrv = std::env::var("CARGO_PKG_RUST_VERSION")
             .ok()
-            .and_then(|v| parse_msrv(&v, None, None));
-        let clippy_msrv = conf_msrv.as_ref().and_then(|s| {
-            parse_msrv(s, None, None).or_else(|| {
-                sess.err(format!(
-                    "error reading Clippy's configuration file. `{s}` is not a valid Rust version"
-                ));
-                None
-            })
-        });
-
-        // if both files have an msrv, let's compare them and emit a warning if they differ
-        if let Some(cargo_msrv) = cargo_msrv
-            && let Some(clippy_msrv) = clippy_msrv
-            && clippy_msrv != cargo_msrv
-        {
-            sess.warn(format!(
-                "the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{clippy_msrv}` from `clippy.toml`"
-            ));
+            .and_then(|v| RustcVersion::parse(&v).ok());
+
+        match (self.current(), cargo_msrv) {
+            (None, Some(cargo_msrv)) => self.stack = vec![cargo_msrv],
+            (Some(clippy_msrv), Some(cargo_msrv)) => {
+                if clippy_msrv != cargo_msrv {
+                    sess.warn(format!(
+                        "the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{clippy_msrv}` from `clippy.toml`"
+                    ));
+                }
+            },
+            _ => {},
         }
-
-        Self::new(clippy_msrv.or(cargo_msrv))
-    }
-
-    /// Set the initial MSRV from the Clippy config file or from Cargo due to the `rust-version`
-    /// field in `Cargo.toml`
-    ///
-    /// Returns a `&'static Msrv` as `Copy` types are more easily passed to the
-    /// `register_{late,early}_pass` callbacks
-    pub fn read(conf_msrv: &Option<String>, sess: &Session) -> &'static Self {
-        static PARSED: OnceLock<Msrv> = OnceLock::new();
-
-        PARSED.get_or_init(|| Self::read_inner(conf_msrv, sess))
     }
 
     pub fn current(&self) -> Option<RustcVersion> {
@@ -125,10 +103,14 @@ impl Msrv {
     fn parse_attr(sess: &Session, attrs: &[Attribute]) -> Option<RustcVersion> {
         if let Some(msrv_attr) = get_unique_attr(sess, attrs, "msrv") {
             if let Some(msrv) = msrv_attr.value_str() {
-                return parse_msrv(&msrv.to_string(), Some(sess), Some(msrv_attr.span));
-            }
+                if let Ok(version) = RustcVersion::parse(msrv.as_str()) {
+                    return Some(version);
+                }
 
-            sess.span_err(msrv_attr.span, "bad clippy attribute");
+                sess.span_err(msrv_attr.span, format!("`{msrv}` is not a valid Rust version"));
+            } else {
+                sess.span_err(msrv_attr.span, "bad clippy attribute");
+            }
         }
 
         None
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index 1f2bb16f459..4a20399e364 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -98,7 +98,6 @@ pub const SYMBOL_TO_IDENT_STRING: [&str; 4] = ["rustc_span", "symbol", "Symbol",
 pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"];
 #[cfg(feature = "internal")]
 pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"];
-pub const TO_STRING_METHOD: [&str; 4] = ["alloc", "string", "ToString", "to_string"];
 #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
 pub const TOKIO_IO_ASYNCREADEXT: [&str; 5] = ["tokio", "io", "util", "async_read_ext", "AsyncReadExt"];
 #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
diff --git a/src/tools/clippy/clippy_utils/src/str_utils.rs b/src/tools/clippy/clippy_utils/src/str_utils.rs
index 03a9d3c25fd..69c25b427e1 100644
--- a/src/tools/clippy/clippy_utils/src/str_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/str_utils.rs
@@ -236,6 +236,59 @@ pub fn count_match_end(str1: &str, str2: &str) -> StrCount {
         })
 }
 
+/// Returns a `snake_case` version of the input
+/// ```
+/// use clippy_utils::str_utils::to_snake_case;
+/// assert_eq!(to_snake_case("AbcDef"), "abc_def");
+/// assert_eq!(to_snake_case("ABCD"), "a_b_c_d");
+/// assert_eq!(to_snake_case("AbcDD"), "abc_d_d");
+/// assert_eq!(to_snake_case("Abc1DD"), "abc1_d_d");
+/// ```
+pub fn to_snake_case(name: &str) -> String {
+    let mut s = String::new();
+    for (i, c) in name.chars().enumerate() {
+        if c.is_uppercase() {
+            // characters without capitalization are considered lowercase
+            if i != 0 {
+                s.push('_');
+            }
+            s.extend(c.to_lowercase());
+        } else {
+            s.push(c);
+        }
+    }
+    s
+}
+/// Returns a `CamelCase` version of the input
+/// ```
+/// use clippy_utils::str_utils::to_camel_case;
+/// assert_eq!(to_camel_case("abc_def"), "AbcDef");
+/// assert_eq!(to_camel_case("a_b_c_d"), "ABCD");
+/// assert_eq!(to_camel_case("abc_d_d"), "AbcDD");
+/// assert_eq!(to_camel_case("abc1_d_d"), "Abc1DD");
+/// ```
+pub fn to_camel_case(item_name: &str) -> String {
+    let mut s = String::new();
+    let mut up = true;
+    for c in item_name.chars() {
+        if c.is_uppercase() {
+            // we only turn snake case text into CamelCase
+            return item_name.to_string();
+        }
+        if c == '_' {
+            up = true;
+            continue;
+        }
+        if up {
+            up = false;
+            s.extend(c.to_uppercase());
+        } else {
+            s.push(c);
+        }
+    }
+    s
+}
+
 #[cfg(test)]
 mod test {
     use super::*;
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index fe2c77ab47f..7c5b5e97a5c 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2023-10-06"
+channel = "nightly-2023-10-21"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index d47767faed9..0e81419f1fa 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -147,9 +147,9 @@ impl rustc_driver::Callbacks for ClippyCallbacks {
                 (previous)(sess, lint_store);
             }
 
-            let conf = clippy_lints::read_conf(sess, &conf_path);
-            clippy_lints::register_plugins(lint_store, sess, &conf);
-            clippy_lints::register_pre_expansion_lints(lint_store, sess, &conf);
+            let conf = clippy_lints::Conf::read(sess, &conf_path);
+            clippy_lints::register_plugins(lint_store, sess, conf);
+            clippy_lints::register_pre_expansion_lints(lint_store, conf);
             clippy_lints::register_renamed(lint_store);
         }));
 
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index f340cf5938a..1494c7d3179 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -105,27 +105,20 @@ static EXTERN_FLAGS: LazyLock<Vec<String>> = LazyLock::new(|| {
 // whether to run internal tests or not
 const RUN_INTERNAL_TESTS: bool = cfg!(feature = "internal");
 
-fn canonicalize(path: impl AsRef<Path>) -> PathBuf {
-    let path = path.as_ref();
-    fs::create_dir_all(path).unwrap();
-    fs::canonicalize(path).unwrap_or_else(|err| panic!("{} cannot be canonicalized: {err}", path.display()))
-}
-
 fn base_config(test_dir: &str) -> (Config, Args) {
     let mut args = Args::test().unwrap();
     args.bless |= var_os("RUSTC_BLESS").is_some_and(|v| v != "0");
 
+    let target_dir = PathBuf::from(var_os("CARGO_TARGET_DIR").unwrap_or_else(|| "target".into()));
     let mut config = Config {
         mode: Mode::Yolo {
             rustfix: ui_test::RustfixMode::Everything,
         },
-        stderr_filters: vec![(Match::PathBackslash, b"/")],
-        stdout_filters: vec![],
         filter_files: env::var("TESTNAME")
             .map(|filters| filters.split(',').map(str::to_string).collect())
             .unwrap_or_default(),
         target: None,
-        out_dir: canonicalize(var_os("CARGO_TARGET_DIR").unwrap_or_else(|| "target".into())).join("ui_test"),
+        out_dir: target_dir.join("ui_test"),
         ..Config::rustc(Path::new("tests").join(test_dir))
     };
     config.with_args(&args, /* bless by default */ false);
@@ -168,19 +161,13 @@ fn run_ui() {
     config
         .program
         .envs
-        .push(("CLIPPY_CONF_DIR".into(), Some(canonicalize("tests").into())));
-
-    let quiet = args.quiet;
+        .push(("CLIPPY_CONF_DIR".into(), Some("tests".into())));
 
     ui_test::run_tests_generic(
         vec![config],
         ui_test::default_file_filter,
         ui_test::default_per_file_config,
-        if quiet {
-            status_emitter::Text::quiet()
-        } else {
-            status_emitter::Text::verbose()
-        },
+        status_emitter::Text::from(args.format),
     )
     .unwrap();
 }
@@ -194,17 +181,12 @@ fn run_internal_tests() {
     if let OutputConflictHandling::Error(err) = &mut config.output_conflict_handling {
         *err = "cargo uitest --features internal -- -- --bless".into();
     }
-    let quiet = args.quiet;
 
     ui_test::run_tests_generic(
         vec![config],
         ui_test::default_file_filter,
         ui_test::default_per_file_config,
-        if quiet {
-            status_emitter::Text::quiet()
-        } else {
-            status_emitter::Text::verbose()
-        },
+        status_emitter::Text::from(args.format),
     )
     .unwrap();
 }
@@ -212,22 +194,9 @@ fn run_internal_tests() {
 fn run_ui_toml() {
     let (mut config, args) = base_config("ui-toml");
 
-    config.stderr_filters = vec![
-        (
-            Match::Exact(
-                canonicalize("tests")
-                    .parent()
-                    .unwrap()
-                    .to_string_lossy()
-                    .as_bytes()
-                    .to_vec(),
-            ),
-            b"$DIR",
-        ),
-        (Match::Exact(b"\\".to_vec()), b"/"),
-    ];
-
-    let quiet = args.quiet;
+    config
+        .stderr_filters
+        .push((Match::from(env::current_dir().unwrap().as_path()), b"$DIR"));
 
     ui_test::run_tests_generic(
         vec![config],
@@ -238,11 +207,7 @@ fn run_ui_toml() {
                 .envs
                 .push(("CLIPPY_CONF_DIR".into(), Some(path.parent().unwrap().into())));
         },
-        if quiet {
-            status_emitter::Text::quiet()
-        } else {
-            status_emitter::Text::verbose()
-        },
+        status_emitter::Text::from(args.format),
     )
     .unwrap();
 }
@@ -270,22 +235,9 @@ fn run_ui_cargo() {
     });
     config.edition = None;
 
-    config.stderr_filters = vec![
-        (
-            Match::Exact(
-                canonicalize("tests")
-                    .parent()
-                    .unwrap()
-                    .to_string_lossy()
-                    .as_bytes()
-                    .to_vec(),
-            ),
-            b"$DIR",
-        ),
-        (Match::Exact(b"\\".to_vec()), b"/"),
-    ];
-
-    let quiet = args.quiet;
+    config
+        .stderr_filters
+        .push((Match::from(env::current_dir().unwrap().as_path()), b"$DIR"));
 
     let ignored_32bit = |path: &Path| {
         // FIXME: for some reason the modules are linted in a different order for this test
@@ -297,20 +249,8 @@ fn run_ui_cargo() {
         |path, config| {
             path.ends_with("Cargo.toml") && ui_test::default_any_file_filter(path, config) && !ignored_32bit(path)
         },
-        |config, path, _file_contents| {
-            config.out_dir = canonicalize(
-                std::env::current_dir()
-                    .unwrap()
-                    .join("target")
-                    .join("ui_test_cargo/")
-                    .join(path.parent().unwrap()),
-            );
-        },
-        if quiet {
-            status_emitter::Text::quiet()
-        } else {
-            status_emitter::Text::verbose()
-        },
+        |_config, _path, _file_contents| {},
+        status_emitter::Text::from(args.format),
     )
     .unwrap();
 }
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs
index 60be2978813..f6abb3cc3d7 100644
--- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs
@@ -12,5 +12,5 @@ fn main() {
     const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
 
     // Don't lint, not a diagnostic or language item
-    const OPS_MOD: [&str; 5] = ["core", "ops"];
+    const OPS_MOD: [&str; 2] = ["core", "ops"];
 }
diff --git a/src/tools/clippy/tests/ui-toml/borrow_interior_mutable_const/clippy.toml b/src/tools/clippy/tests/ui-toml/borrow_interior_mutable_const/clippy.toml
new file mode 100644
index 00000000000..34a1036e891
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/borrow_interior_mutable_const/clippy.toml
@@ -0,0 +1 @@
+ignore-interior-mutability = ["borrow_interior_mutable_const_ignore::Counted"]
\ No newline at end of file
diff --git a/src/tools/clippy/tests/ui-toml/borrow_interior_mutable_const/ignore.rs b/src/tools/clippy/tests/ui-toml/borrow_interior_mutable_const/ignore.rs
new file mode 100644
index 00000000000..79c7cef6ce1
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/borrow_interior_mutable_const/ignore.rs
@@ -0,0 +1,37 @@
+//@compile-flags: --crate-name borrow_interior_mutable_const_ignore
+
+#![warn(clippy::borrow_interior_mutable_const)]
+#![allow(clippy::declare_interior_mutable_const)]
+
+use core::cell::Cell;
+use std::cmp::{Eq, PartialEq};
+use std::collections::{HashMap, HashSet};
+use std::hash::{Hash, Hasher};
+use std::ops::Deref;
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+struct Counted<T> {
+    count: AtomicUsize,
+    val: T,
+}
+
+impl<T> Counted<T> {
+    const fn new(val: T) -> Self {
+        Self {
+            count: AtomicUsize::new(0),
+            val,
+        }
+    }
+}
+
+enum OptionalCell {
+    Unfrozen(Counted<bool>),
+    Frozen,
+}
+
+const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Counted::new(true));
+const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
+
+fn main() {
+    let _ = &UNFROZEN_VARIANT;
+}
diff --git a/src/tools/clippy/tests/ui-toml/declare_interior_mutable_const/clippy.toml b/src/tools/clippy/tests/ui-toml/declare_interior_mutable_const/clippy.toml
new file mode 100644
index 00000000000..71d13212e2a
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/declare_interior_mutable_const/clippy.toml
@@ -0,0 +1 @@
+ignore-interior-mutability = ["declare_interior_mutable_const_ignore::Counted"]
\ No newline at end of file
diff --git a/src/tools/clippy/tests/ui-toml/declare_interior_mutable_const/ignore.rs b/src/tools/clippy/tests/ui-toml/declare_interior_mutable_const/ignore.rs
new file mode 100644
index 00000000000..6385cf4f852
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/declare_interior_mutable_const/ignore.rs
@@ -0,0 +1,46 @@
+//@compile-flags: --crate-name declare_interior_mutable_const_ignore
+
+#![warn(clippy::declare_interior_mutable_const)]
+#![allow(clippy::borrow_interior_mutable_const)]
+
+use core::cell::Cell;
+use std::cmp::{Eq, PartialEq};
+use std::collections::{HashMap, HashSet};
+use std::hash::{Hash, Hasher};
+use std::ops::Deref;
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+struct Counted<T> {
+    count: AtomicUsize,
+    val: T,
+}
+
+impl<T> Counted<T> {
+    const fn new(val: T) -> Self {
+        Self {
+            count: AtomicUsize::new(0),
+            val,
+        }
+    }
+}
+
+enum OptionalCell {
+    Unfrozen(Counted<bool>),
+    Frozen,
+}
+
+const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Counted::new(true));
+const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
+
+const fn unfrozen_variant() -> OptionalCell {
+    OptionalCell::Unfrozen(Counted::new(true))
+}
+
+const fn frozen_variant() -> OptionalCell {
+    OptionalCell::Frozen
+}
+
+const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant();
+const FROZEN_VARIANT_FROM_FN: OptionalCell = frozen_variant();
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/enum_variant_names/enum_variant_names.rs b/src/tools/clippy/tests/ui-toml/enum_variant_names/enum_variant_names.rs
deleted file mode 100644
index 8f4e178ccfe..00000000000
--- a/src/tools/clippy/tests/ui-toml/enum_variant_names/enum_variant_names.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-enum Foo {
-    AFoo,
-    BFoo,
-    CFoo,
-    DFoo,
-}
-enum Foo2 {
-    //~^ ERROR: all variants have the same postfix
-    AFoo,
-    BFoo,
-    CFoo,
-    DFoo,
-    EFoo,
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/enum_variant_names/enum_variant_names.stderr b/src/tools/clippy/tests/ui-toml/enum_variant_names/enum_variant_names.stderr
deleted file mode 100644
index 11039b1db48..00000000000
--- a/src/tools/clippy/tests/ui-toml/enum_variant_names/enum_variant_names.stderr
+++ /dev/null
@@ -1,18 +0,0 @@
-error: all variants have the same postfix: `Foo`
-  --> $DIR/enum_variant_names.rs:7:1
-   |
-LL | / enum Foo2 {
-LL | |
-LL | |     AFoo,
-LL | |     BFoo,
-...  |
-LL | |     EFoo,
-LL | | }
-   | |_^
-   |
-   = help: remove the postfixes and use full paths to the variants instead of glob imports
-   = note: `-D clippy::enum-variant-names` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::enum_variant_names)]`
-
-error: aborting due to previous error
-
diff --git a/src/tools/clippy/tests/ui-toml/impl_trait_in_params/clippy.toml b/src/tools/clippy/tests/ui-toml/impl_trait_in_params/clippy.toml
new file mode 100644
index 00000000000..87e1f235741
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/impl_trait_in_params/clippy.toml
@@ -0,0 +1 @@
+avoid-breaking-exported-api = false
\ No newline at end of file
diff --git a/src/tools/clippy/tests/ui-toml/impl_trait_in_params/impl_trait_in_params.rs b/src/tools/clippy/tests/ui-toml/impl_trait_in_params/impl_trait_in_params.rs
new file mode 100644
index 00000000000..08fc7edf1c8
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/impl_trait_in_params/impl_trait_in_params.rs
@@ -0,0 +1,16 @@
+//! As avoid-breaking-exported-api is `false`, nothing here should lint
+#![warn(clippy::impl_trait_in_params)]
+#![no_main]
+//@no-rustfix
+
+pub trait Trait {}
+
+trait Private {
+    fn t(_: impl Trait);
+    fn tt<T: Trait>(_: T);
+}
+
+pub trait Public {
+    fn t(_: impl Trait); //~ ERROR: `impl Trait` used as a function parameter
+    fn tt<T: Trait>(_: T);
+}
diff --git a/src/tools/clippy/tests/ui-toml/impl_trait_in_params/impl_trait_in_params.stderr b/src/tools/clippy/tests/ui-toml/impl_trait_in_params/impl_trait_in_params.stderr
new file mode 100644
index 00000000000..80c4f5ed4b0
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/impl_trait_in_params/impl_trait_in_params.stderr
@@ -0,0 +1,15 @@
+error: `impl Trait` used as a function parameter
+  --> $DIR/impl_trait_in_params.rs:14:13
+   |
+LL |     fn t(_: impl Trait);
+   |             ^^^^^^^^^^
+   |
+   = note: `-D clippy::impl-trait-in-params` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::impl_trait_in_params)]`
+help: add a type parameter
+   |
+LL |     fn t<{ /* Generic name */ }: Trait>(_: impl Trait);
+   |         +++++++++++++++++++++++++++++++
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs b/src/tools/clippy/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs
index 03fa719975b..85e2fb8c797 100644
--- a/src/tools/clippy/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs
+++ b/src/tools/clippy/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs
@@ -1,4 +1,4 @@
-//@error-in-other-file: `invalid.version` is not a valid Rust version
+//@error-in-other-file: not a valid Rust version
 
 #![allow(clippy::redundant_clone)]
 
diff --git a/src/tools/clippy/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr b/src/tools/clippy/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr
index e9d8fd2e0f5..f127c2408f9 100644
--- a/src/tools/clippy/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr
+++ b/src/tools/clippy/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr
@@ -1,4 +1,8 @@
-error: error reading Clippy's configuration file. `invalid.version` is not a valid Rust version
+error: error reading Clippy's configuration file: not a valid Rust version
+  --> $DIR/$DIR/clippy.toml:1:8
+   |
+LL | msrv = "invalid.version"
+   |        ^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/tools/clippy/tests/ui-toml/enum_variants_threshold0/clippy.toml b/src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold0/clippy.toml
index f85aade6ae8..d41edbaf7fa 100644
--- a/src/tools/clippy/tests/ui-toml/enum_variants_threshold0/clippy.toml
+++ b/src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold0/clippy.toml
@@ -1 +1,2 @@
+struct-field-name-threshold = 0
 enum-variant-name-threshold = 0
diff --git a/src/tools/clippy/tests/ui-toml/enum_variants_threshold0/enum_variants_name_threshold.rs b/src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold0/item_name_repetitions.rs
index 6918d7528c1..b633dcbd19e 100644
--- a/src/tools/clippy/tests/ui-toml/enum_variants_threshold0/enum_variants_name_threshold.rs
+++ b/src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold0/item_name_repetitions.rs
@@ -1,3 +1,5 @@
+struct Data {}
+
 enum Actions {}
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/enum_variant_names/clippy.toml b/src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold5/clippy.toml
index 0ad7a979948..028a6279079 100644
--- a/src/tools/clippy/tests/ui-toml/enum_variant_names/clippy.toml
+++ b/src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold5/clippy.toml
@@ -1 +1,2 @@
 enum-variant-name-threshold = 5
+struct-field-name-threshold = 5
diff --git a/src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.rs b/src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.rs
new file mode 100644
index 00000000000..d437311691d
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.rs
@@ -0,0 +1,32 @@
+#![warn(clippy::struct_field_names)]
+
+struct Data {
+    a_data: u8,
+    b_data: u8,
+    c_data: u8,
+    d_data: u8,
+}
+struct Data2 {
+    //~^ ERROR: all fields have the same postfix
+    a_data: u8,
+    b_data: u8,
+    c_data: u8,
+    d_data: u8,
+    e_data: u8,
+}
+enum Foo {
+    AFoo,
+    BFoo,
+    CFoo,
+    DFoo,
+}
+enum Foo2 {
+    //~^ ERROR: all variants have the same postfix
+    AFoo,
+    BFoo,
+    CFoo,
+    DFoo,
+    EFoo,
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.stderr b/src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.stderr
new file mode 100644
index 00000000000..33802c44bf9
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.stderr
@@ -0,0 +1,34 @@
+error: all fields have the same postfix: `data`
+  --> $DIR/item_name_repetitions.rs:9:1
+   |
+LL | / struct Data2 {
+LL | |
+LL | |     a_data: u8,
+LL | |     b_data: u8,
+...  |
+LL | |     e_data: u8,
+LL | | }
+   | |_^
+   |
+   = help: remove the postfixes
+   = note: `-D clippy::struct-field-names` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::struct_field_names)]`
+
+error: all variants have the same postfix: `Foo`
+  --> $DIR/item_name_repetitions.rs:23:1
+   |
+LL | / enum Foo2 {
+LL | |
+LL | |     AFoo,
+LL | |     BFoo,
+...  |
+LL | |     EFoo,
+LL | | }
+   | |_^
+   |
+   = help: remove the postfixes and use full paths to the variants instead of glob imports
+   = note: `-D clippy::enum-variant-names` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::enum_variant_names)]`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs b/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs
index 830d71f61dd..cd53f504459 100644
--- a/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs
+++ b/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs
@@ -1,5 +1,6 @@
 //! this is crate
 #![allow(missing_docs)]
+#![allow(clippy::struct_field_names)]
 #![warn(clippy::missing_docs_in_private_items)]
 
 /// this is mod
diff --git a/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr b/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr
index 1ecdabbc03e..2cf20b46049 100644
--- a/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr
+++ b/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr
@@ -1,5 +1,5 @@
 error: missing documentation for a function
-  --> $DIR/pub_crate_missing_doc.rs:12:5
+  --> $DIR/pub_crate_missing_doc.rs:13:5
    |
 LL |     pub(crate) fn crate_no_docs() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -8,25 +8,25 @@ LL |     pub(crate) fn crate_no_docs() {}
    = help: to override `-D warnings` add `#[allow(clippy::missing_docs_in_private_items)]`
 
 error: missing documentation for a function
-  --> $DIR/pub_crate_missing_doc.rs:15:5
+  --> $DIR/pub_crate_missing_doc.rs:16:5
    |
 LL |     pub(super) fn super_no_docs() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/pub_crate_missing_doc.rs:23:9
+  --> $DIR/pub_crate_missing_doc.rs:24:9
    |
 LL |         pub(crate) fn sub_crate_no_docs() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a struct field
-  --> $DIR/pub_crate_missing_doc.rs:33:9
+  --> $DIR/pub_crate_missing_doc.rs:34:9
    |
 LL |         pub(crate) crate_field_no_docs: (),
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a struct
-  --> $DIR/pub_crate_missing_doc.rs:39:5
+  --> $DIR/pub_crate_missing_doc.rs:40:5
    |
 LL | /     pub(crate) struct CrateStructNoDocs {
 LL | |         /// some docs
@@ -38,13 +38,13 @@ LL | |     }
    | |_____^
 
 error: missing documentation for a struct field
-  --> $DIR/pub_crate_missing_doc.rs:42:9
+  --> $DIR/pub_crate_missing_doc.rs:43:9
    |
 LL |         pub(crate) crate_field_no_docs: (),
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a type alias
-  --> $DIR/pub_crate_missing_doc.rs:51:1
+  --> $DIR/pub_crate_missing_doc.rs:52:1
    |
 LL | type CrateTypedefNoDocs = String;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index 4bed5c149f5..2f9eaa5178c 100644
--- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -53,6 +53,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
            single-char-binding-names-threshold
            stack-size-threshold
            standard-macro-braces
+           struct-field-name-threshold
            suppress-restriction-lint-in-const
            third-party
            too-large-for-stack
@@ -126,6 +127,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
            single-char-binding-names-threshold
            stack-size-threshold
            standard-macro-braces
+           struct-field-name-threshold
            suppress-restriction-lint-in-const
            third-party
            too-large-for-stack
diff --git a/src/tools/clippy/tests/ui/author/macro_in_closure.rs b/src/tools/clippy/tests/ui/author/macro_in_closure.rs
new file mode 100644
index 00000000000..444e6a12165
--- /dev/null
+++ b/src/tools/clippy/tests/ui/author/macro_in_closure.rs
@@ -0,0 +1,5 @@
+fn main() {
+    #[clippy::author]
+    let print_text = |x| println!("{}", x);
+    print_text("hello");
+}
diff --git a/src/tools/clippy/tests/ui/author/macro_in_closure.stdout b/src/tools/clippy/tests/ui/author/macro_in_closure.stdout
new file mode 100644
index 00000000000..9ab71986f40
--- /dev/null
+++ b/src/tools/clippy/tests/ui/author/macro_in_closure.stdout
@@ -0,0 +1,39 @@
+if let StmtKind::Local(local) = stmt.kind
+    && let Some(init) = local.init
+    && let ExprKind::Closure(CaptureBy::Ref, fn_decl, body_id, _, None) = init.kind
+    && let FnRetTy::DefaultReturn(_) = fn_decl.output
+    && expr = &cx.tcx.hir().body(body_id).value
+    && let ExprKind::Block(block, None) = expr.kind
+    && block.stmts.len() == 1
+    && let StmtKind::Semi(e) = block.stmts[0].kind
+    && let ExprKind::Call(func, args) = e.kind
+    && let ExprKind::Path(ref qpath) = func.kind
+    && match_qpath(qpath, &["$crate", "io", "_print"])
+    && args.len() == 1
+    && let ExprKind::Call(func1, args1) = args[0].kind
+    && let ExprKind::Path(ref qpath1) = func1.kind
+    && args1.len() == 2
+    && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind
+    && let ExprKind::Array(elements) = inner.kind
+    && elements.len() == 2
+    && let ExprKind::Lit(ref lit) = elements[0].kind
+    && let LitKind::Str(s, _) = lit.node
+    && s.as_str() == ""
+    && let ExprKind::Lit(ref lit1) = elements[1].kind
+    && let LitKind::Str(s1, _) = lit1.node
+    && s1.as_str() == "\n"
+    && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args1[1].kind
+    && let ExprKind::Array(elements1) = inner1.kind
+    && elements1.len() == 1
+    && let ExprKind::Call(func2, args2) = elements1[0].kind
+    && let ExprKind::Path(ref qpath2) = func2.kind
+    && args2.len() == 1
+    && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[0].kind
+    && let ExprKind::Path(ref qpath3) = inner2.kind
+    && match_qpath(qpath3, &["x"])
+    && block.expr.is_none()
+    && let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind
+    && name.as_str() == "print_text"
+{
+    // report your lint here
+}
diff --git a/src/tools/clippy/tests/ui/author/macro_in_loop.rs b/src/tools/clippy/tests/ui/author/macro_in_loop.rs
new file mode 100644
index 00000000000..8a520501f8d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/author/macro_in_loop.rs
@@ -0,0 +1,8 @@
+#![feature(stmt_expr_attributes)]
+
+fn main() {
+    #[clippy::author]
+    for i in 0..1 {
+        println!("{}", i);
+    }
+}
diff --git a/src/tools/clippy/tests/ui/author/macro_in_loop.stdout b/src/tools/clippy/tests/ui/author/macro_in_loop.stdout
new file mode 100644
index 00000000000..bd054b6abc4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/author/macro_in_loop.stdout
@@ -0,0 +1,48 @@
+if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::ForLoop::hir(expr)
+    && let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = pat.kind
+    && name.as_str() == "i"
+    && let ExprKind::Struct(qpath, fields, None) = arg.kind
+    && matches!(qpath, QPath::LangItem(LangItem::Range, _))
+    && fields.len() == 2
+    && fields[0].ident.as_str() == "start"
+    && let ExprKind::Lit(ref lit) = fields[0].expr.kind
+    && let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node
+    && fields[1].ident.as_str() == "end"
+    && let ExprKind::Lit(ref lit1) = fields[1].expr.kind
+    && let LitKind::Int(1, LitIntType::Unsuffixed) = lit1.node
+    && let ExprKind::Block(block, None) = body.kind
+    && block.stmts.len() == 1
+    && let StmtKind::Semi(e) = block.stmts[0].kind
+    && let ExprKind::Block(block1, None) = e.kind
+    && block1.stmts.len() == 1
+    && let StmtKind::Semi(e1) = block1.stmts[0].kind
+    && let ExprKind::Call(func, args) = e1.kind
+    && let ExprKind::Path(ref qpath1) = func.kind
+    && match_qpath(qpath1, &["$crate", "io", "_print"])
+    && args.len() == 1
+    && let ExprKind::Call(func1, args1) = args[0].kind
+    && let ExprKind::Path(ref qpath2) = func1.kind
+    && args1.len() == 2
+    && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind
+    && let ExprKind::Array(elements) = inner.kind
+    && elements.len() == 2
+    && let ExprKind::Lit(ref lit2) = elements[0].kind
+    && let LitKind::Str(s, _) = lit2.node
+    && s.as_str() == ""
+    && let ExprKind::Lit(ref lit3) = elements[1].kind
+    && let LitKind::Str(s1, _) = lit3.node
+    && s1.as_str() == "\n"
+    && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args1[1].kind
+    && let ExprKind::Array(elements1) = inner1.kind
+    && elements1.len() == 1
+    && let ExprKind::Call(func2, args2) = elements1[0].kind
+    && let ExprKind::Path(ref qpath3) = func2.kind
+    && args2.len() == 1
+    && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[0].kind
+    && let ExprKind::Path(ref qpath4) = inner2.kind
+    && match_qpath(qpath4, &["i"])
+    && block1.expr.is_none()
+    && block.expr.is_none()
+{
+    // report your lint here
+}
diff --git a/src/tools/clippy/tests/ui/get_first.fixed b/src/tools/clippy/tests/ui/get_first.fixed
index b1a597fc4dd..a7cdd2a93ba 100644
--- a/src/tools/clippy/tests/ui/get_first.fixed
+++ b/src/tools/clippy/tests/ui/get_first.fixed
@@ -14,17 +14,20 @@ impl Bar {
 
 fn main() {
     let x = vec![2, 3, 5];
-    let _ = x.first(); // Use x.first()
+    let _ = x.first();
+    //~^ ERROR: accessing first element with `x.get(0)`
     let _ = x.get(1);
     let _ = x[0];
 
     let y = [2, 3, 5];
-    let _ = y.first(); // Use y.first()
+    let _ = y.first();
+    //~^ ERROR: accessing first element with `y.get(0)`
     let _ = y.get(1);
     let _ = y[0];
 
     let z = &[2, 3, 5];
-    let _ = z.first(); // Use z.first()
+    let _ = z.first();
+    //~^ ERROR: accessing first element with `z.get(0)`
     let _ = z.get(1);
     let _ = z[0];
 
@@ -37,4 +40,8 @@ fn main() {
 
     let bar = Bar { arr: [0, 1, 2] };
     let _ = bar.get(0); // Do not lint, because Bar is struct.
+
+    let non_primitives = [vec![1, 2], vec![3, 4]];
+    let _ = non_primitives.first();
+    //~^ ERROR: accessing first element with `non_primitives.get(0)`
 }
diff --git a/src/tools/clippy/tests/ui/get_first.rs b/src/tools/clippy/tests/ui/get_first.rs
index e27ee4be8c0..cca743c4bf5 100644
--- a/src/tools/clippy/tests/ui/get_first.rs
+++ b/src/tools/clippy/tests/ui/get_first.rs
@@ -14,17 +14,20 @@ impl Bar {
 
 fn main() {
     let x = vec![2, 3, 5];
-    let _ = x.get(0); // Use x.first()
+    let _ = x.get(0);
+    //~^ ERROR: accessing first element with `x.get(0)`
     let _ = x.get(1);
     let _ = x[0];
 
     let y = [2, 3, 5];
-    let _ = y.get(0); // Use y.first()
+    let _ = y.get(0);
+    //~^ ERROR: accessing first element with `y.get(0)`
     let _ = y.get(1);
     let _ = y[0];
 
     let z = &[2, 3, 5];
-    let _ = z.get(0); // Use z.first()
+    let _ = z.get(0);
+    //~^ ERROR: accessing first element with `z.get(0)`
     let _ = z.get(1);
     let _ = z[0];
 
@@ -37,4 +40,8 @@ fn main() {
 
     let bar = Bar { arr: [0, 1, 2] };
     let _ = bar.get(0); // Do not lint, because Bar is struct.
+
+    let non_primitives = [vec![1, 2], vec![3, 4]];
+    let _ = non_primitives.get(0);
+    //~^ ERROR: accessing first element with `non_primitives.get(0)`
 }
diff --git a/src/tools/clippy/tests/ui/get_first.stderr b/src/tools/clippy/tests/ui/get_first.stderr
index 56b4c29a313..8ee66e33cc8 100644
--- a/src/tools/clippy/tests/ui/get_first.stderr
+++ b/src/tools/clippy/tests/ui/get_first.stderr
@@ -1,23 +1,29 @@
 error: accessing first element with `x.get(0)`
   --> $DIR/get_first.rs:17:13
    |
-LL |     let _ = x.get(0); // Use x.first()
+LL |     let _ = x.get(0);
    |             ^^^^^^^^ help: try: `x.first()`
    |
    = note: `-D clippy::get-first` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::get_first)]`
 
 error: accessing first element with `y.get(0)`
-  --> $DIR/get_first.rs:22:13
+  --> $DIR/get_first.rs:23:13
    |
-LL |     let _ = y.get(0); // Use y.first()
+LL |     let _ = y.get(0);
    |             ^^^^^^^^ help: try: `y.first()`
 
 error: accessing first element with `z.get(0)`
-  --> $DIR/get_first.rs:27:13
+  --> $DIR/get_first.rs:29:13
    |
-LL |     let _ = z.get(0); // Use z.first()
+LL |     let _ = z.get(0);
    |             ^^^^^^^^ help: try: `z.first()`
 
-error: aborting due to 3 previous errors
+error: accessing first element with `non_primitives.get(0)`
+  --> $DIR/get_first.rs:45:13
+   |
+LL |     let _ = non_primitives.get(0);
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: try: `non_primitives.first()`
+
+error: aborting due to 4 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 b652e4a4abe..a6251a370d1 100644
--- a/src/tools/clippy/tests/ui/impl_trait_in_params.rs
+++ b/src/tools/clippy/tests/ui/impl_trait_in_params.rs
@@ -1,20 +1,47 @@
 #![allow(unused)]
 #![warn(clippy::impl_trait_in_params)]
+
 //@no-rustfix
 pub trait Trait {}
 pub trait AnotherTrait<T> {}
 
 // Should warn
 pub fn a(_: impl Trait) {}
-//~^ ERROR: '`impl Trait` used as a function parameter'
-//~| NOTE: `-D clippy::impl-trait-in-params` implied by `-D warnings`
+//~^ ERROR: `impl Trait` used as a function parameter
 pub fn c<C: Trait>(_: C, _: impl Trait) {}
-//~^ ERROR: '`impl Trait` used as a function parameter'
-fn d(_: impl AnotherTrait<u32>) {}
+//~^ ERROR: `impl Trait` used as a function parameter
 
 // Shouldn't warn
 
 pub fn b<B: Trait>(_: B) {}
 fn e<T: AnotherTrait<u32>>(_: T) {}
+fn d(_: impl AnotherTrait<u32>) {}
+
+//------ IMPLS
+
+pub trait Public {
+    // See test in ui-toml for a case where avoid-breaking-exported-api is set to false
+    fn t(_: impl Trait);
+    fn tt<T: Trait>(_: T) {}
+}
+
+trait Private {
+    // This shouldn't lint
+    fn t(_: impl Trait);
+    fn tt<T: Trait>(_: T) {}
+}
+
+struct S;
+impl S {
+    pub fn h(_: impl Trait) {} //~ ERROR: `impl Trait` used as a function parameter
+    fn i(_: impl Trait) {}
+    pub fn j<J: Trait>(_: J) {}
+    pub fn k<K: AnotherTrait<u32>>(_: K, _: impl AnotherTrait<u32>) {} //~ ERROR: `impl Trait` used as a function parameter
+}
+
+// Trying with traits
+impl Public for S {
+    fn t(_: impl Trait) {}
+}
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/impl_trait_in_params.stderr b/src/tools/clippy/tests/ui/impl_trait_in_params.stderr
index 36b4f27e9a4..0ae7a3672d1 100644
--- a/src/tools/clippy/tests/ui/impl_trait_in_params.stderr
+++ b/src/tools/clippy/tests/ui/impl_trait_in_params.stderr
@@ -1,5 +1,5 @@
-error: '`impl Trait` used as a function parameter'
-  --> $DIR/impl_trait_in_params.rs:8:13
+error: `impl Trait` used as a function parameter
+  --> $DIR/impl_trait_in_params.rs:9:13
    |
 LL | pub fn a(_: impl Trait) {}
    |             ^^^^^^^^^^
@@ -11,7 +11,7 @@ help: add a type parameter
 LL | pub fn a<{ /* Generic name */ }: Trait>(_: impl Trait) {}
    |         +++++++++++++++++++++++++++++++
 
-error: '`impl Trait` used as a function parameter'
+error: `impl Trait` used as a function parameter
   --> $DIR/impl_trait_in_params.rs:11:29
    |
 LL | pub fn c<C: Trait>(_: C, _: impl Trait) {}
@@ -22,5 +22,27 @@ help: add a type parameter
 LL | pub fn c<C: Trait, { /* Generic name */ }: Trait>(_: C, _: impl Trait) {}
    |                  +++++++++++++++++++++++++++++++
 
-error: aborting due to 2 previous errors
+error: `impl Trait` used as a function parameter
+  --> $DIR/impl_trait_in_params.rs:36:17
+   |
+LL |     pub fn h(_: impl Trait) {}
+   |                 ^^^^^^^^^^
+   |
+help: add a type parameter
+   |
+LL |     pub fn h<{ /* Generic name */ }: Trait>(_: impl Trait) {}
+   |             +++++++++++++++++++++++++++++++
+
+error: `impl Trait` used as a function parameter
+  --> $DIR/impl_trait_in_params.rs:39:45
+   |
+LL |     pub fn k<K: AnotherTrait<u32>>(_: K, _: impl AnotherTrait<u32>) {}
+   |                                             ^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: add a type parameter
+   |
+LL |     pub fn k<K: AnotherTrait<u32>, { /* Generic name */ }: AnotherTrait<u32>>(_: K, _: impl AnotherTrait<u32>) {}
+   |                                  +++++++++++++++++++++++++++++++++++++++++++
+
+error: aborting due to 4 previous errors
 
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 6be3bb8abdd..e6ff821a8ad 100644
--- a/src/tools/clippy/tests/ui/into_iter_without_iter.rs
+++ b/src/tools/clippy/tests/ui/into_iter_without_iter.rs
@@ -122,3 +122,37 @@ fn main() {
         }
     }
 }
+
+fn issue11635() {
+    // A little more involved than the original repro in the issue, but this tests that it correctly
+    // works for more than one deref step
+
+    use std::ops::Deref;
+
+    pub struct Thing(Vec<u8>);
+    pub struct Thing2(Thing);
+
+    impl Deref for Thing {
+        type Target = [u8];
+
+        fn deref(&self) -> &Self::Target {
+            &self.0
+        }
+    }
+
+    impl Deref for Thing2 {
+        type Target = Thing;
+        fn deref(&self) -> &Self::Target {
+            &self.0
+        }
+    }
+
+    impl<'a> IntoIterator for &'a Thing2 {
+        type Item = &'a u8;
+        type IntoIter = <&'a [u8] as IntoIterator>::IntoIter;
+
+        fn into_iter(self) -> Self::IntoIter {
+            self.0.iter()
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/manual_filter_map.fixed b/src/tools/clippy/tests/ui/manual_filter_map.fixed
index 4de45e39b10..a44c46c145c 100644
--- a/src/tools/clippy/tests/ui/manual_filter_map.fixed
+++ b/src/tools/clippy/tests/ui/manual_filter_map.fixed
@@ -2,6 +2,7 @@
 #![warn(clippy::manual_filter_map)]
 #![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure
 #![allow(clippy::useless_vec)]
+#![allow(clippy::struct_field_names)]
 
 fn main() {
     // is_some(), unwrap()
diff --git a/src/tools/clippy/tests/ui/manual_filter_map.rs b/src/tools/clippy/tests/ui/manual_filter_map.rs
index 22f316f90b6..e72d0c4305b 100644
--- a/src/tools/clippy/tests/ui/manual_filter_map.rs
+++ b/src/tools/clippy/tests/ui/manual_filter_map.rs
@@ -2,6 +2,7 @@
 #![warn(clippy::manual_filter_map)]
 #![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure
 #![allow(clippy::useless_vec)]
+#![allow(clippy::struct_field_names)]
 
 fn main() {
     // is_some(), unwrap()
diff --git a/src/tools/clippy/tests/ui/manual_filter_map.stderr b/src/tools/clippy/tests/ui/manual_filter_map.stderr
index 0bfc1f5c745..cf64bb25951 100644
--- a/src/tools/clippy/tests/ui/manual_filter_map.stderr
+++ b/src/tools/clippy/tests/ui/manual_filter_map.stderr
@@ -1,11 +1,11 @@
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
-  --> $DIR/manual_filter_map.rs:8:19
+  --> $DIR/manual_filter_map.rs:9:19
    |
 LL |     let _ = (0..).filter(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap());
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_opt(a))`
    |
 note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
-  --> $DIR/manual_filter_map.rs:8:30
+  --> $DIR/manual_filter_map.rs:9:30
    |
 LL |     let _ = (0..).filter(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap());
    |                              ^^^^^^^^^^
@@ -13,31 +13,31 @@ LL |     let _ = (0..).filter(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap
    = help: to override `-D warnings` add `#[allow(clippy::manual_filter_map)]`
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
-  --> $DIR/manual_filter_map.rs:11:19
+  --> $DIR/manual_filter_map.rs:12:19
    |
 LL |     let _ = (0..).filter(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi"));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_opt(a))`
    |
 note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
-  --> $DIR/manual_filter_map.rs:11:31
+  --> $DIR/manual_filter_map.rs:12:31
    |
 LL |     let _ = (0..).filter(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi"));
    |                               ^^^^^^^^^
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
-  --> $DIR/manual_filter_map.rs:14:19
+  --> $DIR/manual_filter_map.rs:15:19
    |
 LL |     let _ = (0..).filter(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_res(a).ok())`
    |
 note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
-  --> $DIR/manual_filter_map.rs:14:31
+  --> $DIR/manual_filter_map.rs:15:31
    |
 LL |     let _ = (0..).filter(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
    |                               ^^^^^^^^^
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
-  --> $DIR/manual_filter_map.rs:17:10
+  --> $DIR/manual_filter_map.rs:18:10
    |
 LL |           .filter(|&x| to_ref(to_opt(x)).is_some())
    |  __________^
@@ -45,13 +45,13 @@ LL | |         .map(|y| to_ref(to_opt(y)).unwrap());
    | |____________________________________________^ help: try: `filter_map(|y| *to_ref(to_opt(y)))`
    |
 note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
-  --> $DIR/manual_filter_map.rs:17:22
+  --> $DIR/manual_filter_map.rs:18:22
    |
 LL |         .filter(|&x| to_ref(to_opt(x)).is_some())
    |                      ^^^^^^^^^^^^^^^^^
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
-  --> $DIR/manual_filter_map.rs:20:10
+  --> $DIR/manual_filter_map.rs:21:10
    |
 LL |           .filter(|x| to_ref(to_opt(*x)).is_some())
    |  __________^
@@ -59,13 +59,13 @@ LL | |         .map(|y| to_ref(to_opt(y)).unwrap());
    | |____________________________________________^ help: try: `filter_map(|y| *to_ref(to_opt(y)))`
    |
 note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
-  --> $DIR/manual_filter_map.rs:20:21
+  --> $DIR/manual_filter_map.rs:21:21
    |
 LL |         .filter(|x| to_ref(to_opt(*x)).is_some())
    |                     ^^^^^^^^^^^^^^^^^^
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
-  --> $DIR/manual_filter_map.rs:24:10
+  --> $DIR/manual_filter_map.rs:25:10
    |
 LL |           .filter(|&x| to_ref(to_res(x)).is_ok())
    |  __________^
@@ -73,13 +73,13 @@ LL | |         .map(|y| to_ref(to_res(y)).unwrap());
    | |____________________________________________^ help: try: `filter_map(|y| to_ref(to_res(y)).ok())`
    |
 note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
-  --> $DIR/manual_filter_map.rs:24:22
+  --> $DIR/manual_filter_map.rs:25:22
    |
 LL |         .filter(|&x| to_ref(to_res(x)).is_ok())
    |                      ^^^^^^^^^^^^^^^^^
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
-  --> $DIR/manual_filter_map.rs:27:10
+  --> $DIR/manual_filter_map.rs:28:10
    |
 LL |           .filter(|x| to_ref(to_res(*x)).is_ok())
    |  __________^
@@ -87,13 +87,13 @@ LL | |         .map(|y| to_ref(to_res(y)).unwrap());
    | |____________________________________________^ help: try: `filter_map(|y| to_ref(to_res(y)).ok())`
    |
 note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
-  --> $DIR/manual_filter_map.rs:27:21
+  --> $DIR/manual_filter_map.rs:28:21
    |
 LL |         .filter(|x| to_ref(to_res(*x)).is_ok())
    |                     ^^^^^^^^^^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_filter_map.rs:33:27
+  --> $DIR/manual_filter_map.rs:34:27
    |
 LL |     iter::<Option<&u8>>().find(|x| x.is_some()).map(|x| x.cloned().unwrap());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned())`
@@ -102,79 +102,79 @@ LL |     iter::<Option<&u8>>().find(|x| x.is_some()).map(|x| x.cloned().unwrap()
    = help: to override `-D warnings` add `#[allow(clippy::manual_find_map)]`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_filter_map.rs:34:28
+  --> $DIR/manual_filter_map.rs:35:28
    |
 LL |     iter::<&Option<&u8>>().find(|x| x.is_some()).map(|x| x.cloned().unwrap());
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_filter_map.rs:35:31
+  --> $DIR/manual_filter_map.rs:36:31
    |
 LL |     iter::<&Option<String>>().find(|x| x.is_some()).map(|x| x.as_deref().unwrap());
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.as_deref())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_filter_map.rs:36:31
+  --> $DIR/manual_filter_map.rs:37:31
    |
 LL |     iter::<Option<&String>>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap());
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned())`
    |
 note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
-  --> $DIR/manual_filter_map.rs:36:41
+  --> $DIR/manual_filter_map.rs:37:41
    |
 LL |     iter::<Option<&String>>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap());
    |                                         ^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_filter_map.rs:38:30
+  --> $DIR/manual_filter_map.rs:39:30
    |
 LL |     iter::<Result<u8, ()>>().find(|x| x.is_ok()).map(|x| x.unwrap());
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_filter_map.rs:39:31
+  --> $DIR/manual_filter_map.rs:40:31
    |
 LL |     iter::<&Result<u8, ()>>().find(|x| x.is_ok()).map(|x| x.unwrap());
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_filter_map.rs:40:32
+  --> $DIR/manual_filter_map.rs:41:32
    |
 LL |     iter::<&&Result<u8, ()>>().find(|x| x.is_ok()).map(|x| x.unwrap());
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_filter_map.rs:41:31
+  --> $DIR/manual_filter_map.rs:42:31
    |
 LL |     iter::<Result<&u8, ()>>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap());
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned().ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_filter_map.rs:42:32
+  --> $DIR/manual_filter_map.rs:43:32
    |
 LL |     iter::<&Result<&u8, ()>>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap());
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned().ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_filter_map.rs:43:35
+  --> $DIR/manual_filter_map.rs:44:35
    |
 LL |     iter::<&Result<String, ()>>().find(|x| x.is_ok()).map(|x| x.as_deref().unwrap());
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.as_deref().ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_filter_map.rs:44:35
+  --> $DIR/manual_filter_map.rs:45:35
    |
 LL |     iter::<Result<&String, ()>>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap());
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned().ok())`
    |
 note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
-  --> $DIR/manual_filter_map.rs:44:45
+  --> $DIR/manual_filter_map.rs:45:45
    |
 LL |     iter::<Result<&String, ()>>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap());
    |                                             ^^^^^^^^^
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
-  --> $DIR/manual_filter_map.rs:92:10
+  --> $DIR/manual_filter_map.rs:93:10
    |
 LL |           .filter(|f| f.option_field.is_some())
    |  __________^
@@ -182,7 +182,7 @@ LL | |         .map(|f| f.option_field.clone().unwrap());
    | |_________________________________________________^ help: try: `filter_map(|f| f.option_field.clone())`
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
-  --> $DIR/manual_filter_map.rs:97:10
+  --> $DIR/manual_filter_map.rs:98:10
    |
 LL |           .filter(|f| f.ref_field.is_some())
    |  __________^
@@ -190,7 +190,7 @@ LL | |         .map(|f| f.ref_field.cloned().unwrap());
    | |_______________________________________________^ help: try: `filter_map(|f| f.ref_field.cloned())`
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
-  --> $DIR/manual_filter_map.rs:102:10
+  --> $DIR/manual_filter_map.rs:103:10
    |
 LL |           .filter(|f| f.ref_field.is_some())
    |  __________^
@@ -198,7 +198,7 @@ LL | |         .map(|f| f.ref_field.copied().unwrap());
    | |_______________________________________________^ help: try: `filter_map(|f| f.ref_field.copied())`
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
-  --> $DIR/manual_filter_map.rs:107:10
+  --> $DIR/manual_filter_map.rs:108:10
    |
 LL |           .filter(|f| f.result_field.is_ok())
    |  __________^
@@ -206,7 +206,7 @@ LL | |         .map(|f| f.result_field.clone().unwrap());
    | |_________________________________________________^ help: try: `filter_map(|f| f.result_field.clone().ok())`
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
-  --> $DIR/manual_filter_map.rs:112:10
+  --> $DIR/manual_filter_map.rs:113:10
    |
 LL |           .filter(|f| f.result_field.is_ok())
    |  __________^
@@ -214,7 +214,7 @@ LL | |         .map(|f| f.result_field.as_ref().unwrap());
    | |__________________________________________________^ help: try: `filter_map(|f| f.result_field.as_ref().ok())`
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
-  --> $DIR/manual_filter_map.rs:117:10
+  --> $DIR/manual_filter_map.rs:118:10
    |
 LL |           .filter(|f| f.result_field.is_ok())
    |  __________^
@@ -222,7 +222,7 @@ LL | |         .map(|f| f.result_field.as_deref().unwrap());
    | |____________________________________________________^ help: try: `filter_map(|f| f.result_field.as_deref().ok())`
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
-  --> $DIR/manual_filter_map.rs:122:10
+  --> $DIR/manual_filter_map.rs:123:10
    |
 LL |           .filter(|f| f.result_field.is_ok())
    |  __________^
@@ -230,7 +230,7 @@ LL | |         .map(|f| f.result_field.as_mut().unwrap());
    | |__________________________________________________^ help: try: `filter_map(|f| f.result_field.as_mut().ok())`
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
-  --> $DIR/manual_filter_map.rs:127:10
+  --> $DIR/manual_filter_map.rs:128:10
    |
 LL |           .filter(|f| f.result_field.is_ok())
    |  __________^
@@ -238,7 +238,7 @@ LL | |         .map(|f| f.result_field.as_deref_mut().unwrap());
    | |________________________________________________________^ help: try: `filter_map(|f| f.result_field.as_deref_mut().ok())`
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
-  --> $DIR/manual_filter_map.rs:132:10
+  --> $DIR/manual_filter_map.rs:133:10
    |
 LL |           .filter(|f| f.result_field.is_ok())
    |  __________^
@@ -246,7 +246,7 @@ LL | |         .map(|f| f.result_field.to_owned().unwrap());
    | |____________________________________________________^ help: try: `filter_map(|f| f.result_field.to_owned().ok())`
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
-  --> $DIR/manual_filter_map.rs:145:27
+  --> $DIR/manual_filter_map.rs:146:27
    |
 LL |       let _x = iter.clone().filter(|x| matches!(x, Enum::A(_))).map(|x| match x {
    |  ___________________________^
@@ -256,7 +256,7 @@ LL | |     });
    | |______^ help: try: `filter_map(|x| match x { Enum::A(s) => Some(s), _ => None })`
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
-  --> $DIR/manual_filter_map.rs:155:10
+  --> $DIR/manual_filter_map.rs:156:10
    |
 LL |           .filter(|x| matches!(x, Enum::A(_)))
    |  __________^
diff --git a/src/tools/clippy/tests/ui/manual_find_map.fixed b/src/tools/clippy/tests/ui/manual_find_map.fixed
index 0e92d25e68f..2d9a356b9bc 100644
--- a/src/tools/clippy/tests/ui/manual_find_map.fixed
+++ b/src/tools/clippy/tests/ui/manual_find_map.fixed
@@ -2,6 +2,7 @@
 #![warn(clippy::manual_find_map)]
 #![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure
 #![allow(clippy::useless_vec)]
+#![allow(clippy::struct_field_names)]
 
 fn main() {
     // is_some(), unwrap()
diff --git a/src/tools/clippy/tests/ui/manual_find_map.rs b/src/tools/clippy/tests/ui/manual_find_map.rs
index b2568c823eb..7c5cc136695 100644
--- a/src/tools/clippy/tests/ui/manual_find_map.rs
+++ b/src/tools/clippy/tests/ui/manual_find_map.rs
@@ -2,6 +2,7 @@
 #![warn(clippy::manual_find_map)]
 #![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure
 #![allow(clippy::useless_vec)]
+#![allow(clippy::struct_field_names)]
 
 fn main() {
     // is_some(), unwrap()
diff --git a/src/tools/clippy/tests/ui/manual_find_map.stderr b/src/tools/clippy/tests/ui/manual_find_map.stderr
index 0dc9ae1df03..0526382323d 100644
--- a/src/tools/clippy/tests/ui/manual_find_map.stderr
+++ b/src/tools/clippy/tests/ui/manual_find_map.stderr
@@ -1,11 +1,11 @@
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:8:19
+  --> $DIR/manual_find_map.rs:9:19
    |
 LL |     let _ = (0..).find(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap());
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_opt(a))`
    |
 note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
-  --> $DIR/manual_find_map.rs:8:28
+  --> $DIR/manual_find_map.rs:9:28
    |
 LL |     let _ = (0..).find(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap());
    |                            ^^^^^^^^^^
@@ -13,31 +13,31 @@ LL |     let _ = (0..).find(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap()
    = help: to override `-D warnings` add `#[allow(clippy::manual_find_map)]`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:11:19
+  --> $DIR/manual_find_map.rs:12:19
    |
 LL |     let _ = (0..).find(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi"));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_opt(a))`
    |
 note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
-  --> $DIR/manual_find_map.rs:11:29
+  --> $DIR/manual_find_map.rs:12:29
    |
 LL |     let _ = (0..).find(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi"));
    |                             ^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:14:19
+  --> $DIR/manual_find_map.rs:15:19
    |
 LL |     let _ = (0..).find(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_res(a).ok())`
    |
 note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
-  --> $DIR/manual_find_map.rs:14:29
+  --> $DIR/manual_find_map.rs:15:29
    |
 LL |     let _ = (0..).find(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
    |                             ^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:17:10
+  --> $DIR/manual_find_map.rs:18:10
    |
 LL |           .find(|&x| to_ref(to_opt(x)).is_some())
    |  __________^
@@ -45,13 +45,13 @@ LL | |         .map(|y| to_ref(to_opt(y)).unwrap());
    | |____________________________________________^ help: try: `find_map(|y| *to_ref(to_opt(y)))`
    |
 note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
-  --> $DIR/manual_find_map.rs:17:20
+  --> $DIR/manual_find_map.rs:18:20
    |
 LL |         .find(|&x| to_ref(to_opt(x)).is_some())
    |                    ^^^^^^^^^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:20:10
+  --> $DIR/manual_find_map.rs:21:10
    |
 LL |           .find(|x| to_ref(to_opt(*x)).is_some())
    |  __________^
@@ -59,13 +59,13 @@ LL | |         .map(|y| to_ref(to_opt(y)).unwrap());
    | |____________________________________________^ help: try: `find_map(|y| *to_ref(to_opt(y)))`
    |
 note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
-  --> $DIR/manual_find_map.rs:20:19
+  --> $DIR/manual_find_map.rs:21:19
    |
 LL |         .find(|x| to_ref(to_opt(*x)).is_some())
    |                   ^^^^^^^^^^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:24:10
+  --> $DIR/manual_find_map.rs:25:10
    |
 LL |           .find(|&x| to_ref(to_res(x)).is_ok())
    |  __________^
@@ -73,13 +73,13 @@ LL | |         .map(|y| to_ref(to_res(y)).unwrap());
    | |____________________________________________^ help: try: `find_map(|y| to_ref(to_res(y)).ok())`
    |
 note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
-  --> $DIR/manual_find_map.rs:24:20
+  --> $DIR/manual_find_map.rs:25:20
    |
 LL |         .find(|&x| to_ref(to_res(x)).is_ok())
    |                    ^^^^^^^^^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:27:10
+  --> $DIR/manual_find_map.rs:28:10
    |
 LL |           .find(|x| to_ref(to_res(*x)).is_ok())
    |  __________^
@@ -87,109 +87,109 @@ LL | |         .map(|y| to_ref(to_res(y)).unwrap());
    | |____________________________________________^ help: try: `find_map(|y| to_ref(to_res(y)).ok())`
    |
 note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
-  --> $DIR/manual_find_map.rs:27:19
+  --> $DIR/manual_find_map.rs:28:19
    |
 LL |         .find(|x| to_ref(to_res(*x)).is_ok())
    |                   ^^^^^^^^^^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:33:26
+  --> $DIR/manual_find_map.rs:34:26
    |
 LL |     iter::<Option<u8>>().find(|x| x.is_some()).map(|x| x.unwrap());
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x)`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:34:27
+  --> $DIR/manual_find_map.rs:35:27
    |
 LL |     iter::<&Option<u8>>().find(|x| x.is_some()).map(|x| x.unwrap());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| *x)`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:35:28
+  --> $DIR/manual_find_map.rs:36:28
    |
 LL |     iter::<&&Option<u8>>().find(|x| x.is_some()).map(|x| x.unwrap());
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| **x)`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:36:27
+  --> $DIR/manual_find_map.rs:37:27
    |
 LL |     iter::<Option<&u8>>().find(|x| x.is_some()).map(|x| x.cloned().unwrap());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:37:28
+  --> $DIR/manual_find_map.rs:38:28
    |
 LL |     iter::<&Option<&u8>>().find(|x| x.is_some()).map(|x| x.cloned().unwrap());
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:38:31
+  --> $DIR/manual_find_map.rs:39:31
    |
 LL |     iter::<&Option<String>>().find(|x| x.is_some()).map(|x| x.as_deref().unwrap());
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.as_deref())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:39:31
+  --> $DIR/manual_find_map.rs:40:31
    |
 LL |     iter::<Option<&String>>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap());
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned())`
    |
 note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
-  --> $DIR/manual_find_map.rs:39:41
+  --> $DIR/manual_find_map.rs:40:41
    |
 LL |     iter::<Option<&String>>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap());
    |                                         ^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:41:30
+  --> $DIR/manual_find_map.rs:42:30
    |
 LL |     iter::<Result<u8, ()>>().find(|x| x.is_ok()).map(|x| x.unwrap());
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:42:31
+  --> $DIR/manual_find_map.rs:43:31
    |
 LL |     iter::<&Result<u8, ()>>().find(|x| x.is_ok()).map(|x| x.unwrap());
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:43:32
+  --> $DIR/manual_find_map.rs:44:32
    |
 LL |     iter::<&&Result<u8, ()>>().find(|x| x.is_ok()).map(|x| x.unwrap());
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:44:31
+  --> $DIR/manual_find_map.rs:45:31
    |
 LL |     iter::<Result<&u8, ()>>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap());
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned().ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:45:32
+  --> $DIR/manual_find_map.rs:46:32
    |
 LL |     iter::<&Result<&u8, ()>>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap());
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned().ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:46:35
+  --> $DIR/manual_find_map.rs:47:35
    |
 LL |     iter::<&Result<String, ()>>().find(|x| x.is_ok()).map(|x| x.as_deref().unwrap());
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.as_deref().ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:47:35
+  --> $DIR/manual_find_map.rs:48:35
    |
 LL |     iter::<Result<&String, ()>>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap());
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned().ok())`
    |
 note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
-  --> $DIR/manual_find_map.rs:47:45
+  --> $DIR/manual_find_map.rs:48:45
    |
 LL |     iter::<Result<&String, ()>>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap());
    |                                             ^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:95:10
+  --> $DIR/manual_find_map.rs:96:10
    |
 LL |           .find(|f| f.option_field.is_some())
    |  __________^
@@ -197,7 +197,7 @@ LL | |         .map(|f| f.option_field.clone().unwrap());
    | |_________________________________________________^ help: try: `find_map(|f| f.option_field.clone())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:100:10
+  --> $DIR/manual_find_map.rs:101:10
    |
 LL |           .find(|f| f.ref_field.is_some())
    |  __________^
@@ -205,7 +205,7 @@ LL | |         .map(|f| f.ref_field.cloned().unwrap());
    | |_______________________________________________^ help: try: `find_map(|f| f.ref_field.cloned())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:105:10
+  --> $DIR/manual_find_map.rs:106:10
    |
 LL |           .find(|f| f.ref_field.is_some())
    |  __________^
@@ -213,7 +213,7 @@ LL | |         .map(|f| f.ref_field.copied().unwrap());
    | |_______________________________________________^ help: try: `find_map(|f| f.ref_field.copied())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:110:10
+  --> $DIR/manual_find_map.rs:111:10
    |
 LL |           .find(|f| f.result_field.is_ok())
    |  __________^
@@ -221,7 +221,7 @@ LL | |         .map(|f| f.result_field.clone().unwrap());
    | |_________________________________________________^ help: try: `find_map(|f| f.result_field.clone().ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:115:10
+  --> $DIR/manual_find_map.rs:116:10
    |
 LL |           .find(|f| f.result_field.is_ok())
    |  __________^
@@ -229,7 +229,7 @@ LL | |         .map(|f| f.result_field.as_ref().unwrap());
    | |__________________________________________________^ help: try: `find_map(|f| f.result_field.as_ref().ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:120:10
+  --> $DIR/manual_find_map.rs:121:10
    |
 LL |           .find(|f| f.result_field.is_ok())
    |  __________^
@@ -237,7 +237,7 @@ LL | |         .map(|f| f.result_field.as_deref().unwrap());
    | |____________________________________________________^ help: try: `find_map(|f| f.result_field.as_deref().ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:125:10
+  --> $DIR/manual_find_map.rs:126:10
    |
 LL |           .find(|f| f.result_field.is_ok())
    |  __________^
@@ -245,7 +245,7 @@ LL | |         .map(|f| f.result_field.as_mut().unwrap());
    | |__________________________________________________^ help: try: `find_map(|f| f.result_field.as_mut().ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:130:10
+  --> $DIR/manual_find_map.rs:131:10
    |
 LL |           .find(|f| f.result_field.is_ok())
    |  __________^
@@ -253,7 +253,7 @@ LL | |         .map(|f| f.result_field.as_deref_mut().unwrap());
    | |________________________________________________________^ help: try: `find_map(|f| f.result_field.as_deref_mut().ok())`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
-  --> $DIR/manual_find_map.rs:135:10
+  --> $DIR/manual_find_map.rs:136:10
    |
 LL |           .find(|f| f.result_field.is_ok())
    |  __________^
diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed b/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed
index 5be2dd280b8..9c4bd335ad8 100644
--- a/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed
+++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed
@@ -33,6 +33,7 @@ fn msrv_1_23() {
     assert!(matches!(b'1', b'0'..=b'9'));
     assert!(matches!('X', 'A'..='Z'));
     assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
+    assert!(matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F'));
 }
 
 #[clippy::msrv = "1.24"]
@@ -40,14 +41,17 @@ fn msrv_1_24() {
     assert!(b'1'.is_ascii_digit());
     assert!('X'.is_ascii_uppercase());
     assert!('x'.is_ascii_alphabetic());
+    assert!('x'.is_ascii_hexdigit());
 }
 
 #[clippy::msrv = "1.46"]
 fn msrv_1_46() {
     const FOO: bool = matches!('x', '0'..='9');
+    const BAR: bool = matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F');
 }
 
 #[clippy::msrv = "1.47"]
 fn msrv_1_47() {
     const FOO: bool = 'x'.is_ascii_digit();
+    const BAR: bool = 'x'.is_ascii_hexdigit();
 }
diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.rs b/src/tools/clippy/tests/ui/manual_is_ascii_check.rs
index f9249e22a02..785943cd24d 100644
--- a/src/tools/clippy/tests/ui/manual_is_ascii_check.rs
+++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.rs
@@ -33,6 +33,7 @@ fn msrv_1_23() {
     assert!(matches!(b'1', b'0'..=b'9'));
     assert!(matches!('X', 'A'..='Z'));
     assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
+    assert!(matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F'));
 }
 
 #[clippy::msrv = "1.24"]
@@ -40,14 +41,17 @@ fn msrv_1_24() {
     assert!(matches!(b'1', b'0'..=b'9'));
     assert!(matches!('X', 'A'..='Z'));
     assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
+    assert!(matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F'));
 }
 
 #[clippy::msrv = "1.46"]
 fn msrv_1_46() {
     const FOO: bool = matches!('x', '0'..='9');
+    const BAR: bool = matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F');
 }
 
 #[clippy::msrv = "1.47"]
 fn msrv_1_47() {
     const FOO: bool = matches!('x', '0'..='9');
+    const BAR: bool = matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F');
 }
diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr b/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr
index e0fb46e59fa..f69522c5ff8 100644
--- a/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr
+++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr
@@ -98,28 +98,40 @@ LL |     ('A'..='Z').contains(cool_letter);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_uppercase()`
 
 error: manual check for common ascii range
-  --> $DIR/manual_is_ascii_check.rs:40:13
+  --> $DIR/manual_is_ascii_check.rs:41:13
    |
 LL |     assert!(matches!(b'1', b'0'..=b'9'));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'1'.is_ascii_digit()`
 
 error: manual check for common ascii range
-  --> $DIR/manual_is_ascii_check.rs:41:13
+  --> $DIR/manual_is_ascii_check.rs:42:13
    |
 LL |     assert!(matches!('X', 'A'..='Z'));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'X'.is_ascii_uppercase()`
 
 error: manual check for common ascii range
-  --> $DIR/manual_is_ascii_check.rs:42:13
+  --> $DIR/manual_is_ascii_check.rs:43:13
    |
 LL |     assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_alphabetic()`
 
 error: manual check for common ascii range
-  --> $DIR/manual_is_ascii_check.rs:52:23
+  --> $DIR/manual_is_ascii_check.rs:44:13
+   |
+LL |     assert!(matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F'));
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_hexdigit()`
+
+error: manual check for common ascii range
+  --> $DIR/manual_is_ascii_check.rs:55:23
    |
 LL |     const FOO: bool = matches!('x', '0'..='9');
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_digit()`
 
-error: aborting due to 20 previous errors
+error: manual check for common ascii range
+  --> $DIR/manual_is_ascii_check.rs:56:23
+   |
+LL |     const BAR: bool = matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F');
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_hexdigit()`
+
+error: aborting due to 22 previous errors
 
diff --git a/src/tools/clippy/tests/ui/map_identity.fixed b/src/tools/clippy/tests/ui/map_identity.fixed
index cc40b162058..e756d9b5935 100644
--- a/src/tools/clippy/tests/ui/map_identity.fixed
+++ b/src/tools/clippy/tests/ui/map_identity.fixed
@@ -17,6 +17,9 @@ fn main() {
     });
     let _: Result<u32, u32> = Ok(1);
     let _: Result<u32, u32> = Ok(1).map_err(|a: u32| a * 42);
+    // : u32 guides type inference
+    let _ = Ok(1).map_err(|a: u32| a);
+    let _ = Ok(1).map_err(std::convert::identity::<u32>);
 }
 
 fn not_identity(x: &u16) -> u16 {
diff --git a/src/tools/clippy/tests/ui/map_identity.rs b/src/tools/clippy/tests/ui/map_identity.rs
index 97a91aea6dc..74cbaade405 100644
--- a/src/tools/clippy/tests/ui/map_identity.rs
+++ b/src/tools/clippy/tests/ui/map_identity.rs
@@ -19,6 +19,9 @@ fn main() {
     });
     let _: Result<u32, u32> = Ok(1).map_err(|a| a);
     let _: Result<u32, u32> = Ok(1).map_err(|a: u32| a * 42);
+    // : u32 guides type inference
+    let _ = Ok(1).map_err(|a: u32| a);
+    let _ = Ok(1).map_err(std::convert::identity::<u32>);
 }
 
 fn not_identity(x: &u16) -> u16 {
diff --git a/src/tools/clippy/tests/ui/min_ident_chars.rs b/src/tools/clippy/tests/ui/min_ident_chars.rs
index 030863ca0d3..f99c35d5c57 100644
--- a/src/tools/clippy/tests/ui/min_ident_chars.rs
+++ b/src/tools/clippy/tests/ui/min_ident_chars.rs
@@ -1,5 +1,6 @@
 //@aux-build:proc_macros.rs
 #![allow(irrefutable_let_patterns, nonstandard_style, unused)]
+#![allow(clippy::struct_field_names)]
 #![warn(clippy::min_ident_chars)]
 
 extern crate proc_macros;
diff --git a/src/tools/clippy/tests/ui/min_ident_chars.stderr b/src/tools/clippy/tests/ui/min_ident_chars.stderr
index 253636cf91d..e4181157ea2 100644
--- a/src/tools/clippy/tests/ui/min_ident_chars.stderr
+++ b/src/tools/clippy/tests/ui/min_ident_chars.stderr
@@ -1,5 +1,5 @@
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:8:8
+  --> $DIR/min_ident_chars.rs:9:8
    |
 LL | struct A {
    |        ^
@@ -8,169 +8,169 @@ LL | struct A {
    = help: to override `-D warnings` add `#[allow(clippy::min_ident_chars)]`
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:9:5
+  --> $DIR/min_ident_chars.rs:10:5
    |
 LL |     a: u32,
    |     ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:11:5
+  --> $DIR/min_ident_chars.rs:12:5
    |
 LL |     A: u32,
    |     ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:12:5
+  --> $DIR/min_ident_chars.rs:13:5
    |
 LL |     I: u32,
    |     ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:15:8
+  --> $DIR/min_ident_chars.rs:16:8
    |
 LL | struct B(u32);
    |        ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:17:8
+  --> $DIR/min_ident_chars.rs:18:8
    |
 LL | struct O {
    |        ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:18:5
+  --> $DIR/min_ident_chars.rs:19:5
    |
 LL |     o: u32,
    |     ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:23:6
+  --> $DIR/min_ident_chars.rs:24:6
    |
 LL | enum C {
    |      ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:24:5
+  --> $DIR/min_ident_chars.rs:25:5
    |
 LL |     D,
    |     ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:25:5
+  --> $DIR/min_ident_chars.rs:26:5
    |
 LL |     E,
    |     ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:26:5
+  --> $DIR/min_ident_chars.rs:27:5
    |
 LL |     F,
    |     ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:50:9
+  --> $DIR/min_ident_chars.rs:51:9
    |
 LL |     let h = 1;
    |         ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:51:9
+  --> $DIR/min_ident_chars.rs:52:9
    |
 LL |     let e = 2;
    |         ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:52:9
+  --> $DIR/min_ident_chars.rs:53:9
    |
 LL |     let l = 3;
    |         ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:53:9
+  --> $DIR/min_ident_chars.rs:54:9
    |
 LL |     let l = 4;
    |         ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:54:9
+  --> $DIR/min_ident_chars.rs:55:9
    |
 LL |     let o = 6;
    |         ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:58:10
+  --> $DIR/min_ident_chars.rs:59:10
    |
 LL |     let (h, o, w) = (1, 2, 3);
    |          ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:58:13
+  --> $DIR/min_ident_chars.rs:59:13
    |
 LL |     let (h, o, w) = (1, 2, 3);
    |             ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:59:10
+  --> $DIR/min_ident_chars.rs:60:10
    |
 LL |     for (a, (r, e)) in (0..1000).enumerate().enumerate() {}
    |          ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:59:14
+  --> $DIR/min_ident_chars.rs:60:14
    |
 LL |     for (a, (r, e)) in (0..1000).enumerate().enumerate() {}
    |              ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:59:17
+  --> $DIR/min_ident_chars.rs:60:17
    |
 LL |     for (a, (r, e)) in (0..1000).enumerate().enumerate() {}
    |                 ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:61:16
+  --> $DIR/min_ident_chars.rs:62:16
    |
 LL |     while let (d, o, _i, n, g) = (true, true, false, false, true) {}
    |                ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:61:19
+  --> $DIR/min_ident_chars.rs:62:19
    |
 LL |     while let (d, o, _i, n, g) = (true, true, false, false, true) {}
    |                   ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:61:29
+  --> $DIR/min_ident_chars.rs:62:29
    |
 LL |     while let (d, o, _i, n, g) = (true, true, false, false, true) {}
    |                             ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:65:9
+  --> $DIR/min_ident_chars.rs:66:9
    |
 LL |     let o = 1;
    |         ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:66:9
+  --> $DIR/min_ident_chars.rs:67:9
    |
 LL |     let o = O { o };
    |         ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:80:4
+  --> $DIR/min_ident_chars.rs:81:4
    |
 LL | fn b() {}
    |    ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:81:21
+  --> $DIR/min_ident_chars.rs:82:21
    |
 LL | fn wrong_pythagoras(a: f32, b: f32) -> f32 {
    |                     ^
 
 error: this ident consists of a single char
-  --> $DIR/min_ident_chars.rs:81:29
+  --> $DIR/min_ident_chars.rs:82:29
    |
 LL | fn wrong_pythagoras(a: f32, b: f32) -> f32 {
    |                             ^
diff --git a/src/tools/clippy/tests/ui/misnamed_getters.fixed b/src/tools/clippy/tests/ui/misnamed_getters.fixed
index 2a7a2067ee0..70af604b214 100644
--- a/src/tools/clippy/tests/ui/misnamed_getters.fixed
+++ b/src/tools/clippy/tests/ui/misnamed_getters.fixed
@@ -1,4 +1,5 @@
 #![allow(unused)]
+#![allow(clippy::struct_field_names)]
 #![warn(clippy::misnamed_getters)]
 
 struct A {
diff --git a/src/tools/clippy/tests/ui/misnamed_getters.rs b/src/tools/clippy/tests/ui/misnamed_getters.rs
index 56ddc46c4d4..23c3e7bc5cf 100644
--- a/src/tools/clippy/tests/ui/misnamed_getters.rs
+++ b/src/tools/clippy/tests/ui/misnamed_getters.rs
@@ -1,4 +1,5 @@
 #![allow(unused)]
+#![allow(clippy::struct_field_names)]
 #![warn(clippy::misnamed_getters)]
 
 struct A {
diff --git a/src/tools/clippy/tests/ui/misnamed_getters.stderr b/src/tools/clippy/tests/ui/misnamed_getters.stderr
index aadec654908..120a3f3112e 100644
--- a/src/tools/clippy/tests/ui/misnamed_getters.stderr
+++ b/src/tools/clippy/tests/ui/misnamed_getters.stderr
@@ -1,5 +1,5 @@
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:11:5
+  --> $DIR/misnamed_getters.rs:12:5
    |
 LL | /     fn a(&self) -> &u8 {
 LL | |
@@ -13,7 +13,7 @@ LL | |     }
    = help: to override `-D warnings` add `#[allow(clippy::misnamed_getters)]`
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:16:5
+  --> $DIR/misnamed_getters.rs:17:5
    |
 LL | /     fn a_mut(&mut self) -> &mut u8 {
 LL | |
@@ -23,7 +23,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:21:5
+  --> $DIR/misnamed_getters.rs:22:5
    |
 LL | /     fn b(self) -> u8 {
 LL | |
@@ -33,7 +33,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:26:5
+  --> $DIR/misnamed_getters.rs:27:5
    |
 LL | /     fn b_mut(&mut self) -> &mut u8 {
 LL | |
@@ -43,7 +43,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:31:5
+  --> $DIR/misnamed_getters.rs:32:5
    |
 LL | /     fn c(&self) -> &u8 {
 LL | |
@@ -53,7 +53,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:36:5
+  --> $DIR/misnamed_getters.rs:37:5
    |
 LL | /     fn c_mut(&mut self) -> &mut u8 {
 LL | |
@@ -63,7 +63,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:48:5
+  --> $DIR/misnamed_getters.rs:49:5
    |
 LL | /     unsafe fn a(&self) -> &u8 {
 LL | |
@@ -73,7 +73,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:52:5
+  --> $DIR/misnamed_getters.rs:53:5
    |
 LL | /     unsafe fn a_mut(&mut self) -> &mut u8 {
 LL | |
@@ -83,7 +83,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:57:5
+  --> $DIR/misnamed_getters.rs:58:5
    |
 LL | /     unsafe fn b(self) -> u8 {
 LL | |
@@ -93,7 +93,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:62:5
+  --> $DIR/misnamed_getters.rs:63:5
    |
 LL | /     unsafe fn b_mut(&mut self) -> &mut u8 {
 LL | |
@@ -103,7 +103,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:75:5
+  --> $DIR/misnamed_getters.rs:76:5
    |
 LL | /     unsafe fn a_unchecked(&self) -> &u8 {
 LL | |
@@ -113,7 +113,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:79:5
+  --> $DIR/misnamed_getters.rs:80:5
    |
 LL | /     unsafe fn a_unchecked_mut(&mut self) -> &mut u8 {
 LL | |
@@ -123,7 +123,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:84:5
+  --> $DIR/misnamed_getters.rs:85:5
    |
 LL | /     unsafe fn b_unchecked(self) -> u8 {
 LL | |
@@ -133,7 +133,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:89:5
+  --> $DIR/misnamed_getters.rs:90:5
    |
 LL | /     unsafe fn b_unchecked_mut(&mut self) -> &mut u8 {
 LL | |
@@ -143,7 +143,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:122:5
+  --> $DIR/misnamed_getters.rs:123:5
    |
 LL | /     fn a(&self) -> &u8 {
 LL | |
@@ -153,7 +153,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:126:5
+  --> $DIR/misnamed_getters.rs:127:5
    |
 LL | /     fn a_mut(&mut self) -> &mut u8 {
 LL | |
@@ -163,7 +163,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:131:5
+  --> $DIR/misnamed_getters.rs:132:5
    |
 LL | /     fn d(&self) -> &u8 {
 LL | |
@@ -173,7 +173,7 @@ LL | |     }
    | |_____^
 
 error: getter function appears to return the wrong field
-  --> $DIR/misnamed_getters.rs:135:5
+  --> $DIR/misnamed_getters.rs:136:5
    |
 LL | /     fn d_mut(&mut self) -> &mut u8 {
 LL | |
diff --git a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs
index 4ef6f0ca92f..8afb4df20af 100644
--- a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs
+++ b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs
@@ -147,4 +147,11 @@ fn _field_fn_ptr(x: unsafe fn()) {
     }
 }
 
+// await expands to an unsafe block with several operations, but this is fine.: #11312
+async fn await_desugaring_silent() {
+    async fn helper() {}
+
+    helper().await;
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.fixed b/src/tools/clippy/tests/ui/needless_bool/fixable.fixed
index c9ea831f8b2..3059de8f89c 100644
--- a/src/tools/clippy/tests/ui/needless_bool/fixable.fixed
+++ b/src/tools/clippy/tests/ui/needless_bool/fixable.fixed
@@ -7,7 +7,8 @@
     clippy::equatable_if_let,
     clippy::needless_if,
     clippy::needless_return,
-    clippy::self_named_constructors
+    clippy::self_named_constructors,
+    clippy::struct_field_names
 )]
 
 use std::cell::Cell;
diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.rs b/src/tools/clippy/tests/ui/needless_bool/fixable.rs
index b83d9c3f209..b2cbe86e223 100644
--- a/src/tools/clippy/tests/ui/needless_bool/fixable.rs
+++ b/src/tools/clippy/tests/ui/needless_bool/fixable.rs
@@ -7,7 +7,8 @@
     clippy::equatable_if_let,
     clippy::needless_if,
     clippy::needless_return,
-    clippy::self_named_constructors
+    clippy::self_named_constructors,
+    clippy::struct_field_names
 )]
 
 use std::cell::Cell;
diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.stderr b/src/tools/clippy/tests/ui/needless_bool/fixable.stderr
index 2b189c89851..72b0670c95b 100644
--- a/src/tools/clippy/tests/ui/needless_bool/fixable.stderr
+++ b/src/tools/clippy/tests/ui/needless_bool/fixable.stderr
@@ -1,5 +1,5 @@
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:40:5
+  --> $DIR/fixable.rs:41:5
    |
 LL | /     if x {
 LL | |         true
@@ -12,7 +12,7 @@ LL | |     };
    = help: to override `-D warnings` add `#[allow(clippy::needless_bool)]`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:45:5
+  --> $DIR/fixable.rs:46:5
    |
 LL | /     if x {
 LL | |         false
@@ -22,7 +22,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `!x`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:50:5
+  --> $DIR/fixable.rs:51:5
    |
 LL | /     if x && y {
 LL | |         false
@@ -32,7 +32,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `!(x && y)`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:58:5
+  --> $DIR/fixable.rs:59:5
    |
 LL | /     if a == b {
 LL | |         false
@@ -42,7 +42,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `a != b`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:63:5
+  --> $DIR/fixable.rs:64:5
    |
 LL | /     if a != b {
 LL | |         false
@@ -52,7 +52,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `a == b`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:68:5
+  --> $DIR/fixable.rs:69:5
    |
 LL | /     if a < b {
 LL | |         false
@@ -62,7 +62,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `a >= b`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:73:5
+  --> $DIR/fixable.rs:74:5
    |
 LL | /     if a <= b {
 LL | |         false
@@ -72,7 +72,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `a > b`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:78:5
+  --> $DIR/fixable.rs:79:5
    |
 LL | /     if a > b {
 LL | |         false
@@ -82,7 +82,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `a <= b`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:83:5
+  --> $DIR/fixable.rs:84:5
    |
 LL | /     if a >= b {
 LL | |         false
@@ -92,7 +92,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `a < b`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:111:5
+  --> $DIR/fixable.rs:112:5
    |
 LL | /     if x {
 LL | |         return true;
@@ -102,7 +102,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `return x`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:119:5
+  --> $DIR/fixable.rs:120:5
    |
 LL | /     if x {
 LL | |         return false;
@@ -112,7 +112,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `return !x`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:127:5
+  --> $DIR/fixable.rs:128:5
    |
 LL | /     if x && y {
 LL | |         return true;
@@ -122,7 +122,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `return x && y`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:135:5
+  --> $DIR/fixable.rs:136:5
    |
 LL | /     if x && y {
 LL | |         return false;
@@ -132,7 +132,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `return !(x && y)`
 
 error: equality checks against true are unnecessary
-  --> $DIR/fixable.rs:143:8
+  --> $DIR/fixable.rs:144:8
    |
 LL |     if x == true {};
    |        ^^^^^^^^^ help: try simplifying it as shown: `x`
@@ -141,25 +141,25 @@ LL |     if x == true {};
    = help: to override `-D warnings` add `#[allow(clippy::bool_comparison)]`
 
 error: equality checks against false can be replaced by a negation
-  --> $DIR/fixable.rs:147:8
+  --> $DIR/fixable.rs:148:8
    |
 LL |     if x == false {};
    |        ^^^^^^^^^^ help: try simplifying it as shown: `!x`
 
 error: equality checks against true are unnecessary
-  --> $DIR/fixable.rs:157:8
+  --> $DIR/fixable.rs:158:8
    |
 LL |     if x == true {};
    |        ^^^^^^^^^ help: try simplifying it as shown: `x`
 
 error: equality checks against false can be replaced by a negation
-  --> $DIR/fixable.rs:158:8
+  --> $DIR/fixable.rs:159:8
    |
 LL |     if x == false {};
    |        ^^^^^^^^^^ help: try simplifying it as shown: `!x`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:167:12
+  --> $DIR/fixable.rs:168:12
    |
 LL |       } else if returns_bool() {
    |  ____________^
@@ -170,7 +170,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `{ !returns_bool() }`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:180:5
+  --> $DIR/fixable.rs:181:5
    |
 LL | /     if unsafe { no(4) } & 1 != 0 {
 LL | |         true
@@ -180,13 +180,13 @@ LL | |     };
    | |_____^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:185:30
+  --> $DIR/fixable.rs:186:30
    |
 LL |     let _brackets_unneeded = if unsafe { no(4) } & 1 != 0 { true } else { false };
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `unsafe { no(4) } & 1 != 0`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:188:9
+  --> $DIR/fixable.rs:189:9
    |
 LL |         if unsafe { no(4) } & 1 != 0 { true } else { false }
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)`
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs
index 39d76f99900..ea5e74c4c00 100644
--- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs
+++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs
@@ -270,6 +270,38 @@ pub async fn closure4(n: &mut usize) {
     })();
 }
 
+// Should not warn.
+async fn _f(v: &mut Vec<()>) {
+    let x = || v.pop();
+    _ = || || x;
+}
+
+struct Data<T: ?Sized> {
+    value: T,
+}
+// Unsafe functions should not warn.
+unsafe fn get_mut_unchecked<T>(ptr: &mut NonNull<Data<T>>) -> &mut T {
+    &mut (*ptr.as_ptr()).value
+}
+// Unsafe blocks should not warn.
+fn get_mut_unchecked2<T>(ptr: &mut NonNull<Data<T>>) -> &mut T {
+    unsafe { &mut (*ptr.as_ptr()).value }
+}
+
+fn set_true(b: &mut bool) {
+    *b = true;
+}
+
+// Should not warn.
+fn true_setter(b: &mut bool) -> impl FnOnce() + '_ {
+    move || set_true(b)
+}
+
+// Should not warn.
+fn filter_copy<T: Copy>(predicate: &mut impl FnMut(T) -> bool) -> impl FnMut(&T) -> bool + '_ {
+    move |&item| predicate(item)
+}
+
 fn main() {
     let mut u = 0;
     let mut v = vec![0];
diff --git a/src/tools/clippy/tests/ui/redundant_locals.rs b/src/tools/clippy/tests/ui/redundant_locals.rs
index e81db300f15..182d067a5e9 100644
--- a/src/tools/clippy/tests/ui/redundant_locals.rs
+++ b/src/tools/clippy/tests/ui/redundant_locals.rs
@@ -117,6 +117,14 @@ fn macros() {
         let x = 1;
         let x = x;
     }
+
+    let x = 10;
+    macro_rules! rebind_outer_macro {
+        ($x:ident) => {
+            let x = x;
+        };
+    }
+    rebind_outer_macro!(y);
 }
 
 struct WithDrop(usize);
diff --git a/src/tools/clippy/tests/ui/redundant_locals.stderr b/src/tools/clippy/tests/ui/redundant_locals.stderr
index d794a87fe7d..30ab4aa2ea9 100644
--- a/src/tools/clippy/tests/ui/redundant_locals.stderr
+++ b/src/tools/clippy/tests/ui/redundant_locals.stderr
@@ -157,13 +157,13 @@ LL |     let x = 1;
    |         ^
 
 error: redundant redefinition of a binding `a`
-  --> $DIR/redundant_locals.rs:144:5
+  --> $DIR/redundant_locals.rs:152:5
    |
 LL |     let a = a;
    |     ^^^^^^^^^^
    |
 help: `a` is initially defined here
-  --> $DIR/redundant_locals.rs:142:9
+  --> $DIR/redundant_locals.rs:150:9
    |
 LL |     let a = WithoutDrop(1);
    |         ^
diff --git a/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.rs b/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.rs
index e25609f7560..51fe346d092 100644
--- a/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.rs
+++ b/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.rs
@@ -1,4 +1,5 @@
 #![warn(clippy::rest_pat_in_fully_bound_structs)]
+#![allow(clippy::struct_field_names)]
 
 struct A {
     a: i32,
diff --git a/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr b/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr
index 2c221b4dbb2..a62f1d0b65f 100644
--- a/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr
+++ b/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr
@@ -1,5 +1,5 @@
 error: unnecessary use of `..` pattern in struct binding. All fields were already bound
-  --> $DIR/rest_pat_in_fully_bound_structs.rs:22:9
+  --> $DIR/rest_pat_in_fully_bound_structs.rs:23:9
    |
 LL |         A { a: 5, b: 42, c: "", .. } => {}, // Lint
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -9,7 +9,7 @@ LL |         A { a: 5, b: 42, c: "", .. } => {}, // Lint
    = help: to override `-D warnings` add `#[allow(clippy::rest_pat_in_fully_bound_structs)]`
 
 error: unnecessary use of `..` pattern in struct binding. All fields were already bound
-  --> $DIR/rest_pat_in_fully_bound_structs.rs:24:9
+  --> $DIR/rest_pat_in_fully_bound_structs.rs:25:9
    |
 LL |         A { a: 0, b: 0, c: "", .. } => {}, // Lint
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -17,7 +17,7 @@ LL |         A { a: 0, b: 0, c: "", .. } => {}, // Lint
    = help: consider removing `..` from this binding
 
 error: unnecessary use of `..` pattern in struct binding. All fields were already bound
-  --> $DIR/rest_pat_in_fully_bound_structs.rs:31:9
+  --> $DIR/rest_pat_in_fully_bound_structs.rs:32:9
    |
 LL |         A { a: 0, b: 0, c: "", .. } => {}, // Lint
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/struct_fields.rs b/src/tools/clippy/tests/ui/struct_fields.rs
new file mode 100644
index 00000000000..8b1a1446e3c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/struct_fields.rs
@@ -0,0 +1,331 @@
+//@aux-build:proc_macros.rs
+
+#![warn(clippy::struct_field_names)]
+#![allow(unused)]
+
+#[macro_use]
+extern crate proc_macros;
+
+struct Data1 {
+    field_data1: u8,
+    //~^ ERROR: field name ends with the struct's name
+    another: u8,
+    foo: u8,
+    bar: u8,
+}
+
+struct Data2 {
+    another: u8,
+    foo: u8,
+    data2_field: u8,
+    //~^ ERROR: field name starts with the struct's name
+    bar: u8,
+}
+
+struct StructData {
+    //~^ ERROR: all fields have the same postfix: `data`
+    movable_data: u8,
+    fixed_data: u8,
+    invisible_data: u8,
+}
+
+struct DataStruct {
+    //~^ ERROR: all fields have the same prefix: `data`
+    data_movable: u8,
+    data_fixed: u8,
+    data_invisible: u8,
+}
+
+struct DoublePrefix {
+    //~^ ERROR: all fields have the same prefix: `some_data`
+    some_data_a: bool,
+    some_data_b: bool,
+    some_data_c: bool,
+}
+
+struct DoublePostfix {
+    //~^ ERROR: all fields have the same postfix: `some_data`
+    a_some_data: bool,
+    b_some_data: bool,
+    c_some_data: bool,
+}
+
+#[allow(non_snake_case)]
+struct NotSnakeCase {
+    //~^ ERROR: all fields have the same postfix: `someData`
+    a_someData: bool,
+    b_someData: bool,
+    c_someData: bool,
+}
+#[allow(non_snake_case)]
+struct NotSnakeCase2 {
+    //~^ ERROR: all fields have the same prefix: `someData`
+    someData_c: bool,
+    someData_b: bool,
+    someData_a_b: bool,
+}
+
+// no error, threshold is 3 fiels by default
+struct Fooo {
+    foo: u8,
+    bar: u8,
+}
+
+struct NonCaps {
+    //~^ ERROR: all fields have the same prefix: `prefix`
+    prefix_的: u8,
+    prefix_tea: u8,
+    prefix_cake: u8,
+}
+
+// should not lint
+#[allow(clippy::struct_field_names)]
+pub mod allowed {
+    pub struct PubAllowed {
+        some_this: u8,
+        some_that: u8,
+        some_other_what: u8,
+    }
+}
+
+// should not lint
+struct SomeData {
+    foo: u8,
+    bar: bool,
+    path: u8,
+    answer: u8,
+}
+
+// should not lint
+pub struct NetworkLayer {
+    layer1: Vec<u8>,
+    layer2: Vec<u8>,
+    layer3: Vec<u8>,
+    layer4: Vec<u8>,
+}
+
+//should not lint
+struct North {
+    normal: u8,
+    no_left: u8,
+    no_right: u8,
+}
+
+mod issue8324_from_enum_variant_names {
+    // 8324: enum_variant_names warns even if removing the suffix would leave an empty string
+    struct Phase {
+        pre_lookup: u8,
+        lookup: u8,
+        post_lookup: u8,
+    }
+}
+
+mod issue9018_from_enum_variant_names {
+    struct DoLint {
+        //~^ ERROR: all fields have the same prefix: `_type`
+        _type_create: u8,
+        _type_read: u8,
+        _type_update: u8,
+        _type_destroy: u8,
+    }
+
+    struct DoLint2 {
+        //~^ ERROR: all fields have the same prefix: `__type`
+        __type_create: u8,
+        __type_read: u8,
+        __type_update: u8,
+        __type_destroy: u8,
+    }
+
+    struct DoLint3 {
+        //~^ ERROR: all fields have the same prefix: `___type`
+        ___type_create: u8,
+        ___type_read: u8,
+        ___type_update: u8,
+        ___type_destroy: u8,
+    }
+
+    struct DoLint4 {
+        //~^ ERROR: all fields have the same postfix: `_`
+        create_: u8,
+        read_: u8,
+        update_: u8,
+        destroy_: u8,
+    }
+
+    struct DoLint5 {
+        //~^ ERROR: all fields have the same postfix: `__`
+        create__: u8,
+        read__: u8,
+        update__: u8,
+        destroy__: u8,
+    }
+
+    struct DoLint6 {
+        //~^ ERROR: all fields have the same postfix: `___`
+        create___: u8,
+        read___: u8,
+        update___: u8,
+        destroy___: u8,
+    }
+
+    struct DoLintToo {
+        //~^ ERROR: all fields have the same postfix: `type`
+        _create_type: u8,
+        _update_type: u8,
+        _delete_type: u8,
+    }
+
+    struct DoNotLint {
+        _foo: u8,
+        _bar: u8,
+        _baz: u8,
+    }
+
+    struct DoNotLint2 {
+        __foo: u8,
+        __bar: u8,
+        __baz: u8,
+    }
+}
+
+mod allow_attributes_on_fields {
+    struct Struct {
+        #[allow(clippy::struct_field_names)]
+        struct_starts_with: u8,
+        #[allow(clippy::struct_field_names)]
+        ends_with_struct: u8,
+        foo: u8,
+    }
+}
+
+// food field should not lint
+struct Foo {
+    food: i32,
+    a: i32,
+    b: i32,
+}
+
+struct Proxy {
+    proxy: i32,
+    //~^ ERROR: field name starts with the struct's name
+    unrelated1: bool,
+    unrelated2: bool,
+}
+
+// should not lint
+pub struct RegexT {
+    __buffer: i32,
+    __allocated: i32,
+    __used: i32,
+}
+
+mod macro_tests {
+    macro_rules! mk_struct {
+        () => {
+            struct MacroStruct {
+                some_a: i32,
+                some_b: i32,
+                some_c: i32,
+            }
+        };
+    }
+    mk_struct!();
+    //~^ ERROR: all fields have the same prefix: `some`
+
+    macro_rules! mk_struct2 {
+        () => {
+            struct Macrobaz {
+                macrobaz_a: i32,
+                some_b: i32,
+                some_c: i32,
+            }
+        };
+    }
+    mk_struct2!();
+    //~^ ERROR: field name starts with the struct's name
+
+    macro_rules! mk_struct_with_names {
+        ($struct_name:ident, $field:ident) => {
+            struct $struct_name {
+                $field: i32,
+                other_something: i32,
+                other_field: i32,
+            }
+        };
+    }
+    // expands to `struct Foo { foo: i32, ... }`
+    mk_struct_with_names!(Foo, foo);
+    //~^ ERROR: field name starts with the struct's name
+
+    // expands to a struct with all fields starting with `other` but should not
+    // be linted because some fields come from the macro definition and the other from the input
+    mk_struct_with_names!(Some, other_data);
+
+    // should not lint when names come from different places
+    macro_rules! mk_struct_with_field_name {
+        ($field_name:ident) => {
+            struct Baz {
+                one: i32,
+                two: i32,
+                $field_name: i32,
+            }
+        };
+    }
+    mk_struct_with_field_name!(baz_three);
+
+    // should not lint when names come from different places
+    macro_rules! mk_struct_with_field_name {
+        ($field_name:ident) => {
+            struct Bazilisk {
+                baz_one: i32,
+                baz_two: i32,
+                $field_name: i32,
+            }
+        };
+    }
+    mk_struct_with_field_name!(baz_three);
+
+    macro_rules! mk_struct_full_def {
+        ($struct_name:ident, $field1:ident, $field2:ident, $field3:ident) => {
+            struct $struct_name {
+                $field1: i32,
+                $field2: i32,
+                $field3: i32,
+            }
+        };
+    }
+    mk_struct_full_def!(PrefixData, some_data, some_meta, some_other);
+    //~^ ERROR: all fields have the same prefix: `some`
+}
+
+// should not lint on external code
+external! {
+    struct DataExternal {
+        field_data1: u8,
+        another: u8,
+        foo: u8,
+        bar: u8,
+    }
+
+    struct NotSnakeCaseExternal {
+        someData_c: bool,
+        someData_b: bool,
+        someData_a_b: bool,
+    }
+
+    struct DoublePrefixExternal {
+        some_data_a: bool,
+        some_data_b: bool,
+        some_data_c: bool,
+    }
+
+    struct StructDataExternal {
+        movable_data: u8,
+        fixed_data: u8,
+        invisible_data: u8,
+    }
+
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/struct_fields.stderr b/src/tools/clippy/tests/ui/struct_fields.stderr
new file mode 100644
index 00000000000..4ca57715b18
--- /dev/null
+++ b/src/tools/clippy/tests/ui/struct_fields.stderr
@@ -0,0 +1,265 @@
+error: field name ends with the struct's name
+  --> $DIR/struct_fields.rs:10:5
+   |
+LL |     field_data1: u8,
+   |     ^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::struct-field-names` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::struct_field_names)]`
+
+error: field name starts with the struct's name
+  --> $DIR/struct_fields.rs:20:5
+   |
+LL |     data2_field: u8,
+   |     ^^^^^^^^^^^^^^^
+
+error: all fields have the same postfix: `data`
+  --> $DIR/struct_fields.rs:25:1
+   |
+LL | / struct StructData {
+LL | |
+LL | |     movable_data: u8,
+LL | |     fixed_data: u8,
+LL | |     invisible_data: u8,
+LL | | }
+   | |_^
+   |
+   = help: remove the postfixes
+
+error: all fields have the same prefix: `data`
+  --> $DIR/struct_fields.rs:32:1
+   |
+LL | / struct DataStruct {
+LL | |
+LL | |     data_movable: u8,
+LL | |     data_fixed: u8,
+LL | |     data_invisible: u8,
+LL | | }
+   | |_^
+   |
+   = help: remove the prefixes
+
+error: all fields have the same prefix: `some_data`
+  --> $DIR/struct_fields.rs:39:1
+   |
+LL | / struct DoublePrefix {
+LL | |
+LL | |     some_data_a: bool,
+LL | |     some_data_b: bool,
+LL | |     some_data_c: bool,
+LL | | }
+   | |_^
+   |
+   = help: remove the prefixes
+
+error: all fields have the same postfix: `some_data`
+  --> $DIR/struct_fields.rs:46:1
+   |
+LL | / struct DoublePostfix {
+LL | |
+LL | |     a_some_data: bool,
+LL | |     b_some_data: bool,
+LL | |     c_some_data: bool,
+LL | | }
+   | |_^
+   |
+   = help: remove the postfixes
+
+error: all fields have the same postfix: `someData`
+  --> $DIR/struct_fields.rs:54:1
+   |
+LL | / struct NotSnakeCase {
+LL | |
+LL | |     a_someData: bool,
+LL | |     b_someData: bool,
+LL | |     c_someData: bool,
+LL | | }
+   | |_^
+   |
+   = help: remove the postfixes
+
+error: all fields have the same prefix: `someData`
+  --> $DIR/struct_fields.rs:61:1
+   |
+LL | / struct NotSnakeCase2 {
+LL | |
+LL | |     someData_c: bool,
+LL | |     someData_b: bool,
+LL | |     someData_a_b: bool,
+LL | | }
+   | |_^
+   |
+   = help: remove the prefixes
+
+error: all fields have the same prefix: `prefix`
+  --> $DIR/struct_fields.rs:74:1
+   |
+LL | / struct NonCaps {
+LL | |
+LL | |     prefix_的: u8,
+LL | |     prefix_tea: u8,
+LL | |     prefix_cake: u8,
+LL | | }
+   | |_^
+   |
+   = help: remove the prefixes
+
+error: all fields have the same prefix: `_type`
+  --> $DIR/struct_fields.rs:124:5
+   |
+LL | /     struct DoLint {
+LL | |
+LL | |         _type_create: u8,
+LL | |         _type_read: u8,
+LL | |         _type_update: u8,
+LL | |         _type_destroy: u8,
+LL | |     }
+   | |_____^
+   |
+   = help: remove the prefixes
+
+error: all fields have the same prefix: `__type`
+  --> $DIR/struct_fields.rs:132:5
+   |
+LL | /     struct DoLint2 {
+LL | |
+LL | |         __type_create: u8,
+LL | |         __type_read: u8,
+LL | |         __type_update: u8,
+LL | |         __type_destroy: u8,
+LL | |     }
+   | |_____^
+   |
+   = help: remove the prefixes
+
+error: all fields have the same prefix: `___type`
+  --> $DIR/struct_fields.rs:140:5
+   |
+LL | /     struct DoLint3 {
+LL | |
+LL | |         ___type_create: u8,
+LL | |         ___type_read: u8,
+LL | |         ___type_update: u8,
+LL | |         ___type_destroy: u8,
+LL | |     }
+   | |_____^
+   |
+   = help: remove the prefixes
+
+error: all fields have the same postfix: `_`
+  --> $DIR/struct_fields.rs:148:5
+   |
+LL | /     struct DoLint4 {
+LL | |
+LL | |         create_: u8,
+LL | |         read_: u8,
+LL | |         update_: u8,
+LL | |         destroy_: u8,
+LL | |     }
+   | |_____^
+   |
+   = help: remove the postfixes
+
+error: all fields have the same postfix: `__`
+  --> $DIR/struct_fields.rs:156:5
+   |
+LL | /     struct DoLint5 {
+LL | |
+LL | |         create__: u8,
+LL | |         read__: u8,
+LL | |         update__: u8,
+LL | |         destroy__: u8,
+LL | |     }
+   | |_____^
+   |
+   = help: remove the postfixes
+
+error: all fields have the same postfix: `___`
+  --> $DIR/struct_fields.rs:164:5
+   |
+LL | /     struct DoLint6 {
+LL | |
+LL | |         create___: u8,
+LL | |         read___: u8,
+LL | |         update___: u8,
+LL | |         destroy___: u8,
+LL | |     }
+   | |_____^
+   |
+   = help: remove the postfixes
+
+error: all fields have the same postfix: `type`
+  --> $DIR/struct_fields.rs:172:5
+   |
+LL | /     struct DoLintToo {
+LL | |
+LL | |         _create_type: u8,
+LL | |         _update_type: u8,
+LL | |         _delete_type: u8,
+LL | |     }
+   | |_____^
+   |
+   = help: remove the postfixes
+
+error: field name starts with the struct's name
+  --> $DIR/struct_fields.rs:210:5
+   |
+LL |     proxy: i32,
+   |     ^^^^^^^^^^
+
+error: all fields have the same prefix: `some`
+  --> $DIR/struct_fields.rs:226:13
+   |
+LL | /             struct MacroStruct {
+LL | |                 some_a: i32,
+LL | |                 some_b: i32,
+LL | |                 some_c: i32,
+LL | |             }
+   | |_____________^
+...
+LL |       mk_struct!();
+   |       ------------ in this macro invocation
+   |
+   = help: remove the prefixes
+   = note: this error originates in the macro `mk_struct` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: field name starts with the struct's name
+  --> $DIR/struct_fields.rs:239:17
+   |
+LL |                 macrobaz_a: i32,
+   |                 ^^^^^^^^^^^^^^^
+...
+LL |     mk_struct2!();
+   |     ------------- in this macro invocation
+   |
+   = note: this error originates in the macro `mk_struct2` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: field name starts with the struct's name
+  --> $DIR/struct_fields.rs:251:17
+   |
+LL |                 $field: i32,
+   |                 ^^^^^^^^^^^
+...
+LL |     mk_struct_with_names!(Foo, foo);
+   |     ------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `mk_struct_with_names` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: all fields have the same prefix: `some`
+  --> $DIR/struct_fields.rs:291:13
+   |
+LL | /             struct $struct_name {
+LL | |                 $field1: i32,
+LL | |                 $field2: i32,
+LL | |                 $field3: i32,
+LL | |             }
+   | |_____________^
+...
+LL |       mk_struct_full_def!(PrefixData, some_data, some_meta, some_other);
+   |       ----------------------------------------------------------------- in this macro invocation
+   |
+   = help: remove the prefixes
+   = note: this error originates in the macro `mk_struct_full_def` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 21 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed
index 304e7b7fd7f..4778eaefdbd 100644
--- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed
@@ -5,6 +5,7 @@
 #![allow(clippy::map_identity)]
 #![allow(clippy::needless_borrow)]
 #![allow(clippy::unnecessary_literal_unwrap)]
+#![allow(clippy::unit_arg)]
 
 use std::ops::Deref;
 
@@ -76,6 +77,8 @@ fn main() {
     let _ = opt.ok_or(2);
     let _ = nested_tuple_opt.unwrap_or(Some((1, 2)));
     let _ = cond.then_some(astronomers_pi);
+    let _ = true.then_some({});
+    let _ = true.then_some({});
 
     // Should lint - Builtin deref
     let r = &1;
diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs
index ddfa6bb3ef6..d4b7fd31b1b 100644
--- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs
@@ -5,6 +5,7 @@
 #![allow(clippy::map_identity)]
 #![allow(clippy::needless_borrow)]
 #![allow(clippy::unnecessary_literal_unwrap)]
+#![allow(clippy::unit_arg)]
 
 use std::ops::Deref;
 
@@ -76,6 +77,8 @@ fn main() {
     let _ = opt.ok_or_else(|| 2);
     let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2)));
     let _ = cond.then(|| astronomers_pi);
+    let _ = true.then(|| -> _ {});
+    let _ = true.then(|| {});
 
     // Should lint - Builtin deref
     let r = &1;
diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr
index 4f1ca374872..1b0db4759bb 100644
--- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr
@@ -1,5 +1,5 @@
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:68:13
+  --> $DIR/unnecessary_lazy_eval.rs:69:13
    |
 LL |     let _ = opt.unwrap_or_else(|| 2);
    |             ^^^^--------------------
@@ -10,7 +10,7 @@ LL |     let _ = opt.unwrap_or_else(|| 2);
    = help: to override `-D warnings` add `#[allow(clippy::unnecessary_lazy_evaluations)]`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:69:13
+  --> $DIR/unnecessary_lazy_eval.rs:70:13
    |
 LL |     let _ = opt.unwrap_or_else(|| astronomers_pi);
    |             ^^^^---------------------------------
@@ -18,7 +18,7 @@ LL |     let _ = opt.unwrap_or_else(|| astronomers_pi);
    |                 help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:70:13
+  --> $DIR/unnecessary_lazy_eval.rs:71:13
    |
 LL |     let _ = opt.unwrap_or_else(|| ext_str.some_field);
    |             ^^^^-------------------------------------
@@ -26,7 +26,7 @@ LL |     let _ = opt.unwrap_or_else(|| ext_str.some_field);
    |                 help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:72:13
+  --> $DIR/unnecessary_lazy_eval.rs:73:13
    |
 LL |     let _ = opt.and_then(|_| ext_opt);
    |             ^^^^---------------------
@@ -34,7 +34,7 @@ LL |     let _ = opt.and_then(|_| ext_opt);
    |                 help: use `and(..)` instead: `and(ext_opt)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:73:13
+  --> $DIR/unnecessary_lazy_eval.rs:74:13
    |
 LL |     let _ = opt.or_else(|| ext_opt);
    |             ^^^^-------------------
@@ -42,7 +42,7 @@ LL |     let _ = opt.or_else(|| ext_opt);
    |                 help: use `or(..)` instead: `or(ext_opt)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:74:13
+  --> $DIR/unnecessary_lazy_eval.rs:75:13
    |
 LL |     let _ = opt.or_else(|| None);
    |             ^^^^----------------
@@ -50,7 +50,7 @@ LL |     let _ = opt.or_else(|| None);
    |                 help: use `or(..)` instead: `or(None)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:75:13
+  --> $DIR/unnecessary_lazy_eval.rs:76:13
    |
 LL |     let _ = opt.get_or_insert_with(|| 2);
    |             ^^^^------------------------
@@ -58,7 +58,7 @@ LL |     let _ = opt.get_or_insert_with(|| 2);
    |                 help: use `get_or_insert(..)` instead: `get_or_insert(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:76:13
+  --> $DIR/unnecessary_lazy_eval.rs:77:13
    |
 LL |     let _ = opt.ok_or_else(|| 2);
    |             ^^^^----------------
@@ -66,7 +66,7 @@ LL |     let _ = opt.ok_or_else(|| 2);
    |                 help: use `ok_or(..)` instead: `ok_or(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:77:13
+  --> $DIR/unnecessary_lazy_eval.rs:78:13
    |
 LL |     let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2)));
    |             ^^^^^^^^^^^^^^^^^-------------------------------
@@ -74,15 +74,31 @@ LL |     let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2)));
    |                              help: use `unwrap_or(..)` instead: `unwrap_or(Some((1, 2)))`
 
 error: unnecessary closure used with `bool::then`
-  --> $DIR/unnecessary_lazy_eval.rs:78:13
+  --> $DIR/unnecessary_lazy_eval.rs:79:13
    |
 LL |     let _ = cond.then(|| astronomers_pi);
    |             ^^^^^-----------------------
    |                  |
    |                  help: use `then_some(..)` instead: `then_some(astronomers_pi)`
 
+error: unnecessary closure used with `bool::then`
+  --> $DIR/unnecessary_lazy_eval.rs:80:13
+   |
+LL |     let _ = true.then(|| -> _ {});
+   |             ^^^^^----------------
+   |                  |
+   |                  help: use `then_some(..)` instead: `then_some({})`
+
+error: unnecessary closure used with `bool::then`
+  --> $DIR/unnecessary_lazy_eval.rs:81:13
+   |
+LL |     let _ = true.then(|| {});
+   |             ^^^^^-----------
+   |                  |
+   |                  help: use `then_some(..)` instead: `then_some({})`
+
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:82:13
+  --> $DIR/unnecessary_lazy_eval.rs:85:13
    |
 LL |     let _ = Some(1).unwrap_or_else(|| *r);
    |             ^^^^^^^^---------------------
@@ -90,7 +106,7 @@ LL |     let _ = Some(1).unwrap_or_else(|| *r);
    |                     help: use `unwrap_or(..)` instead: `unwrap_or(*r)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:84:13
+  --> $DIR/unnecessary_lazy_eval.rs:87:13
    |
 LL |     let _ = Some(1).unwrap_or_else(|| *b);
    |             ^^^^^^^^---------------------
@@ -98,7 +114,7 @@ LL |     let _ = Some(1).unwrap_or_else(|| *b);
    |                     help: use `unwrap_or(..)` instead: `unwrap_or(*b)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:86:13
+  --> $DIR/unnecessary_lazy_eval.rs:89:13
    |
 LL |     let _ = Some(1).as_ref().unwrap_or_else(|| &r);
    |             ^^^^^^^^^^^^^^^^^---------------------
@@ -106,7 +122,7 @@ LL |     let _ = Some(1).as_ref().unwrap_or_else(|| &r);
    |                              help: use `unwrap_or(..)` instead: `unwrap_or(&r)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:87:13
+  --> $DIR/unnecessary_lazy_eval.rs:90:13
    |
 LL |     let _ = Some(1).as_ref().unwrap_or_else(|| &b);
    |             ^^^^^^^^^^^^^^^^^---------------------
@@ -114,7 +130,7 @@ LL |     let _ = Some(1).as_ref().unwrap_or_else(|| &b);
    |                              help: use `unwrap_or(..)` instead: `unwrap_or(&b)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:90:13
+  --> $DIR/unnecessary_lazy_eval.rs:93:13
    |
 LL |     let _ = Some(10).unwrap_or_else(|| 2);
    |             ^^^^^^^^^--------------------
@@ -122,7 +138,7 @@ LL |     let _ = Some(10).unwrap_or_else(|| 2);
    |                      help: use `unwrap_or(..)` instead: `unwrap_or(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:91:13
+  --> $DIR/unnecessary_lazy_eval.rs:94:13
    |
 LL |     let _ = Some(10).and_then(|_| ext_opt);
    |             ^^^^^^^^^---------------------
@@ -130,7 +146,7 @@ LL |     let _ = Some(10).and_then(|_| ext_opt);
    |                      help: use `and(..)` instead: `and(ext_opt)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:92:28
+  --> $DIR/unnecessary_lazy_eval.rs:95:28
    |
 LL |     let _: Option<usize> = None.or_else(|| ext_opt);
    |                            ^^^^^-------------------
@@ -138,7 +154,7 @@ LL |     let _: Option<usize> = None.or_else(|| ext_opt);
    |                                 help: use `or(..)` instead: `or(ext_opt)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:93:13
+  --> $DIR/unnecessary_lazy_eval.rs:96:13
    |
 LL |     let _ = None.get_or_insert_with(|| 2);
    |             ^^^^^------------------------
@@ -146,7 +162,7 @@ LL |     let _ = None.get_or_insert_with(|| 2);
    |                  help: use `get_or_insert(..)` instead: `get_or_insert(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:94:35
+  --> $DIR/unnecessary_lazy_eval.rs:97:35
    |
 LL |     let _: Result<usize, usize> = None.ok_or_else(|| 2);
    |                                   ^^^^^----------------
@@ -154,7 +170,7 @@ LL |     let _: Result<usize, usize> = None.ok_or_else(|| 2);
    |                                        help: use `ok_or(..)` instead: `ok_or(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:95:28
+  --> $DIR/unnecessary_lazy_eval.rs:98:28
    |
 LL |     let _: Option<usize> = None.or_else(|| None);
    |                            ^^^^^----------------
@@ -162,7 +178,7 @@ LL |     let _: Option<usize> = None.or_else(|| None);
    |                                 help: use `or(..)` instead: `or(None)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:98:13
+  --> $DIR/unnecessary_lazy_eval.rs:101:13
    |
 LL |     let _ = deep.0.unwrap_or_else(|| 2);
    |             ^^^^^^^--------------------
@@ -170,7 +186,7 @@ LL |     let _ = deep.0.unwrap_or_else(|| 2);
    |                    help: use `unwrap_or(..)` instead: `unwrap_or(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:99:13
+  --> $DIR/unnecessary_lazy_eval.rs:102:13
    |
 LL |     let _ = deep.0.and_then(|_| ext_opt);
    |             ^^^^^^^---------------------
@@ -178,7 +194,7 @@ LL |     let _ = deep.0.and_then(|_| ext_opt);
    |                    help: use `and(..)` instead: `and(ext_opt)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:100:13
+  --> $DIR/unnecessary_lazy_eval.rs:103:13
    |
 LL |     let _ = deep.0.or_else(|| None);
    |             ^^^^^^^----------------
@@ -186,7 +202,7 @@ LL |     let _ = deep.0.or_else(|| None);
    |                    help: use `or(..)` instead: `or(None)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:101:13
+  --> $DIR/unnecessary_lazy_eval.rs:104:13
    |
 LL |     let _ = deep.0.get_or_insert_with(|| 2);
    |             ^^^^^^^------------------------
@@ -194,7 +210,7 @@ LL |     let _ = deep.0.get_or_insert_with(|| 2);
    |                    help: use `get_or_insert(..)` instead: `get_or_insert(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:102:13
+  --> $DIR/unnecessary_lazy_eval.rs:105:13
    |
 LL |     let _ = deep.0.ok_or_else(|| 2);
    |             ^^^^^^^----------------
@@ -202,7 +218,7 @@ LL |     let _ = deep.0.ok_or_else(|| 2);
    |                    help: use `ok_or(..)` instead: `ok_or(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:132:28
+  --> $DIR/unnecessary_lazy_eval.rs:135:28
    |
 LL |     let _: Option<usize> = None.or_else(|| Some(3));
    |                            ^^^^^-------------------
@@ -210,7 +226,7 @@ LL |     let _: Option<usize> = None.or_else(|| Some(3));
    |                                 help: use `or(..)` instead: `or(Some(3))`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:133:13
+  --> $DIR/unnecessary_lazy_eval.rs:136:13
    |
 LL |     let _ = deep.0.or_else(|| Some(3));
    |             ^^^^^^^-------------------
@@ -218,7 +234,7 @@ LL |     let _ = deep.0.or_else(|| Some(3));
    |                    help: use `or(..)` instead: `or(Some(3))`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:134:13
+  --> $DIR/unnecessary_lazy_eval.rs:137:13
    |
 LL |     let _ = opt.or_else(|| Some(3));
    |             ^^^^-------------------
@@ -226,7 +242,7 @@ LL |     let _ = opt.or_else(|| Some(3));
    |                 help: use `or(..)` instead: `or(Some(3))`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:140:13
+  --> $DIR/unnecessary_lazy_eval.rs:143:13
    |
 LL |     let _ = res2.unwrap_or_else(|_| 2);
    |             ^^^^^---------------------
@@ -234,7 +250,7 @@ LL |     let _ = res2.unwrap_or_else(|_| 2);
    |                  help: use `unwrap_or(..)` instead: `unwrap_or(2)`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:141:13
+  --> $DIR/unnecessary_lazy_eval.rs:144:13
    |
 LL |     let _ = res2.unwrap_or_else(|_| astronomers_pi);
    |             ^^^^^----------------------------------
@@ -242,7 +258,7 @@ LL |     let _ = res2.unwrap_or_else(|_| astronomers_pi);
    |                  help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:142:13
+  --> $DIR/unnecessary_lazy_eval.rs:145:13
    |
 LL |     let _ = res2.unwrap_or_else(|_| ext_str.some_field);
    |             ^^^^^--------------------------------------
@@ -250,7 +266,7 @@ LL |     let _ = res2.unwrap_or_else(|_| ext_str.some_field);
    |                  help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:164:35
+  --> $DIR/unnecessary_lazy_eval.rs:167:35
    |
 LL |     let _: Result<usize, usize> = res.and_then(|_| Err(2));
    |                                   ^^^^--------------------
@@ -258,7 +274,7 @@ LL |     let _: Result<usize, usize> = res.and_then(|_| Err(2));
    |                                       help: use `and(..)` instead: `and(Err(2))`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:165:35
+  --> $DIR/unnecessary_lazy_eval.rs:168:35
    |
 LL |     let _: Result<usize, usize> = res.and_then(|_| Err(astronomers_pi));
    |                                   ^^^^---------------------------------
@@ -266,7 +282,7 @@ LL |     let _: Result<usize, usize> = res.and_then(|_| Err(astronomers_pi));
    |                                       help: use `and(..)` instead: `and(Err(astronomers_pi))`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:166:35
+  --> $DIR/unnecessary_lazy_eval.rs:169:35
    |
 LL |     let _: Result<usize, usize> = res.and_then(|_| Err(ext_str.some_field));
    |                                   ^^^^-------------------------------------
@@ -274,7 +290,7 @@ LL |     let _: Result<usize, usize> = res.and_then(|_| Err(ext_str.some_field))
    |                                       help: use `and(..)` instead: `and(Err(ext_str.some_field))`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:168:35
+  --> $DIR/unnecessary_lazy_eval.rs:171:35
    |
 LL |     let _: Result<usize, usize> = res.or_else(|_| Ok(2));
    |                                   ^^^^------------------
@@ -282,7 +298,7 @@ LL |     let _: Result<usize, usize> = res.or_else(|_| Ok(2));
    |                                       help: use `or(..)` instead: `or(Ok(2))`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:169:35
+  --> $DIR/unnecessary_lazy_eval.rs:172:35
    |
 LL |     let _: Result<usize, usize> = res.or_else(|_| Ok(astronomers_pi));
    |                                   ^^^^-------------------------------
@@ -290,7 +306,7 @@ LL |     let _: Result<usize, usize> = res.or_else(|_| Ok(astronomers_pi));
    |                                       help: use `or(..)` instead: `or(Ok(astronomers_pi))`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:170:35
+  --> $DIR/unnecessary_lazy_eval.rs:173:35
    |
 LL |     let _: Result<usize, usize> = res.or_else(|_| Ok(ext_str.some_field));
    |                                   ^^^^-----------------------------------
@@ -298,7 +314,7 @@ LL |     let _: Result<usize, usize> = res.or_else(|_| Ok(ext_str.some_field));
    |                                       help: use `or(..)` instead: `or(Ok(ext_str.some_field))`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:171:35
+  --> $DIR/unnecessary_lazy_eval.rs:174:35
    |
 LL |       let _: Result<usize, usize> = res.
    |  ___________________________________^
@@ -312,5 +328,5 @@ LL | |     or_else(|_| Ok(ext_str.some_field));
    |       |
    |       help: use `or(..)` instead: `or(Ok(ext_str.some_field))`
 
-error: aborting due to 38 previous errors
+error: aborting due to 40 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.rs b/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.rs
index 33685bfb738..412d4aaafb4 100644
--- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.rs
@@ -25,3 +25,8 @@ fn main() {
     let arr = [(Some(1),)];
     Some(&0).and_then(|&i| arr[i].0);
 }
+
+fn issue11672() {
+    // Return type annotation helps type inference and removing it can break code
+    let _ = true.then(|| -> &[u8] { &[] });
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.stderr b/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.stderr
index 27fa560d4d7..95b02be91ca 100644
--- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.stderr
@@ -25,5 +25,13 @@ LL |     let _ = Ok(1).unwrap_or_else(|SomeStruct { .. }| 2);
    |                   |
    |                   help: use `unwrap_or(..)` instead: `unwrap_or(2)`
 
-error: aborting due to 3 previous errors
+error: unnecessary closure used with `bool::then`
+  --> $DIR/unnecessary_lazy_eval_unfixable.rs:31:13
+   |
+LL |     let _ = true.then(|| -> &[u8] { &[] });
+   |             ^^^^^-------------------------
+   |                  |
+   |                  help: use `then_some(..)` instead: `then_some({ &[] })`
+
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml
index 6856bb0ab37..419b3c30deb 100644
--- a/src/tools/clippy/triagebot.toml
+++ b/src/tools/clippy/triagebot.toml
@@ -11,6 +11,8 @@ allow-unauthenticated = [
 
 # Have rustbot inform users about the *No Merge Policy*
 [no-merges]
+exclude_titles = ["Rustup"] # exclude syncs from rust-lang/rust
+labels = ["has-merge-commits", "S-waiting-on-author"]
 
 [autolabel."S-waiting-on-review"]
 new_pr = true
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index bc3882bcf2b..0335ad3c1d8 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-249624b5043013d18c00f0401ca431c1a6baa8cd
+9e3f784eb2c7c847b6c3578b373c0e0bc9233ca3
diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs
index 08b26f5fe85..48dafc40c62 100644
--- a/src/tools/miri/src/shims/backtrace.rs
+++ b/src/tools/miri/src/shims/backtrace.rs
@@ -37,7 +37,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         let this = self.eval_context_mut();
         let tcx = this.tcx;
 
-        let flags = if let Some(flags_op) = args.get(0) {
+        let flags = if let Some(flags_op) = args.first() {
             this.read_scalar(flags_op)?.to_u64()?
         } else {
             throw_ub_format!("expected at least 1 argument")
diff --git a/tests/coverage-map/fn_sig_into_try.cov-map b/tests/coverage-map/fn_sig_into_try.cov-map
new file mode 100644
index 00000000000..4672e7c1ce9
--- /dev/null
+++ b/tests/coverage-map/fn_sig_into_try.cov-map
@@ -0,0 +1,53 @@
+Function name: fn_sig_into_try::a
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 01, 04, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 10, 1) to (start + 4, 2)
+
+Function name: fn_sig_into_try::b
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 10, 01, 02, 0f, 00, 02, 0f, 00, 10, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 2
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 16, 1) to (start + 2, 15)
+- Code(Zero) at (prev + 2, 15) to (start + 0, 16)
+- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 12)
+    = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
+    = (c1 + (c0 - c1))
+
+Function name: fn_sig_into_try::c
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 16, 01, 02, 17, 00, 02, 17, 00, 18, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 2
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 22, 1) to (start + 2, 23)
+- Code(Zero) at (prev + 2, 23) to (start + 0, 24)
+- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 12)
+    = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
+    = (c1 + (c0 - c1))
+
+Function name: fn_sig_into_try::d
+Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 1c, 01, 03, 0f, 00, 03, 0f, 00, 10, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 2
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+Number of file 0 mappings: 4
+- Code(Counter(0)) at (prev + 28, 1) to (start + 3, 15)
+- Code(Zero) at (prev + 3, 15) to (start + 0, 16)
+- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 12)
+    = (c0 - c1)
+- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
+    = (c1 + (c0 - c1))
+
diff --git a/tests/coverage-map/fn_sig_into_try.rs b/tests/coverage-map/fn_sig_into_try.rs
new file mode 100644
index 00000000000..92850c8a188
--- /dev/null
+++ b/tests/coverage-map/fn_sig_into_try.rs
@@ -0,0 +1,41 @@
+#![feature(coverage_attribute)]
+// compile-flags: --edition=2021
+
+// Regression test for inconsistent handling of function signature spans that
+// are followed by code using the `?` operator.
+//
+// For each of these similar functions, the line containing the function
+// signature should be handled in the same way.
+
+fn a() -> Option<i32>
+{
+    Some(7i32);
+    Some(0)
+}
+
+fn b() -> Option<i32>
+{
+    Some(7i32)?;
+    Some(0)
+}
+
+fn c() -> Option<i32>
+{
+    let _ = Some(7i32)?;
+    Some(0)
+}
+
+fn d() -> Option<i32>
+{
+    let _: () = ();
+    Some(7i32)?;
+    Some(0)
+}
+
+#[coverage(off)]
+fn main() {
+    a();
+    b();
+    c();
+    d();
+}
diff --git a/tests/coverage-map/status-quo/inline-dead.cov-map b/tests/coverage-map/status-quo/inline-dead.cov-map
index 483f7ef79c6..06b64da5723 100644
--- a/tests/coverage-map/status-quo/inline-dead.cov-map
+++ b/tests/coverage-map/status-quo/inline-dead.cov-map
@@ -31,13 +31,15 @@ Number of file 0 mappings: 2
 - Code(Counter(0)) at (prev + 7, 6) to (start + 2, 2)
 
 Function name: inline_dead::main::{closure#0}
-Raw bytes (16): 0x[01, 01, 01, 01, 05, 02, 00, 09, 0d, 00, 0e, 03, 02, 05, 00, 06]
+Raw bytes (23): 0x[01, 01, 02, 09, 06, 01, 05, 03, 01, 07, 17, 00, 18, 00, 02, 0d, 00, 0e, 03, 02, 05, 00, 06]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 1
-- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-Number of file 0 mappings: 2
-- Code(Zero) at (prev + 9, 13) to (start + 0, 14)
+Number of expressions: 2
+- expression 0 operands: lhs = Counter(2), rhs = Expression(1, Sub)
+- expression 1 operands: lhs = Counter(0), rhs = Counter(1)
+Number of file 0 mappings: 3
+- Code(Counter(0)) at (prev + 7, 23) to (start + 0, 24)
+- Code(Zero) at (prev + 2, 13) to (start + 0, 14)
 - Code(Expression(0, Add)) at (prev + 2, 5) to (start + 0, 6)
-    = (c0 + c1)
+    = (c2 + (c0 - c1))
 
diff --git a/tests/coverage-map/status-quo/issue-84561.cov-map b/tests/coverage-map/status-quo/issue-84561.cov-map
index 01fa7ec573c..76340b1a78c 100644
--- a/tests/coverage-map/status-quo/issue-84561.cov-map
+++ b/tests/coverage-map/status-quo/issue-84561.cov-map
@@ -7,15 +7,15 @@ Number of file 0 mappings: 1
 - Code(Counter(0)) at (prev + 4, 10) to (start + 0, 19)
 
 Function name: <issue_84561::Foo as core::fmt::Debug>::fmt
-Raw bytes (29): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 89, 01, 09, 00, 25, 05, 00, 25, 00, 26, 02, 01, 09, 00, 0f, 07, 01, 05, 00, 06]
+Raw bytes (29): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 88, 01, 05, 01, 25, 05, 01, 25, 00, 26, 02, 01, 09, 00, 0f, 07, 01, 05, 00, 06]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 2
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
 - expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
-- Code(Counter(0)) at (prev + 137, 9) to (start + 0, 37)
-- Code(Counter(1)) at (prev + 0, 37) to (start + 0, 38)
+- Code(Counter(0)) at (prev + 136, 5) to (start + 1, 37)
+- Code(Counter(1)) at (prev + 1, 37) to (start + 0, 38)
 - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 15)
     = (c0 - c1)
 - Code(Expression(1, Add)) at (prev + 1, 5) to (start + 0, 6)
diff --git a/tests/run-coverage/fn_sig_into_try.coverage b/tests/run-coverage/fn_sig_into_try.coverage
new file mode 100644
index 00000000000..f1ddb1da780
--- /dev/null
+++ b/tests/run-coverage/fn_sig_into_try.coverage
@@ -0,0 +1,45 @@
+   LL|       |#![feature(coverage_attribute)]
+   LL|       |// compile-flags: --edition=2021
+   LL|       |
+   LL|       |// Regression test for inconsistent handling of function signature spans that
+   LL|       |// are followed by code using the `?` operator.
+   LL|       |//
+   LL|       |// For each of these similar functions, the line containing the function
+   LL|       |// signature should be handled in the same way.
+   LL|       |
+   LL|      1|fn a() -> Option<i32>
+   LL|      1|{
+   LL|      1|    Some(7i32);
+   LL|      1|    Some(0)
+   LL|      1|}
+   LL|       |
+   LL|      1|fn b() -> Option<i32>
+   LL|      1|{
+   LL|      1|    Some(7i32)?;
+                            ^0
+   LL|      1|    Some(0)
+   LL|      1|}
+   LL|       |
+   LL|      1|fn c() -> Option<i32>
+   LL|      1|{
+   LL|      1|    let _ = Some(7i32)?;
+                                    ^0
+   LL|      1|    Some(0)
+   LL|      1|}
+   LL|       |
+   LL|      1|fn d() -> Option<i32>
+   LL|      1|{
+   LL|      1|    let _: () = ();
+   LL|      1|    Some(7i32)?;
+                            ^0
+   LL|      1|    Some(0)
+   LL|      1|}
+   LL|       |
+   LL|       |#[coverage(off)]
+   LL|       |fn main() {
+   LL|       |    a();
+   LL|       |    b();
+   LL|       |    c();
+   LL|       |    d();
+   LL|       |}
+
diff --git a/tests/run-coverage/fn_sig_into_try.rs b/tests/run-coverage/fn_sig_into_try.rs
new file mode 100644
index 00000000000..92850c8a188
--- /dev/null
+++ b/tests/run-coverage/fn_sig_into_try.rs
@@ -0,0 +1,41 @@
+#![feature(coverage_attribute)]
+// compile-flags: --edition=2021
+
+// Regression test for inconsistent handling of function signature spans that
+// are followed by code using the `?` operator.
+//
+// For each of these similar functions, the line containing the function
+// signature should be handled in the same way.
+
+fn a() -> Option<i32>
+{
+    Some(7i32);
+    Some(0)
+}
+
+fn b() -> Option<i32>
+{
+    Some(7i32)?;
+    Some(0)
+}
+
+fn c() -> Option<i32>
+{
+    let _ = Some(7i32)?;
+    Some(0)
+}
+
+fn d() -> Option<i32>
+{
+    let _: () = ();
+    Some(7i32)?;
+    Some(0)
+}
+
+#[coverage(off)]
+fn main() {
+    a();
+    b();
+    c();
+    d();
+}
diff --git a/tests/run-coverage/issue-84561.coverage b/tests/run-coverage/issue-84561.coverage
index 222f877d36a..e693866e277 100644
--- a/tests/run-coverage/issue-84561.coverage
+++ b/tests/run-coverage/issue-84561.coverage
@@ -135,7 +135,7 @@
    LL|      0|}
    LL|       |
    LL|       |impl std::fmt::Debug for Foo {
-   LL|       |    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+   LL|      7|    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
    LL|      7|        write!(f, "try and succeed")?;
                                                   ^0
    LL|      7|        Ok(())
diff --git a/tests/run-make/unknown-mod-stdin/unknown-mod.stderr b/tests/run-make/unknown-mod-stdin/unknown-mod.stderr
index d7258fe4f68..81ff8393837 100644
--- a/tests/run-make/unknown-mod-stdin/unknown-mod.stderr
+++ b/tests/run-make/unknown-mod-stdin/unknown-mod.stderr
@@ -5,6 +5,7 @@ error[E0583]: file not found for module `unknown`
   | ^^^^^^^^^^^^
   |
   = help: to create the module `unknown`, create file "unknown.rs" or "unknown/mod.rs"
+  = note: if there is a `mod unknown` elsewhere in the crate already, import it with `use crate::...` instead
 
 error: aborting due to previous error
 
diff --git a/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.rs b/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.rs
index 39980ee7c67..aeb68bf05e1 100644
--- a/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.rs
+++ b/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.rs
@@ -1,4 +1,6 @@
 // Test the `rustc::span_use_eq_ctxt` internal lint
+// #[cfg(bootstrap)]
+// ignore-stage1
 // compile-flags: -Z unstable-options
 
 #![feature(rustc_private)]
diff --git a/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.stderr b/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.stderr
index b33f6212545..3d8a7dd1ec0 100644
--- a/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.stderr
+++ b/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.stderr
@@ -1,11 +1,11 @@
 error: use `.eq_ctxt()` instead of `.ctxt() == .ctxt()`
-  --> $DIR/span_use_eq_ctxt.rs:12:5
+  --> $DIR/span_use_eq_ctxt.rs:14:5
    |
 LL |     s.ctxt() == t.ctxt()
    |     ^^^^^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/span_use_eq_ctxt.rs:5:9
+  --> $DIR/span_use_eq_ctxt.rs:7:9
    |
 LL | #![deny(rustc::span_use_eq_ctxt)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui-fulldeps/stable-mir/instance.rs b/tests/ui-fulldeps/stable-mir/check_instance.rs
index fe06d9b5cc9..288c163a6a3 100644
--- a/tests/ui-fulldeps/stable-mir/instance.rs
+++ b/tests/ui-fulldeps/stable-mir/check_instance.rs
@@ -15,7 +15,8 @@ extern crate rustc_smir;
 extern crate stable_mir;
 
 use rustc_middle::ty::TyCtxt;
-
+use mir::{mono::Instance, TerminatorKind::*};
+use stable_mir::ty::{TyKind, RigidTy};
 use stable_mir::*;
 use rustc_smir::rustc_internal;
 use std::io::Write;
@@ -43,9 +44,28 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
     // For all generic items, try_from should fail.
     assert!(generic.iter().all(|item| mir::mono::Instance::try_from(*item).is_err()));
 
+    for instance in instances {
+        test_body(instance.body())
+    }
     ControlFlow::Continue(())
 }
 
+/// Inspect the instance body
+fn test_body(body: mir::Body) {
+    for term in body.blocks.iter().map(|bb| &bb.terminator) {
+        match &term.kind {
+            Call{ func, .. } => {
+                let TyKind::RigidTy(ty) = func.ty(&body.locals).kind() else { unreachable!() };
+                let RigidTy::FnDef(def, args) = ty else { unreachable!() };
+                let result = Instance::resolve(def, &args);
+                assert!(result.is_ok());
+            }
+            Goto {..} | Assert{..} | SwitchInt{..} | Return | Drop {..} => { /* Do nothing */}
+            _ => { unreachable!("Unexpected terminator {term:?}") }
+        }
+    }
+}
+
 
 /// This test will generate and analyze a dummy crate using the stable mir.
 /// For that, it will first write the dummy crate into a file.
@@ -56,6 +76,7 @@ fn main() {
     generate_input(&path).unwrap();
     let args = vec![
         "rustc".to_string(),
+        "-Cpanic=abort".to_string(),
         "--crate-type=lib".to_string(),
         "--crate-name".to_string(),
         CRATE_NAME.to_string(),
@@ -78,6 +99,9 @@ fn generate_input(path: &str) -> std::io::Result<()> {
     }}
 
     pub fn monomorphic() {{
+        let v = vec![10];
+        let dup = ty_param(&v);
+        assert_eq!(v, dup);
     }}
 
     pub mod foo {{
diff --git a/tests/ui/async-await/unnecessary-await.rs b/tests/ui/async-await/unnecessary-await.rs
index cd1e2871432..93b68f018e4 100644
--- a/tests/ui/async-await/unnecessary-await.rs
+++ b/tests/ui/async-await/unnecessary-await.rs
@@ -31,4 +31,9 @@ async fn with_macros() {
     f!(());
 }
 
+// Regression test for issue #117014.
+async fn desugaring_span_ctxt() {
+    for x in [] {}.await //~ ERROR `()` is not a future
+}
+
 fn main() {}
diff --git a/tests/ui/async-await/unnecessary-await.stderr b/tests/ui/async-await/unnecessary-await.stderr
index 9a2a035b2dd..620370a6113 100644
--- a/tests/ui/async-await/unnecessary-await.stderr
+++ b/tests/ui/async-await/unnecessary-await.stderr
@@ -49,6 +49,19 @@ LL |     f!(());
    = note: required for `()` to implement `IntoFuture`
    = note: this error originates in the macro `f` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 3 previous errors
+error[E0277]: `()` is not a future
+  --> $DIR/unnecessary-await.rs:36:20
+   |
+LL |     for x in [] {}.await
+   |                   -^^^^^
+   |                   ||
+   |                   |`()` is not a future
+   |                   help: remove the `.await`
+   |
+   = help: the trait `Future` is not implemented for `()`
+   = note: () must be a future or must implement `IntoFuture` to be awaited
+   = note: required for `()` to implement `IntoFuture`
+
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/error-codes/E0583.stderr b/tests/ui/error-codes/E0583.stderr
index c7bbbf11499..6707f2864f2 100644
--- a/tests/ui/error-codes/E0583.stderr
+++ b/tests/ui/error-codes/E0583.stderr
@@ -5,6 +5,7 @@ LL | mod module_that_doesnt_exist;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: to create the module `module_that_doesnt_exist`, create file "$DIR/module_that_doesnt_exist.rs" or "$DIR/module_that_doesnt_exist/mod.rs"
+   = note: if there is a `mod module_that_doesnt_exist` elsewhere in the crate already, import it with `use crate::...` instead
 
 error: aborting due to previous error
 
diff --git a/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs b/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs
index 9b646060adf..1922bfb4913 100644
--- a/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs
+++ b/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs
@@ -3,13 +3,17 @@
 #![deny(non_exhaustive_omitted_patterns)]
 //~^ WARNING unknown lint: `non_exhaustive_omitted_patterns`
 //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
+//~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
 #![allow(non_exhaustive_omitted_patterns)]
 //~^ WARNING unknown lint: `non_exhaustive_omitted_patterns`
 //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
+//~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
 
 fn main() {
     enum Foo {
-        A, B, C,
+        A,
+        B,
+        C,
     }
 
     #[allow(non_exhaustive_omitted_patterns)]
@@ -17,18 +21,22 @@ fn main() {
     //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
     //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
     //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
+    //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
     match Foo::A {
+        //~^ ERROR non-exhaustive patterns: `Foo::C` not covered
         Foo::A => {}
         Foo::B => {}
     }
-    //~^^^^ ERROR non-exhaustive patterns: `Foo::C` not covered
 
+    #[warn(non_exhaustive_omitted_patterns)]
+    //~^ WARNING unknown lint: `non_exhaustive_omitted_patterns`
+    //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
+    //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
+    //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
+    //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
     match Foo::A {
         Foo::A => {}
         Foo::B => {}
-        #[warn(non_exhaustive_omitted_patterns)]
         _ => {}
     }
-    //~^^^ WARNING unknown lint: `non_exhaustive_omitted_patterns`
-    //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
 }
diff --git a/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr b/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr
index 1c14622d637..eb61c4cf159 100644
--- a/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr
+++ b/tests/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr
@@ -10,7 +10,7 @@ LL | #![deny(non_exhaustive_omitted_patterns)]
    = note: `#[warn(unknown_lints)]` on by default
 
 warning: unknown lint: `non_exhaustive_omitted_patterns`
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:6:1
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:7:1
    |
 LL | #![allow(non_exhaustive_omitted_patterns)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -20,7 +20,7 @@ LL | #![allow(non_exhaustive_omitted_patterns)]
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
 warning: unknown lint: `non_exhaustive_omitted_patterns`
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:19:5
    |
 LL |     #[allow(non_exhaustive_omitted_patterns)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -30,7 +30,7 @@ LL |     #[allow(non_exhaustive_omitted_patterns)]
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
 warning: unknown lint: `non_exhaustive_omitted_patterns`
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:19:5
    |
 LL |     #[allow(non_exhaustive_omitted_patterns)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -41,16 +41,27 @@ LL |     #[allow(non_exhaustive_omitted_patterns)]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 warning: unknown lint: `non_exhaustive_omitted_patterns`
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:29:9
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:31:5
    |
-LL |         #[warn(non_exhaustive_omitted_patterns)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[warn(non_exhaustive_omitted_patterns)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
 warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:31:5
+   |
+LL |     #[warn(non_exhaustive_omitted_patterns)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
+   = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
+   = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+warning: unknown lint: `non_exhaustive_omitted_patterns`
   --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:3:1
    |
 LL | #![deny(non_exhaustive_omitted_patterns)]
@@ -62,7 +73,7 @@ LL | #![deny(non_exhaustive_omitted_patterns)]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 warning: unknown lint: `non_exhaustive_omitted_patterns`
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:6:1
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:7:1
    |
 LL | #![allow(non_exhaustive_omitted_patterns)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -73,7 +84,7 @@ LL | #![allow(non_exhaustive_omitted_patterns)]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 warning: unknown lint: `non_exhaustive_omitted_patterns`
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:19:5
    |
 LL |     #[allow(non_exhaustive_omitted_patterns)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -84,7 +95,7 @@ LL |     #[allow(non_exhaustive_omitted_patterns)]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 warning: unknown lint: `non_exhaustive_omitted_patterns`
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:19:5
    |
 LL |     #[allow(non_exhaustive_omitted_patterns)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -95,10 +106,21 @@ LL |     #[allow(non_exhaustive_omitted_patterns)]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 warning: unknown lint: `non_exhaustive_omitted_patterns`
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:29:9
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:31:5
+   |
+LL |     #[warn(non_exhaustive_omitted_patterns)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
+   = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
+   = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:31:5
    |
-LL |         #[warn(non_exhaustive_omitted_patterns)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[warn(non_exhaustive_omitted_patterns)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
@@ -106,18 +128,19 @@ LL |         #[warn(non_exhaustive_omitted_patterns)]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0004]: non-exhaustive patterns: `Foo::C` not covered
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:20:11
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:25:11
    |
 LL |     match Foo::A {
    |           ^^^^^^ pattern `Foo::C` not covered
    |
 note: `Foo` defined here
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:12:15
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:16:9
    |
 LL |     enum Foo {
    |          ---
-LL |         A, B, C,
-   |               ^ not covered
+...
+LL |         C,
+   |         ^ not covered
    = note: the matched value is of type `Foo`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
@@ -125,6 +148,50 @@ LL ~         Foo::B => {},
 LL +         Foo::C => todo!()
    |
 
-error: aborting due to previous error; 10 warnings emitted
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:3:1
+   |
+LL | #![deny(non_exhaustive_omitted_patterns)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
+   = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
+   = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:7:1
+   |
+LL | #![allow(non_exhaustive_omitted_patterns)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
+   = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
+   = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:19:5
+   |
+LL |     #[allow(non_exhaustive_omitted_patterns)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
+   = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
+   = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:31:5
+   |
+LL |     #[warn(non_exhaustive_omitted_patterns)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
+   = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
+   = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to previous error; 16 warnings emitted
 
 For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/invalid/invalid-llvm-passes.rs b/tests/ui/invalid-compile-flags/invalid-llvm-passes.rs
index ee28f5eb6d6..ee28f5eb6d6 100644
--- a/tests/ui/invalid/invalid-llvm-passes.rs
+++ b/tests/ui/invalid-compile-flags/invalid-llvm-passes.rs
diff --git a/tests/ui/invalid/invalid-llvm-passes.stderr b/tests/ui/invalid-compile-flags/invalid-llvm-passes.stderr
index ae1f85e41e4..ae1f85e41e4 100644
--- a/tests/ui/invalid/invalid-llvm-passes.stderr
+++ b/tests/ui/invalid-compile-flags/invalid-llvm-passes.stderr
diff --git a/tests/ui/invalid-module-declaration/invalid-module-declaration.stderr b/tests/ui/invalid-module-declaration/invalid-module-declaration.stderr
index 7bc8efd7e4a..08aec25928c 100644
--- a/tests/ui/invalid-module-declaration/invalid-module-declaration.stderr
+++ b/tests/ui/invalid-module-declaration/invalid-module-declaration.stderr
@@ -5,6 +5,7 @@ LL | pub mod baz;
    | ^^^^^^^^^^^^
    |
    = help: to create the module `baz`, create file "$DIR/auxiliary/foo/bar/baz.rs" or "$DIR/auxiliary/foo/bar/baz/mod.rs"
+   = note: if there is a `mod baz` elsewhere in the crate already, import it with `use crate::...` instead
 
 error: aborting due to previous error
 
diff --git a/tests/ui/lifetimes/borrowck-let-suggestion.stderr b/tests/ui/lifetimes/borrowck-let-suggestion.stderr
index da0078698ae..62119664764 100644
--- a/tests/ui/lifetimes/borrowck-let-suggestion.stderr
+++ b/tests/ui/lifetimes/borrowck-let-suggestion.stderr
@@ -10,6 +10,10 @@ LL |     x.use_mut();
    |     - borrow later used here
    |
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider consuming the `Vec<i32>` when turning it into an `Iterator`
+   |
+LL |     let mut x = vec![1].into_iter();
+   |                         ~~~~~~~~~
 help: consider using a `let` binding to create a longer lived value
    |
 LL ~     let binding = vec![1];
diff --git a/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr b/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr
index 31e4206a546..5f4d19439ac 100644
--- a/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr
+++ b/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr
@@ -5,6 +5,7 @@ LL | mod missing;
    | ^^^^^^^^^^^^
    |
    = help: to create the module `missing`, create file "$DIR/foo/missing.rs" or "$DIR/foo/missing/mod.rs"
+   = note: if there is a `mod missing` elsewhere in the crate already, import it with `use crate::...` instead
 
 error: aborting due to previous error
 
diff --git a/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr b/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr
index 9d252398b7a..d5f5ea87059 100644
--- a/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr
+++ b/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr
@@ -5,6 +5,7 @@ LL |     mod missing;
    |     ^^^^^^^^^^^^
    |
    = help: to create the module `missing`, create file "$DIR/foo_inline/inline/missing.rs" or "$DIR/foo_inline/inline/missing/mod.rs"
+   = note: if there is a `mod missing` elsewhere in the crate already, import it with `use crate::...` instead
 
 error: aborting due to previous error
 
diff --git a/tests/ui/modules/special_module_name.stderr b/tests/ui/modules/special_module_name.stderr
index bc4b4f1b318..84473bf8c0b 100644
--- a/tests/ui/modules/special_module_name.stderr
+++ b/tests/ui/modules/special_module_name.stderr
@@ -5,6 +5,7 @@ LL | mod lib;
    | ^^^^^^^^
    |
    = help: to create the module `lib`, create file "$DIR/lib.rs" or "$DIR/lib/mod.rs"
+   = note: if there is a `mod lib` elsewhere in the crate already, import it with `use crate::...` instead
 
 error[E0583]: file not found for module `main`
   --> $DIR/special_module_name.rs:4:1
@@ -13,6 +14,7 @@ LL | mod main;
    | ^^^^^^^^^
    |
    = help: to create the module `main`, create file "$DIR/main.rs" or "$DIR/main/mod.rs"
+   = note: if there is a `mod main` elsewhere in the crate already, import it with `use crate::...` instead
 
 warning: found module declaration for lib.rs
   --> $DIR/special_module_name.rs:1:1
diff --git a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed
new file mode 100644
index 00000000000..45c7e07a264
--- /dev/null
+++ b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.fixed
@@ -0,0 +1,10 @@
+// run-rustfix
+trait TraitWithAType {
+    type Item: ?Sized;
+}
+trait Trait {}
+struct A {}
+impl TraitWithAType for A {
+    type Item = dyn Trait; //~ ERROR E0277
+}
+fn main() {}
diff --git a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs
new file mode 100644
index 00000000000..c3e958f4983
--- /dev/null
+++ b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.rs
@@ -0,0 +1,10 @@
+// run-rustfix
+trait TraitWithAType {
+    type Item;
+}
+trait Trait {}
+struct A {}
+impl TraitWithAType for A {
+    type Item = dyn Trait; //~ ERROR E0277
+}
+fn main() {}
diff --git a/tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr
new file mode 100644
index 00000000000..110e7150733
--- /dev/null
+++ b/tests/ui/object-safety/assoc_type_bounds_implicit_sized.stderr
@@ -0,0 +1,20 @@
+error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time
+  --> $DIR/assoc_type_bounds_implicit_sized.rs:8:17
+   |
+LL |     type Item = dyn Trait;
+   |                 ^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `(dyn Trait + 'static)`
+note: required by a bound in `TraitWithAType::Item`
+  --> $DIR/assoc_type_bounds_implicit_sized.rs:3:5
+   |
+LL |     type Item;
+   |     ^^^^^^^^^^ required by this bound in `TraitWithAType::Item`
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL |     type Item: ?Sized;
+   |              ++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/object-safety/assoc_type_bounds_sized_used.stderr b/tests/ui/object-safety/assoc_type_bounds_sized_used.stderr
index 224d33fb2da..b67a1244ece 100644
--- a/tests/ui/object-safety/assoc_type_bounds_sized_used.stderr
+++ b/tests/ui/object-safety/assoc_type_bounds_sized_used.stderr
@@ -33,6 +33,10 @@ help: consider removing the `?Sized` bound to make the type parameter `Sized`
 LL - fn bop<T: Bop + ?Sized>() {
 LL + fn bop<T: Bop>() {
    |
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL |     type Bar: Default + ?Sized
+   |                       ++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/parser/mod_file_not_exist.stderr b/tests/ui/parser/mod_file_not_exist.stderr
index 62456d51880..c2f9d30d9ec 100644
--- a/tests/ui/parser/mod_file_not_exist.stderr
+++ b/tests/ui/parser/mod_file_not_exist.stderr
@@ -5,6 +5,7 @@ LL | mod not_a_real_file;
    | ^^^^^^^^^^^^^^^^^^^^
    |
    = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs" or "$DIR/not_a_real_file/mod.rs"
+   = note: if there is a `mod not_a_real_file` elsewhere in the crate already, import it with `use crate::...` instead
 
 error[E0433]: failed to resolve: use of undeclared crate or module `mod_file_aux`
   --> $DIR/mod_file_not_exist.rs:7:16
diff --git a/tests/ui/parser/mod_file_not_exist_windows.stderr b/tests/ui/parser/mod_file_not_exist_windows.stderr
index d5143dbe982..53b09d8ca53 100644
--- a/tests/ui/parser/mod_file_not_exist_windows.stderr
+++ b/tests/ui/parser/mod_file_not_exist_windows.stderr
@@ -5,6 +5,7 @@ LL | mod not_a_real_file;
    | ^^^^^^^^^^^^^^^^^^^^
    |
    = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs" or "$DIR/not_a_real_file/mod.rs"
+   = note: if there is a `mod not_a_real_file` elsewhere in the crate already, import it with `use crate::...` instead
 
 error[E0433]: failed to resolve: use of undeclared crate or module `mod_file_aux`
   --> $DIR/mod_file_not_exist_windows.rs:7:16
diff --git a/tests/ui/parser/unsafe-mod.stderr b/tests/ui/parser/unsafe-mod.stderr
index dac6e7a3550..fbe24aa10da 100644
--- a/tests/ui/parser/unsafe-mod.stderr
+++ b/tests/ui/parser/unsafe-mod.stderr
@@ -5,6 +5,7 @@ LL | unsafe mod n;
    | ^^^^^^^^^^^^^
    |
    = help: to create the module `n`, create file "$DIR/n.rs" or "$DIR/n/mod.rs"
+   = note: if there is a `mod n` elsewhere in the crate already, import it with `use crate::...` instead
 
 error: module cannot be declared unsafe
   --> $DIR/unsafe-mod.rs:1:1
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.rs
index 3482af74752..ecfeb3f9b98 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.rs
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.rs
@@ -13,8 +13,8 @@ use enums::{
     EmptyNonExhaustiveEnum, NestedNonExhaustive, NonExhaustiveEnum, NonExhaustiveSingleVariant,
     VariantNonExhaustive,
 };
-use unstable::{UnstableEnum, OnlyUnstableEnum, UnstableStruct, OnlyUnstableStruct};
 use structs::{FunctionalRecord, MixedVisFields, NestedStruct, NormalStruct};
+use unstable::{OnlyUnstableEnum, OnlyUnstableStruct, UnstableEnum, UnstableStruct};
 
 #[non_exhaustive]
 #[derive(Default)]
@@ -35,10 +35,10 @@ fn main() {
     let enumeration = Bar::A;
 
     // Ok: this is a crate local non_exhaustive enum
+    #[deny(non_exhaustive_omitted_patterns)]
     match enumeration {
         Bar::A => {}
         Bar::B => {}
-        #[deny(non_exhaustive_omitted_patterns)]
         _ => {}
     }
 
@@ -51,50 +51,87 @@ fn main() {
         _ => {}
     }
 
+    #[deny(non_exhaustive_omitted_patterns)]
     match non_enum {
+        //~^ some variants are not matched explicitly
         NonExhaustiveEnum::Unit => {}
         NonExhaustiveEnum::Tuple(_) => {}
-        #[deny(non_exhaustive_omitted_patterns)]
         _ => {}
     }
-    //~^^ some variants are not matched explicitly
 
+    #[deny(non_exhaustive_omitted_patterns)]
     match non_enum {
+        //~^ some variants are not matched explicitly
         NonExhaustiveEnum::Unit | NonExhaustiveEnum::Struct { .. } => {}
-        #[deny(non_exhaustive_omitted_patterns)]
         _ => {}
     }
-    //~^^ some variants are not matched explicitly
 
     let x = 5;
+    // We ignore the guard.
+    #[deny(non_exhaustive_omitted_patterns)]
     match non_enum {
         NonExhaustiveEnum::Unit if x > 10 => {}
         NonExhaustiveEnum::Tuple(_) => {}
         NonExhaustiveEnum::Struct { .. } => {}
-        #[deny(non_exhaustive_omitted_patterns)]
         _ => {}
     }
-    //~^^ some variants are not matched explicitly
+
+    #[deny(non_exhaustive_omitted_patterns)]
+    match (non_enum, true) {
+        (NonExhaustiveEnum::Unit, true) => {}
+        (NonExhaustiveEnum::Tuple(_), false) => {}
+        (NonExhaustiveEnum::Struct { .. }, false) => {}
+        _ => {}
+    }
+    #[deny(non_exhaustive_omitted_patterns)]
+    match (non_enum, true) {
+        //~^ some variants are not matched explicitly
+        (NonExhaustiveEnum::Unit, true) => {}
+        (NonExhaustiveEnum::Tuple(_), false) => {}
+        _ => {}
+    }
+
+    #[deny(non_exhaustive_omitted_patterns)]
+    match (true, non_enum) {
+        (true, NonExhaustiveEnum::Unit) => {}
+        (false, NonExhaustiveEnum::Tuple(_)) => {}
+        (false, NonExhaustiveEnum::Struct { .. }) => {}
+        _ => {}
+    }
+    #[deny(non_exhaustive_omitted_patterns)]
+    match (true, non_enum) {
+        //~^ some variants are not matched explicitly
+        (true, NonExhaustiveEnum::Unit) => {}
+        (false, NonExhaustiveEnum::Tuple(_)) => {}
+        _ => {}
+    }
+
+    #[deny(non_exhaustive_omitted_patterns)]
+    match Some(non_enum) {
+        //~^ some variants are not matched explicitly
+        Some(NonExhaustiveEnum::Unit) => {}
+        Some(NonExhaustiveEnum::Tuple(_)) => {}
+        _ => {}
+    }
 
     // Ok: all covered and not `unreachable-patterns`
     #[deny(unreachable_patterns)]
+    #[deny(non_exhaustive_omitted_patterns)]
     match non_enum {
         NonExhaustiveEnum::Unit => {}
         NonExhaustiveEnum::Tuple(_) => {}
         NonExhaustiveEnum::Struct { .. } => {}
-        #[deny(non_exhaustive_omitted_patterns)]
         _ => {}
     }
 
     #[deny(non_exhaustive_omitted_patterns)]
     match NestedNonExhaustive::B {
+        //~^ some variants are not matched explicitly
         NestedNonExhaustive::A(NonExhaustiveEnum::Unit) => {}
         NestedNonExhaustive::A(_) => {}
         NestedNonExhaustive::B => {}
         _ => {}
     }
-    //~^^ some variants are not matched explicitly
-    //~^^^^^ some variants are not matched explicitly
 
     #[warn(non_exhaustive_omitted_patterns)]
     match VariantNonExhaustive::Baz(1, 2) {
@@ -120,30 +157,36 @@ fn main() {
     #[warn(non_exhaustive_omitted_patterns)]
     let MixedVisFields { a, b, .. } = MixedVisFields::default();
 
-    // Ok: because this only has 1 variant
+    // Ok: this only has 1 variant
     #[deny(non_exhaustive_omitted_patterns)]
     match NonExhaustiveSingleVariant::A(true) {
         NonExhaustiveSingleVariant::A(true) => {}
         _ => {}
     }
 
+    // We can't catch the case below, so for consistency we don't catch this one either.
     #[deny(non_exhaustive_omitted_patterns)]
     match NonExhaustiveSingleVariant::A(true) {
         _ => {}
     }
-    //~^^ some variants are not matched explicitly
+    // We can't catch this case, because this would require digging fully through all the values of
+    // any type we encounter. We need to be able to only consider present constructors.
+    #[deny(non_exhaustive_omitted_patterns)]
+    match &NonExhaustiveSingleVariant::A(true) {
+        _ => {}
+    }
 
     // Ok: we don't lint on `if let` expressions
     #[deny(non_exhaustive_omitted_patterns)]
     if let NonExhaustiveEnum::Tuple(_) = non_enum {}
 
+    #[deny(non_exhaustive_omitted_patterns)]
     match UnstableEnum::Stable {
+        //~^ some variants are not matched explicitly
         UnstableEnum::Stable => {}
         UnstableEnum::Stable2 => {}
-        #[deny(non_exhaustive_omitted_patterns)]
         _ => {}
     }
-    //~^^ some variants are not matched explicitly
 
     // Ok: the feature is on and all variants are matched
     #[deny(non_exhaustive_omitted_patterns)]
@@ -164,10 +207,10 @@ fn main() {
 
     #[deny(non_exhaustive_omitted_patterns)]
     match OnlyUnstableEnum::Unstable {
+        //~^ some variants are not matched explicitly
         OnlyUnstableEnum::Unstable => {}
         _ => {}
     }
-    //~^^ some variants are not matched explicitly
 
     #[warn(non_exhaustive_omitted_patterns)]
     let OnlyUnstableStruct { unstable, .. } = OnlyUnstableStruct::new();
@@ -194,14 +237,13 @@ fn main() {
     let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit;
     //~^ refutable pattern in local binding
 
-    // Check that matching on a reference results in a correctly spanned diagnostic
     #[deny(non_exhaustive_omitted_patterns)]
     match &non_enum {
+        //~^ some variants are not matched explicitly
         NonExhaustiveEnum::Unit => {}
         NonExhaustiveEnum::Tuple(_) => {}
         _ => {}
     }
-    //~^^ some variants are not matched explicitly
 }
 
 #[deny(non_exhaustive_omitted_patterns)]
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.stderr
index 923394474b2..7db61f1241e 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.stderr
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.stderr
@@ -1,5 +1,5 @@
 warning: some fields are not explicitly listed
-  --> $DIR/omitted-patterns.rs:102:9
+  --> $DIR/omitted-patterns.rs:139:9
    |
 LL |         VariantNonExhaustive::Bar { x, .. } => {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `y` not listed
@@ -7,13 +7,13 @@ LL |         VariantNonExhaustive::Bar { x, .. } => {}
    = help: ensure that all fields are mentioned explicitly by adding the suggested fields
    = note: the pattern is of type `VariantNonExhaustive` and the `non_exhaustive_omitted_patterns` attribute was found
 note: the lint level is defined here
-  --> $DIR/omitted-patterns.rs:99:12
+  --> $DIR/omitted-patterns.rs:136:12
    |
 LL |     #[warn(non_exhaustive_omitted_patterns)]
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: some fields are not explicitly listed
-  --> $DIR/omitted-patterns.rs:107:9
+  --> $DIR/omitted-patterns.rs:144:9
    |
 LL |     let FunctionalRecord { first_field, second_field, .. } = FunctionalRecord::default();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `third_field` not listed
@@ -21,13 +21,13 @@ LL |     let FunctionalRecord { first_field, second_field, .. } = FunctionalReco
    = help: ensure that all fields are mentioned explicitly by adding the suggested fields
    = note: the pattern is of type `FunctionalRecord` and the `non_exhaustive_omitted_patterns` attribute was found
 note: the lint level is defined here
-  --> $DIR/omitted-patterns.rs:106:12
+  --> $DIR/omitted-patterns.rs:143:12
    |
 LL |     #[warn(non_exhaustive_omitted_patterns)]
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: some fields are not explicitly listed
-  --> $DIR/omitted-patterns.rs:115:29
+  --> $DIR/omitted-patterns.rs:152:29
    |
 LL |     let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default();
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `second_field` not listed
@@ -35,13 +35,13 @@ LL |     let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = Nested
    = help: ensure that all fields are mentioned explicitly by adding the suggested fields
    = note: the pattern is of type `NormalStruct` and the `non_exhaustive_omitted_patterns` attribute was found
 note: the lint level is defined here
-  --> $DIR/omitted-patterns.rs:114:12
+  --> $DIR/omitted-patterns.rs:151:12
    |
 LL |     #[warn(non_exhaustive_omitted_patterns)]
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: some fields are not explicitly listed
-  --> $DIR/omitted-patterns.rs:115:9
+  --> $DIR/omitted-patterns.rs:152:9
    |
 LL |     let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `foo` not listed
@@ -50,7 +50,7 @@ LL |     let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = Nested
    = note: the pattern is of type `NestedStruct` and the `non_exhaustive_omitted_patterns` attribute was found
 
 warning: some fields are not explicitly listed
-  --> $DIR/omitted-patterns.rs:173:9
+  --> $DIR/omitted-patterns.rs:216:9
    |
 LL |     let OnlyUnstableStruct { unstable, .. } = OnlyUnstableStruct::new();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `unstable2` not listed
@@ -58,13 +58,13 @@ LL |     let OnlyUnstableStruct { unstable, .. } = OnlyUnstableStruct::new();
    = help: ensure that all fields are mentioned explicitly by adding the suggested fields
    = note: the pattern is of type `OnlyUnstableStruct` and the `non_exhaustive_omitted_patterns` attribute was found
 note: the lint level is defined here
-  --> $DIR/omitted-patterns.rs:172:12
+  --> $DIR/omitted-patterns.rs:215:12
    |
 LL |     #[warn(non_exhaustive_omitted_patterns)]
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: some fields are not explicitly listed
-  --> $DIR/omitted-patterns.rs:181:9
+  --> $DIR/omitted-patterns.rs:224:9
    |
 LL |     let UnstableStruct { stable, stable2, .. } = UnstableStruct::default();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `unstable` not listed
@@ -72,120 +72,125 @@ LL |     let UnstableStruct { stable, stable2, .. } = UnstableStruct::default();
    = help: ensure that all fields are mentioned explicitly by adding the suggested fields
    = note: the pattern is of type `UnstableStruct` and the `non_exhaustive_omitted_patterns` attribute was found
 note: the lint level is defined here
-  --> $DIR/omitted-patterns.rs:180:12
+  --> $DIR/omitted-patterns.rs:223:12
    |
 LL |     #[warn(non_exhaustive_omitted_patterns)]
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: some variants are not matched explicitly
-  --> $DIR/omitted-patterns.rs:58:9
+  --> $DIR/omitted-patterns.rs:55:11
    |
-LL |         _ => {}
-   |         ^ pattern `NonExhaustiveEnum::Struct { .. }` not covered
+LL |     match non_enum {
+   |           ^^^^^^^^ pattern `NonExhaustiveEnum::Struct { .. }` not covered
    |
    = help: ensure that all variants are matched explicitly by adding the suggested match arms
    = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found
 note: the lint level is defined here
-  --> $DIR/omitted-patterns.rs:57:16
+  --> $DIR/omitted-patterns.rs:54:12
    |
-LL |         #[deny(non_exhaustive_omitted_patterns)]
-   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[deny(non_exhaustive_omitted_patterns)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: some variants are not matched explicitly
-  --> $DIR/omitted-patterns.rs:65:9
+  --> $DIR/omitted-patterns.rs:63:11
    |
-LL |         _ => {}
-   |         ^ pattern `NonExhaustiveEnum::Tuple(_)` not covered
+LL |     match non_enum {
+   |           ^^^^^^^^ pattern `NonExhaustiveEnum::Tuple(_)` not covered
    |
    = help: ensure that all variants are matched explicitly by adding the suggested match arms
    = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found
 note: the lint level is defined here
-  --> $DIR/omitted-patterns.rs:64:16
+  --> $DIR/omitted-patterns.rs:62:12
    |
-LL |         #[deny(non_exhaustive_omitted_patterns)]
-   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[deny(non_exhaustive_omitted_patterns)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: some variants are not matched explicitly
-  --> $DIR/omitted-patterns.rs:75:9
+  --> $DIR/omitted-patterns.rs:87:11
    |
-LL |         _ => {}
-   |         ^ pattern `NonExhaustiveEnum::Unit` not covered
+LL |     match (non_enum, true) {
+   |           ^^^^^^^^^^^^^^^^ pattern `(NonExhaustiveEnum::Struct { .. }, _)` not covered
    |
    = help: ensure that all variants are matched explicitly by adding the suggested match arms
-   = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found
+   = note: the matched value is of type `(NonExhaustiveEnum, bool)` and the `non_exhaustive_omitted_patterns` attribute was found
 note: the lint level is defined here
-  --> $DIR/omitted-patterns.rs:74:16
+  --> $DIR/omitted-patterns.rs:86:12
    |
-LL |         #[deny(non_exhaustive_omitted_patterns)]
-   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[deny(non_exhaustive_omitted_patterns)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: some variants are not matched explicitly
-  --> $DIR/omitted-patterns.rs:92:32
+  --> $DIR/omitted-patterns.rs:102:11
    |
-LL |         NestedNonExhaustive::A(_) => {}
-   |                                ^ patterns `NonExhaustiveEnum::Tuple(_)` and `NonExhaustiveEnum::Struct { .. }` not covered
+LL |     match (true, non_enum) {
+   |           ^^^^^^^^^^^^^^^^ pattern `(_, NonExhaustiveEnum::Struct { .. })` not covered
    |
    = help: ensure that all variants are matched explicitly by adding the suggested match arms
-   = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found
+   = note: the matched value is of type `(bool, NonExhaustiveEnum)` and the `non_exhaustive_omitted_patterns` attribute was found
 note: the lint level is defined here
-  --> $DIR/omitted-patterns.rs:89:12
+  --> $DIR/omitted-patterns.rs:101:12
    |
 LL |     #[deny(non_exhaustive_omitted_patterns)]
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: some variants are not matched explicitly
-  --> $DIR/omitted-patterns.rs:94:9
+  --> $DIR/omitted-patterns.rs:110:11
    |
-LL |         _ => {}
-   |         ^ pattern `NestedNonExhaustive::C` not covered
+LL |     match Some(non_enum) {
+   |           ^^^^^^^^^^^^^^ pattern `Some(NonExhaustiveEnum::Struct { .. })` not covered
    |
    = help: ensure that all variants are matched explicitly by adding the suggested match arms
-   = note: the matched value is of type `NestedNonExhaustive` and the `non_exhaustive_omitted_patterns` attribute was found
+   = note: the matched value is of type `Option<NonExhaustiveEnum>` and the `non_exhaustive_omitted_patterns` attribute was found
+note: the lint level is defined here
+  --> $DIR/omitted-patterns.rs:109:12
+   |
+LL |     #[deny(non_exhaustive_omitted_patterns)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: some variants are not matched explicitly
-  --> $DIR/omitted-patterns.rs:132:9
+  --> $DIR/omitted-patterns.rs:128:11
    |
-LL |         _ => {}
-   |         ^ pattern `NonExhaustiveSingleVariant::A(_)` not covered
+LL |     match NestedNonExhaustive::B {
+   |           ^^^^^^^^^^^^^^^^^^^^^^ patterns `NestedNonExhaustive::C`, `NestedNonExhaustive::A(NonExhaustiveEnum::Tuple(_))` and `NestedNonExhaustive::A(NonExhaustiveEnum::Struct { .. })` not covered
    |
    = help: ensure that all variants are matched explicitly by adding the suggested match arms
-   = note: the matched value is of type `NonExhaustiveSingleVariant` and the `non_exhaustive_omitted_patterns` attribute was found
+   = note: the matched value is of type `NestedNonExhaustive` and the `non_exhaustive_omitted_patterns` attribute was found
 note: the lint level is defined here
-  --> $DIR/omitted-patterns.rs:130:12
+  --> $DIR/omitted-patterns.rs:127:12
    |
 LL |     #[deny(non_exhaustive_omitted_patterns)]
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: some variants are not matched explicitly
-  --> $DIR/omitted-patterns.rs:144:9
+  --> $DIR/omitted-patterns.rs:184:11
    |
-LL |         _ => {}
-   |         ^ pattern `UnstableEnum::Unstable` not covered
+LL |     match UnstableEnum::Stable {
+   |           ^^^^^^^^^^^^^^^^^^^^ pattern `UnstableEnum::Unstable` not covered
    |
    = help: ensure that all variants are matched explicitly by adding the suggested match arms
    = note: the matched value is of type `UnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found
 note: the lint level is defined here
-  --> $DIR/omitted-patterns.rs:143:16
+  --> $DIR/omitted-patterns.rs:183:12
    |
-LL |         #[deny(non_exhaustive_omitted_patterns)]
-   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[deny(non_exhaustive_omitted_patterns)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: some variants are not matched explicitly
-  --> $DIR/omitted-patterns.rs:168:9
+  --> $DIR/omitted-patterns.rs:209:11
    |
-LL |         _ => {}
-   |         ^ pattern `OnlyUnstableEnum::Unstable2` not covered
+LL |     match OnlyUnstableEnum::Unstable {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `OnlyUnstableEnum::Unstable2` not covered
    |
    = help: ensure that all variants are matched explicitly by adding the suggested match arms
    = note: the matched value is of type `OnlyUnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found
 note: the lint level is defined here
-  --> $DIR/omitted-patterns.rs:165:12
+  --> $DIR/omitted-patterns.rs:208:12
    |
 LL |     #[deny(non_exhaustive_omitted_patterns)]
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0005]: refutable pattern in local binding
-  --> $DIR/omitted-patterns.rs:194:9
+  --> $DIR/omitted-patterns.rs:237:9
    |
 LL |     let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit;
    |         ^^^^^^^^^^^^^^^ pattern `_` not covered
@@ -199,15 +204,15 @@ LL |     let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit
    |                                                                             ++++++++++++++++
 
 error: some variants are not matched explicitly
-  --> $DIR/omitted-patterns.rs:202:9
+  --> $DIR/omitted-patterns.rs:241:11
    |
-LL |         _ => {}
-   |         ^ pattern `NonExhaustiveEnum::Struct { .. }` not covered
+LL |     match &non_enum {
+   |           ^^^^^^^^^ pattern `&NonExhaustiveEnum::Struct { .. }` not covered
    |
    = help: ensure that all variants are matched explicitly by adding the suggested match arms
-   = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found
+   = note: the matched value is of type `&NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found
 note: the lint level is defined here
-  --> $DIR/omitted-patterns.rs:198:12
+  --> $DIR/omitted-patterns.rs:240:12
    |
 LL |     #[deny(non_exhaustive_omitted_patterns)]
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.rs
index 82ee68687ed..1828fdef901 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.rs
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.rs
@@ -6,23 +6,23 @@
 // aux-build:unstable.rs
 extern crate unstable;
 
-use unstable::{UnstableEnum, OnlyUnstableEnum, UnstableStruct, OnlyUnstableStruct};
+use unstable::{OnlyUnstableEnum, OnlyUnstableStruct, UnstableEnum, UnstableStruct};
 
 fn main() {
     // OK: this matches all the stable variants
+    #[deny(non_exhaustive_omitted_patterns)]
     match UnstableEnum::Stable {
         UnstableEnum::Stable => {}
         UnstableEnum::Stable2 => {}
-        #[deny(non_exhaustive_omitted_patterns)]
         _ => {}
     }
 
+    #[deny(non_exhaustive_omitted_patterns)]
     match UnstableEnum::Stable {
+        //~^ some variants are not matched explicitly
         UnstableEnum::Stable => {}
-        #[deny(non_exhaustive_omitted_patterns)]
         _ => {}
     }
-    //~^^ some variants are not matched explicitly
 
     // Ok: although this is a bit odd, we don't have anything to report
     // since there is no stable variants and the feature is off
diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr
index f38368590fb..27939176f75 100644
--- a/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr
+++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr
@@ -13,18 +13,18 @@ LL |     #[warn(non_exhaustive_omitted_patterns)]
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: some variants are not matched explicitly
-  --> $DIR/stable-omitted-patterns.rs:23:9
+  --> $DIR/stable-omitted-patterns.rs:21:11
    |
-LL |         _ => {}
-   |         ^ pattern `UnstableEnum::Stable2` not covered
+LL |     match UnstableEnum::Stable {
+   |           ^^^^^^^^^^^^^^^^^^^^ pattern `UnstableEnum::Stable2` not covered
    |
    = help: ensure that all variants are matched explicitly by adding the suggested match arms
    = note: the matched value is of type `UnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found
 note: the lint level is defined here
-  --> $DIR/stable-omitted-patterns.rs:22:16
+  --> $DIR/stable-omitted-patterns.rs:20:12
    |
-LL |         #[deny(non_exhaustive_omitted_patterns)]
-   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     #[deny(non_exhaustive_omitted_patterns)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error; 1 warning emitted
 
diff --git a/tests/ui/rfcs/rfc-2457-non-ascii-idents/mod_file_nonascii_forbidden.stderr b/tests/ui/rfcs/rfc-2457-non-ascii-idents/mod_file_nonascii_forbidden.stderr
index 7639ae9f6a4..8ca6a37c625 100644
--- a/tests/ui/rfcs/rfc-2457-non-ascii-idents/mod_file_nonascii_forbidden.stderr
+++ b/tests/ui/rfcs/rfc-2457-non-ascii-idents/mod_file_nonascii_forbidden.stderr
@@ -5,6 +5,7 @@ LL | mod řųśť;
    | ^^^^^^^^^
    |
    = help: to create the module `řųśť`, create file "$DIR/řųśť.rs" or "$DIR/řųśť/mod.rs"
+   = note: if there is a `mod řųśť` elsewhere in the crate already, import it with `use crate::...` instead
 
 error[E0754]: trying to load file for module `řųśť` with non-ascii identifier name
   --> $DIR/mod_file_nonascii_forbidden.rs:1:5
diff --git a/tests/ui/suggestions/issue-81839.stderr b/tests/ui/suggestions/issue-81839.stderr
index 6d0a0c7b3fa..238ee637c7d 100644
--- a/tests/ui/suggestions/issue-81839.stderr
+++ b/tests/ui/suggestions/issue-81839.stderr
@@ -4,15 +4,22 @@ error[E0308]: `match` arms have incompatible types
 LL | /     match num {
 LL | |         1 => {
 LL | |             cx.answer_str("hi");
-   | |             --------------------
-   | |             |                  |
-   | |             |                  help: consider removing this semicolon
-   | |             this is found to be of type `()`
+   | |             -------------------- this is found to be of type `()`
 LL | |         }
 LL | |         _ => cx.answer_str("hi"),
    | |              ^^^^^^^^^^^^^^^^^^^ expected `()`, found future
 LL | |     }
    | |_____- `match` arms have incompatible types
+   |
+help: consider removing this semicolon
+   |
+LL -             cx.answer_str("hi");
+LL +             cx.answer_str("hi")
+   |
+help: consider using a semicolon here, but this will discard any values in the match arms
+   |
+LL |     };
+   |      +
 
 error: aborting due to previous error
 
diff --git a/tests/ui/suggestions/silenced-binding-typo.fixed b/tests/ui/suggestions/silenced-binding-typo.fixed
new file mode 100644
index 00000000000..e0f9e31bef3
--- /dev/null
+++ b/tests/ui/suggestions/silenced-binding-typo.fixed
@@ -0,0 +1,5 @@
+// run-rustfix
+fn main() {
+    let x = 42; //~ HELP
+    let _y = x; //~ ERROR
+}
diff --git a/tests/ui/suggestions/silenced-binding-typo.rs b/tests/ui/suggestions/silenced-binding-typo.rs
new file mode 100644
index 00000000000..6cadd5a93a7
--- /dev/null
+++ b/tests/ui/suggestions/silenced-binding-typo.rs
@@ -0,0 +1,5 @@
+// run-rustfix
+fn main() {
+    let _x = 42; //~ HELP
+    let _y = x; //~ ERROR
+}
diff --git a/tests/ui/suggestions/silenced-binding-typo.stderr b/tests/ui/suggestions/silenced-binding-typo.stderr
new file mode 100644
index 00000000000..9c0e6e26569
--- /dev/null
+++ b/tests/ui/suggestions/silenced-binding-typo.stderr
@@ -0,0 +1,14 @@
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/silenced-binding-typo.rs:4:14
+   |
+LL |     let _y = x;
+   |              ^
+   |
+help: a local variable with a similar name exists, consider changing it
+   |
+LL |     let x = 42;
+   |         ~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui/typeck/issue-36708.stderr b/tests/ui/typeck/issue-36708.stderr
index 140f19f1ff7..f1e0f471928 100644
--- a/tests/ui/typeck/issue-36708.stderr
+++ b/tests/ui/typeck/issue-36708.stderr
@@ -2,7 +2,12 @@ error[E0049]: method `foo` has 1 type parameter but its trait declaration has 0
   --> $DIR/issue-36708.rs:8:12
    |
 LL |     fn foo<T>() {}
-   |            ^ found 1 type parameter, expected 0
+   |            ^ found 1 type parameter
+   |
+  ::: $DIR/auxiliary/issue-36708.rs:4:5
+   |
+LL |     fn foo();
+   |     --------- expected 0 type parameters
 
 error: aborting due to previous error
 
diff --git a/tests/ui/wf/wf-unsafe-trait-obj-match.stderr b/tests/ui/wf/wf-unsafe-trait-obj-match.stderr
index 66504e44060..d5b23572ff5 100644
--- a/tests/ui/wf/wf-unsafe-trait-obj-match.stderr
+++ b/tests/ui/wf/wf-unsafe-trait-obj-match.stderr
@@ -11,6 +11,10 @@ LL | |     }
    |
    = note: expected reference `&S`
               found reference `&R`
+help: consider using a semicolon here, but this will discard any values in the match arms
+   |
+LL |     };
+   |      +
 
 error[E0038]: the trait `Trait` cannot be made into an object
   --> $DIR/wf-unsafe-trait-obj-match.rs:26:21
diff --git a/triagebot.toml b/triagebot.toml
index fbdc28787ff..e3c4233c843 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -23,10 +23,10 @@ allow-unauthenticated = [
     "needs-triage",
 ]
 
-[review-submitted] 
-# This label is added when a "request changes" review is submitted. 
-reviewed_label = "S-waiting-on-author" 
-# These labels are removed when a "request changes" review is submitted. 
+[review-submitted]
+# This label is added when a "request changes" review is submitted.
+reviewed_label = "S-waiting-on-author"
+# These labels are removed when a "request changes" review is submitted.
 review_labels = ["S-waiting-on-review"]
 
 [review-requested]
@@ -586,17 +586,19 @@ message = "`src/tools/x` was changed. Bump version of Cargo.toml in `src/tools/x
 message = "Third-party dependency whitelist may have been modified! You must ensure that any new dependencies have compatible licenses before merging."
 cc = ["@davidtwco", "@wesleywiser"]
 
-[mentions."src/bootstrap/config.rs"]
-message = "This PR changes `src/bootstrap/config.rs`. If appropriate, please also update `CONFIG_CHANGE_HISTORY` in `src/bootstrap/lib.rs` and `change-id` in `config.example.toml`."
+[mentions."src/bootstrap/src/core/config"]
+message = "This PR modifies `src/bootstrap/src/core/config`. If appropriate, please also update `CONFIG_CHANGE_HISTORY` in `src/bootstrap/src/lib.rs` and `change-id` in `config.example.toml`."
+[mentions."src/bootstrap/defaults"]
+message = "This PR modifies `src/bootstrap/defaults`. If appropriate, please also update `CONFIG_CHANGE_HISTORY` in `src/bootstrap/src/lib.rs` and `change-id` in `config.example.toml`."
 [mentions."config.example.toml"]
-message = "This PR changes `config.example.toml`. If appropriate, please also update `CONFIG_CHANGE_HISTORY` in `src/bootstrap/lib.rs` and `change-id` in `config.example.toml`."
+message = "This PR changes `config.example.toml`. If appropriate, please also update `CONFIG_CHANGE_HISTORY` in `src/bootstrap/src/lib.rs` and `change-id` in `config.example.toml`."
 
 [mentions."src/bootstrap/defaults/config.compiler.toml"]
 message = "This PR changes src/bootstrap/defaults/config.compiler.toml. If appropriate, please also update `config.codegen.toml` so the defaults are in sync."
 [mentions."src/bootstrap/defaults/config.codegen.toml"]
 message = "This PR changes src/bootstrap/defaults/config.codegen.toml. If appropriate, please also update `config.compiler.toml` so the defaults are in sync."
 
-[mentions."src/bootstrap/llvm.rs"]
+[mentions."src/bootstrap/src/core/build_steps/llvm.rs"]
 message = "This PR changes how LLVM is built. Consider updating src/bootstrap/download-ci-llvm-stamp."
 
 [mentions."tests/ui/deriving/deriving-all-codegen.stdout"]